ether82563: sync with erik (fixed 82579 eeprom checksum error, adds i350 support)

This commit is contained in:
cinap_lenrek 2012-06-21 01:06:17 +02:00
parent 69470de37d
commit cf4c3e7c5c

View file

@ -1,5 +1,5 @@
/* /*
* Intel 8256[367], 8257[1-9], 8258[03] * Intel 8256[367], 8257[1-9], 8258[03], i350
* Gigabit Ethernet PCI-Express Controllers * Gigabit Ethernet PCI-Express Controllers
* Coraid EtherDrive® hba * Coraid EtherDrive® hba
*/ */
@ -34,6 +34,7 @@ enum {
Fcah = 0x002C, /* Flow Control Address High */ Fcah = 0x002C, /* Flow Control Address High */
Fct = 0x0030, /* Flow Control Type */ Fct = 0x0030, /* Flow Control Type */
Kumctrlsta = 0x0034, /* Kumeran Control and Status Register */ Kumctrlsta = 0x0034, /* Kumeran Control and Status Register */
Connsw = 0x0034, /* copper / fiber switch control; 82575/82576 */
Vet = 0x0038, /* VLAN EtherType */ Vet = 0x0038, /* VLAN EtherType */
Fcttv = 0x0170, /* Flow Control Transmit Timer Value */ Fcttv = 0x0170, /* Flow Control Transmit Timer Value */
Txcw = 0x0178, /* Transmit Configuration Word */ Txcw = 0x0178, /* Transmit Configuration Word */
@ -124,6 +125,12 @@ enum { /* Status */
GIOme = 1<<19, /* GIO Master Enable Status */ GIOme = 1<<19, /* GIO Master Enable Status */
}; };
enum { /* Eec */
Nvpres = 1<<8,
Autord = 1<<9,
Sec1val = 1<<22,
};
enum { /* Eerd */ enum { /* Eerd */
EEstart = 1<<0, /* Start Read */ EEstart = 1<<0, /* Start Read */
EEdone = 1<<1, /* Read done */ EEdone = 1<<1, /* Read done */
@ -131,8 +138,15 @@ enum { /* Eerd */
enum { /* Ctrlext */ enum { /* Ctrlext */
Eerst = 1<<13, /* EEPROM Reset */ Eerst = 1<<13, /* EEPROM Reset */
Linkmode = 3<<23, /* linkmode */ Linkmode = 3<<22, /* linkmode */
Serdes = 3<<23, /* " serdes */ Internalphy = 0<<22, /* " internal phy (copper) */
Sgmii = 2<<22, /* " sgmii */
Serdes = 3<<22, /* " serdes */
};
enum {
/* Connsw */
Enrgirq = 1<<2, /* interrupt on power detect (enrgsrc) */
}; };
enum { /* EEPROM content offsets */ enum { /* EEPROM content offsets */
@ -226,6 +240,7 @@ enum { /* Icr, Ics, Ims, Imc */
Mdac = 0x00000200, /* MDIO Access Completed */ Mdac = 0x00000200, /* MDIO Access Completed */
Rxcfgset = 0x00000400, /* Receiving /C/ ordered sets */ Rxcfgset = 0x00000400, /* Receiving /C/ ordered sets */
Ack = 0x00020000, /* Receive ACK frame */ Ack = 0x00020000, /* Receive ACK frame */
Omed = 1<<20, /* media change; pcs interface */
}; };
enum { /* Txcw */ enum { /* Txcw */
@ -308,12 +323,12 @@ enum { /* Rxcsum */
}; };
typedef struct Rd { /* Receive Descriptor */ typedef struct Rd { /* Receive Descriptor */
uint addr[2]; u32int addr[2];
ushort length; u16int length;
ushort checksum; u16int checksum;
uchar status; uchar status;
uchar errors; uchar errors;
ushort special; u16int special;
} Rd; } Rd;
enum { /* Rd status */ enum { /* Rd status */
@ -337,9 +352,9 @@ enum { /* Rd errors */
}; };
typedef struct { /* Transmit Descriptor */ typedef struct { /* Transmit Descriptor */
uint addr[2]; /* Data */ u32int addr[2]; /* Data */
uint control; u32int control;
uint status; u32int status;
} Td; } Td;
enum { /* Tdesc control */ enum { /* Tdesc control */
@ -369,9 +384,10 @@ enum { /* Tdesc status */
}; };
typedef struct { typedef struct {
ushort *reg; u16int *reg;
ulong *reg32; u32int *reg32;
int sz; uint base;
uint lim;
} Flash; } Flash;
enum { enum {
@ -425,6 +441,7 @@ enum {
i82579, i82579,
i82580, i82580,
i82583, i82583,
i350,
Nctlrtype, Nctlrtype,
}; };
@ -433,7 +450,8 @@ enum {
Fert = 1<<1, Fert = 1<<1,
F75 = 1<<2, F75 = 1<<2,
Fpba = 1<<3, Fpba = 1<<3,
Fflashea = 1<<4, Fflashea= 1<<4,
F79phy = 1<<5,
}; };
typedef struct Ctlrtype Ctlrtype; typedef struct Ctlrtype Ctlrtype;
@ -459,9 +477,10 @@ static Ctlrtype cttab[Nctlrtype] = {
i82577m, 1514, Fload|Fert, "i82577", i82577m, 1514, Fload|Fert, "i82577",
i82578, 4096, Fload|Fert, "i82578", i82578, 4096, Fload|Fert, "i82578",
i82578m, 1514, Fload|Fert, "i82578", i82578m, 1514, Fload|Fert, "i82578",
i82579, 9018, Fload|Fert, "i82579", i82579, 9018, Fload|Fert|F79phy, "i82579",
i82580, 9728, F75, "i82580", i82580, 9728, F75|F79phy, "i82580",
i82583, 1514, 0, "i82583", i82583, 1514, 0, "i82583",
i350, 9728, F75|F79phy, "i350",
}; };
typedef void (*Freefn)(Block*); typedef void (*Freefn)(Block*);
@ -474,7 +493,7 @@ struct Ctlr {
int active; int active;
int type; int type;
int pool; int pool;
ushort eeprom[0x40]; u16int eeprom[0x40];
QLock alock; /* attach */ QLock alock; /* attach */
void *alloc; /* receive/transmit descriptors */ void *alloc; /* receive/transmit descriptors */
@ -482,7 +501,7 @@ struct Ctlr {
int ntd; int ntd;
uint rbsz; uint rbsz;
int *nic; u32int *nic;
Lock imlock; Lock imlock;
int im; /* interrupt mask */ int im; /* interrupt mask */
@ -490,7 +509,7 @@ struct Ctlr {
int lim; int lim;
QLock slock; QLock slock;
uint statistics[Nstatistics]; u32int statistics[Nstatistics];
uint lsleep; uint lsleep;
uint lintr; uint lintr;
uint rsleep; uint rsleep;
@ -504,7 +523,7 @@ struct Ctlr {
uint phyerrata; uint phyerrata;
uchar ra[Eaddrlen]; /* receive address */ uchar ra[Eaddrlen]; /* receive address */
ulong mta[128]; /* multicast table array */ u32int mta[128]; /* multicast table array */
Rendez rrendez; Rendez rrendez;
int rim; int rim;
@ -527,7 +546,7 @@ struct Ctlr {
int fcrtl; int fcrtl;
int fcrth; int fcrth;
uint pba; /* packet buffer allocation */ u32int pba; /* packet buffer allocation */
}; };
typedef struct Rbpool Rbpool; typedef struct Rbpool Rbpool;
@ -918,8 +937,9 @@ i82563im(Ctlr *ctlr, int im)
static void static void
i82563txinit(Ctlr *ctlr) i82563txinit(Ctlr *ctlr)
{ {
uint i, r; u32int r;
Block *b; Block *b;
int i;
if(cttab[ctlr->type].flag & F75) if(cttab[ctlr->type].flag & F75)
csr32w(ctlr, Tctl, 0x0F<<CtSHIFT | Psp); csr32w(ctlr, Tctl, 0x0F<<CtSHIFT | Psp);
@ -1305,20 +1325,23 @@ phyl79proc(void *v)
for(;;){ for(;;){
phy = phyread(c, phyno, Phystat); phy = phyread(c, phyno, Phystat);
if(phy == ~0) if(phy == ~0){
phy = 0;
i = 3;
goto next; goto next;
}
i = (phy>>8) & 3; i = (phy>>8) & 3;
a = phy & Ans; a = phy & Ans;
if(a){ if(a){
r = phyread(c, phyno, Phyctl); r = phyread(c, phyno, Phyctl);
phywrite(c, phyno, Phyctl, r | Ran | Ean); phywrite(c, phyno, Phyctl, r | Ran | Ean);
} }
e->link = (phy & Link) != 0; next:
e->link = i != 3 && (phy & Link) != 0;
if(e->link == 0) if(e->link == 0)
i = 3; i = 3;
c->speeds[i]++; c->speeds[i]++;
e->mbps = speedtab[i]; e->mbps = speedtab[i];
next:
c->lim = 0; c->lim = 0;
i82563im(c, Lsc); i82563im(c, Lsc);
c->lsleep++; c->lsleep++;
@ -1340,8 +1363,11 @@ phylproc(void *v)
phywrite(c, 1, Phyier, phy | Lscie | Ancie | Spdie | Panie); phywrite(c, 1, Phyier, phy | Lscie | Ancie | Spdie | Panie);
for(;;){ for(;;){
phy = phyread(c, 1, Physsr); phy = phyread(c, 1, Physsr);
if(phy == ~0) if(phy == ~0){
phy = 0;
i = 3;
goto next; goto next;
}
i = (phy>>14) & 3; i = (phy>>14) & 3;
switch(c->type){ switch(c->type){
default: default:
@ -1363,6 +1389,7 @@ phylproc(void *v)
} }
if(a) if(a)
phywrite(c, 1, Phyctl, phyread(c, 1, Phyctl) | Ran | Ean); phywrite(c, 1, Phyctl, phyread(c, 1, Phyctl) | Ran | Ean);
next:
e->link = (phy & Rtlink) != 0; e->link = (phy & Rtlink) != 0;
if(e->link == 0) if(e->link == 0)
i = 3; i = 3;
@ -1370,7 +1397,6 @@ phylproc(void *v)
e->mbps = speedtab[i]; e->mbps = speedtab[i];
if(c->type == i82563) if(c->type == i82563)
phyerrata(e, c); phyerrata(e, c);
next:
c->lim = 0; c->lim = 0;
i82563im(c, Lsc); i82563im(c, Lsc);
c->lsleep++; c->lsleep++;
@ -1388,6 +1414,8 @@ pcslproc(void *v)
e = v; e = v;
c = e->ctlr; c = e->ctlr;
if(c->type == i82575 || c->type == i82576)
csr32w(c, Connsw, Enrgirq);
for(;;){ for(;;){
phy = csr32r(c, Pcsstat); phy = csr32r(c, Pcsstat);
e->link = phy & Linkok; e->link = phy & Linkok;
@ -1399,7 +1427,7 @@ pcslproc(void *v)
c->speeds[i]++; c->speeds[i]++;
e->mbps = speedtab[i]; e->mbps = speedtab[i];
c->lim = 0; c->lim = 0;
i82563im(c, Lsc); i82563im(c, Lsc | Omed);
c->lsleep++; c->lsleep++;
sleep(&c->lrendez, i82563lim, c); sleep(&c->lrendez, i82563lim, c);
} }
@ -1488,11 +1516,11 @@ i82563attach(Ether *edev)
} }
snprint(name, sizeof name, "#l%dl", edev->ctlrno); snprint(name, sizeof name, "#l%dl", edev->ctlrno);
if((csr32r(ctlr, Ctrlext) & Linkmode) == Serdes) if(csr32r(ctlr, Status) & Tbimode)
kproc(name, pcslproc, edev); /* phy based serdes */
else if(csr32r(ctlr, Status) & Tbimode)
kproc(name, serdeslproc, edev); /* mac based serdes */ kproc(name, serdeslproc, edev); /* mac based serdes */
else if(ctlr->type == i82579 || ctlr->type == i82580) else if((csr32r(ctlr, Ctrlext) & Linkmode) == Serdes)
kproc(name, pcslproc, edev); /* phy based serdes */
else if(cttab[ctlr->type].flag & F79phy)
kproc(name, phyl79proc, edev); kproc(name, phyl79proc, edev);
else else
kproc(name, phylproc, edev); kproc(name, phylproc, edev);
@ -1522,9 +1550,9 @@ i82563interrupt(Ureg*, void *arg)
im = ctlr->im; im = ctlr->im;
while(icr = csr32r(ctlr, Icr) & ctlr->im){ while(icr = csr32r(ctlr, Icr) & ctlr->im){
if(icr & Lsc){ if(icr & (Lsc | Omed)){
im &= ~Lsc; im &= ~(Lsc | Omed);
ctlr->lim = icr & Lsc; ctlr->lim = icr & (Lsc | Omed);
wakeup(&ctlr->lrendez); wakeup(&ctlr->lrendez);
ctlr->lintr++; ctlr->lintr++;
} }
@ -1619,7 +1647,7 @@ i82563shutdown(Ether *edev)
i82563detach(edev->ctlr); i82563detach(edev->ctlr);
} }
static ushort static int
eeread(Ctlr *ctlr, int adr) eeread(Ctlr *ctlr, int adr)
{ {
csr32w(ctlr, Eerd, EEstart | adr << 2); csr32w(ctlr, Eerd, EEstart | adr << 2);
@ -1631,7 +1659,7 @@ eeread(Ctlr *ctlr, int adr)
static int static int
eeload(Ctlr *ctlr) eeload(Ctlr *ctlr)
{ {
ushort sum; u16int sum;
int data, adr; int data, adr;
sum = 0; sum = 0;
@ -1646,7 +1674,8 @@ eeload(Ctlr *ctlr)
static int static int
fcycle(Ctlr *, Flash *f) fcycle(Ctlr *, Flash *f)
{ {
ushort s, i; u16int s;
int i;
s = f->reg[Fsts]; s = f->reg[Fsts];
if((s&Fvalid) == 0) if((s&Fvalid) == 0)
@ -1664,7 +1693,7 @@ fcycle(Ctlr *, Flash *f)
static int static int
fread(Ctlr *c, Flash *f, int ladr) fread(Ctlr *c, Flash *f, int ladr)
{ {
ushort s; u16int s;
delay(1); delay(1);
if(fcycle(c, f) == -1) if(fcycle(c, f) == -1)
@ -1686,23 +1715,21 @@ fread(Ctlr *c, Flash *f, int ladr)
static int static int
fload(Ctlr *c) fload(Ctlr *c)
{ {
ulong data, io, r, adr; int data, r, adr;
ushort sum; u16int sum;
void *va;
Flash f; Flash f;
io = c->pcidev->mem[1].bar & ~0x0f; va = vmap(c->pcidev->mem[1].bar & ~0x0f, c->pcidev->mem[1].size);
f.reg = vmap(io, c->pcidev->mem[1].size); if(va == nil)
if(f.reg == nil)
return -1; return -1;
f.reg32 = (ulong*)f.reg; f.reg = va;
f.sz = f.reg32[Bfpr]; f.reg32 = va;
if(csr32r(c, Eec) & 1<<22){ f.base = f.reg32[Bfpr] & 0x1fff;
if(c->type == i82579) f.lim = f.reg32[Bfpr]>>16 & 0x1fff;
f.sz += 16; /* sector size: 64k */ if(csr32r(c, Eec) & Sec1val)
else f.base += f.lim+1 - f.base >> 1;
f.sz += 1; /* sector size: 4k */ r = f.base << 12;
}
r = (f.sz & 0x1fff) << 12;
sum = 0; sum = 0;
for(adr = 0; adr < 0x40; adr++) { for(adr = 0; adr < 0x40; adr++) {
data = fread(c, &f, r + adr*2); data = fread(c, &f, r + adr*2);
@ -1711,7 +1738,7 @@ fload(Ctlr *c)
c->eeprom[adr] = data; c->eeprom[adr] = data;
sum += data; sum += data;
} }
vunmap(f.reg, c->pcidev->mem[1].size); vunmap(va, c->pcidev->mem[1].size);
return sum; return sum;
} }
@ -1830,7 +1857,7 @@ i82563ctl(Ether *edev, void *buf, long n)
csr32w(ctlr, Radv, v); csr32w(ctlr, Radv, v);
break; break;
case CMpause: case CMpause:
csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) ^ (1<<27 | 1<<28)); csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) ^ (Rfce | Tfce));
break; break;
case CMan: case CMan:
csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) | Lrst | Phyrst); csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) | Lrst | Phyrst);
@ -1848,8 +1875,8 @@ didtype(int d)
switch(d){ switch(d){
case 0x1096: case 0x1096:
case 0x10ba: /* “gilgal” */ case 0x10ba: /* “gilgal” */
// case 0x1098: /* serdes; not seen */ case 0x1098: /* serdes; not seen */
// case 0x10bb: /* serdes */ case 0x10bb: /* serdes */
return i82563; return i82563;
case 0x1049: /* mm */ case 0x1049: /* mm */
case 0x104a: /* dm */ case 0x104a: /* dm */
@ -1895,6 +1922,7 @@ didtype(int d)
case 0x10c9: /* copper */ case 0x10c9: /* copper */
case 0x10e6: /* fiber */ case 0x10e6: /* fiber */
case 0x10e7: /* serdes; “kawela” */ case 0x10e7: /* serdes; “kawela” */
case 0x150d: /* backplane */
return i82576; return i82576;
case 0x10ea: /* lc “calpella”; aka pch lan */ case 0x10ea: /* lc “calpella”; aka pch lan */
return i82577; return i82577;
@ -1903,7 +1931,7 @@ didtype(int d)
case 0x10ef: /* dc “piketon” */ case 0x10ef: /* dc “piketon” */
return i82578; return i82578;
case 0x1502: /* lm */ case 0x1502: /* lm */
case 0x1503: /* v */ case 0x1503: /* v “lewisville” */
return i82579; return i82579;
case 0x10f0: /* dm “king's creek” */ case 0x10f0: /* dm “king's creek” */
return i82578m; return i82578m;
@ -1915,6 +1943,12 @@ didtype(int d)
return i82580; return i82580;
case 0x1506: /* v */ case 0x1506: /* v */
return i82583; return i82583;
case 0x151f: /* “powerville” eeprom-less */
case 0x1521: /* copper */
case 0x1522: /* fiber */
case 0x1523: /* serdes */
case 0x1524: /* sgmii */
return i350;
} }
return -1; return -1;
} }
@ -2125,6 +2159,12 @@ i82583pnp(Ether *e)
return pnp(e, i82583); return pnp(e, i82583);
} }
static int
i350pnp(Ether *e)
{
return pnp(e, i350);
}
void void
ether82563link(void) ether82563link(void)
{ {
@ -2148,5 +2188,6 @@ ether82563link(void)
addethercard("i82579", i82579pnp); addethercard("i82579", i82579pnp);
addethercard("i82580", i82580pnp); addethercard("i82580", i82580pnp);
addethercard("i82583", i82583pnp); addethercard("i82583", i82583pnp);
addethercard("i350", i350pnp);
addethercard("igbepcie", anypnp); addethercard("igbepcie", anypnp);
} }