The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/ether8169.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Realtek RTL8110S/8169S.
    3  * Mostly there. There are some magic register values used
    4  * which are not described in any datasheet or driver but seem
    5  * to be necessary.
    6  * No tuning has been done. Only tested on an RTL8110S, there
    7  * are slight differences between the chips in the series so some
    8  * tweaks may be needed.
    9  */
   10 #include "u.h"
   11 #include "../port/lib.h"
   12 #include "mem.h"
   13 #include "dat.h"
   14 #include "fns.h"
   15 #include "io.h"
   16 #include "../port/error.h"
   17 #include "../port/netif.h"
   18 
   19 #include "etherif.h"
   20 #include "ethermii.h"
   21 
   22 enum {                                  /* registers */
   23         Idr0            = 0x00,         /* MAC address */
   24         Mar0            = 0x08,         /* Multicast address */
   25         Dtccr           = 0x10,         /* Dump Tally Counter Command */
   26         Tnpds           = 0x20,         /* Transmit Normal Priority Descriptors */
   27         Thpds           = 0x28,         /* Transmit High Priority Descriptors */
   28         Flash           = 0x30,         /* Flash Memory Read/Write */
   29         Erbcr           = 0x34,         /* Early Receive Byte Count */
   30         Ersr            = 0x36,         /* Early Receive Status */
   31         Cr              = 0x37,         /* Command Register */
   32         Tppoll          = 0x38,         /* Transmit Priority Polling */
   33         Imr             = 0x3C,         /* Interrupt Mask */
   34         Isr             = 0x3E,         /* Interrupt Status */
   35         Tcr             = 0x40,         /* Transmit Configuration */
   36         Rcr             = 0x44,         /* Receive Configuration */
   37         Tctr            = 0x48,         /* Timer Count */
   38         Mpc             = 0x4C,         /* Missed Packet Counter */
   39         Cr9346          = 0x50,         /* 9346 Command Register */
   40         Config0         = 0x51,         /* Configuration Register 0 */
   41         Config1         = 0x52,         /* Configuration Register 1 */
   42         Config2         = 0x53,         /* Configuration Register 2 */
   43         Config3         = 0x54,         /* Configuration Register 3 */
   44         Config4         = 0x55,         /* Configuration Register 4 */
   45         Config5         = 0x56,         /* Configuration Register 5 */
   46         Timerint        = 0x58,         /* Timer Interrupt */
   47         Mulint          = 0x5C,         /* Multiple Interrupt Select */
   48         Phyar           = 0x60,         /* PHY Access */
   49         Tbicsr0         = 0x64,         /* TBI Control and Status */
   50         Tbianar         = 0x68,         /* TBI Auto-Negotiation Advertisment */
   51         Tbilpar         = 0x6A,         /* TBI Auto-Negotiation Link Partner */
   52         Phystatus       = 0x6C,         /* PHY Status */
   53 
   54         Rms             = 0xDA,         /* Receive Packet Maximum Size */
   55         Cplusc          = 0xE0,         /* C+ Command */
   56         Rdsar           = 0xE4,         /* Receive Descriptor Start Address */
   57         Mtps            = 0xEC,         /* Max. Transmit Packet Size */
   58 };
   59 
   60 enum {                                  /* Dtccr */
   61         Cmd             = 0x00000008,   /* Command */
   62 };
   63 
   64 enum {                                  /* Cr */
   65         Te              = 0x04,         /* Transmitter Enable */
   66         Re              = 0x08,         /* Receiver Enable */
   67         Rst             = 0x10,         /* Software Reset */
   68 };
   69 
   70 enum {                                  /* Tppoll */
   71         Fswint          = 0x01,         /* Forced Software Interrupt */
   72         Npq             = 0x40,         /* Normal Priority Queue polling */
   73         Hpq             = 0x80,         /* High Priority Queue polling */
   74 };
   75 
   76 enum {                                  /* Imr/Isr */
   77         Rok             = 0x0001,       /* Receive OK */
   78         Rer             = 0x0002,       /* Receive Error */
   79         Tok             = 0x0004,       /* Transmit OK */
   80         Ter             = 0x0008,       /* Transmit Error */
   81         Rdu             = 0x0010,       /* Receive Descriptor Unavailable */
   82         Punlc           = 0x0020,       /* Packet Underrun or Link Change */
   83         Fovw            = 0x0040,       /* Receive FIFO Overflow */
   84         Tdu             = 0x0080,       /* Transmit Descriptor Unavailable */
   85         Swint           = 0x0100,       /* Software Interrupt */
   86         Timeout         = 0x4000,       /* Timer */
   87         Serr            = 0x8000,       /* System Error */
   88 };
   89 
   90 enum {                                  /* Tcr */
   91         MtxdmaSHIFT     = 8,            /* Max. DMA Burst Size */
   92         MtxdmaMASK      = 0x00000700,
   93         Mtxdmaunlimited = 0x00000700,
   94         Acrc            = 0x00010000,   /* Append CRC (not) */
   95         Lbk0            = 0x00020000,   /* Loopback Test 0 */
   96         Lbk1            = 0x00040000,   /* Loopback Test 1 */
   97         Ifg2            = 0x00080000,   /* Interframe Gap 2 */
   98         HwveridSHIFT    = 23,           /* Hardware Version ID */
   99         HwveridMASK     = 0x7C800000,
  100         Macv01          = 0x00000000,   /* RTL8169 */
  101         Macv02          = 0x00800000,   /* RTL8169S/8110S */
  102         Macv03          = 0x04000000,   /* RTL8169S/8110S */
  103         Macv04          = 0x10000000,   /* RTL8169SB/8110SB */
  104         Macv05          = 0x18000000,   /* RTL8169SC/8110SC */
  105         Macv11          = 0x30000000,   /* RTL8168B/8111B */
  106         Macv12          = 0x38000000,   /* RTL8169B/8111B */
  107         Macv13          = 0x34000000,   /* RTL8101E */
  108         Macv14          = 0x30800000,   /* RTL8100E */
  109         Macv15          = 0x38800000,   /* RTL8100E */
  110         Macv16          = 0x24800000,   /* RTL8102EL */
  111         Macv25          = 0x28000000,   /* RTL8168D */
  112         Ifg0            = 0x01000000,   /* Interframe Gap 0 */
  113         Ifg1            = 0x02000000,   /* Interframe Gap 1 */
  114 };
  115 
  116 enum {                                  /* Rcr */
  117         Aap             = 0x00000001,   /* Accept All Packets */
  118         Apm             = 0x00000002,   /* Accept Physical Match */
  119         Am              = 0x00000004,   /* Accept Multicast */
  120         Ab              = 0x00000008,   /* Accept Broadcast */
  121         Ar              = 0x00000010,   /* Accept Runt */
  122         Aer             = 0x00000020,   /* Accept Error */
  123         Sel9356         = 0x00000040,   /* 9356 EEPROM used */
  124         MrxdmaSHIFT     = 8,            /* Max. DMA Burst Size */
  125         MrxdmaMASK      = 0x00000700,
  126         Mrxdmaunlimited = 0x00000700,
  127         RxfthSHIFT      = 13,           /* Receive Buffer Length */
  128         RxfthMASK       = 0x0000E000,
  129         Rxfth256        = 0x00008000,
  130         Rxfthnone       = 0x0000E000,
  131         Rer8            = 0x00010000,   /* Accept Error Packets > 8 bytes */
  132         MulERINT        = 0x01000000,   /* Multiple Early Interrupt Select */
  133 };
  134 
  135 enum {                                  /* Cr9346 */
  136         Eedo            = 0x01,         /* */
  137         Eedi            = 0x02,         /* */
  138         Eesk            = 0x04,         /* */
  139         Eecs            = 0x08,         /* */
  140         Eem0            = 0x40,         /* Operating Mode */
  141         Eem1            = 0x80,
  142 };
  143 
  144 enum {                                  /* Phyar */
  145         DataMASK        = 0x0000FFFF,   /* 16-bit GMII/MII Register Data */
  146         DataSHIFT       = 0,
  147         RegaddrMASK     = 0x001F0000,   /* 5-bit GMII/MII Register Address */
  148         RegaddrSHIFT    = 16,
  149         Flag            = 0x80000000,   /* */
  150 };
  151 
  152 enum {                                  /* Phystatus */
  153         Fd              = 0x01,         /* Full Duplex */
  154         Linksts         = 0x02,         /* Link Status */
  155         Speed10         = 0x04,         /* */
  156         Speed100        = 0x08,         /* */
  157         Speed1000       = 0x10,         /* */
  158         Rxflow          = 0x20,         /* */
  159         Txflow          = 0x40,         /* */
  160         Entbi           = 0x80,         /* */
  161 };
  162 
  163 enum {                                  /* Cplusc */
  164         Mulrw           = 0x0008,       /* PCI Multiple R/W Enable */
  165         Dac             = 0x0010,       /* PCI Dual Address Cycle Enable */
  166         Rxchksum        = 0x0020,       /* Receive Checksum Offload Enable */
  167         Rxvlan          = 0x0040,       /* Receive VLAN De-tagging Enable */
  168         Endian          = 0x0200,       /* Endian Mode */
  169 };
  170 
  171 typedef struct D D;                     /* Transmit/Receive Descriptor */
  172 struct D {
  173         u32int  control;
  174         u32int  vlan;
  175         u32int  addrlo;
  176         u32int  addrhi;
  177 };
  178 
  179 enum {                                  /* Transmit Descriptor control */
  180         TxflMASK        = 0x0000FFFF,   /* Transmit Frame Length */
  181         TxflSHIFT       = 0,
  182         Tcps            = 0x00010000,   /* TCP Checksum Offload */
  183         Udpcs           = 0x00020000,   /* UDP Checksum Offload */
  184         Ipcs            = 0x00040000,   /* IP Checksum Offload */
  185         Lgsen           = 0x08000000,   /* Large Send */
  186 };
  187 
  188 enum {                                  /* Receive Descriptor control */
  189         RxflMASK        = 0x00003FFF,   /* Receive Frame Length */
  190         RxflSHIFT       = 0,
  191         Tcpf            = 0x00004000,   /* TCP Checksum Failure */
  192         Udpf            = 0x00008000,   /* UDP Checksum Failure */
  193         Ipf             = 0x00010000,   /* IP Checksum Failure */
  194         Pid0            = 0x00020000,   /* Protocol ID0 */
  195         Pid1            = 0x00040000,   /* Protocol ID1 */
  196         Crce            = 0x00080000,   /* CRC Error */
  197         Runt            = 0x00100000,   /* Runt Packet */
  198         Res             = 0x00200000,   /* Receive Error Summary */
  199         Rwt             = 0x00400000,   /* Receive Watchdog Timer Expired */
  200         Fovf            = 0x00800000,   /* FIFO Overflow */
  201         Bovf            = 0x01000000,   /* Buffer Overflow */
  202         Bar             = 0x02000000,   /* Broadcast Address Received */
  203         Pam             = 0x04000000,   /* Physical Address Matched */
  204         Mar             = 0x08000000,   /* Multicast Address Received */
  205 };
  206 
  207 enum {                                  /* General Descriptor control */
  208         Ls              = 0x10000000,   /* Last Segment Descriptor */
  209         Fs              = 0x20000000,   /* First Segment Descriptor */
  210         Eor             = 0x40000000,   /* End of Descriptor Ring */
  211         Own             = 0x80000000,   /* Ownership */
  212 };
  213 
  214 /*
  215  */
  216 enum {                                  /* Ring sizes  (<= 1024) */
  217         Ntd             = 32,           /* Transmit Ring */
  218         Nrd             = 128,          /* Receive Ring */
  219 
  220         Mps             = ROUNDUP(ETHERMAXTU+4, 128),
  221 };
  222 
  223 typedef struct Dtcc Dtcc;
  224 struct Dtcc {
  225         u64int  txok;
  226         u64int  rxok;
  227         u64int  txer;
  228         u32int  rxer;
  229         u16int  misspkt;
  230         u16int  fae;
  231         u32int  tx1col;
  232         u32int  txmcol;
  233         u64int  rxokph;
  234         u64int  rxokbrd;
  235         u32int  rxokmu;
  236         u16int  txabt;
  237         u16int  txundrn;
  238 };
  239 
  240 enum {                                          /* Variants */
  241         Rtl8100e        = (0x8136<<16)|0x10EC,  /* RTL810[01]E: pci -e */
  242         Rtl8169c        = (0x0116<<16)|0x16EC,  /* RTL8169C+ (USR997902) */
  243         Rtl8169sc       = (0x8167<<16)|0x10EC,  /* RTL8169SC */
  244         Rtl8168b        = (0x8168<<16)|0x10EC,  /* RTL8168B: pci-e */
  245         Rtl8169         = (0x8169<<16)|0x10EC,  /* RTL8169 */
  246 };
  247 
  248 typedef struct Ctlr Ctlr;
  249 typedef struct Ctlr {
  250         int     port;
  251         Pcidev* pcidev;
  252         Ctlr*   next;
  253         int     active;
  254 
  255         QLock   alock;                  /* attach */
  256         Lock    ilock;                  /* init */
  257         int     init;                   /*  */
  258 
  259         int     pciv;                   /*  */
  260         int     macv;                   /* MAC version */
  261         int     phyv;                   /* PHY version */
  262         int     pcie;                   /* flag: pci-express device? */
  263 
  264         uvlong  mchash;                 /* multicast hash */
  265 
  266         Mii*    mii;
  267 
  268         Lock    tlock;                  /* transmit */
  269         D*      td;                     /* descriptor ring */
  270         Block** tb;                     /* transmit buffers */
  271         int     ntd;
  272 
  273         int     tdh;                    /* head - producer index (host) */
  274         int     tdt;                    /* tail - consumer index (NIC) */
  275         int     ntdfree;
  276         int     ntq;
  277 
  278         int     mtps;                   /* Max. Transmit Packet Size */
  279 
  280         Lock    rlock;                  /* receive */
  281         D*      rd;                     /* descriptor ring */
  282         Block** rb;                     /* receive buffers */
  283         int     nrd;
  284 
  285         int     rdh;                    /* head - producer index (NIC) */
  286         int     rdt;                    /* tail - consumer index (host) */
  287         int     nrdfree;
  288 
  289         int     tcr;                    /* transmit configuration register */
  290         int     rcr;                    /* receive configuration register */
  291         int     imr;
  292 
  293         QLock   slock;                  /* statistics */
  294         Dtcc*   dtcc;
  295         uint    txdu;
  296         uint    tcpf;
  297         uint    udpf;
  298         uint    ipf;
  299         uint    fovf;
  300         uint    ierrs;
  301         uint    rer;
  302         uint    rdu;
  303         uint    punlc;
  304         uint    fovw;
  305         uint    mcast;
  306 } Ctlr;
  307 
  308 static Ctlr* rtl8169ctlrhead;
  309 static Ctlr* rtl8169ctlrtail;
  310 
  311 #define csr8r(c, r)     (inb((c)->port+(r)))
  312 #define csr16r(c, r)    (ins((c)->port+(r)))
  313 #define csr32r(c, r)    (inl((c)->port+(r)))
  314 #define csr8w(c, r, b)  (outb((c)->port+(r), (u8int)(b)))
  315 #define csr16w(c, r, w) (outs((c)->port+(r), (u16int)(w)))
  316 #define csr32w(c, r, l) (outl((c)->port+(r), (u32int)(l)))
  317 
  318 static int
  319 rtl8169miimir(Mii* mii, int pa, int ra)
  320 {
  321         uint r;
  322         int timeo;
  323         Ctlr *ctlr;
  324 
  325         if(pa != 1)
  326                 return -1;
  327         ctlr = mii->ctlr;
  328 
  329         r = (ra<<16) & RegaddrMASK;
  330         csr32w(ctlr, Phyar, r);
  331         delay(1);
  332         for(timeo = 0; timeo < 2000; timeo++){
  333                 if((r = csr32r(ctlr, Phyar)) & Flag)
  334                         break;
  335                 microdelay(100);
  336         }
  337         if(!(r & Flag))
  338                 return -1;
  339 
  340         return (r & DataMASK)>>DataSHIFT;
  341 }
  342 
  343 static int
  344 rtl8169miimiw(Mii* mii, int pa, int ra, int data)
  345 {
  346         uint r;
  347         int timeo;
  348         Ctlr *ctlr;
  349 
  350         if(pa != 1)
  351                 return -1;
  352         ctlr = mii->ctlr;
  353 
  354         r = Flag|((ra<<16) & RegaddrMASK)|((data<<DataSHIFT) & DataMASK);
  355         csr32w(ctlr, Phyar, r);
  356         delay(1);
  357         for(timeo = 0; timeo < 2000; timeo++){
  358                 if(!((r = csr32r(ctlr, Phyar)) & Flag))
  359                         break;
  360                 microdelay(100);
  361         }
  362         if(r & Flag)
  363                 return -1;
  364 
  365         return 0;
  366 }
  367 
  368 static int
  369 rtl8169mii(Ctlr* ctlr)
  370 {
  371         MiiPhy *phy;
  372 
  373         /*
  374          * Link management.
  375          */
  376         if((ctlr->mii = malloc(sizeof(Mii))) == nil)
  377                 return -1;
  378         ctlr->mii->mir = rtl8169miimir;
  379         ctlr->mii->miw = rtl8169miimiw;
  380         ctlr->mii->ctlr = ctlr;
  381 
  382         /*
  383          * Get rev number out of Phyidr2 so can config properly.
  384          * There's probably more special stuff for Macv0[234] needed here.
  385          */
  386         ctlr->phyv = rtl8169miimir(ctlr->mii, 1, Phyidr2) & 0x0F;
  387         if(ctlr->macv == Macv02){
  388                 csr8w(ctlr, 0x82, 1);                           /* magic */
  389                 rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000);      /* magic */
  390         }
  391 
  392         if(mii(ctlr->mii, (1<<1)) == 0 || (phy = ctlr->mii->curphy) == nil){
  393                 free(ctlr->mii);
  394                 ctlr->mii = nil;
  395                 return -1;
  396         }
  397         print("oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n",
  398                 phy->oui, phy->phyno, ctlr->macv, ctlr->phyv);
  399 
  400         miiane(ctlr->mii, ~0, ~0, ~0);
  401 
  402         return 0;
  403 }
  404 
  405 static void
  406 rtl8169promiscuous(void* arg, int on)
  407 {
  408         Ether *edev;
  409         Ctlr * ctlr;
  410 
  411         edev = arg;
  412         ctlr = edev->ctlr;
  413         ilock(&ctlr->ilock);
  414 
  415         if(on)
  416                 ctlr->rcr |= Aap;
  417         else
  418                 ctlr->rcr &= ~Aap;
  419         csr32w(ctlr, Rcr, ctlr->rcr);
  420         iunlock(&ctlr->ilock);
  421 }
  422 
  423 enum {
  424         /* everyone else uses 0x04c11db7, but they both produce the same crc */
  425         Etherpolybe = 0x04c11db6,
  426         Bytemask = (1<<8) - 1,
  427 };
  428 
  429 static ulong
  430 ethercrcbe(uchar *addr, long len)
  431 {
  432         int i, j;
  433         ulong c, crc, carry;
  434 
  435         crc = ~0UL;
  436         for (i = 0; i < len; i++) {
  437                 c = addr[i];
  438                 for (j = 0; j < 8; j++) {
  439                         carry = ((crc & (1UL << 31))? 1: 0) ^ (c & 1);
  440                         crc <<= 1;
  441                         c >>= 1;
  442                         if (carry)
  443                                 crc = (crc ^ Etherpolybe) | carry;
  444                 }
  445         }
  446         return crc;
  447 }
  448 
  449 static ulong
  450 swabl(ulong l)
  451 {
  452         return l>>24 | (l>>8) & (Bytemask<<8) |
  453                 (l<<8) & (Bytemask<<16) | l<<24;
  454 }
  455 
  456 static void
  457 rtl8169multicast(void* ether, uchar *eaddr, int add)
  458 {
  459         Ether *edev;
  460         Ctlr *ctlr;
  461 
  462         if (!add)
  463                 return; /* ok to keep receiving on old mcast addrs */
  464 
  465         edev = ether;
  466         ctlr = edev->ctlr;
  467         ilock(&ctlr->ilock);
  468 
  469         ctlr->mchash |= 1ULL << (ethercrcbe(eaddr, Eaddrlen) >> 26);
  470 
  471         ctlr->rcr |= Am;
  472         csr32w(ctlr, Rcr, ctlr->rcr);
  473 
  474         /* pci-e variants reverse the order of the hash byte registers */
  475         if (ctlr->pcie) {
  476                 csr32w(ctlr, Mar0,   swabl(ctlr->mchash>>32));
  477                 csr32w(ctlr, Mar0+4, swabl(ctlr->mchash));
  478         } else {
  479                 csr32w(ctlr, Mar0,   ctlr->mchash);
  480                 csr32w(ctlr, Mar0+4, ctlr->mchash>>32);
  481         }
  482 
  483         iunlock(&ctlr->ilock);
  484 }
  485 
  486 static long
  487 rtl8169ifstat(Ether* edev, void* a, long n, ulong offset)
  488 {
  489         char *p;
  490         Ctlr *ctlr;
  491         Dtcc *dtcc;
  492         int i, l, r, timeo;
  493 
  494         ctlr = edev->ctlr;
  495         qlock(&ctlr->slock);
  496 
  497         p = nil;
  498         if(waserror()){
  499                 qunlock(&ctlr->slock);
  500                 free(p);
  501                 nexterror();
  502         }
  503 
  504         csr32w(ctlr, Dtccr+4, 0);
  505         csr32w(ctlr, Dtccr, PCIWADDR(ctlr->dtcc)|Cmd);
  506         for(timeo = 0; timeo < 1000; timeo++){
  507                 if(!(csr32r(ctlr, Dtccr) & Cmd))
  508                         break;
  509                 delay(1);
  510         }
  511         if(csr32r(ctlr, Dtccr) & Cmd)
  512                 error(Eio);
  513         dtcc = ctlr->dtcc;
  514 
  515         edev->oerrs = dtcc->txer;
  516         edev->crcs = dtcc->rxer;
  517         edev->frames = dtcc->fae;
  518         edev->buffs = dtcc->misspkt;
  519         edev->overflows = ctlr->txdu+ctlr->rdu;
  520 
  521         if(n == 0){
  522                 qunlock(&ctlr->slock);
  523                 poperror();
  524                 return 0;
  525         }
  526 
  527         if((p = malloc(READSTR)) == nil)
  528                 error(Enomem);
  529 
  530         l = snprint(p, READSTR, "TxOk: %llud\n", dtcc->txok);
  531         l += snprint(p+l, READSTR-l, "RxOk: %llud\n", dtcc->rxok);
  532         l += snprint(p+l, READSTR-l, "TxEr: %llud\n", dtcc->txer);
  533         l += snprint(p+l, READSTR-l, "RxEr: %ud\n", dtcc->rxer);
  534         l += snprint(p+l, READSTR-l, "MissPkt: %ud\n", dtcc->misspkt);
  535         l += snprint(p+l, READSTR-l, "FAE: %ud\n", dtcc->fae);
  536         l += snprint(p+l, READSTR-l, "Tx1Col: %ud\n", dtcc->tx1col);
  537         l += snprint(p+l, READSTR-l, "TxMCol: %ud\n", dtcc->txmcol);
  538         l += snprint(p+l, READSTR-l, "RxOkPh: %llud\n", dtcc->rxokph);
  539         l += snprint(p+l, READSTR-l, "RxOkBrd: %llud\n", dtcc->rxokbrd);
  540         l += snprint(p+l, READSTR-l, "RxOkMu: %ud\n", dtcc->rxokmu);
  541         l += snprint(p+l, READSTR-l, "TxAbt: %ud\n", dtcc->txabt);
  542         l += snprint(p+l, READSTR-l, "TxUndrn: %ud\n", dtcc->txundrn);
  543 
  544         l += snprint(p+l, READSTR-l, "txdu: %ud\n", ctlr->txdu);
  545         l += snprint(p+l, READSTR-l, "tcpf: %ud\n", ctlr->tcpf);
  546         l += snprint(p+l, READSTR-l, "udpf: %ud\n", ctlr->udpf);
  547         l += snprint(p+l, READSTR-l, "ipf: %ud\n", ctlr->ipf);
  548         l += snprint(p+l, READSTR-l, "fovf: %ud\n", ctlr->fovf);
  549         l += snprint(p+l, READSTR-l, "ierrs: %ud\n", ctlr->ierrs);
  550         l += snprint(p+l, READSTR-l, "rer: %ud\n", ctlr->rer);
  551         l += snprint(p+l, READSTR-l, "rdu: %ud\n", ctlr->rdu);
  552         l += snprint(p+l, READSTR-l, "punlc: %ud\n", ctlr->punlc);
  553         l += snprint(p+l, READSTR-l, "fovw: %ud\n", ctlr->fovw);
  554 
  555         l += snprint(p+l, READSTR-l, "tcr: %#8.8ux\n", ctlr->tcr);
  556         l += snprint(p+l, READSTR-l, "rcr: %#8.8ux\n", ctlr->rcr);
  557         l += snprint(p+l, READSTR-l, "multicast: %ud\n", ctlr->mcast);
  558 
  559         if(ctlr->mii != nil && ctlr->mii->curphy != nil){
  560                 l += snprint(p+l, READSTR, "phy:   ");
  561                 for(i = 0; i < NMiiPhyr; i++){
  562                         if(i && ((i & 0x07) == 0))
  563                                 l += snprint(p+l, READSTR-l, "\n       ");
  564                         r = miimir(ctlr->mii, i);
  565                         l += snprint(p+l, READSTR-l, " %4.4ux", r);
  566                 }
  567                 snprint(p+l, READSTR-l, "\n");
  568         }
  569 
  570         n = readstr(offset, a, n, p);
  571 
  572         qunlock(&ctlr->slock);
  573         poperror();
  574         free(p);
  575 
  576         return n;
  577 }
  578 
  579 static void
  580 rtl8169halt(Ctlr* ctlr)
  581 {
  582         csr8w(ctlr, Cr, 0);
  583         csr16w(ctlr, Imr, 0);
  584         csr16w(ctlr, Isr, ~0);
  585 }
  586 
  587 static int
  588 rtl8169reset(Ctlr* ctlr)
  589 {
  590         u32int r;
  591         int timeo;
  592 
  593         /*
  594          * Soft reset the controller.
  595          */
  596         csr8w(ctlr, Cr, Rst);
  597         for(r = timeo = 0; timeo < 1000; timeo++){
  598                 r = csr8r(ctlr, Cr);
  599                 if(!(r & Rst))
  600                         break;
  601                 delay(1);
  602         }
  603         rtl8169halt(ctlr);
  604 
  605         if(r & Rst)
  606                 return -1;
  607         return 0;
  608 }
  609 
  610 static void
  611 rtl8169replenish(Ctlr* ctlr)
  612 {
  613         D *d;
  614         int rdt;
  615         Block *bp;
  616 
  617         rdt = ctlr->rdt;
  618         while(NEXT(rdt, ctlr->nrd) != ctlr->rdh){
  619                 d = &ctlr->rd[rdt];
  620                 if(ctlr->rb[rdt] == nil){
  621                         /*
  622                          * Simple allocation for now.
  623                          * This better be aligned on 8.
  624                          */
  625                         bp = iallocb(Mps);
  626                         if(bp == nil){
  627                                 iprint("no available buffers\n");
  628                                 break;
  629                         }
  630                         ctlr->rb[rdt] = bp;
  631                         d->addrlo = PCIWADDR(bp->rp);
  632                         d->addrhi = 0;
  633                 }
  634                 coherence();
  635                 d->control |= Own|Mps;
  636                 rdt = NEXT(rdt, ctlr->nrd);
  637                 ctlr->nrdfree++;
  638         }
  639         ctlr->rdt = rdt;
  640 }
  641 
  642 static int
  643 rtl8169init(Ether* edev)
  644 {
  645         int i;
  646         u32int r;
  647         Block *bp;
  648         Ctlr *ctlr;
  649         u8int cplusc;
  650 
  651         ctlr = edev->ctlr;
  652         ilock(&ctlr->ilock);
  653 
  654         rtl8169halt(ctlr);
  655 
  656         /*
  657          * MAC Address.
  658          * Must put chip into config register write enable mode.
  659          */
  660         csr8w(ctlr, Cr9346, Eem1|Eem0);
  661         r = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0];
  662         csr32w(ctlr, Idr0, r);
  663         r = (edev->ea[5]<<8)|edev->ea[4];
  664         csr32w(ctlr, Idr0+4, r);
  665 
  666         /*
  667          * Transmitter.
  668          */
  669         memset(ctlr->td, 0, sizeof(D)*ctlr->ntd);
  670         ctlr->tdh = ctlr->tdt = 0;
  671         ctlr->td[ctlr->ntd-1].control = Eor;
  672 
  673         /*
  674          * Receiver.
  675          * Need to do something here about the multicast filter.
  676          */
  677         memset(ctlr->rd, 0, sizeof(D)*ctlr->nrd);
  678         ctlr->nrdfree = ctlr->rdh = ctlr->rdt = 0;
  679         ctlr->rd[ctlr->nrd-1].control = Eor;
  680 
  681         for(i = 0; i < ctlr->nrd; i++){
  682                 if((bp = ctlr->rb[i]) != nil){
  683                         ctlr->rb[i] = nil;
  684                         freeb(bp);
  685                 }
  686         }
  687         rtl8169replenish(ctlr);
  688         ctlr->rcr = Rxfthnone|Mrxdmaunlimited|Ab|Am|Apm;
  689 
  690         /*
  691          * Mtps is in units of 128 except for the RTL8169
  692          * where is is 32. If using jumbo frames should be
  693          * set to 0x3F.
  694          * Setting Mulrw in Cplusc disables the Tx/Rx DMA burst
  695          * settings in Tcr/Rcr; the (1<<14) is magic.
  696          */
  697         ctlr->mtps = HOWMANY(Mps, 128);
  698         cplusc = csr16r(ctlr, Cplusc) & ~(1<<14);
  699         cplusc |= /*Rxchksum|*/Mulrw;
  700         switch(ctlr->macv){
  701         default:
  702                 iunlock(&ctlr->ilock);
  703                 print("ether8169: unknown macv %#08ux for vid %#ux did %#ux\n",
  704                         ctlr->macv, ctlr->pcidev->vid, ctlr->pcidev->did);
  705                 return -1;
  706         case Macv01:
  707                 ctlr->mtps = HOWMANY(Mps, 32);
  708                 break;
  709         case Macv02:
  710         case Macv03:
  711                 cplusc |= (1<<14);                      /* magic */
  712                 break;
  713         case Macv05:
  714                 /*
  715                  * This is interpreted from clearly bogus code
  716                  * in the manufacturer-supplied driver, it could
  717                  * be wrong. Untested.
  718                  */
  719                 r = csr8r(ctlr, Config2) & 0x07;
  720                 if(r == 0x01)                           /* 66MHz PCI */
  721                         csr32w(ctlr, 0x7C, 0x0007FFFF); /* magic */
  722                 else
  723                         csr32w(ctlr, 0x7C, 0x0007FF00); /* magic */
  724                 pciclrmwi(ctlr->pcidev);
  725                 break;
  726         case Macv13:
  727                 /*
  728                  * This is interpreted from clearly bogus code
  729                  * in the manufacturer-supplied driver, it could
  730                  * be wrong. Untested.
  731                  */
  732                 pcicfgw8(ctlr->pcidev, 0x68, 0x00);     /* magic */
  733                 pcicfgw8(ctlr->pcidev, 0x69, 0x08);     /* magic */
  734                 break;
  735         case Macv04:
  736         case Macv11:
  737         case Macv12:
  738         case Macv14:
  739         case Macv15:
  740         case Macv16:
  741         case Macv25:
  742                 break;
  743         }
  744 
  745         /*
  746          * Enable receiver/transmitter.
  747          * Need to do this first or some of the settings below
  748          * won't take.
  749          */
  750         switch(ctlr->pciv){
  751         default:
  752                 csr8w(ctlr, Cr, Te|Re);
  753                 csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited);
  754                 csr32w(ctlr, Rcr, ctlr->rcr);
  755                 csr32w(ctlr, Mar0,   0);
  756                 csr32w(ctlr, Mar0+4, 0);
  757                 ctlr->mchash = 0;
  758         case Rtl8169sc:
  759         case Rtl8168b:
  760                 break;
  761         }
  762 
  763         /*
  764          * Interrupts.
  765          * Disable Tdu|Tok for now, the transmit routine will tidy.
  766          * Tdu means the NIC ran out of descriptors to send, so it
  767          * doesn't really need to ever be on.
  768          */
  769         csr32w(ctlr, Timerint, 0);
  770         ctlr->imr = Serr|Timeout|Fovw|Punlc|Rdu|Ter|Rer|Rok;
  771         csr16w(ctlr, Imr, ctlr->imr);
  772 
  773         /*
  774          * Clear missed-packet counter;
  775          * initial early transmit threshold value;
  776          * set the descriptor ring base addresses;
  777          * set the maximum receive packet size;
  778          * no early-receive interrupts.
  779          */
  780         csr32w(ctlr, Mpc, 0);
  781         csr8w(ctlr, Mtps, ctlr->mtps);
  782         csr32w(ctlr, Tnpds+4, 0);
  783         csr32w(ctlr, Tnpds, PCIWADDR(ctlr->td));
  784         csr32w(ctlr, Rdsar+4, 0);
  785         csr32w(ctlr, Rdsar, PCIWADDR(ctlr->rd));
  786         csr16w(ctlr, Rms, Mps);
  787         r = csr16r(ctlr, Mulint) & 0xF000;
  788         csr16w(ctlr, Mulint, r);
  789         csr16w(ctlr, Cplusc, cplusc);
  790 
  791         /*
  792          * Set configuration.
  793          */
  794         switch(ctlr->pciv){
  795         default:
  796                 break;
  797         case Rtl8169sc:
  798                 csr16w(ctlr, 0xE2, 0);                  /* magic */
  799                 csr8w(ctlr, Cr, Te|Re);
  800                 csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited);
  801                 csr32w(ctlr, Rcr, ctlr->rcr);
  802                 break;
  803         case Rtl8168b:
  804         case Rtl8169c:
  805                 csr16w(ctlr, 0xE2, 0);                  /* magic */
  806                 csr16w(ctlr, Cplusc, 0x2000);           /* magic */
  807                 csr8w(ctlr, Cr, Te|Re);
  808                 csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited);
  809                 csr32w(ctlr, Rcr, ctlr->rcr);
  810                 csr16w(ctlr, Rms, 0x0800);
  811                 csr8w(ctlr, Mtps, 0x3F);
  812                 break;
  813         }
  814         ctlr->tcr = csr32r(ctlr, Tcr);
  815         csr8w(ctlr, Cr9346, 0);
  816 
  817         iunlock(&ctlr->ilock);
  818 
  819 //      rtl8169mii(ctlr);
  820 
  821         return 0;
  822 }
  823 
  824 static void
  825 rtl8169attach(Ether* edev)
  826 {
  827         int timeo;
  828         Ctlr *ctlr;
  829 
  830         ctlr = edev->ctlr;
  831         qlock(&ctlr->alock);
  832         if(ctlr->init == 0){
  833                 /*
  834                  * Handle allocation/init errors here.
  835                  */
  836                 ctlr->td = mallocalign(sizeof(D)*Ntd, 256, 0, 0);
  837                 ctlr->tb = malloc(Ntd*sizeof(Block*));
  838                 ctlr->ntd = Ntd;
  839                 ctlr->rd = mallocalign(sizeof(D)*Nrd, 256, 0, 0);
  840                 ctlr->rb = malloc(Nrd*sizeof(Block*));
  841                 ctlr->nrd = Nrd;
  842                 ctlr->dtcc = mallocalign(sizeof(Dtcc), 64, 0, 0);
  843                 rtl8169init(edev);
  844                 ctlr->init = 1;
  845         }
  846         qunlock(&ctlr->alock);
  847 
  848         /*
  849          * Wait for link to be ready.
  850          */
  851         for(timeo = 0; timeo < 35; timeo++){
  852                 if(miistatus(ctlr->mii) == 0)
  853                         break;
  854                 delay(100);             /* print fewer miistatus messages */
  855         }
  856 }
  857 
  858 static void
  859 rtl8169link(Ether* edev)
  860 {
  861         uint r;
  862         int limit;
  863         Ctlr *ctlr;
  864 
  865         ctlr = edev->ctlr;
  866 
  867         /*
  868          * Maybe the link changed - do we care very much?
  869          * Could stall transmits if no link, maybe?
  870          */
  871         if(!((r = csr8r(ctlr, Phystatus)) & Linksts)){
  872                 edev->link = 0;
  873                 return;
  874         }
  875         edev->link = 1;
  876 
  877         limit = 256*1024;
  878         if(r & Speed10){
  879                 edev->mbps = 10;
  880                 limit = 65*1024;
  881         } else if(r & Speed100)
  882                 edev->mbps = 100;
  883         else if(r & Speed1000)
  884                 edev->mbps = 1000;
  885 
  886         if(edev->oq != nil)
  887                 qsetlimit(edev->oq, limit);
  888 }
  889 
  890 static void
  891 rtl8169transmit(Ether* edev)
  892 {
  893         D *d;
  894         Block *bp;
  895         Ctlr *ctlr;
  896         int control, x;
  897 
  898         ctlr = edev->ctlr;
  899 
  900         ilock(&ctlr->tlock);
  901         for(x = ctlr->tdh; ctlr->ntq > 0; x = NEXT(x, ctlr->ntd)){
  902                 d = &ctlr->td[x];
  903                 if((control = d->control) & Own)
  904                         break;
  905 
  906                 /*
  907                  * Check errors and log here.
  908                  */
  909                 USED(control);
  910 
  911                 /*
  912                  * Free it up.
  913                  * Need to clean the descriptor here? Not really.
  914                  * Simple freeb for now (no chain and freeblist).
  915                  * Use ntq count for now.
  916                  */
  917                 freeb(ctlr->tb[x]);
  918                 ctlr->tb[x] = nil;
  919                 d->control &= Eor;
  920 
  921                 ctlr->ntq--;
  922         }
  923         ctlr->tdh = x;
  924 
  925         x = ctlr->tdt;
  926         while(ctlr->ntq < (ctlr->ntd-1)){
  927                 if((bp = qget(edev->oq)) == nil)
  928                         break;
  929 
  930                 d = &ctlr->td[x];
  931                 d->addrlo = PCIWADDR(bp->rp);
  932                 d->addrhi = 0;
  933                 ctlr->tb[x] = bp;
  934                 coherence();
  935                 d->control |= Own|Fs|Ls|((BLEN(bp)<<TxflSHIFT) & TxflMASK);
  936 
  937                 x = NEXT(x, ctlr->ntd);
  938                 ctlr->ntq++;
  939         }
  940         if(x != ctlr->tdt){
  941                 ctlr->tdt = x;
  942                 csr8w(ctlr, Tppoll, Npq);
  943         }
  944         else if(ctlr->ntq >= (ctlr->ntd-1))
  945                 ctlr->txdu++;
  946 
  947         iunlock(&ctlr->tlock);
  948 }
  949 
  950 static void
  951 rtl8169receive(Ether* edev)
  952 {
  953         D *d;
  954         int rdh;
  955         Block *bp;
  956         Ctlr *ctlr;
  957         u32int control;
  958 
  959         ctlr = edev->ctlr;
  960 
  961         rdh = ctlr->rdh;
  962         for(;;){
  963                 d = &ctlr->rd[rdh];
  964 
  965                 if(d->control & Own)
  966                         break;
  967 
  968                 control = d->control;
  969                 if((control & (Fs|Ls|Res)) == (Fs|Ls)){
  970                         bp = ctlr->rb[rdh];
  971                         ctlr->rb[rdh] = nil;
  972                         bp->wp = bp->rp + ((control & RxflMASK)>>RxflSHIFT)-4;
  973                         bp->next = nil;
  974 
  975                         if(control & Fovf)
  976                                 ctlr->fovf++;
  977                         if(control & Mar)
  978                                 ctlr->mcast++;
  979 
  980                         switch(control & (Pid1|Pid0)){
  981                         default:
  982                                 break;
  983                         case Pid0:
  984                                 if(control & Tcpf){
  985                                         ctlr->tcpf++;
  986                                         break;
  987                                 }
  988                                 bp->flag |= Btcpck;
  989                                 break;
  990                         case Pid1:
  991                                 if(control & Udpf){
  992                                         ctlr->udpf++;
  993                                         break;
  994                                 }
  995                                 bp->flag |= Budpck;
  996                                 break;
  997                         case Pid1|Pid0:
  998                                 if(control & Ipf){
  999                                         ctlr->ipf++;
 1000                                         break;
 1001                                 }
 1002                                 bp->flag |= Bipck;
 1003                                 break;
 1004                         }
 1005                         etheriq(edev, bp, 1);
 1006                 }
 1007                 else{
 1008                         /*
 1009                          * Error stuff here.
 1010                         print("control %#8.8ux\n", control);
 1011                          */
 1012                 }
 1013                 d->control &= Eor;
 1014                 ctlr->nrdfree--;
 1015                 rdh = NEXT(rdh, ctlr->nrd);
 1016 
 1017                 if(ctlr->nrdfree < ctlr->nrd/2)
 1018                         rtl8169replenish(ctlr);
 1019         }
 1020         ctlr->rdh = rdh;
 1021 }
 1022 
 1023 static void
 1024 rtl8169interrupt(Ureg*, void* arg)
 1025 {
 1026         Ctlr *ctlr;
 1027         Ether *edev;
 1028         u32int isr;
 1029 
 1030         edev = arg;
 1031         ctlr = edev->ctlr;
 1032 
 1033         while((isr = csr16r(ctlr, Isr)) != 0 && isr != 0xFFFF){
 1034                 csr16w(ctlr, Isr, isr);
 1035                 if((isr & ctlr->imr) == 0)
 1036                         break;
 1037                 if(isr & (Fovw|Punlc|Rdu|Rer|Rok)){
 1038                         rtl8169receive(edev);
 1039                         if(!(isr & (Punlc|Rok)))
 1040                                 ctlr->ierrs++;
 1041                         if(isr & Rer)
 1042                                 ctlr->rer++;
 1043                         if(isr & Rdu)
 1044                                 ctlr->rdu++;
 1045                         if(isr & Punlc)
 1046                                 ctlr->punlc++;
 1047                         if(isr & Fovw)
 1048                                 ctlr->fovw++;
 1049                         isr &= ~(Fovw|Rdu|Rer|Rok);
 1050                 }
 1051 
 1052                 if(isr & (Tdu|Ter|Tok)){
 1053                         rtl8169transmit(edev);
 1054                         isr &= ~(Tdu|Ter|Tok);
 1055                 }
 1056 
 1057                 if(isr & Punlc){
 1058                         rtl8169link(edev);
 1059                         isr &= ~Punlc;
 1060                 }
 1061 
 1062                 /*
 1063                  * Some of the reserved bits get set sometimes...
 1064                  */
 1065                 if(isr & (Serr|Timeout|Tdu|Fovw|Punlc|Rdu|Ter|Tok|Rer|Rok))
 1066                         panic("rtl8169interrupt: imr %#4.4ux isr %#4.4ux\n",
 1067                                 csr16r(ctlr, Imr), isr);
 1068         }
 1069 }
 1070 
 1071 static void
 1072 rtl8169pci(void)
 1073 {
 1074         Pcidev *p;
 1075         Ctlr *ctlr;
 1076         int i, port, pcie;
 1077 
 1078         p = nil;
 1079         while(p = pcimatch(p, 0, 0)){
 1080                 if(p->ccrb != 0x02 || p->ccru != 0)
 1081                         continue;
 1082 
 1083                 pcie = 0;
 1084                 switch(i = ((p->did<<16)|p->vid)){
 1085                 default:
 1086                         continue;
 1087                 case Rtl8100e:                  /* RTL810[01]E ? */
 1088                 case Rtl8168b:                  /* RTL8168B */
 1089                         pcie = 1;
 1090                         break;
 1091                 case Rtl8169c:                  /* RTL8169C */
 1092                 case Rtl8169sc:                 /* RTL8169SC */
 1093                 case Rtl8169:                   /* RTL8169 */
 1094                         break;
 1095                 case (0xC107<<16)|0x1259:       /* Corega CG-LAPCIGT */
 1096                         i = Rtl8169;
 1097                         break;
 1098                 }
 1099 
 1100                 port = p->mem[0].bar & ~0x01;
 1101                 if(ioalloc(port, p->mem[0].size, 0, "rtl8169") < 0){
 1102                         print("rtl8169: port %#ux in use\n", port);
 1103                         continue;
 1104                 }
 1105 
 1106                 ctlr = malloc(sizeof(Ctlr));
 1107                 ctlr->port = port;
 1108                 ctlr->pcidev = p;
 1109                 ctlr->pciv = i;
 1110                 ctlr->pcie = pcie;
 1111 
 1112                 if(pcigetpms(p) > 0){
 1113                         pcisetpms(p, 0);
 1114 
 1115                         for(i = 0; i < 6; i++)
 1116                                 pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar);
 1117                         pcicfgw8(p, PciINTL, p->intl);
 1118                         pcicfgw8(p, PciLTR, p->ltr);
 1119                         pcicfgw8(p, PciCLS, p->cls);
 1120                         pcicfgw16(p, PciPCR, p->pcr);
 1121                 }
 1122 
 1123                 if(rtl8169reset(ctlr)){
 1124                         iofree(port);
 1125                         free(ctlr);
 1126                         continue;
 1127                 }
 1128 
 1129                 /*
 1130                  * Extract the chip hardware version,
 1131                  * needed to configure each properly.
 1132                  */
 1133                 ctlr->macv = csr32r(ctlr, Tcr) & HwveridMASK;
 1134 
 1135                 rtl8169mii(ctlr);
 1136 
 1137                 pcisetbme(p);
 1138 
 1139                 if(rtl8169ctlrhead != nil)
 1140                         rtl8169ctlrtail->next = ctlr;
 1141                 else
 1142                         rtl8169ctlrhead = ctlr;
 1143                 rtl8169ctlrtail = ctlr;
 1144         }
 1145 }
 1146 
 1147 static int
 1148 rtl8169pnp(Ether* edev)
 1149 {
 1150         u32int r;
 1151         Ctlr *ctlr;
 1152         uchar ea[Eaddrlen];
 1153 
 1154         if(rtl8169ctlrhead == nil)
 1155                 rtl8169pci();
 1156 
 1157         /*
 1158          * Any adapter matches if no edev->port is supplied,
 1159          * otherwise the ports must match.
 1160          */
 1161         for(ctlr = rtl8169ctlrhead; ctlr != nil; ctlr = ctlr->next){
 1162                 if(ctlr->active)
 1163                         continue;
 1164                 if(edev->port == 0 || edev->port == ctlr->port){
 1165                         ctlr->active = 1;
 1166                         break;
 1167                 }
 1168         }
 1169         if(ctlr == nil)
 1170                 return -1;
 1171 
 1172         edev->ctlr = ctlr;
 1173         edev->port = ctlr->port;
 1174         edev->irq = ctlr->pcidev->intl;
 1175         edev->tbdf = ctlr->pcidev->tbdf;
 1176         edev->mbps = 100;
 1177 
 1178         /*
 1179          * Check if the adapter's station address is to be overridden.
 1180          * If not, read it from the device and set in edev->ea.
 1181          */
 1182         memset(ea, 0, Eaddrlen);
 1183         if(memcmp(ea, edev->ea, Eaddrlen) == 0){
 1184                 r = csr32r(ctlr, Idr0);
 1185                 edev->ea[0] = r;
 1186                 edev->ea[1] = r>>8;
 1187                 edev->ea[2] = r>>16;
 1188                 edev->ea[3] = r>>24;
 1189                 r = csr32r(ctlr, Idr0+4);
 1190                 edev->ea[4] = r;
 1191                 edev->ea[5] = r>>8;
 1192         }
 1193 
 1194         edev->attach = rtl8169attach;
 1195         edev->transmit = rtl8169transmit;
 1196         edev->interrupt = rtl8169interrupt;
 1197         edev->ifstat = rtl8169ifstat;
 1198 
 1199         edev->arg = edev;
 1200         edev->promiscuous = rtl8169promiscuous;
 1201         edev->multicast = rtl8169multicast;
 1202 //      edev->shutdown = rtl8169shutdown;
 1203 
 1204         rtl8169link(edev);
 1205 
 1206         return 0;
 1207 }
 1208 
 1209 void
 1210 ether8169link(void)
 1211 {
 1212         addethercard("rtl8169", rtl8169pnp);
 1213 }

Cache object: 2715f0ebd3173a6e13a267ab1eef0818


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.