]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/ether82563.c
ether82563: add 0x15bd i219-lm variant (thanks crab1)
[plan9front.git] / sys / src / 9 / pc / ether82563.c
index 6fea78ce8c532bf377060e8e2c83b1c35d405a83..2322e40265a195a5c1d3605e831a1efebeb7eb6c 100644 (file)
@@ -9,10 +9,10 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "../port/pci.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 +105,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 +131,7 @@ enum {                                      /* Status */
 enum {                                 /* Eec */
        Nvpres          = 1<<8,
        Autord          = 1<<9,
+       Flupd           = 1<<19,
        Sec1val         = 1<<22,
 };
 
@@ -169,6 +173,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 */
@@ -440,6 +447,10 @@ enum {
        i82579,
        i82580,
        i82583,
+       i210,
+       i217,
+       i218,
+       i219,
        i350,
        Nctlrtype,
 };
@@ -451,42 +462,48 @@ 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*);
 
 typedef struct Ctlr Ctlr;
 struct Ctlr {
-       ulong   port;
+       uvlong  port;
        Pcidev  *pcidev;
        Ctlr    *next;
        int     active;
@@ -497,7 +514,7 @@ struct Ctlr {
        void    *alloc;                 /* receive/transmit descriptors */
        int     nrd;
        int     ntd;
-       uint    rbsz;
+       int     rbsz;
 
        u32int  *nic;
        Lock    imlock;
@@ -698,13 +715,13 @@ i82563ifstat(Ether *edev, void *a, long n, ulong offset)
                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);
@@ -743,10 +760,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.
@@ -756,8 +789,6 @@ i82563multicast(void *arg, uchar *addr, int on)
         */
        if(on)
                ctlr->mta[x] |= 1<<bit;
-//     else
-//             ctlr->mta[x] &= ~(1<<bit);
 
        csr32w(ctlr, Mta+x*4, ctlr->mta[x]);
 }
@@ -850,6 +881,8 @@ i82563tproc(void *v)
        i82563txinit(ctlr);
 
        tdt = ctlr->tdt;
+       while(waserror())
+               ;
        for(;;){
                n = NEXT(tdt, ctlr->ntd);
                if(n == i82563cleanup(ctlr)){
@@ -910,8 +943,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)
@@ -983,6 +1014,8 @@ i82563rproc(void *arg)
        }else
                im = Rxt0|Rxo|Rxdmt0|Rxseq|Ack;
 
+       while(waserror())
+               ;
        for(;;){
                i82563im(ctlr, im);
                ctlr->rsleep++;
@@ -1007,7 +1040,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){
@@ -1029,7 +1061,7 @@ i82563rproc(void *arg)
                                        bp->checksum = rd->checksum;
                                        bp->flag |= Bpktck;
                                }
-                               etheriq(edev, bp, 1);
+                               etheriq(edev, bp);
                        } else
                                freeb(bp);
                        ctlr->rb[rdh] = nil;
@@ -1065,7 +1097,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;
@@ -1116,72 +1148,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;
@@ -1196,18 +1264,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)
@@ -1215,11 +1283,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);
        }
 }
 
@@ -1232,6 +1297,8 @@ pcslproc(void *v)
 
        e = v;
        c = e->ctlr;
+       while(waserror())
+               ;
 
        if(c->type == i82575 || c->type == i82576)
                csr32w(c, Connsw, Enrgirq);
@@ -1245,10 +1312,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);
        }
 }
 
@@ -1261,7 +1325,8 @@ serdeslproc(void *v)
 
        e = v;
        c = e->ctlr;
-
+       while(waserror())
+               ;
        for(;;){
                rx = csr32r(c, Rxcw);
                tx = csr32r(c, Txcw);
@@ -1273,35 +1338,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);
-       }
-}
-
-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);
        }
 }
 
@@ -1354,8 +1391,6 @@ i82563attach(Ether *edev)
                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);
 
@@ -1520,49 +1555,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
@@ -1573,7 +1664,14 @@ fload(Ctlr *c)
        void *va;
        Flash f;
 
-       va = vmap(c->pcidev->mem[1].bar & ~0x0f, c->pcidev->mem[1].size);
+       memset(c->eeprom, 0xFF, sizeof(c->eeprom));
+       if(c->pcidev->mem[1].bar == 0)
+               return fload32(c);      /* i219 */
+
+       if(c->pcidev->mem[1].bar & 1)
+               return -1;
+
+       va = vmap(c->pcidev->mem[1].bar & ~0xF, c->pcidev->mem[1].size);
        if(va == nil)
                return -1;
        f.reg = va;
@@ -1585,16 +1683,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)
 {
@@ -1624,18 +1757,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;
@@ -1649,14 +1791,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;
 }
@@ -1822,12 +1966,48 @@ 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 0x15bb:            /* i219-lm */
+       case 0x15bd:            /* i219-lm */
+       case 0x15d6:            /* i219-v */
+       case 0x15d7:            /* i219-lm */
+       case 0x15d8:            /* i219-v */
+       case 0x15e3:            /* i219-lm */
+       case 0x0d4c:            /* 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;
@@ -1852,6 +2032,8 @@ i82563pci(void)
 
        for(p = nil; p = pcimatch(p, 0x8086, 0);){
                hbafixup(p);
+               if(p->mem[0].bar & 1)
+                       continue;
                if((type = didtype(p->did)) == -1)
                        continue;
                ctlr = malloc(sizeof(Ctlr));
@@ -1861,8 +2043,8 @@ i82563pci(void)
                }
                ctlr->type = type;
                ctlr->pcidev = p;
-               ctlr->rbsz = cttab[type].mtu;
-               ctlr->port = p->mem[0].bar & ~0x0F;
+               ctlr->rbsz = ROUND(cttab[type].mtu, 1024);
+               ctlr->port = p->mem[0].bar & ~0xF;
                if(i82563ctlrhead != nil)
                        i82563ctlrtail->next = ctlr;
                else
@@ -1879,14 +2061,16 @@ setup(Ctlr *ctlr)
        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 %llux\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;
 }
 
@@ -1925,7 +2109,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);
 
        /*
@@ -1933,7 +2117,6 @@ pnp(Ether *edev, int type)
         */
        edev->attach = i82563attach;
 //     edev->transmit = i82563transmit;
-       edev->interrupt = i82563interrupt;
        edev->ifstat = i82563ifstat;
        edev->ctl = i82563ctl;
 
@@ -1942,6 +2125,8 @@ pnp(Ether *edev, int type)
        edev->shutdown = i82563shutdown;
        edev->multicast = i82563multicast;
 
+       intrenable(edev->irq, i82563interrupt, edev, edev->tbdf, edev->name);
+
        return 0;
 }
 
@@ -2035,6 +2220,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)
 {
@@ -2064,6 +2273,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);
 }