#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
Torl = 0xC0/4, /* Total Octets Received */
Totl = 0xC8/4, /* Total Octets Transmitted */
Nstatistics = 0x124/4,
+
+ /* iNVM (i211) */
+ Invmdata0 = 0x12120,
};
enum { /* Ctrl */
enum { /* Eec */
Nvpres = 1<<8,
Autord = 1<<9,
+ Flupd = 1<<19,
Sec1val = 1<<22,
};
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 */
i82579,
i82580,
i82583,
+ i210,
+ i217,
+ i218,
+ i219,
i350,
Nctlrtype,
};
Fpba = 1<<3,
Fflashea= 1<<4,
F79phy = 1<<5,
+ Fnofct = 1<<6,
+ Fbadcsum= 1<<7,
};
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, /* 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", 9728, Fload|Fnofct|Fert|Fbadcsum,
+[i218] "i218", 9728, Fload|Fert|F79phy|Fnofct|Fbadcsum,
+[i219] "i219", 9728, Fload|Fert|F79phy|Fnofct|Fbadcsum,
+[i350] "i350", 9728, F75|F79phy|Fnofct,
};
typedef void (*Freefn)(Block*);
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);
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 i210:
+ 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.
*/
if(on)
ctlr->mta[x] |= 1<<bit;
-// else
-// ctlr->mta[x] &= ~(1<<bit);
csr32w(ctlr, Mta+x*4, ctlr->mta[x]);
}
i82563txinit(ctlr);
tdt = ctlr->tdt;
+ while(waserror())
+ ;
for(;;){
n = NEXT(tdt, ctlr->ntd);
if(n == i82563cleanup(ctlr)){
}else
im = Rxt0|Rxo|Rxdmt0|Rxseq|Ack;
+ while(waserror())
+ ;
for(;;){
i82563im(ctlr, im);
ctlr->rsleep++;
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){
bp->checksum = rd->checksum;
bp->flag |= Bpktck;
}
- etheriq(edev, bp, 1);
+ etheriq(edev, bp);
} else
freeb(bp);
ctlr->rb[rdh] = nil;
}
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)
{
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);
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;
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)
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);
}
}
e = v;
c = e->ctlr;
+ while(waserror())
+ ;
if(c->type == i82575 || c->type == i82576)
csr32w(c, Connsw, Enrgirq);
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);
}
}
e = v;
c = e->ctlr;
-
+ while(waserror())
+ ;
for(;;){
rx = csr32r(c, Rxcw);
tx = csr32r(c, Txcw);
i = 2;
c->speeds[i]++;
e->mbps = speedtab[i];
- c->lim = 0;
- i82563im(c, Lsc);
- c->lsleep++;
- sleep(&c->lrendez, i82563lim, c);
- }
-}
-
-static void
-maclproc(void *v)
-{
- uint i;
- Ctlr *c;
- Ether *e;
-
- e = v;
- c = e->ctlr;
-
- for(;;){
- i = csr32r(c, Status);
- e->link = (i & Lu) != 0;
- i = (i >> 6) & 3; /* link speed 6:7 */
- 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);
}
}
kproc(name, pcslproc, edev); /* phy based serdes */
else if(cttab[ctlr->type].flag & F79phy)
kproc(name, phyl79proc, edev);
- else if(ctlr->type == i82567)
- kproc(name, maclproc, edev); /* use mac link status */
else
kproc(name, phylproc, edev);
}
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
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;
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)
{
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;
csr32w(ctlr, Mta + i*4, 0);
csr32w(ctlr, Fcal, 0x00C28001);
csr32w(ctlr, Fcah, 0x0100);
- if(ctlr->type != i82579)
+ 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;
}
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;
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;
}
if(i82563reset(ctlr)){
*/
edev->attach = i82563attach;
// edev->transmit = i82563transmit;
- edev->interrupt = i82563interrupt;
edev->ifstat = i82563ifstat;
edev->ctl = i82563ctl;
edev->shutdown = i82563shutdown;
edev->multicast = i82563multicast;
+ intrenable(edev->irq, i82563interrupt, edev, edev->tbdf, edev->name);
+
return 0;
}
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)
{
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);
}