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/ethervt6105m.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  * VIA VT6105M Fast Ethernet Controller (Rhine III).
    3  * To do:
    4  *      cache-line size alignments - done
    5  *      reduce tx interrupts - done
    6  *      reorganise initialisation/shutdown/reset
    7  *      adjust Tx FIFO threshold on underflow - untested
    8  *      why does the link status never cause an interrupt?
    9  *      use the lproc as a periodic timer for stalls, etc.
   10  *      checksum offload - done
   11  *      take non-HW stuff out of descriptor for 64-bit
   12  *      cleanliness
   13  *      why does the receive buffer alloc have a +3?
   14  */
   15 #include "u.h"
   16 #include "../port/lib.h"
   17 #include "mem.h"
   18 #include "dat.h"
   19 #include "fns.h"
   20 #include "io.h"
   21 #include "../port/error.h"
   22 #include "../port/netif.h"
   23 
   24 #include "etherif.h"
   25 #include "ethermii.h"
   26 
   27 enum {
   28         Par0            = 0x00,                 /* Ethernet Address */
   29         Rcr             = 0x06,                 /* Receive Configuration */
   30         Tcr             = 0x07,                 /* Transmit Configuration */
   31         Cr              = 0x08,                 /* Control */
   32         Tqw             = 0x0A,                 /* Transmit Queue Wake */
   33         Isr             = 0x0C,                 /* Interrupt Status */
   34         Imr             = 0x0E,                 /* Interrupt Mask */
   35         Mcfilt0         = 0x10,                 /* Multicast Filter 0 */
   36         Mcfilt1         = 0x14,                 /* Multicast Filter 1 */
   37         Rxdaddr         = 0x18,                 /* Current Rd Address */
   38         Txdaddr         = 0x1C,                 /* Current Td Address */
   39         Phyadr          = 0x6C,                 /* Phy Address */
   40         Miisr           = 0x6D,                 /* MII Status */
   41         Bcr0            = 0x6E,                 /* Bus Control */
   42         Bcr1            = 0x6F,
   43         Miicr           = 0x70,                 /* MII Control */
   44         Miiadr          = 0x71,                 /* MII Address */
   45         Miidata         = 0x72,                 /* MII Data */
   46         Eecsr           = 0x74,                 /* EEPROM Control and Status */
   47         CfgA            = 0x78,                 /* Chip Configuration A */
   48         CfgB            = 0x79,
   49         CfgC            = 0x7A,
   50         CfgD            = 0x7B,
   51         Cr0             = 0x80,                 /* Miscellaneous Control */
   52         Cr1             = 0x81,
   53         Pmcc            = 0x82,                 /* Power Mgmt Capability Control */
   54         Stickhw         = 0x83,                 /* Sticky Hardware Control */
   55         Misr            = 0x84,                 /* MII Interrupt Control */
   56         Mimr            = 0x85,                 /* MII Interrupt Mask */
   57         Wolcrclr        = 0xA4,
   58         Wolcgclr        = 0xA7,
   59         Pwrcsrclr       = 0xAC,
   60 };
   61 
   62 enum {                                          /* Rcr */
   63         Sep             = 0x01,                 /* Accept Error Packets */
   64         Ar              = 0x02,                 /* Accept Small Packets */
   65         Am              = 0x04,                 /* Accept Multicast */
   66         Ab              = 0x08,                 /* Accept Broadcast */
   67         Prom            = 0x10,                 /* Accept Physical Address Packets */
   68         RrftMASK        = 0xE0,                 /* Receive FIFO Threshold */
   69         RrftSHIFT       = 5,
   70         Rrft64          = 0<<RrftSHIFT,
   71         Rrft32          = 1<<RrftSHIFT,
   72         Rrft128         = 2<<RrftSHIFT,
   73         Rrft256         = 3<<RrftSHIFT,
   74         Rrft512         = 4<<RrftSHIFT,
   75         Rrft768         = 5<<RrftSHIFT,
   76         Rrft1024        = 6<<RrftSHIFT,
   77         RrftSAF         = 7<<RrftSHIFT,
   78 };
   79 
   80 enum {                                          /* Tcr */
   81         Lb0             = 0x02,                 /* Loopback Mode */
   82         Lb1             = 0x04,
   83         Ofset           = 0x08,                 /* Select Back-off Priority */
   84         RtsfMASK        = 0xE0,                 /* Transmit FIFO Threshold */
   85         RtsfSHIFT       = 5,
   86         Rtsf128         = 0<<RtsfSHIFT,
   87         Rtsf256         = 1<<RtsfSHIFT,
   88         Rtsf512         = 2<<RtsfSHIFT,
   89         Rtsf1024        = 3<<RtsfSHIFT,
   90         RtsfSAF         = 7<<RtsfSHIFT,
   91 };
   92 
   93 enum {                                          /* Cr */
   94         Init            = 0x0001,               /* INIT Process Begin */
   95         Strt            = 0x0002,               /* Start NIC */
   96         Stop            = 0x0004,               /* Stop NIC */
   97         Rxon            = 0x0008,               /* Turn on Receive Process */
   98         Txon            = 0x0010,               /* Turn on Transmit Process */
   99         Tdmd            = 0x0020,               /* Transmit Poll Demand */
  100         Rdmd            = 0x0040,               /* Receive Poll Demand */
  101         Eren            = 0x0100,               /* Early Receive Enable */
  102         Fdx             = 0x0400,               /* Set MAC to Full Duplex */
  103         Dpoll           = 0x0800,               /* Disable Td/Rd Auto Polling */
  104         Tdmd1           = 0x2000,               /* Transmit Poll Demand 1 */
  105         Rdmd1           = 0x4000,               /* Receive Poll Demand 1 */
  106         Sfrst           = 0x8000,               /* Software Reset */
  107 };
  108 
  109 enum {                                          /* Isr/Imr */
  110         Prx             = 0x0001,               /* Packet Received OK */
  111         Ptx             = 0x0002,               /* Packet Transmitted OK */
  112         Rxe             = 0x0004,               /* Receive Error */
  113         Txe             = 0x0008,               /* Transmit Error */
  114         Tu              = 0x0010,               /* Transmit Buffer Underflow */
  115         Ru              = 0x0020,               /* Receive Buffer Link Error */
  116         Be              = 0x0040,               /* PCI Bus Error */
  117         Cnt             = 0x0080,               /* Counter Overflow */
  118         Eri             = 0x0100,               /* Early Receive Interrupt */
  119         Udfi            = 0x0200,               /* Tx FIFO Underflow */
  120         Ovfi            = 0x0400,               /* Receive FIFO Overflow */
  121         Pktrace         = 0x0800,               /* Hmmm... */
  122         Norbf           = 0x1000,               /* No Receive Buffers */
  123         Abti            = 0x2000,               /* Transmission Abort */
  124         Srci            = 0x4000,               /* Port State Change */
  125         Geni            = 0x8000,               /* General Purpose Interrupt */
  126 };
  127 
  128 enum {                                          /* Phyadr */
  129         PhyadMASK       = 0x1F,                 /* PHY Address */
  130         PhyadSHIFT      = 0,
  131         Mfdc            = 0x20,                 /* Accelerate MDC Speed */
  132         Mpo0            = 0x40,                 /* MII Polling Timer Interval */
  133         Mpo1            = 0x80,
  134 };
  135 
  136 enum {                                          /* Bcr0 */
  137         DmaMASK         = 0x07,                 /* DMA Length */
  138         DmaSHIFT        = 0,
  139         Dma32           = 0<<DmaSHIFT,
  140         Dma64           = 1<<DmaSHIFT,
  141         Dma128          = 2<<DmaSHIFT,
  142         Dma256          = 3<<DmaSHIFT,
  143         Dma512          = 4<<DmaSHIFT,
  144         Dma1024         = 5<<DmaSHIFT,
  145         DmaSAF          = 7<<DmaSHIFT,
  146         CrftMASK        = 0x38,                 /* Rx FIFO Threshold */
  147         CrftSHIFT       = 3,
  148         Crft64          = 1<<CrftSHIFT,
  149         Crft128         = 2<<CrftSHIFT,
  150         Crft256         = 3<<CrftSHIFT,
  151         Crft512         = 4<<CrftSHIFT,
  152         Crft1024        = 5<<CrftSHIFT,
  153         CrftSAF         = 7<<CrftSHIFT,
  154         Extled          = 0x40,                 /* Extra LED Support Control */
  155         Med2            = 0x80,                 /* Medium Select Control */
  156 };
  157 
  158 enum {                                          /* Bcr1 */
  159         PotMASK         = 0x07,                 /* Polling Timer Interval */
  160         PotSHIFT        = 0,
  161         CtftMASK        = 0x38,                 /* Tx FIFO Threshold */
  162         CtftSHIFT       = 3,
  163         Ctft64          = 1<<CtftSHIFT,
  164         Ctft128         = 2<<CtftSHIFT,
  165         Ctft256         = 3<<CtftSHIFT,
  166         Ctft512         = 4<<CtftSHIFT,
  167         Ctft1024        = 5<<CtftSHIFT,
  168         CtftSAF         = 7<<CtftSHIFT,
  169 };
  170 
  171 enum {                                          /* Miicr */
  172         Mdc             = 0x01,                 /* Clock */
  173         Mdi             = 0x02,                 /* Data In */
  174         Mdo             = 0x04,                 /* Data Out */
  175         Mout            = 0x08,                 /* Output Enable */
  176         Mdpm            = 0x10,                 /* Direct Program Mode Enable */
  177         Wcmd            = 0x20,                 /* Write Enable */
  178         Rcmd            = 0x40,                 /* Read Enable */
  179         Mauto           = 0x80,                 /* Auto Polling Enable */
  180 };
  181 
  182 enum {                                          /* Miiadr */
  183         MadMASK         = 0x1F,                 /* MII Port Address */
  184         MadSHIFT        = 0,
  185         Mdone           = 0x20,                 /* Accelerate MDC Speed */
  186         Msrcen          = 0x40,                 /* MII Polling Timer Interval */
  187         Midle           = 0x80,
  188 };
  189 
  190 enum {                                          /* Eecsr */
  191         Edo             = 0x01,                 /* Data Out */
  192         Edi             = 0x02,                 /* Data In */
  193         Eck             = 0x04,                 /* Clock */
  194         Ecs             = 0x08,                 /* Chip Select */
  195         Dpm             = 0x10,                 /* Direct Program Mode Enable */
  196         Autold          = 0x20,                 /* Dynamic Reload */
  197         Embp            = 0x40,                 /* Embedded Program Enable */
  198         Eepr            = 0x80,                 /* Programmed */
  199 };
  200 
  201 /*
  202  * Ring descriptor. The space allocated for each
  203  * of these will be rounded up to a cache-line boundary.
  204  * The first 4 elements are known to the hardware.
  205  */
  206 typedef struct Ds Ds;
  207 typedef struct Ds {
  208         u32int  status;
  209         u32int  control;
  210         u32int  addr;
  211         u32int  branch;
  212 
  213         Block*  bp;
  214         Ds*     next;
  215         Ds*     prev;
  216 } Ds;
  217 
  218 enum {                                          /* Rx Ds status */
  219         Rerr            = 0x00000001,           /* Buff|Rxserr|Fov|Fae|Crc */
  220         Crc             = 0x00000002,           /* CRC Error */
  221         Fae             = 0x00000004,           /* Frame Alignment Error */
  222         Fov             = 0x00000008,           /* FIFO Overflow */
  223         Long            = 0x00000010,           /* A Long Packet */
  224         Runt            = 0x00000020,           /* A Runt Packet */
  225         Rxserr          = 0x00000040,           /* System Error */
  226         Buff            = 0x00000080,           /* Buffer Underflow Error */
  227         Rxedp           = 0x00000100,           /* End of Packet Buffer */
  228         Rxstp           = 0x00000200,           /* Packet Start */
  229         Chn             = 0x00000400,           /* Chain Buffer */
  230         Phy             = 0x00000800,           /* Physical Address Packet */
  231         Bar             = 0x00001000,           /* Broadcast Packet */
  232         Mar             = 0x00002000,           /* Multicast Packet */
  233         Rxok            = 0x00008000,           /* Packet Received OK */
  234         LengthMASK      = 0x07FF0000,           /* Received Packet Length */
  235         LengthSHIFT     = 16,
  236 
  237         Own             = 0x80000000,           /* Descriptor Owned by NIC */
  238 };
  239 
  240 enum {                                          /* Rx Ds control */
  241         RbsizeMASK      = 0x000007FF,           /* Receive Buffer Size */
  242         RbsizeSHIFT     = 0,
  243         Tag             = 0x00010000,           /* Receive a Tagged Packet */
  244         Udpkt           = 0x00020000,           /* Receive a UDP Packet */
  245         Tcpkt           = 0x00040000,           /* Receive a TCP Packet */
  246         Ipkt            = 0x00080000,           /* Receive an IP Packet */
  247         Tuok            = 0x00100000,           /* TCP/UDP Checksum OK */
  248         Ipok            = 0x00200000,           /* IP Checksum OK */
  249         Snaptag         = 0x00400000,           /* Snap Packet + 802.1q Tag */
  250         Rxlerr          = 0x00800000,           /* Receive Length Check Error */
  251         IpktMASK        = 0xff000000,           /* Interesting Packet */
  252         IpktSHIFT       = 24,
  253 };
  254 
  255 enum {                                          /* Tx Ds status */
  256         NcrMASK         = 0x0000000F,           /* Collision Retry Count */
  257         NcrSHIFT        = 0,
  258         Cols            = 0x00000010,           /* Experienced Collisions */
  259         Cdh             = 0x00000080,           /* CD Heartbeat */
  260         Abt             = 0x00000100,           /* Aborted after Excessive Collisions */
  261         Owc             = 0x00000200,           /* Out of Window Collision */
  262         Crs             = 0x00000400,           /* Carrier Sense Lost */
  263         Udf             = 0x00000800,           /* FIFO Underflow */
  264         Tbuff           = 0x00001000,           /* Invalid Td */
  265         Txserr          = 0x00002000,           /* System Error */
  266         Terr            = 0x00008000,           /* Excessive Collisions */
  267 };
  268 
  269 enum {                                          /* Tx Ds control */
  270         TbsMASK         = 0x000007FF,           /* Tx Buffer Size */
  271         TbsSHIFT        = 0,
  272         Chain           = 0x00008000,           /* Chain Buffer */
  273         Crcdisable      = 0x00010000,           /* Disable CRC generation */
  274         Stp             = 0x00200000,           /* Start of Packet */
  275         Edp             = 0x00400000,           /* End of Packet */
  276         Ic              = 0x00800000,           /* Interrupt Control */
  277 };
  278 
  279 enum {                                          /* Tx Ds branch */
  280         Tdctl           = 0x00000001,           /* No Interrupt Generated */
  281 };
  282 
  283 enum {
  284         Nrd             = 196,
  285         Ntd             = 128,
  286         Crcsz           = 4,
  287         Bslop           = 48,
  288         Rdbsz           = ETHERMAXTU+Crcsz+Bslop,
  289 
  290         Nrxstats        = 8,
  291         Ntxstats        = 9,
  292 
  293         Txcopy          = 128,
  294 };
  295 
  296 typedef struct Ctlr Ctlr;
  297 typedef struct Ctlr {
  298         int     port;
  299         Pcidev* pcidev;
  300         Ctlr*   next;
  301         int     active;
  302         int     id;
  303         uchar   par[Eaddrlen];
  304 
  305         QLock   alock;                          /* attach */
  306         void*   alloc;                          /* descriptors, etc. */
  307         int     cls;                            /* alignment */
  308         int     nrd;
  309         int     ntd;
  310 
  311         Ds*     rd;
  312         Ds*     rdh;
  313 
  314         Lock    tlock;
  315         Ds*     td;
  316         Ds*     tdh;
  317         Ds*     tdt;
  318         int     tdused;
  319 
  320         Lock    clock;                          /*  */
  321         int     cr;
  322         int     imr;
  323         int     tft;                            /* Tx threshold */
  324 
  325         Mii*    mii;
  326         Rendez  lrendez;
  327         int     lwakeup;
  328 
  329         uint    rxstats[Nrxstats];              /* statistics */
  330         uint    txstats[Ntxstats];
  331         ulong   totalt;
  332         uint    intr;
  333         uint    lintr;                  
  334         uint    lsleep;
  335         uint    rintr;
  336         uint    tintr;
  337         uint    txdw;
  338         int     tdumax;
  339 
  340         uint    abt;
  341         uint    tbuff;
  342         uint    udf;
  343 
  344         uint    abti;
  345         uint    udfi;
  346         uint    tu;
  347 
  348         uint    tuok;
  349         uint    ipok;
  350 } Ctlr;
  351 
  352 static Ctlr* vt6105Mctlrhead;
  353 static Ctlr* vt6105Mctlrtail;
  354 
  355 #define csr8r(c, r)     (inb((c)->port+(r)))
  356 #define csr16r(c, r)    (ins((c)->port+(r)))
  357 #define csr32r(c, r)    (inl((c)->port+(r)))
  358 #define csr8w(c, r, b)  (outb((c)->port+(r), (int)(b)))
  359 #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
  360 #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
  361 
  362 static Lock vt6105Mrblock;                      /* receive Block freelist */
  363 static Block* vt6105Mrbpool;
  364 static uint vt6105Mrbpoolsz;
  365 
  366 typedef struct Regs Regs;
  367 typedef struct Regs {
  368         char*   name;
  369         int     offset;
  370         int     size;
  371 } Regs;
  372 
  373 static Regs regs[] = {
  374 //      "Par0",         Par0,   1,
  375 //      "Par1",         Par0+1, 1,
  376 //      "Par2",         Par0+2, 1,
  377 //      "Par3",         Par0+3, 1,
  378 //      "Par4",         Par0+4, 1,
  379 //      "Par5",         Par0+5, 1,
  380         "Rcr",          Rcr,    1,
  381         "Tcr",          Tcr,    1,
  382         "Cr0",          Cr,     1,
  383         "Cr1",          Cr+1,   1,
  384         "Isr0",         Isr,    1,
  385         "Isr1",         Isr+1,  1,
  386         "Imr0",         Imr,    1,
  387         "Imr1",         Imr+1,  1,
  388 //      "Mcfilt0",      Mcfilt0,4,
  389 //      "Mcfilt1",      Mcfilt1,4,
  390 //      "Rxdaddr",      Rxdaddr,4,
  391 //      "Txdaddr",      Txdaddr,4,
  392         "Phyadr",       Phyadr, 1,
  393         "Miisr",        Miisr,  1,
  394         "Bcr0",         Bcr0,   1,
  395         "Bcr1",         Bcr1,   1,
  396         "Miicr",        Miicr,  1,
  397         "Miiadr",       Miiadr, 1,
  398 //      "Miidata",      Miidata,2,
  399         "Eecsr",        Eecsr,  1,
  400         "CfgA",         CfgA,   1,
  401         "CfgB",         CfgB,   1,
  402         "CfgC",         CfgC,   1,
  403         "CfgD",         CfgD,   1,
  404         "Cr0",          Cr0,    1,
  405         "Cr1",          Cr1,    1,
  406         "Pmcc",         Pmcc,   1,
  407         "Stickhw",      Stickhw,1,
  408         "Misr",         Misr,   1,
  409         "Mimr",         Mimr,   1,
  410         nil,
  411 };
  412 
  413 static char* rxstats[Nrxstats] = {
  414         "Receiver Error",
  415         "CRC Error",
  416         "Frame Alignment Error",
  417         "FIFO Overflow",
  418         "Long Packet",
  419         "Runt Packet",
  420         "System Error",
  421         "Buffer Underflow Error",
  422 };
  423 static char* txstats[Ntxstats] = {
  424         "Aborted after Excessive Collisions",
  425         "Out of Window Collision Seen",
  426         "Carrier Sense Lost",
  427         "FIFO Underflow",
  428         "Invalid Td",
  429         "System Error",
  430         nil,
  431         "Excessive Collisions",
  432 };
  433 
  434 static long
  435 vt6105Mifstat(Ether* edev, void* a, long n, ulong offset)
  436 {
  437         int i, r;
  438         Ctlr *ctlr;
  439         char *alloc, *e, *p;
  440 
  441         ctlr = edev->ctlr;
  442 
  443         alloc = malloc(READSTR);
  444         p = alloc;
  445         e = p + READSTR;
  446         for(i = 0; i < Nrxstats; i++){
  447                 p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
  448         }
  449         for(i = 0; i < Ntxstats; i++){
  450                 if(txstats[i] == nil)
  451                         continue;
  452                 p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
  453         }
  454         p = seprint(p, e, "cls: %ud\n", ctlr->cls);
  455         p = seprint(p, e, "intr: %ud\n", ctlr->intr);
  456         p = seprint(p, e, "lintr: %ud\n", ctlr->lintr);
  457         p = seprint(p, e, "lsleep: %ud\n", ctlr->lsleep);
  458         p = seprint(p, e, "rintr: %ud\n", ctlr->rintr);
  459         p = seprint(p, e, "tintr: %ud\n", ctlr->tintr);
  460         p = seprint(p, e, "txdw: %ud\n", ctlr->txdw);
  461         p = seprint(p, e, "tdumax: %ud\n", ctlr->tdumax);
  462         p = seprint(p, e, "tft: %ud\n", ctlr->tft);
  463 
  464         p = seprint(p, e, "abt: %ud\n", ctlr->abt);
  465         p = seprint(p, e, "tbuff: %ud\n", ctlr->tbuff);
  466         p = seprint(p, e, "udf: %ud\n", ctlr->udf);
  467         p = seprint(p, e, "abti: %ud\n", ctlr->abti);
  468         p = seprint(p, e, "udfi: %ud\n", ctlr->udfi);
  469         p = seprint(p, e, "tu: %ud\n", ctlr->tu);
  470 
  471         p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
  472         p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
  473 
  474         p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
  475         p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
  476 
  477         for(i = 0; regs[i].name != nil; i++){
  478                 p = seprint(p, e, "%s: %2.2x\n",
  479                         regs[i].name,  csr8r(ctlr, regs[i].offset));
  480         }
  481 
  482         if(ctlr->mii != nil && ctlr->mii->curphy != nil){
  483                 p = seprint(p, e, "phy:   ");
  484                 for(i = 0; i < NMiiPhyr; i++){
  485                         if(i && ((i & 0x07) == 0))
  486                                 p = seprint(p, e, "\n       ");
  487                         r = miimir(ctlr->mii, i);
  488                         p = seprint(p, e, " %4.4uX", r);
  489                 }
  490                 seprint(p, e, "\n");
  491         }
  492 
  493         n = readstr(offset, a, n, alloc);
  494         free(alloc);
  495 
  496         return n;
  497 }
  498 
  499 static void
  500 vt6105Mpromiscuous(void* arg, int on)
  501 {
  502         int rcr;
  503         Ctlr *ctlr;
  504         Ether *edev;
  505 
  506         edev = arg;
  507         ctlr = edev->ctlr;
  508         rcr = csr8r(ctlr, Rcr);
  509         if(on)
  510                 rcr |= Prom;
  511         else
  512                 rcr &= ~Prom;
  513         csr8w(ctlr, Rcr, rcr);
  514 }
  515 
  516 static void
  517 vt6105Mmulticast(void* arg, uchar* addr, int on)
  518 {
  519         /*
  520          * For now Am is set in Rcr.
  521          * Will need to interlock with promiscuous
  522          * when this gets filled in.
  523          */
  524         USED(arg, addr, on);
  525 }
  526 
  527 static int
  528 vt6105Mwakeup(void* v)
  529 {
  530         return *((int*)v) != 0;
  531 }
  532 
  533 static void
  534 vt6105Mimr(Ctlr* ctlr, int imr)
  535 {
  536         ilock(&ctlr->clock);
  537         ctlr->imr |= imr;
  538         csr16w(ctlr, Imr, ctlr->imr);
  539         iunlock(&ctlr->clock);
  540 }
  541 
  542 static void
  543 vt6105Mlproc(void* arg)
  544 {
  545         Ctlr *ctlr;
  546         Ether *edev;
  547         MiiPhy *phy;
  548 
  549         edev = arg;
  550         ctlr = edev->ctlr;
  551         for(;;){
  552                 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
  553                         break;
  554                 if(miistatus(ctlr->mii) < 0)
  555                         goto enable;
  556 
  557                 phy = ctlr->mii->curphy;
  558                 ilock(&ctlr->clock);
  559                 csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
  560                 if(phy->fd)
  561                         ctlr->cr |= Fdx;
  562                 else
  563                         ctlr->cr &= ~Fdx;
  564                 csr16w(ctlr, Cr, ctlr->cr);
  565                 iunlock(&ctlr->clock);
  566 enable:
  567                 ctlr->lwakeup = 0;
  568                 vt6105Mimr(ctlr, Srci);
  569 
  570                 ctlr->lsleep++;
  571                 sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
  572 
  573         }
  574         pexit("vt6105Mlproc: done", 1);
  575 }
  576 
  577 static void
  578 vt6105Mrbfree(Block* bp)
  579 {
  580         bp->rp = bp->lim - (Rdbsz+3);
  581         bp->wp = bp->rp;
  582 
  583         ilock(&vt6105Mrblock);
  584         bp->next = vt6105Mrbpool;
  585         vt6105Mrbpool = bp;
  586         iunlock(&vt6105Mrblock);
  587 }
  588 
  589 static Block*
  590 vt6105Mrballoc(void)
  591 {
  592         Block *bp;
  593 
  594         ilock(&vt6105Mrblock);
  595         if((bp = vt6105Mrbpool) != nil){
  596                 vt6105Mrbpool = bp->next;
  597                 bp->next = nil;
  598                 _xinc(&bp->ref);        /* prevent bp from being freed */
  599         }
  600         iunlock(&vt6105Mrblock);
  601 
  602         if(bp == nil && (bp = iallocb(Rdbsz+3)) != nil){
  603                 bp->free = vt6105Mrbfree;
  604                 vt6105Mrbpoolsz++;
  605         }
  606         return bp;
  607 }
  608 
  609 static void
  610 vt6105Mattach(Ether* edev)
  611 {
  612         Ctlr *ctlr;
  613 //      MiiPhy *phy;
  614         uchar *alloc;
  615         Ds *ds, *prev;
  616         int dsz, i, timeo;
  617         char name[KNAMELEN];
  618 
  619         ctlr = edev->ctlr;
  620         qlock(&ctlr->alock);
  621         if(ctlr->alloc != nil){
  622                 qunlock(&ctlr->alock);
  623                 return;
  624         }
  625 
  626         /*
  627          * Descriptor space.
  628          * Receive descriptors should all be aligned on a 4-byte boundary,
  629          * but try to do cache-line alignment.
  630          */
  631         ctlr->nrd = Nrd;
  632         ctlr->ntd = Ntd;
  633         dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
  634         alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz, dsz, 0, 0);
  635         if(alloc == nil){
  636                 qunlock(&ctlr->alock);
  637                 return;
  638         }
  639         ctlr->alloc = alloc;
  640 
  641         ctlr->rd = (Ds*)alloc;
  642 
  643         if(waserror()){
  644                 ds = ctlr->rd;
  645                 for(i = 0; i < ctlr->nrd; i++){
  646                         if(ds->bp != nil){
  647                                 freeb(ds->bp);
  648                                 ds->bp = nil;
  649                         }
  650                         if((ds = ds->next) == nil)
  651                                 break;
  652                 }
  653                 free(ctlr->alloc);
  654                 ctlr->alloc = nil;
  655                 qunlock(&ctlr->alock);
  656                 nexterror();
  657         }
  658 
  659         prev = (Ds*)(alloc + (ctlr->nrd-1)*dsz);
  660         for(i = 0; i < ctlr->nrd; i++){
  661                 ds = (Ds*)alloc;
  662                 alloc += dsz;
  663 
  664                 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
  665                 ds->branch = PCIWADDR(alloc);
  666 
  667                 ds->bp = vt6105Mrballoc();
  668                 if(ds->bp == nil)
  669                         error("vt6105M: can't allocate receive ring\n");
  670                 ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
  671                 ds->addr = PCIWADDR(ds->bp->rp);
  672 
  673                 ds->next = (Ds*)alloc;
  674                 ds->prev = prev;
  675                 prev = ds;
  676 
  677                 ds->status = Own;
  678         }
  679         prev->branch = 0;
  680         prev->next = ctlr->rd;
  681         prev->status = 0;
  682         ctlr->rdh = ctlr->rd;
  683 
  684         ctlr->td = (Ds*)alloc;
  685         prev = (Ds*)(alloc + (ctlr->ntd-1)*dsz);
  686         for(i = 0; i < ctlr->ntd; i++){
  687                 ds = (Ds*)alloc;
  688                 alloc += dsz;
  689 
  690                 ds->next = (Ds*)alloc;
  691                 ds->prev = prev;
  692                 prev = ds;
  693         }
  694         prev->next = ctlr->td;
  695         ctlr->tdh = ctlr->tdt = ctlr->td;
  696         ctlr->tdused = 0;
  697 
  698         ctlr->cr = Dpoll|Rdmd/*|Txon|Rxon*/|Strt;
  699         /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
  700         ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
  701 
  702         ilock(&ctlr->clock);
  703         csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
  704         csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
  705         csr16w(ctlr, Isr, ~0);
  706         csr16w(ctlr, Imr, ctlr->imr);
  707         csr16w(ctlr, Cr, ctlr->cr);
  708         iunlock(&ctlr->clock);
  709 
  710         /*
  711          * Wait for link to be ready.
  712          */
  713         for(timeo = 0; timeo < 350; timeo++){
  714                 if(miistatus(ctlr->mii) == 0)
  715                         break;
  716                 tsleep(&up->sleep, return0, 0, 10);
  717         }
  718 //      phy = ctlr->mii->curphy;
  719 //      print("%s: speed %d fd %d link %d rfc %d tfc %d\n",
  720 //              edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc);
  721 
  722         ilock(&ctlr->clock);
  723         ctlr->cr |= Txon|Rxon;
  724         csr16w(ctlr, Cr, ctlr->cr);
  725         iunlock(&ctlr->clock);
  726 
  727         snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
  728         kproc(name, vt6105Mlproc, edev);
  729 
  730         qunlock(&ctlr->alock);
  731         poperror();
  732 }
  733 
  734 static void
  735 vt6105Mtransmit(Ether* edev)
  736 {
  737         Block *bp;
  738         Ctlr *ctlr;
  739         Ds *ds, *next;
  740         int control, i, size, tdused, timeo;
  741         long t;
  742 
  743         ctlr = edev->ctlr;
  744 
  745         ilock(&ctlr->tlock);
  746         t = lcycles();
  747 
  748         /*
  749          * Free any completed packets
  750          */
  751         ds = ctlr->tdh;
  752         for(tdused = ctlr->tdused; tdused > 0; tdused--){
  753                 /*
  754                  * For some errors the chip will turn the Tx engine
  755                  * off. Wait for that to happen.
  756                  * Could reset and re-init the chip here if it doesn't
  757                  * play fair.
  758                  * To do: adjust Tx FIFO threshold on underflow.
  759                  */
  760                 if(ds->status & (Abt|Tbuff|Udf)){
  761                         if(ds->status & Abt)
  762                                 ctlr->abt++;
  763                         if(ds->status & Tbuff)
  764                                 ctlr->tbuff++;
  765                         if(ds->status & Udf)
  766                                 ctlr->udf++;
  767                         for(timeo = 0; timeo < 1000; timeo++){
  768                                 if(!(csr16r(ctlr, Cr) & Txon))
  769                                         break;
  770                                 microdelay(1);
  771                         }
  772                         ds->status = Own;
  773                         csr32w(ctlr, Txdaddr, PCIWADDR(ds));
  774                 }
  775 
  776                 if(ds->status & Own)
  777                         break;
  778                 ds->addr = 0;
  779                 ds->branch = 0;
  780 
  781                 if(ds->bp != nil){
  782                         freeb(ds->bp);
  783                         ds->bp = nil;
  784                 }
  785                 for(i = 0; i < Ntxstats-1; i++){
  786                         if(ds->status & (1<<i))
  787                                 ctlr->txstats[i]++;
  788                 }
  789                 ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
  790 
  791                 ds = ds->next;
  792         }
  793         ctlr->tdh = ds;
  794 
  795         /*
  796          * Try to fill the ring back up.
  797          */
  798         ds = ctlr->tdt;
  799         while(tdused < ctlr->ntd-2){
  800                 if((bp = qget(edev->oq)) == nil)
  801                         break;
  802                 tdused++;
  803 
  804                 size = BLEN(bp);
  805 
  806                 next = ds->next;
  807                 ds->branch = PCIWADDR(ds->next)|Tdctl;
  808 
  809                 ds->bp = bp;
  810                 ds->addr = PCIWADDR(bp->rp);
  811                 control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
  812 
  813                 ds->control = control;
  814                 if(tdused >= ctlr->ntd-2){
  815                         ctlr->txdw++;
  816                         ds->branch &= ~Tdctl;
  817                 }
  818                 coherence();
  819                 ds->status = Own;
  820 
  821                 ds = next;
  822         }
  823         ctlr->tdt = ds;
  824         ctlr->tdused = tdused;
  825         if(ctlr->tdused){
  826                 csr16w(ctlr, Cr, Tdmd|ctlr->cr);
  827                 if(tdused > ctlr->tdumax)
  828                         ctlr->tdumax = tdused;
  829         }
  830 
  831         ctlr->totalt += lcycles() - t;
  832         iunlock(&ctlr->tlock);
  833 }
  834 
  835 static void
  836 vt6105Mreceive(Ether* edev)
  837 {
  838         Ds *ds;
  839         Block *bp;
  840         Ctlr *ctlr;
  841         int i, len;
  842 
  843         ctlr = edev->ctlr;
  844 
  845         ds = ctlr->rdh;
  846         while(!(ds->status & Own) && ds->status != 0){
  847                 /*
  848                  * Can Long packets be received OK?
  849                  * What happens to the Rxok bit?
  850                  */
  851                 if(ds->status & Rerr){
  852                         for(i = 0; i < Nrxstats; i++){
  853                                 if(ds->status & (1<<i))
  854                                         ctlr->rxstats[i]++;
  855                         }
  856                 }
  857                 else if(bp = vt6105Mrballoc()){
  858                         if(ds->control & Tuok){
  859                                 ds->bp->flag |= Btcpck|Budpck;
  860                                 ctlr->tuok++;
  861                         }
  862                         if(ds->control & Ipok){
  863                                 ds->bp->flag |= Bipck;
  864                                 ctlr->ipok++;
  865                         }
  866                         len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
  867                         ds->bp->wp = ds->bp->rp+len;
  868                         etheriq(edev, ds->bp, 1);
  869                         bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
  870                         ds->addr = PCIWADDR(bp->rp);
  871                         ds->bp = bp;
  872                 }
  873                 ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
  874                 ds->branch = 0;
  875                 ds->status = 0;
  876 
  877                 ds->prev->branch = PCIWADDR(ds);
  878                 coherence();
  879                 ds->prev->status = Own;
  880 
  881                 ds = ds->next;
  882         }
  883         ctlr->rdh = ds;
  884 
  885         csr16w(ctlr, Cr, ctlr->cr);
  886 }
  887 
  888 static void
  889 vt6105Minterrupt(Ureg*, void* arg)
  890 {
  891         Ctlr *ctlr;
  892         Ether *edev;
  893         int imr, isr, r, timeo;
  894         long t;
  895 
  896         edev = arg;
  897         ctlr = edev->ctlr;
  898 
  899         ilock(&ctlr->clock);
  900         t = lcycles();
  901 
  902         csr16w(ctlr, Imr, 0);
  903         imr = ctlr->imr;
  904         ctlr->intr++;
  905         for(;;){
  906                 if((isr = csr16r(ctlr, Isr)) != 0)
  907                         csr16w(ctlr, Isr, isr);
  908                 if((isr & ctlr->imr) == 0)
  909                         break;
  910                         
  911                 if(isr & Srci){
  912                         imr &= ~Srci;
  913                         ctlr->lwakeup = isr & Srci;
  914                         wakeup(&ctlr->lrendez);
  915                         isr &= ~Srci;
  916                         ctlr->lintr++;
  917                 }
  918                 if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
  919                         vt6105Mreceive(edev);
  920                         isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
  921                         ctlr->rintr++;
  922                 }
  923                 if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
  924                         if(isr & (Abti|Udfi|Tu)){
  925                                 if(isr & Abti)
  926                                         ctlr->abti++;
  927                                 if(isr & Udfi)
  928                                         ctlr->udfi++;
  929                                 if(isr & Tu)
  930                                         ctlr->tu++;
  931                                 for(timeo = 0; timeo < 1000; timeo++){
  932                                         if(!(csr16r(ctlr, Cr) & Txon))
  933                                                 break;
  934                                         microdelay(1);
  935                                 }
  936 
  937                                 if((isr & Udfi) && ctlr->tft < CtftSAF){
  938                                         ctlr->tft += 1<<CtftSHIFT;
  939                                         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
  940                                         csr8w(ctlr, Bcr1, r|ctlr->tft);
  941                                 }
  942                         }
  943                         
  944                         
  945                         ctlr->totalt += lcycles() - t;
  946                         vt6105Mtransmit(edev);
  947                         t = lcycles();
  948                         isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
  949                         ctlr->tintr++;
  950                 }
  951                 if(isr)
  952                         panic("vt6105M: isr %4.4uX\n", isr);
  953         }
  954         ctlr->imr = imr;
  955         csr16w(ctlr, Imr, ctlr->imr);
  956         
  957         ctlr->totalt += lcycles() - t;
  958         iunlock(&ctlr->clock);
  959 }
  960 
  961 static int
  962 vt6105Mmiimicmd(Mii* mii, int pa, int ra, int cmd, int data)
  963 {
  964         Ctlr *ctlr;
  965         int r, timeo;
  966 
  967         ctlr = mii->ctlr;
  968 
  969         csr8w(ctlr, Miicr, 0);
  970         r = csr8r(ctlr, Phyadr);
  971         csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
  972         csr8w(ctlr, Phyadr, pa);
  973         csr8w(ctlr, Miiadr, ra);
  974         if(cmd == Wcmd)
  975                 csr16w(ctlr, Miidata, data);
  976         csr8w(ctlr, Miicr, cmd);
  977 
  978         for(timeo = 0; timeo < 10000; timeo++){
  979                 if(!(csr8r(ctlr, Miicr) & cmd))
  980                         break;
  981                 microdelay(1);
  982         }
  983         if(timeo >= 10000)
  984                 return -1;
  985 
  986         if(cmd == Wcmd)
  987                 return 0;
  988         return csr16r(ctlr, Miidata);
  989 }
  990 
  991 static int
  992 vt6105Mmiimir(Mii* mii, int pa, int ra)
  993 {
  994         return vt6105Mmiimicmd(mii, pa, ra, Rcmd, 0);
  995 }
  996 
  997 static int
  998 vt6105Mmiimiw(Mii* mii, int pa, int ra, int data)
  999 {
 1000         return vt6105Mmiimicmd(mii, pa, ra, Wcmd, data);
 1001 }
 1002 
 1003 static int
 1004 vt6105Mdetach(Ctlr* ctlr)
 1005 {
 1006         int revid, timeo;
 1007 
 1008         /*
 1009          * Reset power management registers.
 1010          */
 1011         revid = pcicfgr8(ctlr->pcidev, PciRID);
 1012         if(revid >= 0x40){
 1013                 /* Set power state D0. */
 1014                 csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
 1015 
 1016                 /* Disable force PME-enable. */
 1017                 csr8w(ctlr, Wolcgclr, 0x80);
 1018 
 1019                 /* Clear WOL config and status bits. */
 1020                 csr8w(ctlr, Wolcrclr, 0xFF);
 1021                 csr8w(ctlr, Pwrcsrclr, 0xFF);
 1022         }
 1023 
 1024         /*
 1025          * Soft reset the controller.
 1026          */
 1027         csr16w(ctlr, Cr, Stop);
 1028         csr16w(ctlr, Cr, Stop|Sfrst);
 1029         for(timeo = 0; timeo < 10000; timeo++){
 1030                 if(!(csr16r(ctlr, Cr) & Sfrst))
 1031                         break;
 1032                 microdelay(1);
 1033         }
 1034         if(timeo >= 1000)
 1035                 return -1;
 1036 
 1037         return 0;
 1038 }
 1039 
 1040 static int
 1041 vt6105Mreset(Ctlr* ctlr)
 1042 {
 1043         MiiPhy *phy;
 1044         int i, r, timeo;
 1045 
 1046         if(vt6105Mdetach(ctlr) < 0)
 1047                 return -1;
 1048 
 1049         /*
 1050          * Load the MAC address into the PAR[01]
 1051          * registers.
 1052          */
 1053         r = csr8r(ctlr, Eecsr);
 1054         csr8w(ctlr, Eecsr, Autold|r);
 1055         for(timeo = 0; timeo < 100; timeo++){
 1056                 if(!(csr8r(ctlr, Cr) & Autold))
 1057                         break;
 1058                 microdelay(1);
 1059         }
 1060         if(timeo >= 100)
 1061                 return -1;
 1062 
 1063         for(i = 0; i < Eaddrlen; i++)
 1064                 ctlr->par[i] = csr8r(ctlr, Par0+i);
 1065 
 1066         /*
 1067          * Configure DMA and Rx/Tx thresholds.
 1068          * If the Rx/Tx threshold bits in Bcr[01] are 0 then
 1069          * the thresholds are determined by Rcr/Tcr.
 1070          */
 1071         r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
 1072         csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
 1073         r = csr8r(ctlr, Bcr1) & ~CtftMASK;
 1074         csr8w(ctlr, Bcr1, r|ctlr->tft);
 1075 
 1076         r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
 1077         csr8w(ctlr, Rcr, r|Ab|Am);
 1078         csr32w(ctlr, Mcfilt0, ~0UL);    /* accept all multicast */
 1079         csr32w(ctlr, Mcfilt1, ~0UL);
 1080 
 1081         r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
 1082         csr8w(ctlr, Tcr, r);
 1083 
 1084         /*
 1085          * Link management.
 1086          */
 1087         if((ctlr->mii = malloc(sizeof(Mii))) == nil)
 1088                 return -1;
 1089         ctlr->mii->mir = vt6105Mmiimir;
 1090         ctlr->mii->miw = vt6105Mmiimiw;
 1091         ctlr->mii->ctlr = ctlr;
 1092 
 1093         if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
 1094                 free(ctlr->mii);
 1095                 ctlr->mii = nil;
 1096                 return -1;
 1097         }
 1098 //      print("oui %X phyno %d\n", phy->oui, phy->phyno);
 1099         USED(phy);
 1100 
 1101         if(miistatus(ctlr->mii) < 0){
 1102 //              miireset(ctlr->mii);
 1103                 miiane(ctlr->mii, ~0, ~0, ~0);
 1104         }
 1105 
 1106         return 0;
 1107 }
 1108 
 1109 static void
 1110 vt6105Mpci(void)
 1111 {
 1112         Pcidev *p;
 1113         Ctlr *ctlr;
 1114         int cls, port;
 1115 
 1116         p = nil;
 1117         while(p = pcimatch(p, 0, 0)){
 1118                 if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
 1119                         continue;
 1120 
 1121                 switch((p->did<<16)|p->vid){
 1122                 default:
 1123                         continue;
 1124                 case (0x3053<<16)|0x1106:       /* Rhine III-M vt6105M */
 1125                         break;
 1126                 }
 1127 
 1128                 port = p->mem[0].bar & ~0x01;
 1129                 if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
 1130                         print("vt6105M: port 0x%uX in use\n", port);
 1131                         continue;
 1132                 }
 1133                 ctlr = malloc(sizeof(Ctlr));
 1134                 ctlr->port = port;
 1135                 ctlr->pcidev = p;
 1136                 ctlr->id = (p->did<<16)|p->vid;
 1137                 if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
 1138                         cls = 0x10;
 1139                 ctlr->cls = cls*4;
 1140                 if(ctlr->cls < sizeof(Ds)){
 1141                         print("vt6105M: cls %d < sizeof(Ds)\n", ctlr->cls);
 1142                         iofree(port);
 1143                         free(ctlr);
 1144                         continue;
 1145                 }
 1146                 ctlr->tft = CtftSAF;
 1147 
 1148                 if(vt6105Mreset(ctlr)){
 1149                         iofree(port);
 1150                         free(ctlr);
 1151                         continue;
 1152                 }
 1153                 pcisetbme(p);
 1154 
 1155                 if(vt6105Mctlrhead != nil)
 1156                         vt6105Mctlrtail->next = ctlr;
 1157                 else
 1158                         vt6105Mctlrhead = ctlr;
 1159                 vt6105Mctlrtail = ctlr;
 1160         }
 1161 }
 1162 
 1163 static int
 1164 vt6105Mpnp(Ether* edev)
 1165 {
 1166         Ctlr *ctlr;
 1167 
 1168         if(vt6105Mctlrhead == nil)
 1169                 vt6105Mpci();
 1170 
 1171         /*
 1172          * Any adapter matches if no edev->port is supplied,
 1173          * otherwise the ports must match.
 1174          */
 1175         for(ctlr = vt6105Mctlrhead; ctlr != nil; ctlr = ctlr->next){
 1176                 if(ctlr->active)
 1177                         continue;
 1178                 if(edev->port == 0 || edev->port == ctlr->port){
 1179                         ctlr->active = 1;
 1180                         break;
 1181                 }
 1182         }
 1183         if(ctlr == nil)
 1184                 return -1;
 1185 
 1186         edev->ctlr = ctlr;
 1187         edev->port = ctlr->port;
 1188         edev->irq = ctlr->pcidev->intl;
 1189         edev->tbdf = ctlr->pcidev->tbdf;
 1190         /*
 1191          * Set to 1000Mb/s to fool the bsz calculation.  We need 
 1192          * something better, though.
 1193          */
 1194         edev->mbps = 1000;
 1195         memmove(edev->ea, ctlr->par, Eaddrlen);
 1196 
 1197         /*
 1198          * Linkage to the generic ethernet driver.
 1199          */
 1200         edev->attach = vt6105Mattach;
 1201         edev->transmit = vt6105Mtransmit;
 1202         edev->interrupt = vt6105Minterrupt;
 1203         edev->ifstat = vt6105Mifstat;
 1204         edev->ctl = nil;
 1205 
 1206         edev->arg = edev;
 1207         edev->promiscuous = vt6105Mpromiscuous;
 1208         edev->multicast = vt6105Mmulticast;
 1209 
 1210         edev->maxmtu = ETHERMAXTU+Bslop;
 1211 
 1212         return 0;
 1213 }
 1214 
 1215 void
 1216 ethervt6105mlink(void)
 1217 {
 1218         addethercard("vt6105M", vt6105Mpnp);
 1219 }

Cache object: 5fa5cc5760269d4ecfcf6ffc1b25b9f3


[ 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.