xref: /netbsd-src/sys/arch/emips/stand/common/enic.c (revision f41ff51f42bafa3a0ac1b49afd60b4bba1f7a295)
1*f41ff51fSandvar /*	$NetBSD: enic.c,v 1.5 2023/01/22 21:36:12 andvar Exp $	*/
25f7e80a8Spooka 
35f7e80a8Spooka /*-
45f7e80a8Spooka  * Copyright (c) 2010 The NetBSD Foundation, Inc.
55f7e80a8Spooka  * All rights reserved.
65f7e80a8Spooka  *
75f7e80a8Spooka  * This code was written by Alessandro Forin and Neil Pittman
85f7e80a8Spooka  * at Microsoft Research and contributed to The NetBSD Foundation
95f7e80a8Spooka  * by Microsoft Corporation.
105f7e80a8Spooka  *
115f7e80a8Spooka  * Redistribution and use in source and binary forms, with or without
125f7e80a8Spooka  * modification, are permitted provided that the following conditions
135f7e80a8Spooka  * are met:
145f7e80a8Spooka  * 1. Redistributions of source code must retain the above copyright
155f7e80a8Spooka  *    notice, this list of conditions and the following disclaimer.
165f7e80a8Spooka  * 2. Redistributions in binary form must reproduce the above copyright
175f7e80a8Spooka  *    notice, this list of conditions and the following disclaimer in the
185f7e80a8Spooka  *    documentation and/or other materials provided with the distribution.
195f7e80a8Spooka  *
205f7e80a8Spooka  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
215f7e80a8Spooka  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
225f7e80a8Spooka  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
235f7e80a8Spooka  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
245f7e80a8Spooka  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
255f7e80a8Spooka  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
265f7e80a8Spooka  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
275f7e80a8Spooka  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
285f7e80a8Spooka  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
295f7e80a8Spooka  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
305f7e80a8Spooka  * POSSIBILITY OF SUCH DAMAGE.
315f7e80a8Spooka  */
325f7e80a8Spooka 
335f7e80a8Spooka /* --------------------------------------------------------------------------
345f7e80a8Spooka  *
355f7e80a8Spooka  * Module:
365f7e80a8Spooka  *
375f7e80a8Spooka  *    enic.c
385f7e80a8Spooka  *
395f7e80a8Spooka  * Purpose:
405f7e80a8Spooka  *
415f7e80a8Spooka  *    Driver for the Microsoft eNIC (eMIPS system) Ethernet
425f7e80a8Spooka  *
435f7e80a8Spooka  * Author:
445f7e80a8Spooka  *    A. Forin (sandrof)
455f7e80a8Spooka  *
465f7e80a8Spooka  * References:
475f7e80a8Spooka  *    Internal Microsoft specifications, file eNIC_Design.docx titled
485f7e80a8Spooka  *    "eNIC: a simple Ethernet" Revision 4/30/99
495f7e80a8Spooka  *
505f7e80a8Spooka  *    Giano simulation module, file Peripherals\enic.cpp
515f7e80a8Spooka  *
525f7e80a8Spooka  *    Various other drivers I wrote for said hardware
535f7e80a8Spooka  * --------------------------------------------------------------------------
545f7e80a8Spooka  */
555f7e80a8Spooka 
565f7e80a8Spooka #include <sys/param.h>
575f7e80a8Spooka #include <sys/types.h>
585f7e80a8Spooka 
595f7e80a8Spooka #include <net/if_ether.h>
605f7e80a8Spooka #include <netinet/in.h>
615f7e80a8Spooka #include <netinet/in_systm.h>
625f7e80a8Spooka #include <netinet/ip.h>
635f7e80a8Spooka 
645f7e80a8Spooka #include <lib/libsa/stand.h>
655f7e80a8Spooka #include <lib/libsa/net.h>
665f7e80a8Spooka #include <lib/libsa/netif.h>
675f7e80a8Spooka #include <lib/libkern/libkern.h>
685f7e80a8Spooka 
69ebb0f5eaSmartin 
705f7e80a8Spooka #include <machine/emipsreg.h>
7160d0010eSchristos 
7260d0010eSchristos #include "start.h"
7360d0010eSchristos #include "common.h"
7460d0010eSchristos 
755f7e80a8Spooka #define the_enic ((struct _Enic *)ETHERNET_DEFAULT_ADDRESS)
765f7e80a8Spooka 
775f7e80a8Spooka /* forward declarations */
785f7e80a8Spooka static int  enicprobe (struct netif *, void *);
795f7e80a8Spooka static int  enicmatch (struct netif *, void *);
805f7e80a8Spooka static void enicinit (struct iodesc *, void *);
815f7e80a8Spooka static int  enicget (struct iodesc *, void *, size_t, saseconds_t);
825f7e80a8Spooka static int  enicput (struct iodesc *, void *, size_t);
835f7e80a8Spooka static void enicend (struct netif *);
845f7e80a8Spooka 
855f7e80a8Spooka #ifdef NET_DEBUG
865f7e80a8Spooka static void dump_packet(void *, int);
875f7e80a8Spooka #endif
885f7e80a8Spooka 
895f7e80a8Spooka /* BUGBUG do we have this? */
905f7e80a8Spooka #define kvtophys(_v_)  ((paddr_t)(_v_) & ~0x80000000)
915f7e80a8Spooka 
925f7e80a8Spooka #define rpostone(_r_,_p_,_s_) \
935f7e80a8Spooka     (_r_)->SizeAndFlags = ES_F_RECV | (_s_); \
945f7e80a8Spooka     (_r_)->BufferAddressHi32 = 0; \
955f7e80a8Spooka     (_r_)->BufferAddressLo32 = _p_;
965f7e80a8Spooka #define tpostone(_r_,_p_,_s_) \
975f7e80a8Spooka     (_r_)->SizeAndFlags = ES_F_XMIT | (_s_); \
985f7e80a8Spooka     (_r_)->BufferAddressHi32 = 0; \
995f7e80a8Spooka     (_r_)->BufferAddressLo32 = _p_;
1005f7e80a8Spooka 
1015f7e80a8Spooka 
1025f7e80a8Spooka /* Send a packet
1035f7e80a8Spooka  */
10460d0010eSchristos static int
enic_putpkt(struct _Enic * regs,void * buf,int bytes)10560d0010eSchristos enic_putpkt(struct _Enic *regs, void *buf, int bytes)
1065f7e80a8Spooka {
1075f7e80a8Spooka     paddr_t phys = kvtophys(buf);
1085f7e80a8Spooka 
1095f7e80a8Spooka     tpostone(regs,phys,bytes);
1105f7e80a8Spooka 
1115f7e80a8Spooka     /* poll till done? */
1125f7e80a8Spooka     //printf("\tenic: sent %d at %x\n",bytes,phys);
1135f7e80a8Spooka     return bytes;
1145f7e80a8Spooka }
1155f7e80a8Spooka 
1165f7e80a8Spooka /* Get a packet
1175f7e80a8Spooka  */
11860d0010eSchristos static int
enic_getpkt(struct _Enic * regs,void * buf,int bytes,int timeo)11960d0010eSchristos enic_getpkt(struct _Enic *regs, void *buf, int bytes, int timeo)
1205f7e80a8Spooka {
1215f7e80a8Spooka     paddr_t phys;
1225f7e80a8Spooka     unsigned int isr, saf, hi, lo, fl;
1235f7e80a8Spooka 
1245f7e80a8Spooka     phys = kvtophys(buf);
1255f7e80a8Spooka     rpostone(regs,phys,bytes);
1265f7e80a8Spooka 
1275f7e80a8Spooka     //printf("\tenic: recv %d at %x\n",bytes,phys);
1285f7e80a8Spooka 
1295f7e80a8Spooka     /* poll till we get some */
1305f7e80a8Spooka     timeo += getsecs();
1315f7e80a8Spooka 
1325f7e80a8Spooka     for (;;) {
1335f7e80a8Spooka 
1345f7e80a8Spooka         /* anything there? */
1355f7e80a8Spooka         isr = regs->Control;
1365f7e80a8Spooka 
1375f7e80a8Spooka         if (isr & EC_ERROR) {
1385f7e80a8Spooka             printf("enic: internal error %x\n", isr);
1395f7e80a8Spooka             regs->Control = EC_RESET;
1405f7e80a8Spooka             break;
1415f7e80a8Spooka         }
1425f7e80a8Spooka 
1435f7e80a8Spooka 		//printf("isr %x ",isr);
1445f7e80a8Spooka 
1455f7e80a8Spooka         if ((isr & (EC_DONE|EC_OF_EMPTY)) == EC_DONE) {
1465f7e80a8Spooka 
1475f7e80a8Spooka             /* beware, order matters */
1485f7e80a8Spooka             saf = regs->SizeAndFlags;
1495f7e80a8Spooka             hi = regs->BufferAddressHi32; /* BUGBUG 64bit */
1505f7e80a8Spooka             lo = regs->BufferAddressLo32; /* this pops the fifo */
15160d0010eSchristos 	    __USE(hi);
1525f7e80a8Spooka 
1535f7e80a8Spooka             fl = saf & (ES_F_MASK &~ ES_F_DONE);
1545f7e80a8Spooka 
1555f7e80a8Spooka             if (fl == ES_F_RECV)
1565f7e80a8Spooka             {
1575f7e80a8Spooka                 /* and we are done? */
1585f7e80a8Spooka                 if (phys == lo)
1595f7e80a8Spooka                     return saf & ES_S_MASK;
1605f7e80a8Spooka             } else if (fl == ES_F_XMIT)
1615f7e80a8Spooka             {
1625f7e80a8Spooka                 ;/* nothing */
1635f7e80a8Spooka             } else if (fl != ES_F_CMD)
1645f7e80a8Spooka             {
165ebb0f5eaSmartin                 printf("enic: invalid saf=x%x (lo=%x, hi=%x)\n", saf, lo, hi);
1665f7e80a8Spooka             }
1675f7e80a8Spooka         }
1685f7e80a8Spooka 
1695f7e80a8Spooka         if (getsecs() >= timeo) {
1705f7e80a8Spooka             //printf("enic: timeout\n");
1715f7e80a8Spooka             regs->Control = EC_RESET;
1725f7e80a8Spooka             break;
1735f7e80a8Spooka         }
1745f7e80a8Spooka     }
1755f7e80a8Spooka 
1765f7e80a8Spooka     return 0;
1775f7e80a8Spooka }
1785f7e80a8Spooka 
1795f7e80a8Spooka /*
1805f7e80a8Spooka  */
enic_getmac(struct _Enic * regs,uint8_t * mac)1815f7e80a8Spooka static int enic_getmac(struct _Enic *regs, uint8_t *mac)
1825f7e80a8Spooka {
1835f7e80a8Spooka     uint8_t buffer[8];
1845f7e80a8Spooka     paddr_t phys = kvtophys(&buffer[0]);
1855f7e80a8Spooka     int i;
1865f7e80a8Spooka 
1875f7e80a8Spooka     regs->Control = EC_RESET;
1885f7e80a8Spooka     Delay(1);
1895f7e80a8Spooka     regs->Control = regs->Control & (~EC_RXDIS);
1905f7e80a8Spooka 
1915f7e80a8Spooka     buffer[0] = ENIC_CMD_GET_ADDRESS;
1925f7e80a8Spooka 
1935f7e80a8Spooka 	//printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
1945f7e80a8Spooka 
1955f7e80a8Spooka     regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD;
1965f7e80a8Spooka     regs->BufferAddressHi32 = 0;
1975f7e80a8Spooka     regs->BufferAddressLo32 = phys; /* go! */
1985f7e80a8Spooka 
1995f7e80a8Spooka     for (i = 0; i < 100; i++) {
2005f7e80a8Spooka         Delay(100);
2015f7e80a8Spooka         if (0 == (regs->Control & EC_OF_EMPTY))
2025f7e80a8Spooka             break;
2035f7e80a8Spooka     }
2045f7e80a8Spooka     if (i == 100)
2055f7e80a8Spooka         return 0;
2065f7e80a8Spooka 
2075f7e80a8Spooka 	//printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
2085f7e80a8Spooka 
2095f7e80a8Spooka     memcpy(mac,buffer,6);
2105f7e80a8Spooka     return 1;
2115f7e80a8Spooka }
2125f7e80a8Spooka 
2135f7e80a8Spooka /* Exported interface
2145f7e80a8Spooka  */
21560d0010eSchristos int
enic_present(int unit)21660d0010eSchristos enic_present(int unit)
2175f7e80a8Spooka {
2185f7e80a8Spooka     if ((unit != 0) || (the_enic->Tag != PMTTAG_ETHERNET))
2195f7e80a8Spooka 	return 0;
2205f7e80a8Spooka 
2215f7e80a8Spooka     return 1;
2225f7e80a8Spooka }
2235f7e80a8Spooka 
2245f7e80a8Spooka extern int try_bootp;
2255f7e80a8Spooka 
2265f7e80a8Spooka extern struct netif_stats       enicstats[];
2275f7e80a8Spooka struct netif_dif enicifs[] = {
2285f7e80a8Spooka /*	dif_unit	dif_nsel	dif_stats		dif_private	*/
2295f7e80a8Spooka {	0,			1,			&enicstats[0],	the_enic,		},
2305f7e80a8Spooka };
2315f7e80a8Spooka #define NENICIFS (sizeof(enicifs) / sizeof(enicifs[0]))
2325f7e80a8Spooka struct netif_stats enicstats[NENICIFS];
2335f7e80a8Spooka 
2345f7e80a8Spooka struct netif_driver enic_netif_driver = {
2355f7e80a8Spooka 	"enic",				/* netif_bname */
2365f7e80a8Spooka 	enicmatch,			/* netif_match */
2375f7e80a8Spooka 	enicprobe,			/* netif_probe */
2385f7e80a8Spooka 	enicinit,			/* netif_init */
2395f7e80a8Spooka 	enicget,			/* netif_get */
2405f7e80a8Spooka 	enicput,			/* netif_put */
2415f7e80a8Spooka 	enicend,			/* netif_end */
2425f7e80a8Spooka 	enicifs,			/* netif_ifs */
2435f7e80a8Spooka 	NENICIFS			/* netif_nifs */
2445f7e80a8Spooka };
2455f7e80a8Spooka 
2465f7e80a8Spooka static int
enicmatch(struct netif * nif,void * machdep_hint)2475f7e80a8Spooka enicmatch(struct netif *nif, void *machdep_hint)
2485f7e80a8Spooka {
2495f7e80a8Spooka 	return (1);
2505f7e80a8Spooka }
2515f7e80a8Spooka 
2525f7e80a8Spooka /* NB: We refuse anything but unit==0
2535f7e80a8Spooka  */
2545f7e80a8Spooka static int
enicprobe(struct netif * nif,void * machdep_hint)2555f7e80a8Spooka enicprobe(struct netif *nif, void *machdep_hint)
2565f7e80a8Spooka {
2575f7e80a8Spooka     int unit = nif->nif_unit;
2585f7e80a8Spooka #ifdef NET_DEBUG
2595f7e80a8Spooka 	printf("enic%d: probe\n", unit);
2605f7e80a8Spooka #endif
2615f7e80a8Spooka 	return (enic_present(unit) ? 0 : 1);
2625f7e80a8Spooka }
2635f7e80a8Spooka 
2645f7e80a8Spooka static void
enicinit(struct iodesc * desc,void * machdep_hint)2655f7e80a8Spooka enicinit(struct iodesc *desc, void *machdep_hint)
2665f7e80a8Spooka {
2675f7e80a8Spooka #ifdef NET_DEBUG
2685f7e80a8Spooka     struct netif *nif = (struct netif *)desc->io_netif;
2695f7e80a8Spooka     int unit = nif->nif_driver->netif_ifs->dif_unit;
2705f7e80a8Spooka 	printf("enic%d: init %s\n", unit, machdep_hint);
2715f7e80a8Spooka #endif
2725f7e80a8Spooka 
2735f7e80a8Spooka     /*
274*f41ff51fSandvar      * Yes we want DHCP and this is our MAC
2755f7e80a8Spooka      */
2765f7e80a8Spooka 	try_bootp = 1;
2775f7e80a8Spooka     enic_getmac(the_enic,desc->myea);
2785f7e80a8Spooka 	desc->xid = 0xfe63d095;
2795f7e80a8Spooka }
2805f7e80a8Spooka 
2815f7e80a8Spooka 
2825f7e80a8Spooka static int
enicput(struct iodesc * desc,void * pkt,size_t len)2835f7e80a8Spooka enicput(struct iodesc *desc, void *pkt,	size_t len)
2845f7e80a8Spooka {
2855f7e80a8Spooka #ifdef NET_DEBUG
2865f7e80a8Spooka 	if (debug)
2875f7e80a8Spooka 		dump_packet(pkt,len);
2885f7e80a8Spooka #endif
2895f7e80a8Spooka 
2905f7e80a8Spooka     return enic_putpkt(the_enic,pkt,len);
2915f7e80a8Spooka }
2925f7e80a8Spooka 
2935f7e80a8Spooka 
2945f7e80a8Spooka int
enicget(struct iodesc * desc,void * pkt,size_t len,saseconds_t timeout)2955f7e80a8Spooka enicget(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
2965f7e80a8Spooka {
2975f7e80a8Spooka #ifdef NET_DEBUG
2985f7e80a8Spooka 	printf("enicget: %lx %lx\n",len,timeout);
2995f7e80a8Spooka #endif
3005f7e80a8Spooka     return enic_getpkt(the_enic,pkt,len,timeout);
3015f7e80a8Spooka }
3025f7e80a8Spooka 
3035f7e80a8Spooka 
3045f7e80a8Spooka static void
enicend(struct netif * nif)3055f7e80a8Spooka enicend(struct netif *nif)
3065f7e80a8Spooka {
3075f7e80a8Spooka     /* BUGBUG stop it in reset? */
3085f7e80a8Spooka }
3095f7e80a8Spooka 
3105f7e80a8Spooka #ifdef NET_DEBUG
dump_packet(void * pkt,int len)3115f7e80a8Spooka static void dump_packet(void *pkt, int len)
3125f7e80a8Spooka {
3135f7e80a8Spooka 	struct ether_header *eh = (struct ether_header *)pkt;
3145f7e80a8Spooka 	struct ip *ih = (struct ip *)(eh + 1);
3155f7e80a8Spooka 
3165f7e80a8Spooka 	printf("ether_dhost = %s\n", ether_sprintf(eh->ether_dhost));
3175f7e80a8Spooka 	printf("ether_shost = %s\n", ether_sprintf(eh->ether_shost));
3185f7e80a8Spooka 	printf("ether_type = 0x%x\n", ntohs(eh->ether_type));
3195f7e80a8Spooka 
3205f7e80a8Spooka 	if (ntohs(eh->ether_type) == 0x0800) {
3215f7e80a8Spooka 		printf("ip packet version %d\n", ih->ip_v);
3225f7e80a8Spooka 		printf("source ip: 0x%x\n", ih->ip_src.s_addr);
3235f7e80a8Spooka 		printf("dest ip: 0x%x\n", ih->ip_dst.s_addr);
3245f7e80a8Spooka 
3255f7e80a8Spooka 	}
3265f7e80a8Spooka }
3275f7e80a8Spooka #endif
328