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

Cache object: f2f29c65f07f13a96bf1cc2aa0c7ff0d


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