Home | History | Annotate | Line # | Download | only in common
enic.c revision 1.2
      1 /*	$NetBSD: enic.c,v 1.2 2014/02/24 08:00:52 martin Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code was written by Alessandro Forin and Neil Pittman
      8  * at Microsoft Research and contributed to The NetBSD Foundation
      9  * by Microsoft Corporation.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /* --------------------------------------------------------------------------
     34  *
     35  * Module:
     36  *
     37  *    enic.c
     38  *
     39  * Purpose:
     40  *
     41  *    Driver for the Microsoft eNIC (eMIPS system) Ethernet
     42  *
     43  * Author:
     44  *    A. Forin (sandrof)
     45  *
     46  * References:
     47  *    Internal Microsoft specifications, file eNIC_Design.docx titled
     48  *    "eNIC: a simple Ethernet" Revision 4/30/99
     49  *
     50  *    Giano simulation module, file Peripherals\enic.cpp
     51  *
     52  *    Various other drivers I wrote for said hardware
     53  * --------------------------------------------------------------------------
     54  */
     55 
     56 #include <sys/param.h>
     57 #include <sys/types.h>
     58 
     59 #include <net/if_ether.h>
     60 #include <netinet/in.h>
     61 #include <netinet/in_systm.h>
     62 #include <netinet/ip.h>
     63 
     64 #include <lib/libsa/stand.h>
     65 #include <lib/libsa/net.h>
     66 #include <lib/libsa/netif.h>
     67 #include <lib/libkern/libkern.h>
     68 
     69 #include "start.h"
     70 
     71 #include <machine/emipsreg.h>
     72 #define the_enic ((struct _Enic *)ETHERNET_DEFAULT_ADDRESS)
     73 
     74 /* forward declarations */
     75 static int  enicprobe (struct netif *, void *);
     76 static int  enicmatch (struct netif *, void *);
     77 static void enicinit (struct iodesc *, void *);
     78 static int  enicget (struct iodesc *, void *, size_t, saseconds_t);
     79 static int  enicput (struct iodesc *, void *, size_t);
     80 static void enicend (struct netif *);
     81 int enic_getpkt(struct _Enic *regs, void *buf, int bytes, int timeo);
     82 int enic_present(int unit);
     83 
     84 #ifdef NET_DEBUG
     85 static void dump_packet(void *, int);
     86 #endif
     87 
     88 /* BUGBUG do we have this? */
     89 #define kvtophys(_v_)  ((paddr_t)(_v_) & ~0x80000000)
     90 
     91 #define rpostone(_r_,_p_,_s_) \
     92     (_r_)->SizeAndFlags = ES_F_RECV | (_s_); \
     93     (_r_)->BufferAddressHi32 = 0; \
     94     (_r_)->BufferAddressLo32 = _p_;
     95 #define tpostone(_r_,_p_,_s_) \
     96     (_r_)->SizeAndFlags = ES_F_XMIT | (_s_); \
     97     (_r_)->BufferAddressHi32 = 0; \
     98     (_r_)->BufferAddressLo32 = _p_;
     99 
    100 
    101 /* Send a packet
    102  */
    103 static int enic_putpkt(struct _Enic *regs, void *buf, int bytes)
    104 {
    105     paddr_t phys = kvtophys(buf);
    106 
    107     tpostone(regs,phys,bytes);
    108 
    109     /* poll till done? */
    110     //printf("\tenic: sent %d at %x\n",bytes,phys);
    111     return bytes;
    112 }
    113 
    114 /* Get a packet
    115  */
    116 int enic_getpkt(struct _Enic *regs, void *buf, int bytes, int timeo)
    117 {
    118     paddr_t phys;
    119     unsigned int isr, saf, hi, lo, fl;
    120 
    121     phys = kvtophys(buf);
    122     rpostone(regs,phys,bytes);
    123 
    124     //printf("\tenic: recv %d at %x\n",bytes,phys);
    125 
    126     /* poll till we get some */
    127     timeo += getsecs();
    128 
    129     for (;;) {
    130 
    131         /* anything there? */
    132         isr = regs->Control;
    133 
    134         if (isr & EC_ERROR) {
    135             printf("enic: internal error %x\n", isr);
    136             regs->Control = EC_RESET;
    137             break;
    138         }
    139 
    140 		//printf("isr %x ",isr);
    141 
    142         if ((isr & (EC_DONE|EC_OF_EMPTY)) == EC_DONE) {
    143 
    144             /* beware, order matters */
    145             saf = regs->SizeAndFlags;
    146             hi  = regs->BufferAddressHi32; /* BUGBUG 64bit */
    147             lo  = regs->BufferAddressLo32; /* this pops the fifo */
    148 
    149             fl = saf & (ES_F_MASK &~ ES_F_DONE);
    150 
    151             if (fl == ES_F_RECV)
    152             {
    153                 /* and we are done? */
    154                 if (phys == lo)
    155                     return saf & ES_S_MASK;
    156             } else if (fl == ES_F_XMIT)
    157             {
    158                 ;/* nothing */
    159             } else if (fl != ES_F_CMD)
    160             {
    161                 printf("enic: invalid saf=x%x (lo=%x, hi=%x)\n", saf, lo, hi);
    162             }
    163         }
    164 
    165         if (getsecs() >= timeo) {
    166             //printf("enic: timeout\n");
    167             regs->Control = EC_RESET;
    168             break;
    169         }
    170     }
    171 
    172     return 0;
    173 }
    174 
    175 /*
    176  */
    177 static int enic_getmac(struct _Enic *regs, uint8_t *mac)
    178 {
    179     uint8_t buffer[8];
    180     paddr_t phys = kvtophys(&buffer[0]);
    181     int i;
    182 
    183     regs->Control = EC_RESET;
    184     Delay(1);
    185 	regs->Control = regs->Control & (~EC_RXDIS);
    186 
    187     buffer[0] = ENIC_CMD_GET_ADDRESS;
    188 
    189 	//printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
    190 
    191     regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD;
    192     regs->BufferAddressHi32 = 0;
    193     regs->BufferAddressLo32 = phys; /* go! */
    194 
    195     for (i = 0; i < 100; i++) {
    196         Delay(100);
    197         if (0 == (regs->Control & EC_OF_EMPTY))
    198             break;
    199     }
    200     if (i == 100)
    201         return 0;
    202 
    203 	//printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
    204 
    205     memcpy(mac,buffer,6);
    206     return 1;
    207 }
    208 
    209 /* Exported interface
    210  */
    211 int enic_present(int unit)
    212 {
    213 	if ((unit != 0) || (the_enic->Tag != PMTTAG_ETHERNET))
    214         return 0;
    215 
    216     return 1;
    217 }
    218 
    219 extern int try_bootp;
    220 
    221 extern struct netif_stats       enicstats[];
    222 struct netif_dif enicifs[] = {
    223 /*	dif_unit	dif_nsel	dif_stats		dif_private	*/
    224 {	0,			1,			&enicstats[0],	the_enic,		},
    225 };
    226 #define NENICIFS (sizeof(enicifs) / sizeof(enicifs[0]))
    227 struct netif_stats enicstats[NENICIFS];
    228 
    229 struct netif_driver enic_netif_driver = {
    230 	"enic",				/* netif_bname */
    231 	enicmatch,			/* netif_match */
    232 	enicprobe,			/* netif_probe */
    233 	enicinit,			/* netif_init */
    234 	enicget,			/* netif_get */
    235 	enicput,			/* netif_put */
    236 	enicend,			/* netif_end */
    237 	enicifs,			/* netif_ifs */
    238 	NENICIFS			/* netif_nifs */
    239 };
    240 
    241 static int
    242 enicmatch(struct netif *nif, void *machdep_hint)
    243 {
    244 	return (1);
    245 }
    246 
    247 /* NB: We refuse anything but unit==0
    248  */
    249 static int
    250 enicprobe(struct netif *nif, void *machdep_hint)
    251 {
    252     int unit = nif->nif_unit;
    253 #ifdef NET_DEBUG
    254 	printf("enic%d: probe\n", unit);
    255 #endif
    256 	return (enic_present(unit) ? 0 : 1);
    257 }
    258 
    259 static void
    260 enicinit(struct iodesc *desc, void *machdep_hint)
    261 {
    262 #ifdef NET_DEBUG
    263     struct netif *nif = (struct netif *)desc->io_netif;
    264     int unit = nif->nif_driver->netif_ifs->dif_unit;
    265 	printf("enic%d: init %s\n", unit, machdep_hint);
    266 #endif
    267 
    268     /*
    269      * Yes we wan tDHCP adn this is our MAC
    270      */
    271 	try_bootp = 1;
    272     enic_getmac(the_enic,desc->myea);
    273 	desc->xid = 0xfe63d095;
    274 }
    275 
    276 
    277 static int
    278 enicput(struct iodesc *desc, void *pkt,	size_t len)
    279 {
    280 #ifdef NET_DEBUG
    281 	if (debug)
    282 		dump_packet(pkt,len);
    283 #endif
    284 
    285     return enic_putpkt(the_enic,pkt,len);
    286 }
    287 
    288 
    289 int
    290 enicget(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
    291 {
    292 #ifdef NET_DEBUG
    293 	printf("enicget: %lx %lx\n",len,timeout);
    294 #endif
    295     return enic_getpkt(the_enic,pkt,len,timeout);
    296 }
    297 
    298 
    299 static void
    300 enicend(struct netif *nif)
    301 {
    302     /* BUGBUG stop it in reset? */
    303 }
    304 
    305 #ifdef NET_DEBUG
    306 static void dump_packet(void *pkt, int len)
    307 {
    308 	struct ether_header *eh = (struct ether_header *)pkt;
    309 	struct ip *ih = (struct ip *)(eh + 1);
    310 
    311 	printf("ether_dhost = %s\n", ether_sprintf(eh->ether_dhost));
    312 	printf("ether_shost = %s\n", ether_sprintf(eh->ether_shost));
    313 	printf("ether_type = 0x%x\n", ntohs(eh->ether_type));
    314 
    315 	if (ntohs(eh->ether_type) == 0x0800) {
    316 		printf("ip packet version %d\n", ih->ip_v);
    317 		printf("source ip: 0x%x\n", ih->ip_src.s_addr);
    318 		printf("dest ip: 0x%x\n", ih->ip_dst.s_addr);
    319 
    320 	}
    321 }
    322 #endif
    323