]> 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 94213a0134084ca247ef3806d00d3ab1f2561e95..2322e40265a195a5c1d3605e831a1efebeb7eb6c 100644 (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
  * Coraid EtherDrive® hba
  */
@@ -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
@@ -34,6 +34,7 @@ enum {
        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 */
@@ -104,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 */
@@ -124,6 +128,13 @@ enum {                                     /* Status */
        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 */
@@ -131,8 +142,15 @@ enum {                                     /* Eerd */
 
 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 */
@@ -155,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 */
@@ -226,6 +247,7 @@ enum {                                      /* Icr, Ics, Ims, Imc */
        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 */
@@ -308,12 +330,12 @@ enum {                                    /* Rxcsum */
 };
 
 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 */
@@ -337,9 +359,9 @@ enum {                                      /* Rd errors */
 };
 
 typedef struct {                       /* Transmit Descriptor */
-       uint    addr[2];                /* Data */
-       uint    control;
-       uint    status;
+       u32int  addr[2];                /* Data */
+       u32int  control;
+       u32int  status;
 } Td;
 
 enum {                                 /* Tdesc control */
@@ -369,9 +391,10 @@ enum {                                     /* Tdesc status */
 };
 
 typedef struct {
-       ushort  *reg;
-       ulong   *reg32;
-       int     sz;
+       u16int  *reg;
+       u32int  *reg32;
+       uint    base;
+       uint    lim;
 } Flash;
 
 enum {
@@ -400,7 +423,6 @@ enum {
        Ntd             = 128,          /* power of two */
        Nrb             = 512+512,      /* private receive buffers per Ctlr */
        Rbalign         = BY2PG,        /* rx buffer alignment */
-       Npool           = 8,
 };
 
 /*
@@ -425,6 +447,11 @@ enum {
        i82579,
        i82580,
        i82583,
+       i210,
+       i217,
+       i218,
+       i219,
+       i350,
        Nctlrtype,
 };
 
@@ -433,56 +460,63 @@ enum {
        Fert    = 1<<1,
        F75     = 1<<2,
        Fpba    = 1<<3,
-       Fflashea        = 1<<4,
+       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,   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|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;
        int     type;
-       int     pool;
-       ushort  eeprom[0x40];
+       u16int  eeprom[0x40];
 
        QLock   alock;                  /* attach */
        void    *alloc;                 /* receive/transmit descriptors */
        int     nrd;
        int     ntd;
-       uint    rbsz;
+       int     rbsz;
 
-       int     *nic;
+       u32int  *nic;
        Lock    imlock;
        int     im;                     /* interrupt mask */
 
@@ -490,7 +524,7 @@ struct Ctlr {
        int     lim;
 
        QLock   slock;
-       uint    statistics[Nstatistics];
+       u32int  statistics[Nstatistics];
        uint    lsleep;
        uint    lintr;
        uint    rsleep;
@@ -504,7 +538,7 @@ struct Ctlr {
        uint    phyerrata;
 
        uchar   ra[Eaddrlen];           /* receive address */
-       ulong   mta[128];               /* multicast table array */
+       u32int  mta[128];               /* multicast table array */
 
        Rendez  rrendez;
        int     rim;
@@ -527,26 +561,7 @@ struct Ctlr {
        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)))
@@ -554,7 +569,6 @@ struct Rbpool {
 
 static Ctlr    *i82563ctlrhead;
 static Ctlr    *i82563ctlrtail;
-static Rbpool  rbtab[Npool];
 
 static char *statistics[Nstatistics] = {
        "CRC Error",
@@ -645,12 +659,12 @@ 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;
 
        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);
@@ -697,20 +711,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);
@@ -749,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.
@@ -762,148 +789,10 @@ 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]);
 }
 
-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;
-                       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)
 {
@@ -916,22 +805,15 @@ 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;
@@ -939,6 +821,13 @@ i82563txinit(Ctlr *ctlr)
                }
                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);
@@ -949,17 +838,14 @@ i82563txinit(Ctlr *ctlr)
        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;
@@ -988,78 +874,63 @@ i82563tproc(void *v)
        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
@@ -1072,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)
@@ -1092,7 +961,6 @@ i82563rxinit(Ctlr *ctlr)
                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;
@@ -1129,7 +997,7 @@ i82563rim(void *v)
 static void
 i82563rproc(void *arg)
 {
-       uint m, rdh, rim, im;
+       uint rdh, rim, im;
        Block *bp;
        Ctlr *ctlr;
        Ether *edev;
@@ -1145,19 +1013,20 @@ i82563rproc(void *arg)
                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;
 
@@ -1171,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){
@@ -1193,16 +1061,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, m);
+                       ctlr->rdh = rdh = NEXT(rdh, ctlr->nrd);
                        if(ctlr->nrd-ctlr->rdfree >= 32 || (rim & Rxdmt0))
-                               if(i82563replenish(ctlr, 0) == -1)
-                                       break;
+                               i82563replenish(ctlr);
                }
        }
 }
@@ -1231,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;
@@ -1282,71 +1148,113 @@ 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(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)
 {
-       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)
-                       goto next;
-               i = (phy>>8) & 3;
-               a = phy & Ans;
-               if(a){
-                       r = phyread(c, phyno, Phyctl);
-                       phywrite(c, phyno, Phyctl, r | Ran | Ean);
+               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;
                }
-               e->link = (phy & Link) != 0;
+               i = (phy>>8) & 3;
+               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:
@@ -1356,30 +1264,27 @@ 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)
                        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);
        }
 }
 
@@ -1392,7 +1297,11 @@ pcslproc(void *v)
 
        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;
@@ -1403,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);
-               c->lsleep++;
-               sleep(&c->lrendez, i82563lim, c);
+               lsleep(c, Lsc | Omed);
        }
 }
 
@@ -1419,7 +1325,8 @@ serdeslproc(void *v)
 
        e = v;
        c = e->ctlr;
-
+       while(waserror())
+               ;
        for(;;){
                rx = csr32r(c, Rxcw);
                tx = csr32r(c, Txcw);
@@ -1431,10 +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);
+               lsleep(c, Lsc);
        }
 }
 
@@ -1442,8 +1346,6 @@ static void
 i82563attach(Ether *edev)
 {
        char name[KNAMELEN];
-       int i;
-       Block *bp;
        Ctlr *ctlr;
 
        ctlr = edev->ctlr;
@@ -1456,21 +1358,22 @@ i82563attach(Ether *edev)
        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);
@@ -1481,18 +1384,12 @@ 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, 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);
@@ -1522,9 +1419,9 @@ i82563interrupt(Ureg*, void *arg)
        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++;
                }
@@ -1576,6 +1473,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++){
@@ -1619,24 +1522,32 @@ i82563shutdown(Ether *edev)
        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;
        }
@@ -1644,77 +1555,179 @@ eeload(Ctlr *ctlr)
 }
 
 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 */
+
+       if(c->pcidev->mem[1].bar & 1)
                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;
+
+       va = vmap(c->pcidev->mem[1].bar & ~0xF, c->pcidev->mem[1].size);
+       if(va == nil)
+               return -1;
+       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)
 {
@@ -1744,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;
@@ -1769,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;
 }
@@ -1830,7 +1854,7 @@ i82563ctl(Ether *edev, void *buf, long n)
                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);
@@ -1845,56 +1869,82 @@ i82563ctl(Ether *edev, void *buf, long n)
 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;
@@ -1903,18 +1953,62 @@ didtype(int d)
        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 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;
 }
@@ -1938,13 +2032,19 @@ 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));
+               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;
-               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
@@ -1958,21 +2058,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 %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;
 }
 
@@ -2011,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);
 
        /*
@@ -2019,7 +2117,6 @@ pnp(Ether *edev, int type)
         */
        edev->attach = i82563attach;
 //     edev->transmit = i82563transmit;
-       edev->interrupt = i82563interrupt;
        edev->ifstat = i82563ifstat;
        edev->ctl = i82563ctl;
 
@@ -2028,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;
 }
 
@@ -2121,6 +2220,36 @@ 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)
+{
+       return pnp(e, i350);
+}
+
 void
 ether82563link(void)
 {
@@ -2144,5 +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);
 }