]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/ether8169.c
pc/ether*: use 64-bit physical addresses and check pci membar types and sizes
[plan9front.git] / sys / src / 9 / pc / ether8169.c
index 020fd69d1765e26e4e51b43c8911f42e21395063..bf6cf8ef48f5f90a37fa33f150a810653c6658b3 100644 (file)
@@ -15,9 +15,8 @@
 #include "io.h"
 #include "../port/error.h"
 #include "../port/netif.h"
-
-#include "etherif.h"
-#include "ethermii.h"
+#include "../port/etherif.h"
+#include "../port/ethermii.h"
 
 enum {                                 /* registers */
        Idr0            = 0x00,         /* MAC address */
@@ -50,6 +49,8 @@ enum {                                        /* registers */
        Tbianar         = 0x68,         /* TBI Auto-Negotiation Advertisment */
        Tbilpar         = 0x6A,         /* TBI Auto-Negotiation Link Partner */
        Phystatus       = 0x6C,         /* PHY Status */
+       Pmch            = 0x6F,         /* power management */
+       Ldps            = 0x82,         /* link down power saving */
 
        Rms             = 0xDA,         /* Receive Packet Maximum Size */
        Cplusc          = 0xE0,         /* C+ Command */
@@ -113,6 +114,17 @@ enum {                                     /* Tcr */
        Macv15          = 0x38800000,   /* RTL8100E */
 //     Macv19          = 0x3c000000,   /* dup Macv12a: RTL8111c-gr */
        Macv25          = 0x28000000,   /* RTL8168D */
+       Macv26          = 0x48000000,   /* RTL8111/8168B */
+       Macv27          = 0x2c800000,   /* RTL8111e */
+       Macv28          = 0x2c000000,   /* RTL8111/8168B */
+       Macv29          = 0x40800000,   /* RTL8101/8102E */
+       Macv30          = 0x24000000,   /* RTL8101E? (untested) */
+       Macv39          = 0x44800000,   /* RTL8106E */
+       Macv40          = 0x4c000000,   /* RTL8168G */
+       Macv42          = 0x50800000,   /* RTL8168GU */
+       Macv44          = 0x5c800000,   /* RTL8411B */
+       Macv45          = 0x54000000,   /* RTL8111HN */
+
        Ifg0            = 0x01000000,   /* Interframe Gap 0 */
        Ifg1            = 0x02000000,   /* Interframe Gap 1 */
 };
@@ -171,6 +183,7 @@ enum {                                      /* Cplusc */
        Dac             = 0x0010,       /* PCI Dual Address Cycle Enable */
        Rxchksum        = 0x0020,       /* Receive Checksum Offload Enable */
        Rxvlan          = 0x0040,       /* Receive VLAN De-tagging Enable */
+       Macstatdis      = 0x0080,       /* Disable Mac Statistics */
        Endian          = 0x0200,       /* Endian Mode */
 };
 
@@ -383,13 +396,27 @@ rtl8169mii(Ctlr* ctlr)
        ctlr->mii->miw = rtl8169miimiw;
        ctlr->mii->ctlr = ctlr;
 
+       /*
+        * PHY wakeup
+        */
+       switch(ctlr->macv){
+       case Macv25:
+       case Macv28:
+       case Macv29:
+       case Macv30:
+               csr8w(ctlr, Pmch, csr8r(ctlr, Pmch) | 0x80);
+               break;
+       }
+       rtl8169miimiw(ctlr->mii, 1, 0x1f, 0);
+       rtl8169miimiw(ctlr->mii, 1, 0x0e, 0);
+
        /*
         * Get rev number out of Phyidr2 so can config properly.
         * There's probably more special stuff for Macv0[234] needed here.
         */
        ctlr->phyv = rtl8169miimir(ctlr->mii, 1, Phyidr2) & 0x0F;
        if(ctlr->macv == Macv02){
-               csr8w(ctlr, 0x82, 1);                           /* magic */
+               csr8w(ctlr, Ldps, 1);                           /* magic */
                rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000);      /* magic */
        }
 
@@ -401,6 +428,10 @@ rtl8169mii(Ctlr* ctlr)
        print("rtl8169: oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n",
                phy->oui, phy->phyno, ctlr->macv, ctlr->phyv);
 
+       miireset(ctlr->mii);
+
+       microdelay(100);
+
        miiane(ctlr->mii, ~0, ~0, ~0);
 
        return 0;
@@ -560,7 +591,7 @@ rtl8169ifstat(Ether* edev, void* a, long n, ulong offset)
        l += snprint(p+l, READSTR-l, "multicast: %ud\n", ctlr->mcast);
 
        if(ctlr->mii != nil && ctlr->mii->curphy != nil){
-               l += snprint(p+l, READSTR, "phy:   ");
+               l += snprint(p+l, READSTR-l, "phy:   ");
                for(i = 0; i < NMiiPhyr; i++){
                        if(i && ((i & 0x07) == 0))
                                l += snprint(p+l, READSTR-l, "\n       ");
@@ -643,7 +674,7 @@ rtl8169init(Ether* edev)
        u32int r;
        Block *bp;
        Ctlr *ctlr;
-       u8int cplusc;
+       u16int cplusc;
 
        ctlr = edev->ctlr;
        ilock(ctlr);
@@ -672,7 +703,16 @@ rtl8169init(Ether* edev)
 
        cplusc = csr16r(ctlr, Cplusc);
        cplusc &= ~(Endian|Rxchksum);
-       cplusc |= Txenb|Rxenb|Mulrw;
+       cplusc |= Txenb|Mulrw;
+       switch(ctlr->macv){
+       case Macv40:
+       case Macv44:
+               cplusc |= Macstatdis;
+               break;
+       default:
+               cplusc |= Rxenb;
+               break;
+       }
        csr16w(ctlr, Cplusc, cplusc);
 
        csr32w(ctlr, Tnpds+4, 0);
@@ -684,7 +724,15 @@ rtl8169init(Ether* edev)
 
        csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited);
        ctlr->tcr = csr32r(ctlr, Tcr);
-       ctlr->rcr = Rxfthnone|Mrxdmaunlimited|Ab|Am|Apm;
+       switch(ctlr->macv){
+       case Macv42:
+       case Macv45:
+               ctlr->rcr = Rxfth256|Mrxdmaunlimited|Ab|Am|Apm;
+               break;
+       default:
+               ctlr->rcr = Rxfthnone|Mrxdmaunlimited|Ab|Am|Apm;
+               break;
+       }
        ctlr->mchash = 0;
        csr32w(ctlr, Mar0,   0);
        csr32w(ctlr, Mar0+4, 0);
@@ -741,16 +789,33 @@ rtl8169attach(Ether* edev)
 
        ctlr = edev->ctlr;
        qlock(&ctlr->alock);
-       if(ctlr->init++ == 0){
-               ctlr->td = mallocalign(sizeof(D)*Ntd, 256, 0, 0);
-               ctlr->tb = malloc(Ntd*sizeof(Block*));
+       if(!ctlr->init){
                ctlr->ntd = Ntd;
-               ctlr->rd = mallocalign(sizeof(D)*Nrd, 256, 0, 0);
-               ctlr->rb = malloc(Nrd*sizeof(Block*));
                ctlr->nrd = Nrd;
+               ctlr->tb = malloc(ctlr->ntd*sizeof(Block*));
+               ctlr->rb = malloc(ctlr->nrd*sizeof(Block*));
+               ctlr->td = mallocalign(sizeof(D)*ctlr->ntd, 256, 0, 0);
+               ctlr->rd = mallocalign(sizeof(D)*ctlr->nrd, 256, 0, 0);
                ctlr->dtcc = mallocalign(sizeof(Dtcc), 64, 0, 0);
-
+               if(ctlr->rb == nil || ctlr->rb == nil || 
+                  ctlr->rd == nil || ctlr->rd == nil || ctlr->dtcc == nil){
+                       free(ctlr->tb);
+                       ctlr->tb = nil;
+                       free(ctlr->rb);
+                       ctlr->rb = nil;
+                       free(ctlr->td);
+                       ctlr->td = nil;
+                       free(ctlr->rd);
+                       ctlr->rd = nil;
+                       free(ctlr->dtcc);
+                       ctlr->dtcc = nil;
+                       qunlock(&ctlr->alock);
+                       error(Enomem);
+               }
+               ctlr->init = 1;
                kproc("rtl8169", rtl8169reseter, edev);
+
+               /* rtl8169reseter() does qunlock(&ctlr->alock) when complete */
                qlock(&ctlr->alock);
        }
        qunlock(&ctlr->alock);
@@ -774,15 +839,12 @@ rtl8169link(Ether* edev)
 
        ctlr = edev->ctlr;
 
+       r = csr8r(ctlr, Phystatus);
        /*
         * Maybe the link changed - do we care very much?
         * Could stall transmits if no link, maybe?
         */
-       if(!((r = csr8r(ctlr, Phystatus)) & Linksts)){
-               edev->link = 0;
-               return;
-       }
-       edev->link = 1;
+       edev->link = (r & Linksts) != 0;
 
        limit = 256*1024;
        if(r & Speed10){
@@ -864,8 +926,10 @@ rtl8169receive(Ether* edev)
        int x;
 
        ctlr = edev->ctlr;
-       x = ctlr->rdh;
-       for(;;){
+       if(ctlr->nrq < ctlr->nrd/2)
+               rtl8169replenish(ctlr);
+
+       for(x = ctlr->rdh; x != ctlr->rdt;){
                d = &ctlr->rd[x];
                if((control = d->control) & Own)
                        break;
@@ -913,7 +977,7 @@ rtl8169receive(Ether* edev)
                                bp->flag |= Bipck;
                                break;
                        }
-                       etheriq(edev, bp, 1);
+                       etheriq(edev, bp);
                }else{
                        if(!(control & Res))
                                ctlr->frag++;
@@ -993,6 +1057,16 @@ vetmacv(Ctlr *ctlr, uint *macv)
        case Macv14:
        case Macv15:
        case Macv25:
+       case Macv26:
+       case Macv27:
+       case Macv28:
+       case Macv29:
+       case Macv30:
+       case Macv39:
+       case Macv40:
+       case Macv42:
+       case Macv44:
+       case Macv45:
                break;
        }
        return 0;
@@ -1034,30 +1108,27 @@ rtl8169pci(void)
                        continue;
                }
                ctlr = malloc(sizeof(Ctlr));
+               if(ctlr == nil){
+                       print("rtl8169: can't allocate memory\n");
+                       iofree(port);
+                       continue;
+               }
                ctlr->port = port;
                ctlr->pcidev = p;
                ctlr->pciv = i;
                ctlr->pcie = pcie;
 
+               pcienable(p);
                if(vetmacv(ctlr, &macv) == -1){
+                       pcidisable(p);
                        iofree(port);
                        free(ctlr);
                        print("rtl8169: unknown mac %.4ux %.8ux\n", p->did, macv);
                        continue;
                }
 
-               if(pcigetpms(p) > 0){
-                       pcisetpms(p, 0);
-
-                       for(i = 0; i < 6; i++)
-                               pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar);
-                       pcicfgw8(p, PciINTL, p->intl);
-                       pcicfgw8(p, PciLTR, p->ltr);
-                       pcicfgw8(p, PciCLS, p->cls);
-                       pcicfgw16(p, PciPCR, p->pcr);
-               }
-
                if(rtl8169reset(ctlr)){
+                       pcidisable(p);
                        iofree(port);
                        free(ctlr);
                        print("rtl8169: reset failed\n");
@@ -1135,7 +1206,6 @@ rtl8169pnp(Ether* edev)
 
        edev->attach = rtl8169attach;
        edev->transmit = rtl8169transmit;
-       edev->interrupt = rtl8169interrupt;
        edev->ifstat = rtl8169ifstat;
 
        edev->arg = edev;
@@ -1144,6 +1214,8 @@ rtl8169pnp(Ether* edev)
 
        rtl8169link(edev);
 
+       intrenable(edev->irq, rtl8169interrupt, edev, edev->tbdf, edev->name);
+
        return 0;
 }