/*
- * Intel 8256[367], 8257[1-9], 8258[03]
+ * Intel 8256[367], 8257[1-9], 8258[03], i350
* Gigabit Ethernet PCI-Express Controllers
* Coraid EtherDrive® hba
*/
#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
Fcah = 0x002C, /* Flow Control Address High */
Fct = 0x0030, /* Flow Control Type */
Kumctrlsta = 0x0034, /* Kumeran Control and Status Register */
+ Connsw = 0x0034, /* copper / fiber switch control; 82575/82576 */
Vet = 0x0038, /* VLAN EtherType */
Fcttv = 0x0170, /* Flow Control Transmit Timer Value */
Txcw = 0x0178, /* Transmit Configuration Word */
Torl = 0xC0/4, /* Total Octets Received */
Totl = 0xC8/4, /* Total Octets Transmitted */
Nstatistics = 0x124/4,
+
+ /* iNVM (i211) */
+ Invmdata0 = 0x12120,
};
enum { /* Ctrl */
GIOme = 1<<19, /* GIO Master Enable Status */
};
+enum { /* Eec */
+ Nvpres = 1<<8,
+ Autord = 1<<9,
+ Flupd = 1<<19,
+ Sec1val = 1<<22,
+};
+
enum { /* Eerd */
EEstart = 1<<0, /* Start Read */
EEdone = 1<<1, /* Read done */
enum { /* Ctrlext */
Eerst = 1<<13, /* EEPROM Reset */
- Linkmode = 3<<23, /* linkmode */
- Serdes = 3<<23, /* " serdes */
+ Linkmode = 3<<22, /* linkmode */
+ 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 { /* 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 */
Mdac = 0x00000200, /* MDIO Access Completed */
Rxcfgset = 0x00000400, /* Receiving /C/ ordered sets */
Ack = 0x00020000, /* Receive ACK frame */
+ Omed = 1<<20, /* media change; pcs interface */
};
enum { /* Txcw */
};
typedef struct Rd { /* Receive Descriptor */
- uint addr[2];
- ushort length;
- ushort checksum;
+ u32int addr[2];
+ u16int length;
+ u16int checksum;
uchar status;
uchar errors;
- ushort special;
+ u16int special;
} Rd;
enum { /* Rd status */
};
typedef struct { /* Transmit Descriptor */
- uint addr[2]; /* Data */
- uint control;
- uint status;
+ u32int addr[2]; /* Data */
+ u32int control;
+ u32int status;
} Td;
enum { /* Tdesc control */
};
typedef struct {
- ushort *reg;
- ulong *reg32;
- int sz;
+ u16int *reg;
+ u32int *reg32;
+ uint base;
+ uint lim;
} Flash;
enum {
Ntd = 128, /* power of two */
Nrb = 512+512, /* private receive buffers per Ctlr */
Rbalign = BY2PG, /* rx buffer alignment */
- Npool = 8,
};
/*
i82579,
i82580,
i82583,
+ i210,
+ i217,
+ i218,
+ i219,
+ i350,
Nctlrtype,
};
Fert = 1<<1,
F75 = 1<<2,
Fpba = 1<<3,
- Fflashea = 1<<4,
+ 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, 0, "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, "i82579",
- i82580, 9728, F75, "i82580",
- i82583, 1514, 0, "i82583",
+[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 *next;
int active;
int type;
- int pool;
- ushort eeprom[0x40];
+ u16int eeprom[0x40];
QLock alock; /* attach */
void *alloc; /* receive/transmit descriptors */
int ntd;
uint rbsz;
- int *nic;
+ u32int *nic;
Lock imlock;
int im; /* interrupt mask */
int lim;
QLock slock;
- uint statistics[Nstatistics];
+ u32int statistics[Nstatistics];
uint lsleep;
uint lintr;
uint rsleep;
uint phyerrata;
uchar ra[Eaddrlen]; /* receive address */
- ulong mta[128]; /* multicast table array */
+ u32int mta[128]; /* multicast table array */
Rendez rrendez;
int rim;
int fcrtl;
int fcrth;
- uint 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;
+ u32int pba; /* packet buffer allocation */
};
#define csr32r(c, r) (*((c)->nic+((r)/4)))
static Ctlr *i82563ctlrhead;
static Ctlr *i82563ctlrtail;
-static Rbpool rbtab[Npool];
static char *statistics[Nstatistics] = {
"CRC Error",
int i, r;
uvlong tuvl, ruvl;
Ctlr *ctlr;
- Rbpool *b;
+
+ p = s = smalloc(READSTR);
+ e = p + READSTR;
ctlr = edev->ctlr;
qlock(&ctlr->slock);
- p = s = malloc(READSTR);
- e = p + READSTR;
for(i = 0; i < Nstatistics; i++){
r = csr32r(ctlr, Statistics + i*4);
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);
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]);
}
-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)
{
static void
i82563txinit(Ctlr *ctlr)
{
- int i, r;
+ u32int r;
Block *b;
+ int i;
if(cttab[ctlr->type].flag & F75)
csr32w(ctlr, Tctl, 0x0F<<CtSHIFT | Psp);
else
csr32w(ctlr, Tctl, 0x0F<<CtSHIFT | Psp | 66<<ColdSHIFT | Mulr);
csr32w(ctlr, Tipg, 6<<20 | 8<<10 | 8); /* yb sez: 0x702008 */
- csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
-// csr32w(ctlr, Tdbah, Pciwaddrh(ctlr->tdba));
- csr32w(ctlr, Tdbah, 0);
- csr32w(ctlr, Tdlen, ctlr->ntd * sizeof(Td));
- ctlr->tdh = PREV(0, ctlr->ntd);
- csr32w(ctlr, Tdh, 0);
- ctlr->tdt = 0;
- csr32w(ctlr, Tdt, 0);
for(i = 0; i < ctlr->ntd; i++){
if((b = ctlr->tb[i]) != nil){
ctlr->tb[i] = nil;
}
memset(&ctlr->tdba[i], 0, sizeof(Td));
}
+ csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
+ csr32w(ctlr, Tdbah, 0);
+ csr32w(ctlr, Tdlen, ctlr->ntd * sizeof(Td));
+ ctlr->tdh = PREV(0, ctlr->ntd);
+ csr32w(ctlr, Tdh, 0);
+ ctlr->tdt = 0;
+ csr32w(ctlr, Tdt, 0);
csr32w(ctlr, Tidv, 128);
csr32w(ctlr, Tadv, 64);
csr32w(ctlr, Tctl, csr32r(ctlr, Tctl) | Ten);
csr32w(ctlr, Txdctl, r);
}
-#define Next(x, m) (((x)+1) & (m))
-
-static int
+static uint
i82563cleanup(Ctlr *c)
{
Block *b;
- int tdh, m, n;
+ uint tdh, n;
tdh = c->tdh;
- m = c->ntd-1;
- while(c->tdba[n = Next(tdh, m)].status & Tdd){
+ while(c->tdba[n = NEXT(tdh, c->ntd)].status & Tdd){
tdh = n;
if((b = c->tb[tdh]) != nil){
c->tb[tdh] = nil;
Block *bp;
Ether *edev;
Ctlr *ctlr;
- int tdh, tdt, m;
+ uint tdt, n;
edev = v;
ctlr = edev->ctlr;
- tdt = ctlr->tdt;
- m = ctlr->ntd-1;
-
i82563txinit(ctlr);
+ tdt = ctlr->tdt;
+ while(waserror())
+ ;
for(;;){
- tdh = i82563cleanup(ctlr);
-
- if(Next(tdt, m) == tdh){
+ n = NEXT(tdt, ctlr->ntd);
+ if(n == i82563cleanup(ctlr)){
ctlr->txdw++;
i82563im(ctlr, Txdw);
sleep(&ctlr->trendez, notrim, ctlr);
+ continue;
}
bp = qbread(edev->oq, 100000);
td = &ctlr->tdba[tdt];
td->addr[0] = PCIWADDR(bp->rp);
-// td->addr[1] = Pciwaddrh(bp->rp);
+ td->addr[1] = 0;
td->control = Ide|Rs|Ifcs|Teop|BLEN(bp);
+ coherence();
ctlr->tb[tdt] = bp;
- tdt = Next(tdt, m);
+ ctlr->tdt = tdt = n;
csr32w(ctlr, Tdt, tdt);
}
}
-static int
-i82563replenish(Ctlr *ctlr, int maysleep)
+static void
+i82563replenish(Ctlr *ctlr)
{
- uint rdt, m, i;
+ uint rdt, i;
Block *bp;
- Rbpool *p;
Rd *rd;
- rdt = ctlr->rdt;
- m = ctlr->nrd-1;
- p = rbtab + ctlr->pool;
i = 0;
- for(; Next(rdt, m) != ctlr->rdh; rdt = Next(rdt, m)){
+ 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] = Pciwaddrh(bp->rp);
+ rd->addr[1] = 0;
rd->status = 0;
ctlr->rdfree++;
}
if(i != 0){
+ coherence();
ctlr->rdt = rdt;
csr32w(ctlr, Rdt, rdt);
}
- return 0;
}
static void
csr32w(ctlr, Pbs, 16);
csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));
-// csr32w(ctlr, Rdbah, Pciwaddrh(ctlr->rdba));
csr32w(ctlr, Rdbah, 0);
csr32w(ctlr, Rdlen, ctlr->nrd * sizeof(Rd));
ctlr->rdh = 0;
static void
i82563rproc(void *arg)
{
- uint m, rdh, rim, im;
+ uint rdh, rim, im;
Block *bp;
Ctlr *ctlr;
Ether *edev;
im = Rxt0|Rxo|Rxdmt0|Rxseq|Ack;
}else
im = Rxt0|Rxo|Rxdmt0|Rxseq|Ack;
- m = ctlr->nrd-1;
+ 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;
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;
- rd->status = 0;
ctlr->rdfree--;
- ctlr->rdh = rdh = Next(rdh, m);
+ ctlr->rdh = rdh = NEXT(rdh, ctlr->nrd);
if(ctlr->nrd-ctlr->rdfree >= 32 || (rim & Rxdmt0))
- if(i82563replenish(ctlr, 0) == -1)
- break;
+ i82563replenish(ctlr);
}
}
}
}
static void
-phyerrata(Ether *e, Ctlr *c)
+phyerrata(Ether *e, Ctlr *c, uint phyno)
{
- if(e->mbps == 0)
+ 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
+ }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);
- if(phy == ~0)
+ if(phy == ~0){
+ phy = 0;
+ i = 3;
goto next;
+ }
i = (phy>>8) & 3;
a = phy & Ans;
if(a){
r = phyread(c, phyno, Phyctl);
phywrite(c, phyno, Phyctl, r | Ran | Ean);
}
- e->link = (phy & Link) != 0;
+next:
+ e->link = i != 3 && (phy & Link) != 0;
if(e->link == 0)
i = 3;
c->speeds[i]++;
e->mbps = speedtab[i];
-next:
- 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);
- if(phy == ~0)
+ phy = phyread(c, phyno, Physsr);
+ if(phy == ~0){
+ phy = 0;
+ i = 3;
goto next;
+ }
i = (phy>>14) & 3;
switch(c->type){
default:
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)
i = 3;
c->speeds[i]++;
e->mbps = speedtab[i];
if(c->type == i82563)
- phyerrata(e, c);
-next:
- 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);
for(;;){
phy = csr32r(c, Pcsstat);
e->link = phy & Linkok;
csr32w(c, Pcsctl, csr32r(c, Pcsctl) | Pan | Prestart);
c->speeds[i]++;
e->mbps = speedtab[i];
- c->lim = 0;
- i82563im(c, Lsc);
- 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);
+ lsleep(c, Lsc);
}
}
i82563attach(Ether *edev)
{
char name[KNAMELEN];
- int i;
- Block *bp;
Ctlr *ctlr;
ctlr = edev->ctlr;
ctlr->nrd = Nrd;
ctlr->ntd = Ntd;
ctlr->alloc = malloc(ctlr->nrd*sizeof(Rd)+ctlr->ntd*sizeof(Td) + 255);
- if(ctlr->alloc == nil){
+ ctlr->rb = malloc(ctlr->nrd * sizeof(Block*));
+ ctlr->tb = malloc(ctlr->ntd * sizeof(Block*));
+ if(ctlr->alloc == nil || ctlr->rb == nil || ctlr->tb == nil){
+ free(ctlr->rb);
+ ctlr->rb = nil;
+ free(ctlr->tb);
+ ctlr->tb = nil;
+ free(ctlr->alloc);
+ ctlr->alloc = nil;
qunlock(&ctlr->alock);
error(Enomem);
}
ctlr->rdba = (Rd*)ROUNDUP((uintptr)ctlr->alloc, 256);
ctlr->tdba = (Td*)(ctlr->rdba + ctlr->nrd);
- ctlr->rb = malloc(ctlr->nrd * sizeof(Block*));
- ctlr->tb = malloc(ctlr->ntd * sizeof(Block*));
-
if(waserror()){
- while(bp = i82563rballoc(rbtab + ctlr->pool)){
- bp->free = nil;
- freeb(bp);
- }
free(ctlr->tb);
ctlr->tb = nil;
free(ctlr->rb);
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, Ctrlext) & Linkmode) == Serdes)
- kproc(name, pcslproc, edev); /* phy based serdes */
- else if(csr32r(ctlr, Status) & Tbimode)
+ if(csr32r(ctlr, Status) & Tbimode)
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);
else
kproc(name, phylproc, edev);
im = ctlr->im;
while(icr = csr32r(ctlr, Icr) & ctlr->im){
- if(icr & Lsc){
- im &= ~Lsc;
- ctlr->lim = icr & Lsc;
+ if(icr & (Lsc | Omed)){
+ im &= ~(Lsc | Omed);
+ ctlr->lim = icr & (Lsc | Omed);
wakeup(&ctlr->lrendez);
ctlr->lintr++;
}
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++){
i82563detach(edev->ctlr);
}
-static ushort
+static int
eeread(Ctlr *ctlr, int adr)
{
+ int timeout;
+
csr32w(ctlr, Eerd, EEstart | adr << 2);
- while ((csr32r(ctlr, Eerd) & EEdone) == 0)
- ;
- return csr32r(ctlr, Eerd) >> 16;
+ timeout = 1000;
+ while ((csr32r(ctlr, Eerd) & EEdone) == 0 && timeout--)
+ microdelay(5);
+ if (timeout < 0) {
+ print("%s: eeread timeout\n", cname(ctlr));
+ return -1;
+ }
+ return (csr32r(ctlr, Eerd) >> 16) & 0xffff;
}
static int
eeload(Ctlr *ctlr)
{
- ushort sum;
+ u16int sum;
int data, adr;
sum = 0;
for (adr = 0; adr < 0x40; adr++) {
data = eeread(ctlr, adr);
+ if(data == -1) return -1;
ctlr->eeprom[adr] = data;
sum += data;
}
}
static int
-fcycle(Ctlr *, Flash *f)
+fread16(Ctlr *c, Flash *f, int ladr)
{
- ushort s, i;
+ u16int s;
+ 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)
{
- ushort 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 */
-
- while((f->reg[Fsts] & Fdone) == 0)
- ;
- if(f->reg[Fsts] & (Fcerr|Ael))
+ s = (f->reg32[Fctl/2] >> 16) & ~0x3ff;
+ f->reg32[Fctl/2] = (s | 3<<8 | Fgo) << 16; /* 4 byte read */
+ timeout = 1000;
+ while((f->reg32[Fsts/2] & Fdone) == 0 && timeout--)
+ microdelay(5);
+ if(timeout < 0){
+ print("%s: fread timeout\n", cname(c));
return -1;
- return f->reg32[Fdata] & 0xffff;
+ }
+ if(f->reg32[Fsts/2] & (Fcerr|Ael))
+ return -1;
+ *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
fload(Ctlr *c)
{
- ulong data, io, r, adr;
- ushort sum;
+ int data, r, adr;
+ u16int sum;
+ void *va;
Flash f;
- io = c->pcidev->mem[1].bar & ~0x0f;
- f.reg = vmap(io, c->pcidev->mem[1].size);
- if(f.reg == nil)
+ 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;
- f.reg32 = (ulong*)f.reg;
- f.sz = f.reg32[Bfpr];
- if(csr32r(c, Eec) & 1<<22){
- if(c->type == i82579)
- f.sz += 16; /* sector size: 64k */
- else
- f.sz += 1; /* sector size: 4k */
- }
- r = (f.sz & 0x1fff) << 12;
+ f.reg = va;
+ f.reg32 = va;
+ f.base = f.reg32[Bfpr] & 0x1fff;
+ f.lim = f.reg32[Bfpr]>>16 & 0x1fff;
+ if(csr32r(c, Eec) & Sec1val)
+ f.base += f.lim+1 - f.base >> 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;
}
- vunmap(f.reg, c->pcidev->mem[1].size);
+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;
}
csr32w(ctlr, Radv, v);
break;
case CMpause:
- csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) ^ (1<<27 | 1<<28));
+ csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) ^ (Rfce | Tfce));
break;
case CMan:
csr32w(ctlr, Ctrl, csr32r(ctlr, Ctrl) | Lrst | Phyrst);
static int
didtype(int d)
{
+ /*
+ * Some names and did values are from
+ * OpenBSD's em(4) Intel driver.
+ */
switch(d){
- case 0x1096:
- case 0x10ba: /* “gilgal” */
- // case 0x1098: /* serdes; not seen */
- // case 0x10bb: /* serdes */
+ case 0x1096: /* copper */
+ case 0x10ba: /* copper “gilgal” */
+ case 0x1098: /* serdes; not seen */
+ case 0x10bb: /* serdes */
return i82563;
- case 0x1049: /* mm */
- case 0x104a: /* dm */
- case 0x104b: /* dc */
- case 0x104d: /* v “ninevah” */
- case 0x10bd: /* dm-2 */
- case 0x294c: /* ich 9 */
+ case 0x1049: /* ich8; mm */
+ case 0x104a: /* ich8; dm */
+ case 0x104b: /* ich8; dc */
+ case 0x104d: /* ich8; v “ninevah” */
+ case 0x10bd: /* ich9; dm-2 */
+ case 0x294c: /* ich9 */
+ case 0x104c: /* ich8; untested */
+ case 0x10c4: /* ich8; untested */
+ case 0x10c5: /* ich8; untested */
return i82566;
case 0x10de: /* lm ich10d */
case 0x10df: /* lf ich10 */
case 0x10e5: /* lm ich9 */
case 0x10f5: /* lm ich9m; “boazman” */
+ case 0x10ce: /* v ich10 */
+ case 0x10c0: /* ich9 */
+ case 0x10c2: /* ich9; untested */
+ case 0x10c3: /* ich9; untested */
+ case 0x1501: /* ich8; untested */
return i82567;
case 0x10bf: /* lf ich9m */
case 0x10cb: /* v ich9m */
case 0x10cd: /* lf ich10 */
- case 0x10ce: /* v ich10 */
case 0x10cc: /* lm ich10 */
return i82567m;
- case 0x105e: /* eb */
- case 0x105f: /* eb */
- case 0x1060: /* eb */
- case 0x10a4: /* eb */
- case 0x10a5: /* eb fiber */
- case 0x10bc: /* eb */
+ case 0x105e: /* eb copper */
+ case 0x105f: /* eb fiber */
+ case 0x1060: /* eb serdes */
+ case 0x10a4: /* eb copper */
+ case 0x10a5: /* eb fiber */
+ case 0x10bc: /* eb copper */
case 0x10d9: /* eb serdes */
case 0x10da: /* eb serdes “ophir” */
+ case 0x10a0: /* eb; untested */
+ case 0x10a1: /* eb; untested */
+ case 0x10d5: /* copper; untested */
return i82571;
- case 0x107d: /* eb copper */
+ case 0x107d: /* ei copper */
case 0x107e: /* ei fiber */
- case 0x107f: /* ei */
+ case 0x107f: /* ei serdes */
case 0x10b9: /* ei “rimon” */
return i82572;
- case 0x108b: /* e “vidalia” */
- case 0x108c: /* e (iamt) */
- case 0x109a: /* l “tekoa” */
+ case 0x108b: /* e “vidalia” */
+ case 0x108c: /* e (iamt) */
+ case 0x109a: /* l “tekoa” */
+ case 0x10b0: /* l; untested */
+ case 0x10b2: /* v; untested */
+ case 0x10b3: /* e; untested */
+ case 0x10b4: /* l; untested */
return i82573;
case 0x10d3: /* l or it; “hartwell” */
+ case 0x10f6: /* la; untested */
return i82574;
- case 0x10a7:
- case 0x10a9: /* fiber/serdes */
+ case 0x10a7: /* eb */
+ case 0x10a9: /* eb fiber/serdes */
+ case 0x10d6: /* untested */
+ case 0x10e2: /* untested */
return i82575;
case 0x10c9: /* copper */
case 0x10e6: /* fiber */
case 0x10e7: /* serdes; “kawela” */
+ case 0x10e8: /* copper; untested */
+ case 0x150a: /* untested */
+ case 0x150d: /* serdes backplane */
+ case 0x1518: /* serdes; untested */
+ case 0x1526: /* untested */
return i82576;
case 0x10ea: /* lc “calpella”; aka pch lan */
return i82577;
case 0x10ef: /* dc “piketon” */
return i82578;
case 0x1502: /* lm */
- case 0x1503: /* v */
+ case 0x1503: /* v “lewisville” */
return i82579;
case 0x10f0: /* dm “king's creek” */
return i82578m;
- case 0x150e: /* “barton hills” */
+ case 0x150e: /* copper “barton hills” */
case 0x150f: /* fiber */
- case 0x1510: /* backplane */
- case 0x1511: /* sfp */
- case 0x1516:
+ case 0x1510: /* serdes backplane */
+ case 0x1511: /* sgmii sfp */
+ case 0x1516: /* copper */
return i82580;
case 0x1506: /* v */
+ case 0x150c: /* untested */
return i82583;
+ 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;
}
if((type = didtype(p->did)) == -1)
continue;
ctlr = malloc(sizeof(Ctlr));
+ if(ctlr == nil){
+ print("%s: can't allocate memory\n", cttab[type].name);
+ continue;
+ }
ctlr->type = type;
ctlr->pcidev = p;
ctlr->rbsz = cttab[type].mtu;
{
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;
}
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)
+{
+ return pnp(e, i350);
+}
+
void
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);
}