#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ip.h" #include "etherif.h" static Ether ether[MaxEther]; extern int ether2114xreset(Ether*); extern int elnk3reset(Ether*); extern int i82557reset(Ether*); extern int igbepnp(Ether *); extern int i82563pnp(Ether*); extern int i82598pnp(Ether*); extern int elnk3reset(Ether*); extern int ether589reset(Ether*); extern int ne2000reset(Ether*); extern int wd8003reset(Ether*); extern int ec2treset(Ether*); extern int amd79c970reset(Ether*); extern int rtl8139pnp(Ether*); extern int rtl8169pnp(Ether*); extern int ether83815reset(Ether*); extern int rhinepnp(Ether*); // extern int ga620pnp(Ether*); extern int dp83820pnp(Ether*); extern int m10gpnp(Ether*); extern int yukpnp(Ether*); struct { char *type; int (*reset)(Ether*); int noprobe; } ethercards[] = { // { "m10g", m10gpnp, 0, }, /* must be first; myri f/w bug leaves irq ringing */ { "21140", ether2114xreset, 0, }, { "2114x", ether2114xreset, 0, }, { "i82557", i82557reset, 0, }, { "i82563", i82563pnp, 0, }, { "igbe", igbepnp, 0, }, { "elnk3", elnk3reset, 0, }, { "3C509", elnk3reset, 0, }, { "3C575", elnk3reset, 0, }, { "3C589", ether589reset, 1, }, { "3C562", ether589reset, 1, }, { "589E", ether589reset, 1, }, { "NE2000", ne2000reset, 0, }, { "WD8003", wd8003reset, 1, }, { "EC2T", ec2treset, 0, }, { "AMD79C970", amd79c970reset, 0, }, { "RTL8139", rtl8139pnp, 0, }, { "RTL8169", rtl8169pnp, 0, }, { "83815", ether83815reset, 0, }, { "rhine", rhinepnp, 0, }, { "vt6102", rhinepnp, 0, }, { "vt6105m", rhinepnp, 0, }, /* until we have a 6105 boot driver */ // { "GA620", ga620pnp, 0, }, { "83820", dp83820pnp, 0, }, { "dp83820", dp83820pnp, 0, }, { "yuk", yukpnp, 0, }, { "i82598", i82598pnp, 0, }, { 0, } }; static void xetherdetach(void); int etherinit(void) { Ether *ctlr; int ctlrno, i, mask, n, x; if(nelem(ethercards) >= 8*sizeof mask) panic("ether: mask to small"); fmtinstall('E', eipfmt); etherdetach = xetherdetach; mask = 0; for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ ctlr = ðer[ctlrno]; memset(ctlr, 0, sizeof(Ether)); if(iniread && isaconfig("ether", ctlrno, ctlr) == 0) continue; for(n = 0; ethercards[n].type; n++){ if(!iniread){ if(ethercards[n].noprobe) continue; memset(ctlr, 0, sizeof(Ether)); strcpy(ctlr->type, ethercards[n].type); } else if(cistrcmp(ethercards[n].type, ctlr->type)) continue; ctlr->ctlrno = ctlrno; x = splhi(); if((*ethercards[n].reset)(ctlr)){ splx(x); if(iniread) break; else continue; } mask |= 1<irq == 2) ctlr->irq = 9; setvec(VectorPIC + ctlr->irq, ctlr->interrupt, ctlr); print("ether#%d: %s: port 0x%luX irq %lud", ctlr->ctlrno, ctlr->type, ctlr->port, ctlr->irq); if(ctlr->mem) print(" addr 0x%luX", ctlr->mem & ~KZERO); if(ctlr->size) print(" size 0x%luX", ctlr->size); print(": %E\n", ctlr->ea); if(ctlr->nrb == 0) ctlr->nrb = Nrb; ctlr->rb = ialloc(sizeof(RingBuf)*ctlr->nrb, 0); if(ctlr->ntb == 0) ctlr->ntb = Ntb; ctlr->tb = ialloc(sizeof(RingBuf)*ctlr->ntb, 0); ctlr->rh = 0; ctlr->ri = 0; for(i = 0; i < ctlr->nrb; i++) ctlr->rb[i].owner = Interface; ctlr->th = 0; ctlr->ti = 0; for(i = 0; i < ctlr->ntb; i++) ctlr->tb[i].owner = Host; ctlr->state = 1; /* card found */ splx(x); break; } } return mask; } void etherinitdev(int i, char *s) { sprint(s, "ether%d", i); } void etherprintdevs(int i) { print(" ether%d", i); } static Ether* attach(int ctlrno) { Ether *ctlr; if(ctlrno >= MaxEther || ether[ctlrno].state == 0) return 0; ctlr = ðer[ctlrno]; if(ctlr->state == 1){ /* card found? */ ctlr->state = 2; /* attaching */ (*ctlr->attach)(ctlr); } return ctlr; } static void xetherdetach(void) { Ether *ctlr; int ctlrno, x; x = splhi(); for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ ctlr = ðer[ctlrno]; if(ctlr->detach && ctlr->state != 0) /* found | attaching? */ ctlr->detach(ctlr); } splx(x); } uchar* etheraddr(int ctlrno) { Ether *ctlr; if((ctlr = attach(ctlrno)) == 0) return 0; return ctlr->ea; } static int wait(RingBuf* ring, uchar owner, int timo) { ulong start; start = m->ticks; while(TK2MS(m->ticks - start) < timo){ if(ring->owner != owner) return 1; /* * idling here cuts time to load 9pc.gz in a parallels vm * from 4 minutes to about 1 second. */ idle(); } return 0; } int etherrxpkt(int ctlrno, Etherpkt* pkt, int timo) { int n; Ether *ctlr; RingBuf *ring; if((ctlr = attach(ctlrno)) == 0) return 0; ring = &ctlr->rb[ctlr->rh]; if(wait(ring, Interface, timo) == 0){ if(debug) print("ether%d: rx timeout\n", ctlrno); return 0; } n = ring->len; memmove(pkt, ring->pkt, n); ring->owner = Interface; ctlr->rh = NEXT(ctlr->rh, ctlr->nrb); return n; } int etherrxflush(int ctlrno) { int n; Ether *ctlr; RingBuf *ring; if((ctlr = attach(ctlrno)) == 0) return 0; n = 0; for(;;){ ring = &ctlr->rb[ctlr->rh]; if(wait(ring, Interface, 100) == 0) break; ring->owner = Interface; ctlr->rh = NEXT(ctlr->rh, ctlr->nrb); n++; } return n; } int ethertxpkt(int ctlrno, Etherpkt* pkt, int len, int) { Ether *ctlr; RingBuf *ring; int s; if((ctlr = attach(ctlrno)) == 0) return 0; ring = &ctlr->tb[ctlr->th]; if(wait(ring, Interface, 1000) == 0){ print("ether%d: tx buffer timeout\n", ctlrno); return 0; } memmove(pkt->s, ctlr->ea, Eaddrlen); if(debug) print("%E to %E...\n", pkt->s, pkt->d); memmove(ring->pkt, pkt, len); if(len < ETHERMINTU){ memset(ring->pkt+len, 0, ETHERMINTU-len); len = ETHERMINTU; } ring->len = len; ring->owner = Interface; ctlr->th = NEXT(ctlr->th, ctlr->ntb); s = splhi(); (*ctlr->transmit)(ctlr); splx(s); return 1; } void toringbuf(Ether *e, void *u, int len) { RingBuf *rb; if(e->state < 1) return; rb = e->rb + e->ri; if (rb->owner == Interface){ if(interesting(u, len)){ rb->len = len; memmove(rb->pkt, u, rb->len); rb->owner = Host; e->ri = NEXT(e->ri, e->nrb); } }else print("%d: toringbuf: drop @ %d\n", e->ctlrno, e->ri); } Block* fromringbuf(Ether *e) { Block *b; RingBuf *tb; tb = e->tb + e->ti; b = allocb(tb->len); memmove(b->wp, tb->pkt, tb->len); memmove(b->wp+Eaddrlen, e->ea, Eaddrlen); b->wp += tb->len; return b; }