X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=sys%2Fsrc%2F9%2Fpc%2Fether82563.c;h=7d62e735b1cb650a6fbd34c63b47857fdfc24fcf;hb=e38f75fc45bba789ceea05d5e62f1d8662bf508b;hp=d7f07b75bbccbe7e2933bfd51dc9371b90b55834;hpb=eddc8dea860e8ddc77761d2b61b58ff843009698;p=plan9front.git diff --git a/sys/src/9/pc/ether82563.c b/sys/src/9/pc/ether82563.c index d7f07b75b..7d62e735b 100644 --- a/sys/src/9/pc/ether82563.c +++ b/sys/src/9/pc/ether82563.c @@ -11,8 +11,7 @@ #include "io.h" #include "../port/error.h" #include "../port/netif.h" - -#include "etherif.h" +#include "../port/etherif.h" /* * note: the 82575, 82576 and 82580 are operated using registers aliased @@ -105,6 +104,9 @@ enum { Torl = 0xC0/4, /* Total Octets Received */ Totl = 0xC8/4, /* Total Octets Transmitted */ Nstatistics = 0x124/4, + + /* iNVM (i211) */ + Invmdata0 = 0x12120, }; enum { /* Ctrl */ @@ -128,6 +130,7 @@ enum { /* Status */ enum { /* Eec */ Nvpres = 1<<8, Autord = 1<<9, + Flupd = 1<<19, Sec1val = 1<<22, }; @@ -169,6 +172,9 @@ enum { /* Mdic */ enum { /* phy interface */ Phyctl = 0, /* phy ctl register */ + Physr = 1, /* phy status register */ + Phyid1 = 2, /* phy id1 */ + Phyid2 = 3, /* phy id2 */ Phyisr = 19, /* 82563 phy interrupt status register */ Phylhr = 19, /* 8257[12] link health register */ Physsr = 17, /* phy secondary status register */ @@ -416,7 +422,6 @@ enum { Ntd = 128, /* power of two */ Nrb = 512+512, /* private receive buffers per Ctlr */ Rbalign = BY2PG, /* rx buffer alignment */ - Npool = 8, }; /* @@ -441,6 +446,10 @@ enum { i82579, i82580, i82583, + i210, + i217, + i218, + i219, i350, Nctlrtype, }; @@ -452,35 +461,41 @@ enum { Fpba = 1<<3, Fflashea= 1<<4, F79phy = 1<<5, + Fnofct = 1<<6, + Fbadcsum= 1<<7, + Fnofca = 1<<8, }; typedef struct Ctlrtype Ctlrtype; struct Ctlrtype { - int type; + char *name; int mtu; int flag; - char *name; }; static Ctlrtype cttab[Nctlrtype] = { - i82563, 9014, Fpba, "i82563", - i82566, 1514, Fload, "i82566", - i82567, 9234, Fload, "i82567", - i82567m, 1514, Fload, "i82567m", - i82571, 9234, Fpba, "i82571", - i82572, 9234, Fpba, "i82572", - i82573, 8192, Fert, "i82573", /* terrible perf above 8k */ - i82574, 9018, 0, "i82574", - i82575, 9728, F75|Fflashea, "i82575", - i82576, 9728, F75, "i82576", - i82577, 4096, Fload|Fert, "i82577", - i82577m, 1514, Fload|Fert, "i82577", - i82578, 4096, Fload|Fert, "i82578", - i82578m, 1514, Fload|Fert, "i82578", - i82579, 9018, Fload|Fert|F79phy, "i82579", - i82580, 9728, F75|F79phy, "i82580", - i82583, 1514, 0, "i82583", - i350, 9728, F75|F79phy, "i350", +[i82563] "i82563", 9014, Fpba, +[i82566] "i82566", 1514, Fload, +[i82567] "i82567", 9234, Fload, +[i82567m] "i82567m", 1514, Fload, +[i82571] "i82571", 9234, Fpba, +[i82572] "i82572", 9234, Fpba, +[i82573] "i82573", 8192, Fert|Fbadcsum, /* terrible perf above 8k */ +[i82574] "i82574", 9018, 0, +[i82575] "i82575", 9728, F75|Fflashea, +[i82576] "i82576", 9728, F75, +[i82577] "i82577", 4096, Fload|Fert, +[i82577m] "i82577", 1514, Fload|Fert, +[i82578] "i82578", 4096, Fload|Fert, +[i82578m] "i82578", 1514, Fload|Fert, +[i82579] "i82579", 9018, Fload|Fert|F79phy|Fnofct, +[i82580] "i82580", 9728, F75|F79phy, +[i82583] "i82583", 1514, 0, +[i210] "i210", 9728, F75|Fnofct|Fert, +[i217] "i217", 2048, Fload|Fert|F79phy|Fnofct|Fnofca|Fbadcsum,/* 9018, but unstable above 2k */ +[i218] "i218", 9018, Fload|Fert|F79phy|Fnofct|Fnofca|Fbadcsum, +[i219] "i219", 9018, Fload|Fert|F79phy|Fnofct|Fnofca|Fbadcsum, +[i350] "i350", 9728, F75|F79phy|Fnofct, }; typedef void (*Freefn)(Block*); @@ -492,14 +507,13 @@ struct Ctlr { Ctlr *next; int active; int type; - int pool; u16int eeprom[0x40]; QLock alock; /* attach */ void *alloc; /* receive/transmit descriptors */ int nrd; int ntd; - uint rbsz; + int rbsz; u32int *nic; Lock imlock; @@ -549,31 +563,11 @@ struct Ctlr { u32int pba; /* packet buffer allocation */ }; -typedef struct Rbpool Rbpool; -struct Rbpool { - union { - struct { - Lock; - Block *b; - uint nstarve; - uint nwakey; - uint starve; - Rendez; - }; - uchar pad[128]; /* cacheline */ - }; - - Block *x; - uint nfast; - uint nslow; -}; - #define csr32r(c, r) (*((c)->nic+((r)/4))) #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v)) static Ctlr *i82563ctlrhead; static Ctlr *i82563ctlrtail; -static Rbpool rbtab[Npool]; static char *statistics[Nstatistics] = { "CRC Error", @@ -664,7 +658,6 @@ i82563ifstat(Ether *edev, void *a, long n, ulong offset) int i, r; uvlong tuvl, ruvl; Ctlr *ctlr; - Rbpool *b; p = s = smalloc(READSTR); e = p + READSTR; @@ -717,20 +710,17 @@ i82563ifstat(Ether *edev, void *a, long n, ulong offset) p = seprint(p, e, "txdctl: %.8ux\n", csr32r(ctlr, Txdctl)); p = seprint(p, e, "pba: %.8ux\n", ctlr->pba); - b = rbtab + ctlr->pool; - p = seprint(p, e, "pool: fast %ud slow %ud nstarve %ud nwakey %ud starve %ud\n", - b->nfast, b->nslow, b->nstarve, b->nwakey, b->starve); p = seprint(p, e, "speeds: 10:%ud 100:%ud 1000:%ud ?:%ud\n", ctlr->speeds[0], ctlr->speeds[1], ctlr->speeds[2], ctlr->speeds[3]); p = seprint(p, e, "type: %s\n", cname(ctlr)); -// p = seprint(p, e, "eeprom:"); -// for(i = 0; i < 0x40; i++){ -// if(i && ((i & 7) == 0)) -// p = seprint(p, e, "\n "); -// p = seprint(p, e, " %4.4ux", ctlr->eeprom[i]); -// } -// p = seprint(p, e, "\n"); + p = seprint(p, e, "eeprom:"); + for(i = 0; i < 0x40; i++){ + if(i && ((i & 7) == 0)) + p = seprint(p, e, "\n "); + p = seprint(p, e, " %4.4ux", ctlr->eeprom[i]); + } + p = seprint(p, e, "\n"); USED(p); n = readstr(offset, a, n, s); @@ -769,10 +759,26 @@ i82563multicast(void *arg, uchar *addr, int on) edev = arg; ctlr = edev->ctlr; - x = addr[5]>>1; - if(ctlr->type == i82566) - x &= 31; - bit = ((addr[5] & 1)<<4)|(addr[4]>>4); + switch(ctlr->type){ + case i82566: + case i82567: + case i82567m: + case i82577: + case i82577m: + case i82579: + case i217: + case i218: + case i219: + bit = (addr[5]<<2)|(addr[4]>>6); + x = (bit>>5) & 31; + break; + default: + bit = (addr[5]<<4)|(addr[4]>>4); + x = (bit>>5) & 127; + break; + } + bit &= 31; + /* * multiple ether addresses can hash to the same filter bit, * so it's never safe to clear a filter bit. @@ -782,149 +788,10 @@ i82563multicast(void *arg, uchar *addr, int on) */ if(on) ctlr->mta[x] |= 1<mta[x] &= ~(1<mta[x]); } -static int -icansleep(void *v) -{ - Rbpool *p; - int r; - - p = v; - ilock(p); - r = p->starve == 0; - iunlock(p); - - return r; -} - -static Block* -i82563rballoc(Rbpool *p) -{ - Block *b; - - for(;;){ - if((b = p->x) != nil){ - p->nfast++; - p->x = b->next; - b->next = nil; - _xinc(&b->ref); - return b; - } - - ilock(p); - b = p->b; - p->b = nil; - if(b == nil){ - p->nstarve++; - iunlock(p); - return nil; - } - p->nslow++; - iunlock(p); - p->x = b; - } -} - -static void -rbfree(Block *b, int t) -{ - Rbpool *p; - - p = rbtab + t; - b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, Rbalign); - b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck); - - ilock(p); - b->next = p->b; - p->b = b; - if(p->starve){ - if(0) - iprint("wakey %d; %d %d\n", t, p->nstarve, p->nwakey); - p->nwakey++; - p->starve = 0; - wakeup(p); - } - iunlock(p); -} - -static void -rbfree0(Block *b) -{ - rbfree(b, 0); -} - -static void -rbfree1(Block *b) -{ - rbfree(b, 1); -} - -static void -rbfree2(Block *b) -{ - rbfree(b, 2); -} - -static void -rbfree3(Block *b) -{ - rbfree(b, 3); -} - -static void -rbfree4(Block *b) -{ - rbfree(b, 4); -} - -static void -rbfree5(Block *b) -{ - rbfree(b, 5); -} - -static void -rbfree6(Block *b) -{ - rbfree(b, 6); -} - -static void -rbfree7(Block *b) -{ - rbfree(b, 7); -} - -static Freefn freetab[Npool] = { - rbfree0, - rbfree1, - rbfree2, - rbfree3, - rbfree4, - rbfree5, - rbfree6, - rbfree7, -}; - -static int -newpool(void) -{ - static int seq; - - if(seq == nelem(freetab)) - return -1; - if(freetab[seq] == nil){ - print("82563: bad freetab\n"); - return -1; - } - return seq++; -} - static void i82563im(Ctlr *ctlr, int im) { @@ -1013,6 +880,8 @@ i82563tproc(void *v) i82563txinit(ctlr); tdt = ctlr->tdt; + while(waserror()) + ; for(;;){ n = NEXT(tdt, ctlr->ntd); if(n == i82563cleanup(ctlr)){ @@ -1033,38 +902,23 @@ i82563tproc(void *v) } } -static int -i82563replenish(Ctlr *ctlr, int maysleep) +static void +i82563replenish(Ctlr *ctlr) { uint rdt, i; Block *bp; - Rbpool *p; Rd *rd; - rdt = ctlr->rdt; - p = rbtab + ctlr->pool; i = 0; - for(; NEXT(rdt, ctlr->nrd) != ctlr->rdh; rdt = NEXT(rdt, ctlr->nrd)){ + for(rdt = ctlr->rdt; NEXT(rdt, ctlr->nrd) != ctlr->rdh; rdt = NEXT(rdt, ctlr->nrd)){ rd = &ctlr->rdba[rdt]; if(ctlr->rb[rdt] != nil){ iprint("82563: tx overrun\n"); break; } - redux: - bp = i82563rballoc(p); - if(bp == nil){ - if(rdt - ctlr->rdh >= 16) - break; - print("i82563%d: no rx buffers\n", ctlr->pool); - if(maysleep == 0) - return -1; - ilock(p); - p->starve = 1; - iunlock(p); - sleep(p, icansleep, p); - goto redux; - } i++; + bp = allocb(ctlr->rbsz + Rbalign); + bp->rp = bp->wp = (uchar*)ROUND((uintptr)bp->base, Rbalign); ctlr->rb[rdt] = bp; rd->addr[0] = PCIWADDR(bp->rp); rd->addr[1] = 0; @@ -1076,7 +930,6 @@ i82563replenish(Ctlr *ctlr, int maysleep) ctlr->rdt = rdt; csr32w(ctlr, Rdt, rdt); } - return 0; } static void @@ -1089,8 +942,6 @@ i82563rxinit(Ctlr *ctlr) csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF); else{ i = ctlr->rbsz / 1024; - if(ctlr->rbsz % 1024) - i++; if(cttab[ctlr->type].flag & F75){ csr32w(ctlr, Rctl, Lpe|Dpf|Bsize2048|Bam|RdtmsHALF|Secrc); if(ctlr->type != i82575) @@ -1162,17 +1013,19 @@ i82563rproc(void *arg) }else im = Rxt0|Rxo|Rxdmt0|Rxseq|Ack; + while(waserror()) + ; for(;;){ i82563im(ctlr, im); ctlr->rsleep++; - i82563replenish(ctlr, 1); + i82563replenish(ctlr); sleep(&ctlr->rrendez, i82563rim, ctlr); rdh = ctlr->rdh; for(;;){ - rd = &ctlr->rdba[rdh]; rim = ctlr->rim; ctlr->rim = 0; + rd = &ctlr->rdba[rdh]; if(!(rd->status & Rdd)) break; @@ -1186,7 +1039,6 @@ i82563rproc(void *arg) bp = ctlr->rb[rdh]; if((rd->status & Reop) && rd->errors == 0){ bp->wp += rd->length; - bp->lim = bp->wp; /* lie like a dog. avoid packblock. */ if(!(rd->status & Ixsm)){ ctlr->ixsm++; if(rd->status & Ipcs){ @@ -1208,16 +1060,14 @@ i82563rproc(void *arg) bp->checksum = rd->checksum; bp->flag |= Bpktck; } - etheriq(edev, bp, 1); + etheriq(edev, bp); } else freeb(bp); ctlr->rb[rdh] = nil; - rd->status = 0; ctlr->rdfree--; ctlr->rdh = rdh = NEXT(rdh, ctlr->nrd); if(ctlr->nrd-ctlr->rdfree >= 32 || (rim & Rxdmt0)) - if(i82563replenish(ctlr, 0) == -1) - break; + i82563replenish(ctlr); } } } @@ -1246,7 +1096,7 @@ phyread(Ctlr *c, int phyno, int reg) microdelay(1); } if((phy & (MDIe|MDIready)) != MDIready){ - print("%s: phy %d wedged %.8ux\n", cttab[c->type].name, phyno, phy); + print("%s: phy %d wedged %.8ux\n", cname(c), phyno, phy); return ~0; } return phy & 0xffff; @@ -1297,72 +1147,108 @@ phywrite(Ctlr *c, uint phyno, uint reg, ushort v) } static void -phyerrata(Ether *e, Ctlr *c) +phyerrata(Ether *e, Ctlr *c, uint phyno) { if(e->mbps == 0){ if(c->phyerrata == 0){ c->phyerrata++; - phywrite(c, 1, Phyprst, Prst); /* try a port reset */ + phywrite(c, phyno, Phyprst, Prst); /* try a port reset */ print("%s: phy port reset\n", cname(c)); } }else c->phyerrata = 0; } +static uint +phyprobe(Ctlr *c, uint mask) +{ + uint phy, phyno; + + for(phyno=0; mask != 0; phyno++, mask>>=1){ + if((mask & 1) == 0) + continue; + if(phyread(c, phyno, Physr) == ~0) + continue; + phy = (phyread(c, phyno, Phyid1) & 0x3FFF)<<6; + phy |= phyread(c, phyno, Phyid2) >> 10; + if(phy == 0xFFFFF || phy == 0) + continue; + print("%s: phy%d oui %#ux\n", cname(c), phyno, phy); + return phyno; + } + print("%s: no phy\n", cname(c)); + return ~0; +} + +static void +lsleep(Ctlr *c, uint m) +{ + c->lim = 0; + i82563im(c, m); + c->lsleep++; + sleep(&c->lrendez, i82563lim, c); +} + static void phyl79proc(void *v) { - uint a, i, r, phy, phyno; + uint i, r, phy, phyno; Ctlr *c; Ether *e; e = v; c = e->ctlr; + while(waserror()) + ; - phyno = 1; - if(c->type == i82579) - phyno = 2; + while((phyno = phyprobe(c, 3<<1)) == ~0) + lsleep(c, Lsc); for(;;){ - phy = phyread(c, phyno, Phystat); - if(phy == ~0){ - phy = 0; - i = 3; - goto next; + phy = 0; + for(i=0; i<4; i++){ + tsleep(&up->sleep, return0, 0, 150); + phy = phyread(c, phyno, Phystat); + if(phy == ~0) + continue; + if(phy & Ans){ + r = phyread(c, phyno, Phyctl); + if(r == ~0) + continue; + phywrite(c, phyno, Phyctl, r | Ran | Ean); + } + break; } i = (phy>>8) & 3; - a = phy & Ans; - if(a){ - r = phyread(c, phyno, Phyctl); - phywrite(c, phyno, Phyctl, r | Ran | Ean); - } -next: e->link = i != 3 && (phy & Link) != 0; if(e->link == 0) i = 3; c->speeds[i]++; e->mbps = speedtab[i]; - c->lim = 0; - i82563im(c, Lsc); - c->lsleep++; - sleep(&c->lrendez, i82563lim, c); + lsleep(c, Lsc); } } static void phylproc(void *v) { - uint a, i, phy; + uint a, i, phy, phyno; Ctlr *c; Ether *e; e = v; c = e->ctlr; + while(waserror()) + ; + + while((phyno = phyprobe(c, 3<<1)) == ~0) + lsleep(c, Lsc); + + if(c->type == i82573 && (phy = phyread(c, phyno, Phyier)) != ~0) + phywrite(c, phyno, Phyier, phy | Lscie | Ancie | Spdie | Panie); - if(c->type == i82573 && (phy = phyread(c, 1, Phyier)) != ~0) - phywrite(c, 1, Phyier, phy | Lscie | Ancie | Spdie | Panie); for(;;){ - phy = phyread(c, 1, Physsr); + phy = phyread(c, phyno, Physsr); if(phy == ~0){ phy = 0; i = 3; @@ -1377,18 +1263,18 @@ phylproc(void *v) case i82578: case i82578m: case i82583: - a = phyread(c, 1, Phyisr) & Ane; + a = phyread(c, phyno, Phyisr) & Ane; break; case i82571: case i82572: case i82575: case i82576: - a = phyread(c, 1, Phylhr) & Anf; + a = phyread(c, phyno, Phylhr) & Anf; i = (i-1) & 3; break; } if(a) - phywrite(c, 1, Phyctl, phyread(c, 1, Phyctl) | Ran | Ean); + phywrite(c, phyno, Phyctl, phyread(c, phyno, Phyctl) | Ran | Ean); next: e->link = (phy & Rtlink) != 0; if(e->link == 0) @@ -1396,11 +1282,8 @@ next: c->speeds[i]++; e->mbps = speedtab[i]; if(c->type == i82563) - phyerrata(e, c); - c->lim = 0; - i82563im(c, Lsc); - c->lsleep++; - sleep(&c->lrendez, i82563lim, c); + phyerrata(e, c, phyno); + lsleep(c, Lsc); } } @@ -1413,6 +1296,8 @@ pcslproc(void *v) e = v; c = e->ctlr; + while(waserror()) + ; if(c->type == i82575 || c->type == i82576) csr32w(c, Connsw, Enrgirq); @@ -1426,10 +1311,7 @@ pcslproc(void *v) csr32w(c, Pcsctl, csr32r(c, Pcsctl) | Pan | Prestart); c->speeds[i]++; e->mbps = speedtab[i]; - c->lim = 0; - i82563im(c, Lsc | Omed); - c->lsleep++; - sleep(&c->lrendez, i82563lim, c); + lsleep(c, Lsc | Omed); } } @@ -1442,7 +1324,8 @@ serdeslproc(void *v) e = v; c = e->ctlr; - + while(waserror()) + ; for(;;){ rx = csr32r(c, Rxcw); tx = csr32r(c, Txcw); @@ -1454,10 +1337,7 @@ serdeslproc(void *v) i = 2; c->speeds[i]++; e->mbps = speedtab[i]; - c->lim = 0; - i82563im(c, Lsc); - c->lsleep++; - sleep(&c->lrendez, i82563lim, c); + lsleep(c, Lsc); } } @@ -1465,8 +1345,6 @@ static void i82563attach(Ether *edev) { char name[KNAMELEN]; - int i; - Block *bp; Ctlr *ctlr; ctlr = edev->ctlr; @@ -1495,10 +1373,6 @@ i82563attach(Ether *edev) ctlr->tdba = (Td*)(ctlr->rdba + ctlr->nrd); if(waserror()){ - while(bp = i82563rballoc(rbtab + ctlr->pool)){ - bp->free = nil; - freeb(bp); - } free(ctlr->tb); ctlr->tb = nil; free(ctlr->rb); @@ -1509,12 +1383,6 @@ i82563attach(Ether *edev) nexterror(); } - for(i = 0; i < Nrb; i++){ - bp = allocb(ctlr->rbsz + Rbalign); - bp->free = freetab[ctlr->pool]; - freeb(bp); - } - snprint(name, sizeof name, "#l%dl", edev->ctlrno); if(csr32r(ctlr, Status) & Tbimode) kproc(name, serdeslproc, edev); /* mac based serdes */ @@ -1604,6 +1472,12 @@ i82563detach(Ctlr *ctlr) r = csr32r(ctlr, Ctrl); if(ctlr->type == i82566 || ctlr->type == i82579) r |= Phyrst; + /* + * hack: 82579LM on lenovo X230 is stuck at 10mbps after + * reseting the phy, but works fine if we dont reset. + */ + if(ctlr->pcidev->did == 0x1502) + r &= ~Phyrst; csr32w(ctlr, Ctrl, Devrst | r); delay(1); for(timeo = 0;; timeo++){ @@ -1680,49 +1554,105 @@ eeload(Ctlr *ctlr) } static int -fcycle(Ctlr *, Flash *f) +fread16(Ctlr *c, Flash *f, int ladr) { u16int s; - int i; + int timeout; + delay(1); s = f->reg[Fsts]; if((s&Fvalid) == 0) return -1; f->reg[Fsts] |= Fcerr | Ael; - for(i = 0; i < 10; i++){ + for(timeout = 0; timeout < 10; timeout++){ if((s&Scip) == 0) - return 0; + goto done; delay(1); s = f->reg[Fsts]; } return -1; +done: + f->reg[Fsts] |= Fdone; + f->reg32[Faddr] = ladr; + + /* setup flash control register */ + s = f->reg[Fctl] & ~0x3ff; + f->reg[Fctl] = s | 1<<8 | Fgo; /* 2 byte read */ + timeout = 1000; + while((f->reg[Fsts] & Fdone) == 0 && timeout--) + microdelay(5); + if(timeout < 0){ + print("%s: fread timeout\n", cname(c)); + return -1; + } + if(f->reg[Fsts] & (Fcerr|Ael)) + return -1; + return f->reg32[Fdata] & 0xffff; } static int -fread(Ctlr *c, Flash *f, int ladr) +fread32(Ctlr *c, Flash *f, int ladr, u32int *data) { - u16int s; + u32int s; int timeout; delay(1); - if(fcycle(c, f) == -1) + s = f->reg32[Fsts/2]; + if((s&Fvalid) == 0) return -1; - f->reg[Fsts] |= Fdone; + f->reg32[Fsts/2] |= Fcerr | Ael; + for(timeout = 0; timeout < 10; timeout++){ + if((s&Scip) == 0) + goto done; + delay(1); + s = f->reg32[Fsts/2]; + } + return -1; +done: + f->reg32[Fsts/2] |= Fdone; f->reg32[Faddr] = ladr; /* setup flash control register */ - s = f->reg[Fctl] & ~0x3ff; - f->reg[Fctl] = s | 1<<8 | Fgo; /* 2 byte read */ + s = (f->reg32[Fctl/2] >> 16) & ~0x3ff; + f->reg32[Fctl/2] = (s | 3<<8 | Fgo) << 16; /* 4 byte read */ timeout = 1000; - while((f->reg[Fsts] & Fdone) == 0 && timeout--) + while((f->reg32[Fsts/2] & Fdone) == 0 && timeout--) microdelay(5); if(timeout < 0){ print("%s: fread timeout\n", cname(c)); return -1; } - if(f->reg[Fsts] & (Fcerr|Ael)) + if(f->reg32[Fsts/2] & (Fcerr|Ael)) return -1; - return f->reg32[Fdata] & 0xffff; + *data = f->reg32[Fdata]; + return 0; +} + +static int +fload32(Ctlr *c) +{ + int r, adr; + u16int sum; + u32int w; + Flash f; + + f.reg32 = &c->nic[0xe000/4]; + f.reg = nil; + f.base = 0; + f.lim = (((csr32r(c, 0xC) >> 1) & 0x1F) + 1) << 12; + r = f.lim >> 1; + if(fread32(c, &f, r + 0x24, &w) == -1 || (w & 0xC000) != 0x8000) + r = 0; + sum = 0; + for(adr = 0; adr < 0x20; adr++) { + if(fread32(c, &f, r + adr*4, &w) == -1) + return -1; + c->eeprom[adr*2+0] = w; + c->eeprom[adr*2+1] = w>>16; + sum += w & 0xFFFF; + sum += w >> 16; + } + return sum; } static int @@ -1733,6 +1663,10 @@ fload(Ctlr *c) void *va; Flash f; + memset(c->eeprom, 0xFF, sizeof(c->eeprom)); + if(c->pcidev->mem[1].bar == 0) + return fload32(c); /* i219 */ + va = vmap(c->pcidev->mem[1].bar & ~0x0f, c->pcidev->mem[1].size); if(va == nil) return -1; @@ -1745,16 +1679,51 @@ fload(Ctlr *c) r = f.base << 12; sum = 0; for(adr = 0; adr < 0x40; adr++) { - data = fread(c, &f, r + adr*2); + data = fread16(c, &f, r + adr*2); if(data == -1) - return -1; + goto out; c->eeprom[adr] = data; sum += data; } +out: vunmap(va, c->pcidev->mem[1].size); return sum; } +static int +invmload(Ctlr *c) +{ + int i, a; + u32int w; + + memset(c->eeprom, 0xFF, sizeof(c->eeprom)); + for(i=0; i<64; i++){ + w = csr32r(c, Invmdata0 + i*4); + switch(w & 7){ + case 0: // uninitialized structure + break; + case 1: // word auto load + a = (w & 0xFE00) >> 9; + if(a < nelem(c->eeprom)) + c->eeprom[a] = w >> 16; + continue; + case 2: // csr auto load + i++; + case 3: // phy auto load + continue; + case 4: // rsa key sha256 + i += 256/32; + case 5: // invalidated structure + continue; + default: + print("invm: %.2x %.8ux\n", i, w); + continue; + } + break; + } + return 0; +} + static void defaultea(Ctlr *ctlr, uchar *ra) { @@ -1784,18 +1753,27 @@ static int i82563reset(Ctlr *ctlr) { uchar *ra; - int i, r; + int i, r, flag; if(i82563detach(ctlr)) return -1; - if(cttab[ctlr->type].flag & Fload) + flag = cttab[ctlr->type].flag; + + if(ctlr->type == i210 && (csr32r(ctlr, Eec) & Flupd) == 0) + r = invmload(ctlr); + else if(flag & Fload) r = fload(ctlr); else r = eeload(ctlr); + if(r != 0 && r != 0xbaba){ - print("%s: bad eeprom checksum - %#.4ux\n", - cname(ctlr), r); - return -1; + print("%s: bad eeprom checksum - %#.4ux", cname(ctlr), r); + if(flag & Fbadcsum) + print("; ignored\n"); + else { + print("\n"); + return -1; + } } ra = ctlr->ra; @@ -1809,14 +1787,16 @@ i82563reset(Ctlr *ctlr) memset(ctlr->mta, 0, sizeof(ctlr->mta)); for(i = 0; i < 128; i++) csr32w(ctlr, Mta + i*4, 0); - csr32w(ctlr, Fcal, 0x00C28001); - csr32w(ctlr, Fcah, 0x0100); - if(ctlr->type != i82579) + if((flag & Fnofca) == 0){ + csr32w(ctlr, Fcal, 0x00C28001); + csr32w(ctlr, Fcah, 0x0100); + } + if((flag & Fnofct) == 0) csr32w(ctlr, Fct, 0x8808); csr32w(ctlr, Fcttv, 0x0100); csr32w(ctlr, Fcrtl, ctlr->fcrtl); csr32w(ctlr, Fcrth, ctlr->fcrth); - if(cttab[ctlr->type].flag & F75) + if(flag & F75) csr32w(ctlr, Eitr, 128<<2); /* 128 ¼ microsecond intervals */ return 0; } @@ -1982,12 +1962,45 @@ didtype(int d) case 0x1506: /* v */ case 0x150c: /* untested */ return i82583; - case 0x151f: /* “powerville” eeprom-less */ - case 0x1521: /* copper */ - case 0x1522: /* fiber */ - case 0x1523: /* serdes */ - case 0x1524: /* sgmii */ - case 0x1546: /* untested */ + case 0x1533: /* i210-t1 */ + case 0x1534: /* i210 */ + case 0x1536: /* i210-fiber */ + case 0x1537: /* i210-backplane */ + case 0x1538: /* i210 sgmii */ + case 0x1539: /* i211 copper */ + case 0x157b: /* i210 copper flashless */ + case 0x157c: /* i210 serdes flashless */ + return i210; + case 0x153a: /* i217-lm */ + case 0x153b: /* i217-v */ + return i217; + case 0x1559: /* i218-v */ + case 0x155a: /* i218-lm */ + case 0x15a0: /* i218-lm */ + case 0x15a1: /* i218-v */ + case 0x15a2: /* i218-lm */ + case 0x15a3: /* i218-v */ + return i218; + case 0x156f: /* i219-lm */ + case 0x15b7: /* i219-lm */ + case 0x1570: /* i219-v */ + case 0x15b8: /* i219-v */ + case 0x15b9: /* i219-lm */ + case 0x15d6: /* i219-v */ + case 0x15d7: /* i219-lm */ + case 0x15d8: /* i219-v */ + case 0x15e3: /* i219-lm */ + return i219; + case 0x151f: /* i350 “powerville” eeprom-less */ + case 0x1521: /* i350 copper */ + case 0x1522: /* i350 fiber */ + case 0x1523: /* i350 serdes */ + case 0x1524: /* i350 sgmii */ + case 0x1546: /* i350 DA4 (untested) */ + case 0x1f40: /* i354 backplane */ + case 0x1f41: /* i354 sgmii */ + case 0x1f42: /* i354 sgmii (c2000) */ + case 0x1f45: /* i354 backplane 2.5 */ return i350; } return -1; @@ -2021,7 +2034,7 @@ i82563pci(void) } ctlr->type = type; ctlr->pcidev = p; - ctlr->rbsz = cttab[type].mtu; + ctlr->rbsz = ROUND(cttab[type].mtu, 1024); ctlr->port = p->mem[0].bar & ~0x0F; if(i82563ctlrhead != nil) i82563ctlrtail->next = ctlr; @@ -2036,21 +2049,19 @@ setup(Ctlr *ctlr) { Pcidev *p; - if((ctlr->pool = newpool()) == -1){ - print("%s: no pool\n", cname(ctlr)); - return -1; - } p = ctlr->pcidev; ctlr->nic = vmap(ctlr->port, p->mem[0].size); if(ctlr->nic == nil){ - print("%s: can't map %#p\n", cname(ctlr), ctlr->port); + print("%s: can't map 0x%lux\n", cname(ctlr), ctlr->port); return -1; } + pcienable(p); if(i82563reset(ctlr)){ + pcidisable(p); vunmap(ctlr->nic, p->mem[0].size); return -1; } - pcisetbme(ctlr->pcidev); + pcisetbme(p); return 0; } @@ -2089,7 +2100,7 @@ pnp(Ether *edev, int type) edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; edev->mbps = 1000; - edev->maxmtu = ctlr->rbsz; + edev->maxmtu = cttab[ctlr->type].mtu; memmove(edev->ea, ctlr->ra, Eaddrlen); /* @@ -2097,7 +2108,6 @@ pnp(Ether *edev, int type) */ edev->attach = i82563attach; // edev->transmit = i82563transmit; - edev->interrupt = i82563interrupt; edev->ifstat = i82563ifstat; edev->ctl = i82563ctl; @@ -2106,6 +2116,8 @@ pnp(Ether *edev, int type) edev->shutdown = i82563shutdown; edev->multicast = i82563multicast; + intrenable(edev->irq, i82563interrupt, edev, edev->tbdf, edev->name); + return 0; } @@ -2199,6 +2211,30 @@ i82583pnp(Ether *e) return pnp(e, i82583); } +static int +i210pnp(Ether *e) +{ + return pnp(e, i210); +} + +static int +i217pnp(Ether *e) +{ + return pnp(e, i217); +} + +static int +i218pnp(Ether *e) +{ + return pnp(e, i218); +} + +static int +i219pnp(Ether *e) +{ + return pnp(e, i219); +} + static int i350pnp(Ether *e) { @@ -2228,6 +2264,10 @@ ether82563link(void) addethercard("i82579", i82579pnp); addethercard("i82580", i82580pnp); addethercard("i82583", i82583pnp); + addethercard("i210", i210pnp); + addethercard("i217", i217pnp); + addethercard("i218", i218pnp); + addethercard("i219", i219pnp); addethercard("i350", i350pnp); addethercard("igbepcie", anypnp); }