diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/boot/pc/ether.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/boot/pc/ether.c')
-rwxr-xr-x | sys/src/boot/pc/ether.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/sys/src/boot/pc/ether.c b/sys/src/boot/pc/ether.c new file mode 100755 index 000000000..1e7543fbd --- /dev/null +++ b/sys/src/boot/pc/ether.c @@ -0,0 +1,331 @@ +#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 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*); + +struct { + char *type; + int (*reset)(Ether*); + int noprobe; +} ethercards[] = { + { "21140", ether2114xreset, 0, }, + { "2114x", ether2114xreset, 0, }, + { "i82557", i82557reset, 0, }, + { "igbe", igbepnp, 0, }, + { "i82563",i82563pnp, 0, }, + { "igbepcie",i82563pnp, 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, }, + + { 0, } +}; + +static void xetherdetach(void); + +static void +fakeintrs(Alarm *) +{ + int ctlrno; + Ether *eth; + + for(ctlrno = 0; ctlrno < MaxEther; ctlrno++) { + eth = ðer[ctlrno]; + if (eth->interrupt) + eth->interrupt(nil, eth); + } + alarm(TK2MS(1), fakeintrs, nil); +} + +/* + * terrible temporary hack for 82575. + * if we do actually get the right interrupts, this quickly floods + * the alarm table and we panic, so use with caution. + */ +static void +startfakeintrs(void) +{ + static int first = 1; + + if (first) { + first = 0; + fakeintrs(nil); + } +} + +int +etherinit(void) +{ + Ether *ctlr; + int ctlrno, i, mask, n, x; + + fmtinstall('E', eipfmt); + + if (getconf("*fakeintrs") != nil || getconf("*9loadfakeintrs") != nil) + startfakeintrs(); + 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; + } + + ctlr->state = 1; /* card found */ + mask |= 1<<ctlrno; + if(ctlr->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; + + splx(x); + break; + } + } + if (mask == 0) { + print("no ethernet interfaces recognised\n"); + pcihinv(nil, Pcibcnet); + } + 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; +} |