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/ethervgbe.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 Velocity gigabit ethernet.
    3  * Register info has been stolen from FreeBSD driver.
    4  *
    5  * Has been tested on:
    6  *      - VIA8237 (ABIT AV8): 100Mpbs Full duplex only.
    7  *        It works enough to run replica/pull, vncv, ...
    8  *
    9  * To do:
   10  *      - 64/48 bits
   11  *      - autonegotiation
   12  *      - thresholds
   13  *      - dynamic ring sizing ??
   14  *      - link status change
   15  *      - shutdown
   16  *      - promiscuous
   17  *      - report error
   18  *      - Rx/Tx Csum
   19  *      - Jumbo frames
   20  *
   21  * Philippe Anel, xigh@free.fr
   22  */
   23 
   24 #include "u.h"
   25 #include "../port/lib.h"
   26 #include "mem.h"
   27 #include "dat.h"
   28 #include "fns.h"
   29 #include "io.h"
   30 #include "../port/error.h"
   31 #include "../port/netif.h"
   32 
   33 #include "etherif.h"
   34 #include "ethermii.h"
   35 
   36 #define DEBUG
   37 
   38 enum
   39 {
   40         DumpIntr        = (1<<0),
   41         DumpRx          = (1<<1),
   42         DumpTx          = (1<<2),
   43 };
   44 
   45 #define htole16(x) (x)
   46 #define htole32(x) (x)
   47 #define le32toh(x) (x)
   48 
   49 enum
   50 {
   51         Timeout         = 50000,
   52         RxCount         = 256,
   53         TxCount         = 256,
   54         RxSize          = 2048,
   55 
   56         EthAddr         = 0x00,
   57 
   58         /* Command registers. */
   59         Cr0S            = 0x08,                 /* Global command 0 (Set) */
   60         Cr0C            = 0x0c,                 /* Global command 0 (Clear) */
   61                 Cr0_Start       = 0x01,         /* - start MAC */
   62                 Cr0_Stop        = 0x02,         /* - stop MAC */
   63                 Cr0_EnableRx    = 0x04,         /* - turn on Rx engine */
   64                 Cr0_EnableTx    = 0x08,         /* - turn on Tx engine */
   65 
   66         Cr1S            = 0x09,                 /* Global command 1 (Set) */
   67         Cr1C            = 0x0d,                 /* Global command 1 (Clear) */
   68                 Cr1_NoPool      = 0x08,         /* - disable Rx/Tx desc pool */
   69                 Cr1_reset       = 0x80,         /* - software reset */
   70 
   71         Cr2S            = 0x0a,                 /* Global command 2 (Set) */
   72                 Cr2_XonEnable   = 0x80,         /* - 802.3x XON/XOFF flow control */
   73 
   74         Cr3S            = 0x0b,                 /* Global command 3 (Set) */
   75         Cr3C            = 0x0f,                 /* Global command 3 (Set) */
   76                 Cr3_IntMask     = 0x02,         /* - Mask all interrupts */
   77 
   78         /* Eeprom registers. */
   79         Eecsr           = 0x93,                 /* EEPROM control/status */
   80                 Eecsr_Autold    = 0x20,         /* - trigger reload from EEPROM */
   81 
   82         /* Mii registers. */
   83         MiiStatus       = 0x6D,                 /* MII port status */
   84                 MiiStatus_idle  = 0x80,         /* - idle */
   85 
   86         MiiCmd          = 0x70,                 /* MII command */
   87                 MiiCmd_write    = 0x20,         /* - write */
   88                 MiiCmd_read     = 0x40,         /* - read */
   89                 MiiCmd_auto     = 0x80,         /* - enable autopolling */
   90 
   91         MiiAddr         = 0x71,                 /* MII address */
   92         MiiData         = 0x72,                 /* MII data */
   93 
   94         /* 64 bits related registers. */
   95         TxDescHi        = 0x18,
   96         DataBufHi       = 0x1d,
   97 
   98         /* Rx engine registers. */
   99         RxDescLo        = 0x38,                 /* Rx descriptor base address (lo 32 bits) */
  100         RxCsrS          = 0x32,                 /* Rx descriptor queue control/status (Set) */
  101         RxCsrC          = 0x36,                 /* Rx descriptor queue control/status (Clear) */
  102                 RxCsr_RunQueue  = 0x01,         /*      - enable queue */
  103                 RxCsr_Active    = 0x02,         /* - queue active indicator */
  104                 RxCsr_Wakeup    = 0x04,         /* - wake up queue */
  105                 RxCsr_Dead      = 0x08,         /* - queue dead indicator */
  106         RxNum           = 0x50,                 /* Size of Rx desc ring */
  107         RxDscIdx        = 0x3c,                 /* Current Rx descriptor index */
  108         RxResCnt        = 0x5e,                 /* Rx descriptor residue count */
  109         RxHostErr       = 0x23,                 /* Rx host error status */
  110         RxTimer         = 0x3e,                 /* Rx queue timer pend */
  111         RxControl       = 0x06,                 /* MAC Rx control */
  112                 RxControl_BadFrame = 0x01,      /* - accept CRC error frames */
  113                 RxControl_Runt = 0x02,          /* - accept runts */
  114                 RxControl_MultiCast = 0x04,     /* - accept multicasts */
  115                 RxControl_BroadCast = 0x08,     /* - accept broadcasts */
  116                 RxControl_Promisc = 0x10,       /* - promisc mode */
  117                 RxControl_Giant = 0x20,         /* - accept VLAN tagged frames */
  118                 RxControl_UniCast = 0x40,       /* - use perfect filtering */
  119                 RxControl_SymbolErr = 0x80,     /* - accept symbol err packet */
  120         RxConfig        = 0x7e,                 /* MAC Rx config */
  121                 RxConfig_VlanFilter = 0x01,     /* - filter VLAN ID mismatches */
  122                 RxConfig_VlanOpt0 = (0<<1),     /* - TX: no tag insert, RX: all, no extr */
  123                 RxConfig_VlanOpt1 = (1<<1),     /* - TX: no tag insert, RX: tagged pkts, no extr */
  124                 RxConfig_VlanOpt2 = (2<<1),     /* - TX: tag insert, RX: all, extract tags */
  125                 RxConfig_VlanOpt3 = (3<<1),     /* - TX: tag insert, RX: tagged pkts, with extr */
  126                 RxConfig_FifoLowWat = 0x08,     /* - RX FIFO low watermark (7QW/15QW) */
  127                 RxConfig_FifoTh128 = (0<<4),    /* - RX FIFO threshold 128 bytes */
  128                 RxConfig_FifoTh512 = (1<<4),    /* - RX FIFO threshold 512 bytes */
  129                 RxConfig_FifoTh1024 = (2<<4),   /* - RX FIFO threshold 1024 bytes */
  130                 RxConfig_FifoThFwd = (3<<4),    /* - RX FIFO threshold ??? */
  131                 RxConfig_ArbPrio = 0x80,        /* - arbitration priority */
  132 
  133         /* Tx engine registers. */
  134         TxDescLo        = 0x40,                 /* Tx descriptor base address (lo 32 bits) */
  135         TxCsrS          = 0x30,                 /* Tx descriptor queue control/status (Set) */
  136         TxCsrC          = 0x38,                 /* Tx descriptor queue control/status (Clear) */
  137                 TxCsr_RunQueue  = 0x01,         /*      - enable queue */
  138                 TxCsr_Active    = 0x02,         /* - queue active indicator */
  139                 TxCsr_Wakeup    = 0x04,         /* - wake up queue */
  140                 TxCsr_Dead      = 0x08,         /* - queue dead indicator */
  141         TxNum           = 0x52,                 /* Size of Tx desc ring */
  142         TxDscIdx        = 0x54,                 /* Current Tx descriptor index */
  143         TxHostErr       = 0x22,                 /* Tx host error status */
  144         TxTimer         = 0x3f,                 /* Tx queue timer pend */
  145         TxControl       = 0x07,                 /* MAC Rx control */
  146                 TxControl_LC_Off = (0<<0),      /* - loopback control off */
  147                 TxControl_LC_Mac = (1<<0),      /* - loopback control MAC internal */
  148                 TxControl_LC_Ext = (2<<0),      /* - loopback control external */
  149                 TxControl_Coll16 = (0<<2),      /* - one set of 16 retries */
  150                 TxControl_Coll32 = (1<<2),      /* - two sets of 16 retries */
  151                 TxControl_Coll48 = (2<<2),      /* - three sets of 16 retries */
  152                 TxControl_CollInf = (3<<2),     /* - retry forever */
  153 
  154         TxConfig        = 0x7f,                 /* MAC Tx config */
  155                 TxConfig_SnapOpt = 0x01,        /* - 1 == insert VLAN tag at 13th byte, */
  156                                                                                 /*        0 == insert VLAN tag after SNAP header (21st byte) */
  157                 TxConfig_NonBlk = 0x02,         /* - priority TX/non-blocking mode */
  158                 TxConfig_Blk64  = (0<<3),       /* - non-blocking threshold 64 packets */
  159                 TxConfig_Blk32  = (1<<3),       /* - non-blocking threshold 32 packets */
  160                 TxConfig_Blk128 = (2<<3),       /* - non-blocking threshold 128 packets */
  161                 TxConfig_Blk8   = (3<<3),       /* - non-blocking threshold 8 packets */
  162                 TxConfig_ArbPrio        = 0x80, /* - arbitration priority */
  163 
  164         /* Timer registers. */
  165         Timer0          = 0x74,                 /* single-shot timer */
  166         Timer1          = 0x76,                 /* periodic timer */
  167 
  168         /* Chip config registers. */
  169         ChipCfgA        = 0x78,                 /* chip config A */
  170         ChipCfgB        = 0x79,                 /* chip config B */
  171         ChipCfgC        = 0x7a,                 /* chip config C */
  172         ChipCfgD        = 0x7b,                 /* chip config D */
  173 
  174         /* DMA config registers. */
  175         DmaCfg0         = 0x7C,                 /* DMA config 0 */
  176         DmaCfg1         = 0x7D,                 /* DMA config 1 */
  177 
  178         /* Interrupt registers. */
  179         IntCtl          = 0x20,                 /* Interrupt control */
  180         Imr             = 0x28,                 /* Interrupt mask */
  181         Isr             = 0x24,                 /* Interrupt status */
  182                 Isr_RxHiPrio    = (1<<0),       /* - hi prio Rx int */
  183                 Isr_TxHiPrio    = (1<<1),       /* - hi prio Tx int */
  184                 Isr_RxComplete  = (1<<2),       /* - Rx queue completed */
  185                 Isr_TxComplete  = (1<<3),       /* - One of Tx queues completed */
  186 
  187                 Isr_TxComplete0 = (1<<4),       /* - Tx queue 0 completed */
  188                 Isr_TxComplete1 = (1<<5),       /* - Tx queue 1 completed */
  189                 Isr_TxComplete2 = (1<<6),       /* - Tx queue 2 completed */
  190                 Isr_TxComplete3 = (1<<7),       /* - Tx queue 3 completed */
  191 
  192                 Isr_Reserved8   = (1<<8),       /* - reserved */
  193                 Isr_Reserver9   = (1<<9),       /* - reserved */
  194                 Isr_RxCountOvflow = (1<<10),    /* - Rx packet count overflow */
  195                 Isr_RxPause     = (1<<11),      /* - pause frame Rx */
  196 
  197                 Isr_RxFifoOvflow = (1<<12),     /* - RX FIFO overflow */
  198                 Isr_RxNoDesc    = (1<<13),      /* - ran out of Rx descriptors */
  199                 Isr_RxNoDescWar = (1<<14),      /* - running out of Rx descriptors */
  200                 Isr_LinkStatus  = (1<<15),      /* - link status change */
  201 
  202                 Isr_Timer0      = (1<<16),      /* - one shot timer expired */
  203                 Isr_Timer1      = (1<<17),      /* - periodic timer expired */
  204                 Isr_Power       = (1<<18),      /* - wake up power event */
  205                 Isr_PhyIntr     = (1<<19),      /* - PHY interrupt */
  206 
  207                 Isr_Stopped     = (1<<20),      /* - software shutdown complete */
  208                 Isr_MibOvflow   = (1<<21),      /* - MIB counter overflow warning */
  209                 Isr_SoftIntr    = (1<<22),      /* - software interrupt */
  210                 Isr_HoldOffReload = (1<<23),    /* - reload hold timer */
  211 
  212                 Isr_RxDmaStall  = (1<<24),      /* - Rx DMA stall */
  213                 Isr_TxDmaStall  = (1<<25),      /* - Tx DMA stall */
  214                 Isr_Reserved26  = (1<<26),      /* - reserved */
  215                 Isr_Reserved27  = (1<<27),      /* - reserved */
  216 
  217                 Isr_Source0     = (1<<28),      /* - interrupt source indication */
  218                 Isr_Source1     = (1<<29),      /* - interrupt source indication */
  219                 Isr_Source2     = (1<<30),      /* - interrupt source indication */
  220                 Isr_Source3     = (1<<31),      /* - interrupt source indication */
  221 
  222         Isr_Mask = Isr_TxComplete0|Isr_RxComplete|Isr_Stopped|
  223                         Isr_RxFifoOvflow|Isr_PhyIntr|Isr_LinkStatus|
  224                         Isr_RxNoDesc|Isr_RxDmaStall|Isr_TxDmaStall
  225 };
  226 
  227 typedef struct Frag Frag;
  228 struct Frag
  229 {
  230         ulong   addr_lo;
  231         ushort  addr_hi;
  232         ushort  length;
  233 };
  234 
  235 typedef struct RxDesc RxDesc;
  236 struct RxDesc
  237 {
  238         ulong   status;
  239         ulong   control;
  240         Frag;
  241 };
  242 
  243 typedef struct TxDesc TxDesc;
  244 struct TxDesc
  245 {
  246         ulong   status;
  247         ulong   control;
  248         Frag    frags[7];
  249 };
  250 
  251 enum
  252 {
  253         RxDesc_Status_VidMiss   = (1<<0),       /* VLAN tag filter miss */
  254         RxDesc_Status_CrcErr    = (1<<1),       /* bad CRC error */
  255         RxDesc_Status_FrAlErr   = (1<<3),       /* frame alignment error */
  256         RxDesc_Status_CsumErr   = (1<<3),       /* bad TCP/IP checksum */
  257         RxDesc_Status_RxLenErr  = (1<<4),       /* Rx length error */
  258         RxDesc_Status_SymErr    = (1<<5),       /* PCS symbol error */
  259         RxDesc_Status_SnTag     = (1<<6),       /* RX'ed tagged SNAP pkt */
  260         RxDesc_Status_DeTag     = (1<<7),       /* VLAN tag extracted */
  261 
  262         RxDesc_Status_OneFrag   = (0<<8),       /* only one fragment */
  263         RxDesc_Status_FirstFrag = (1<<8),       /* first frag in frame */
  264         RxDesc_Status_LastFrag  = (2<<8),       /* last frag in frame */
  265         RxDesc_Status_MidFrag   = (3<<8),       /* intermediate frag */
  266 
  267         RxDesc_Status_Vtag      = (1<<10),      /* VLAN tag indicator */
  268         RxDesc_Status_UniCast   = (1<<11),      /* unicast frame */
  269         RxDesc_Status_BroadCast = (1<<12),      /* broadcast frame */
  270         RxDesc_Status_MultiCast = (1<<13),      /* multicast frame */
  271         RxDesc_Status_Perfect   = (1<<14),      /* perfect filter hit */
  272         RxDesc_Status_Goodframe = (1<<15),      /* frame is good. */
  273 
  274         RxDesc_Status_SizShift  = 16,           /* received frame len shift */
  275         RxDesc_Status_SizMask   = 0x3FFF,       /* received frame len mask */
  276 
  277         RxDesc_Status_Shutdown  = (1<<30),      /* shutdown during RX */
  278         RxDesc_Status_Own       = (1<<31),      /* own bit */
  279 
  280         /* ... */
  281         TxDesc_Status_Own       = (1<<31),      /* own bit */
  282 
  283         /* ... */
  284         TxDesc_Control_Intr     = (1<<23),      /* Tx intr request */
  285         TxDesc_Control_Normal   = (3<<24),      /* normal frame */
  286 };
  287 
  288 typedef struct Stats Stats;
  289 struct Stats
  290 {
  291         ulong   rx;
  292         ulong   tx;
  293         ulong   txe;
  294         ulong   intr;
  295 };
  296 
  297 typedef struct Ctlr Ctlr;
  298 struct Ctlr
  299 {
  300         Ctlr*   link;
  301         Pcidev* pdev;
  302         int     port;
  303 
  304         int     inited;
  305         Lock    init_lock;
  306 
  307         ulong   debugflags;
  308         ulong   debugcount;
  309 
  310         Mii*    mii;
  311         int     active;
  312         uchar   ea[6];
  313 
  314         RxDesc* rx_ring;
  315         Block*  rx_blocks[RxCount];
  316 
  317         Lock    tx_lock;
  318         TxDesc* tx_ring;
  319         Block*  tx_blocks[TxCount];
  320         ulong   tx_count;
  321 
  322         Stats   stats;
  323 };
  324 
  325 static Ctlr* vgbehead;
  326 static Ctlr* vgbetail;
  327 
  328 #define riob(c, r)      inb(c->port + r)
  329 #define riow(c, r)      ins(c->port + r)
  330 #define riol(c, r)      inl(c->port + r)
  331 #define wiob(c, r, d)   outb(c->port + r, d)
  332 #define wiow(c, r, d)   outs(c->port + r, d)
  333 #define wiol(c, r, d)   outl(c->port + r, d)
  334 
  335 #define siob(c, r, b)   wiob(c, r, riob(c, r) | b)
  336 #define siow(c, r, b)   wiow(c, r, riob(c, r) | b)
  337 #define siol(c, r, b)   wiol(c, r, riob(c, r) | b)
  338 #define ciob(c, r, b)   wiob(c, r, riob(c, r) & ~b)
  339 #define ciow(c, r, b)   wiow(c, r, riob(c, r) & ~b)
  340 #define ciol(c, r, b)   wiol(c, r, riob(c, r) & ~b)
  341 
  342 static int
  343 vgbemiiw(Mii* mii, int phy, int addr, int data)
  344 {
  345         Ctlr* ctlr;
  346         int i;
  347 
  348         if(phy != 1)
  349                 return -1;
  350 
  351         ctlr = mii->ctlr;
  352 
  353         wiob(ctlr, MiiAddr, addr);
  354         wiow(ctlr, MiiData, (ushort) data);
  355         wiob(ctlr, MiiCmd, MiiCmd_write);
  356 
  357         for(i = 0; i < Timeout; i++)
  358                 if((riob(ctlr, MiiCmd) & MiiCmd_write) == 0)
  359                         break;
  360 
  361         if(i >= Timeout){
  362                 print("vgbe: miiw timeout\n");
  363                 return -1;
  364         }
  365 
  366         return 0;
  367 }
  368 
  369 static int
  370 vgbemiir(Mii* mii, int phy, int addr)
  371 {
  372         Ctlr* ctlr;
  373         int i;
  374 
  375         if(phy != 1)
  376                 return -1;
  377 
  378         ctlr = mii->ctlr;
  379 
  380         wiob(ctlr, MiiAddr, addr);
  381         wiob(ctlr, MiiCmd, MiiCmd_read);
  382 
  383         for(i = 0; i < Timeout; i++)
  384                 if((riob(ctlr, MiiCmd) & MiiCmd_read) == 0)
  385                         break;
  386 
  387         if(i >= Timeout){
  388                 print("vgbe: miir timeout\n");
  389                 return -1;
  390         }
  391 
  392         return riow(ctlr, MiiData);
  393 }
  394 
  395 static long
  396 vgbeifstat(Ether* edev, void* a, long n, ulong offset)
  397 {
  398         char* p;
  399         Ctlr* ctlr;
  400         int l;
  401 
  402         ctlr = edev->ctlr;
  403 
  404         p = malloc(READSTR);
  405         l = 0;
  406         l += snprint(p+l, READSTR-l, "tx: %uld\n", ctlr->stats.tx);
  407         l += snprint(p+l, READSTR-l, "tx [errs]: %uld\n", ctlr->stats.txe);
  408         l += snprint(p+l, READSTR-l, "rx: %uld\n", ctlr->stats.rx);
  409         l += snprint(p+l, READSTR-l, "intr: %uld\n", ctlr->stats.intr);
  410         snprint(p+l, READSTR-l, "\n");
  411 
  412         n = readstr(offset, a, n, p);
  413         free(p);
  414 
  415         return n;
  416 }
  417 
  418 static char* vgbeisr_info[] = {
  419         "hi prio Rx int",
  420         "hi prio Tx int",
  421         "Rx queue completed",
  422         "One of Tx queues completed",
  423         "Tx queue 0 completed",
  424         "Tx queue 1 completed",
  425         "Tx queue 2 completed",
  426         "Tx queue 3 completed",
  427         "reserved",
  428         "reserved",
  429         "Rx packet count overflow",
  430         "pause frame Rx'ed",
  431         "RX FIFO overflow",
  432         "ran out of Rx descriptors",
  433         "running out of Rx descriptors",
  434         "link status change",
  435         "one shot timer expired",
  436         "periodic timer expired",
  437         "wake up power event",
  438         "PHY interrupt",
  439         "software shutdown complete",
  440         "MIB counter overflow warning",
  441         "software interrupt",
  442         "reload hold timer",
  443         "Rx DMA stall",
  444         "Tx DMA stall",
  445         "reserved",
  446         "reserved",
  447         "interrupt source indication 0",
  448         "interrupt source indication 1",
  449         "interrupt source indication 2",
  450         "interrupt source indication 3",
  451 };
  452 
  453 static void
  454 vgbedumpisr(ulong isr)
  455 {
  456         int i;
  457 
  458         for(i = 0; i < 32; i++){
  459                 ulong mask;
  460 
  461                 mask = 1<<i;
  462                 if(isr & mask)
  463                         print("vgbe: irq:  - %02d : %c %s\n", i,
  464                                 Isr_Mask & mask ? '*' : '-', vgbeisr_info[i]);
  465         }
  466 }
  467 
  468 static void
  469 noop(Block *)
  470 {
  471 }
  472 
  473 static int
  474 vgbenewrx(Ctlr* ctlr, int i)
  475 {
  476         Block* block;
  477         RxDesc* desc;
  478 
  479         /*
  480          * allocate a receive Block.  we're maintaining
  481          * a private pool of Blocks, so we don't want freeb
  482          * to actually free them, thus we set block->free.
  483          */
  484         block = allocb(RxSize);
  485         block->free = noop;
  486 
  487         /* Remember that block. */
  488         ctlr->rx_blocks[i] = block;
  489 
  490         /* Initialize Rx descriptor. (TODO: 48/64 bits support ?) */
  491         desc = &ctlr->rx_ring[i];
  492         desc->status = htole32(RxDesc_Status_Own);
  493         desc->control = htole32(0);
  494 
  495         desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
  496         desc->addr_hi = htole16(0);
  497         desc->length = htole16(RxSize | 0x8000);
  498 
  499         return 0;
  500 }
  501 
  502 static void
  503 vgberxeof(Ether* edev)
  504 {
  505         Ctlr* ctlr;
  506         int i;
  507         Block* block;
  508         ulong length, status;
  509         RxDesc* desc;
  510 
  511         ctlr = edev->ctlr;
  512 
  513         if(ctlr->debugflags & DumpRx)
  514                 print("vgbe: rx_eof\n");
  515 
  516         for(i = 0; i < RxCount; i++){
  517                 /* Remember that block. */
  518                 desc = &ctlr->rx_ring[i];
  519 
  520                 status = le32toh(desc->status);
  521 
  522                 if(status & RxDesc_Status_Own)
  523                         continue;
  524 
  525                 if(status & RxDesc_Status_Goodframe){
  526                         length = status >> RxDesc_Status_SizShift;
  527                         length &= RxDesc_Status_SizMask;
  528 
  529                         if(ctlr->debugflags & DumpRx)
  530                                 print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n",
  531                                         i, status, desc->control, length);
  532 
  533                         block = ctlr->rx_blocks[i];
  534                         block->wp = block->rp + length;
  535 
  536                         ctlr->stats.rx++;
  537                         etheriq(edev, block, 1);
  538                 }
  539                 else
  540                         print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
  541                                 i, status, desc->control);
  542 
  543                 /* reset packet ... */
  544                 desc->status = htole32(RxDesc_Status_Own);
  545                 desc->control = htole32(0);
  546         }
  547 
  548         if(ctlr->debugflags & DumpRx)
  549                 print("vgbe: rx_eof: done\n");
  550 
  551         wiow(ctlr, RxResCnt, RxCount);
  552         wiob(ctlr, RxCsrS, RxCsr_Wakeup);
  553 }
  554 
  555 static void
  556 vgbetxeof(Ether* edev)
  557 {
  558         Ctlr* ctlr;
  559         int i, count;
  560         Block* block;
  561         ulong status;
  562 
  563         ctlr = edev->ctlr;
  564 
  565         ilock(&ctlr->tx_lock);
  566 
  567         if(ctlr->debugflags & DumpTx)
  568                 print("vgbe: tx_eof\n");
  569 
  570         for(count = 0, i = 0; i < TxCount; i++){
  571                 block = ctlr->tx_blocks[i];
  572                 if(block == nil)
  573                         continue;
  574 
  575                 status = le32toh(ctlr->tx_ring[i].status);
  576                 if(status & TxDesc_Status_Own)
  577                         continue;
  578 
  579                 /* Todo add info if it failed */
  580                 ctlr->stats.tx++;
  581 
  582                 if(ctlr->debugflags & DumpTx)
  583                         print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
  584 
  585                 count++;
  586                 ctlr->tx_blocks[i] = nil;
  587                 freeb(block);
  588 
  589                 if(ctlr->debugflags & DumpTx)
  590                         print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
  591         }
  592         ctlr->tx_count -= count;
  593 
  594         if(ctlr->debugflags & DumpTx)
  595                 print("vgbe: tx_eof: done [count=%d]\n", count);
  596 
  597         iunlock(&ctlr->tx_lock);
  598 
  599         if(ctlr->tx_count)
  600                 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
  601 }
  602 
  603 static void
  604 vgbeinterrupt(Ureg *, void* arg)
  605 {
  606         Ether* edev;
  607         Ctlr* ctlr;
  608         ulong status;
  609 
  610         edev = (Ether *) arg;
  611         if(edev == nil)
  612                 return;
  613 
  614         ctlr = edev->ctlr;
  615         if(ctlr == nil)
  616                 return;
  617 
  618         /* Mask interrupts. */
  619         wiol(ctlr, Imr, 0);
  620 
  621         status = riol(ctlr, Isr);
  622         if(status == 0xffff)
  623                 goto end;
  624 
  625         /* acknowledge */
  626         if(status)
  627                 wiol(ctlr, Isr, status);
  628 
  629         if((status & Isr_Mask) == 0)
  630                 goto end;
  631 
  632         ctlr->stats.intr++;
  633 
  634         if(ctlr->debugflags & DumpIntr)
  635                 if(ctlr->debugcount){
  636                         print("vgbe: irq: status = %#08ulx\n", status);
  637                         vgbedumpisr(status);
  638                         ctlr->debugcount--;
  639                 }
  640 
  641         if(status & Isr_RxComplete)
  642                 vgberxeof(edev);
  643 
  644         if(status & Isr_TxComplete0)
  645                 vgbetxeof(edev);
  646 
  647         if(status & Isr_Stopped)
  648                 print("vgbe: irq: software shutdown complete\n");
  649 
  650         if(status & Isr_RxFifoOvflow)
  651                 print("vgbe: irq: RX FIFO overflow\n");
  652 
  653         if(status & Isr_PhyIntr)
  654                 print("vgbe: irq: PHY interrupt\n");
  655 
  656         if(status & Isr_LinkStatus)
  657                 print("vgbe: irq: link status change\n");
  658 
  659         if(status & Isr_RxNoDesc)
  660                 print("vgbe: irq: ran out of Rx descriptors\n");
  661 
  662         if(status & Isr_RxDmaStall){
  663                 print("vgbe: irq: Rx DMA stall\n");
  664                 wiol(ctlr, Cr3C, Cr3_IntMask);
  665                 return;
  666         }
  667 
  668         if(status & Isr_TxDmaStall){
  669                 print("vgbe: irq: Tx DMA stall\n");
  670                 wiol(ctlr, Cr3C, Cr3_IntMask);
  671                 return;
  672         }
  673 
  674 end:
  675         /* Unmask interrupts. */
  676         wiol(ctlr, Imr, ~0);
  677 }
  678 
  679 static void
  680 vgbetransmit(Ether* edev)
  681 {
  682         Block* block;
  683         Ctlr* ctlr;
  684         int i, index, start, count;
  685         TxDesc* desc;
  686         ulong status, length;
  687 
  688         ctlr = edev->ctlr;
  689 
  690         ilock(&ctlr->tx_lock);
  691 
  692         start = riow(ctlr, TxDscIdx);
  693 
  694         if(ctlr->debugflags & DumpTx)
  695                 print("vgbe: transmit (start=%d)\n", start);
  696 
  697         /* find empty slot */
  698         for(count = 0, i = 0; i < TxCount; i++){
  699                 index = (i + start) % TxCount;
  700 
  701                 if(ctlr->tx_blocks[index])
  702                         continue;
  703 
  704                 desc = &ctlr->tx_ring[index];
  705 
  706                 status = le32toh(desc->status);
  707                 if(status & TxDesc_Status_Own)
  708                         continue;
  709 
  710                 block = qget(edev->oq);
  711                 if(block == nil)
  712                         break;
  713 
  714                 count++;
  715 
  716                 length = BLEN(block);
  717 
  718                 if(ctlr->debugflags & DumpTx)
  719                         print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block,
  720                                 PCIWADDR(block->rp), length);
  721 
  722                 ctlr->tx_blocks[index] = block;
  723 
  724                 /* Initialize Tx descriptor. */
  725                 desc->status = htole32((length<<16)|TxDesc_Status_Own);
  726                 desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28));
  727 
  728                 desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp));
  729                 desc->frags[0].addr_hi = htole16(0);
  730                 desc->frags[0].length = htole16(length);
  731         }
  732         ctlr->tx_count += count;
  733 
  734         if(ctlr->debugflags & DumpTx)
  735                 print("vgbe: transmit: done [count=%d]\n", count);
  736 
  737         iunlock(&ctlr->tx_lock);
  738 
  739         if(ctlr->tx_count)
  740                 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
  741 
  742         if(count == 0)
  743                 print("vgbe: transmit: no Tx entry available\n");
  744 }
  745 
  746 static void
  747 vgbeattach(Ether* edev)
  748 {
  749         Ctlr* ctlr;
  750         RxDesc* rxdesc;
  751         TxDesc* txdesc;
  752         int i;
  753 
  754         ctlr = edev->ctlr;
  755 
  756         lock(&ctlr->init_lock);
  757         if(ctlr->inited){
  758                 unlock(&ctlr->init_lock);
  759                 return;
  760         }
  761 
  762 //      print("vgbe: attach\n");
  763 
  764         /* Allocate Rx ring.  (TODO: Alignment ?) */
  765         rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
  766         if(rxdesc == nil){
  767                 print("vgbe: unable to alloc Rx ring\n");
  768                 unlock(&ctlr->init_lock);
  769                 return;
  770         }
  771         ctlr->rx_ring = rxdesc;
  772 
  773         /* Allocate Rx blocks, initialize Rx ring. */
  774         for(i = 0; i < RxCount; i++)
  775                 vgbenewrx(ctlr, i);
  776 
  777         /* Init Rx MAC. */
  778         wiob(ctlr, RxControl,
  779                 RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
  780         wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
  781 
  782         /* Load Rx ring. */
  783         wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
  784         wiow(ctlr, RxNum, RxCount - 1);
  785         wiow(ctlr, RxDscIdx, 0);
  786         wiow(ctlr, RxResCnt, RxCount);
  787 
  788         /* Allocate Tx ring. */
  789         txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
  790         if(txdesc == nil){
  791                 print("vgbe: unable to alloc Tx ring\n");
  792                 unlock(&ctlr->init_lock);
  793                 return;
  794         }
  795         ctlr->tx_ring = txdesc;
  796 
  797         /* Init DMAs */
  798         wiob(ctlr, DmaCfg0, 4);
  799 
  800         /* Init Tx MAC. */
  801         wiob(ctlr, TxControl, 0);
  802         wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio);
  803 
  804         /* Load Tx ring. */
  805         wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc));
  806         wiow(ctlr, TxNum, TxCount - 1);
  807         wiow(ctlr, TxDscIdx, 0);
  808 
  809         /* Enable Xon/Xoff */
  810         wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable);
  811 
  812         /* Enable Rx queue */
  813         wiob(ctlr, RxCsrS, RxCsr_RunQueue);
  814 
  815         /* Enable Tx queue */
  816         wiob(ctlr, TxCsrS, TxCsr_RunQueue);
  817 
  818         /* Done */
  819         ctlr->inited = 1;
  820         unlock(&ctlr->init_lock);
  821 
  822         /* Enable interrupts */
  823         wiol(ctlr, Isr, 0xffffffff);
  824         wiob(ctlr, Cr3S, Cr3_IntMask);
  825 
  826         /* Wake up Rx queue */
  827         wiob(ctlr, RxCsrS, RxCsr_Wakeup);
  828 }
  829 
  830 static void
  831 vgbereset(Ctlr* ctlr)
  832 {
  833 //      MiiPhy* phy;
  834         int timeo, i;
  835 
  836 //      print("vgbe: reset\n");
  837 
  838         /* Soft reset the controller. */
  839         wiob(ctlr, Cr1S, Cr1_reset);
  840 
  841         for(timeo = 0; timeo < Timeout; timeo++)
  842                 if((riob(ctlr, Cr1S) & Cr1_reset) == 0)
  843                         break;
  844 
  845         if(timeo >= Timeout){
  846                 print("vgbe: softreset timeout\n");
  847                 return;
  848         }
  849 
  850         /* Reload eeprom. */
  851         siob(ctlr, Eecsr, Eecsr_Autold);
  852 
  853         for(timeo = 0; timeo < Timeout; timeo++)
  854                 if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0)
  855                         break;
  856 
  857         if(timeo >= Timeout){
  858                 print("vgbe: eeprom reload timeout\n");
  859                 return;
  860         }
  861 
  862         /* Load the MAC address. */
  863         for(i = 0; i < Eaddrlen; i++)
  864                 ctlr->ea[i] = riob(ctlr, EthAddr+i);
  865 
  866         /* Initialize interrupts. */
  867         wiol(ctlr, Isr, 0xffffffff);
  868         wiol(ctlr, Imr, 0xffffffff);
  869 
  870         /* Disable interrupts. */
  871         wiol(ctlr, Cr3C, Cr3_IntMask);
  872 
  873         /* 32 bits addresses only. (TODO: 64 bits ?) */
  874         wiol(ctlr, TxDescHi, 0);
  875         wiow(ctlr, DataBufHi, 0);
  876 
  877         /* Enable MAC (turning off Rx/Tx engines for the moment). */
  878         wiob(ctlr, Cr0C, Cr0_Stop|Cr0_EnableRx|Cr0_EnableTx);
  879         wiob(ctlr, Cr0S, Cr0_Start);
  880 
  881         /* Initialize Rx engine. */
  882         wiow(ctlr, RxCsrC, RxCsr_RunQueue);
  883 
  884         /* Initialize Tx engine. */
  885         wiow(ctlr, TxCsrC, TxCsr_RunQueue);
  886 
  887         /* Enable Rx/Tx engines. */
  888         wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx);
  889 
  890         /* Initialize link management. */
  891         ctlr->mii = malloc(sizeof(Mii));
  892         if(ctlr->mii == nil){
  893                 print("vgbe: unable to alloc Mii\n");
  894                 return;
  895         }
  896 
  897         ctlr->mii->mir = vgbemiir;
  898         ctlr->mii->miw = vgbemiiw;
  899         ctlr->mii->ctlr = ctlr;
  900 
  901         if(mii(ctlr->mii, 1<<1) == 0){
  902                 print("vgbe: no phy found\n");
  903                 return;
  904         }
  905 
  906 //      phy = ctlr->mii->curphy;
  907 //      print("vgbe: phy:oui %#x\n", phy->oui);
  908 }
  909 
  910 static void
  911 vgbepci(void)
  912 {
  913         Pcidev* pdev;
  914 
  915 //      print("vgbe: pci\n");
  916 
  917         pdev = nil;
  918         while(pdev = pcimatch(pdev, 0, 0)){
  919                 Ctlr* ctlr;
  920                 int port, size;
  921 
  922                 if(pdev->ccrb != 0x02 || pdev->ccru != 0)
  923                         continue;
  924 
  925                 switch((pdev->did<<16) | pdev->vid){
  926                 default:
  927                         continue;
  928 
  929                 case (0x3119<<16)|0x1106:       /* VIA Velocity (VT6122) */
  930                         break;
  931                 }
  932 
  933                 if((pdev->pcr & 1) == 0){
  934                         print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr);
  935                         continue;
  936                 }
  937 
  938                 pcisetbme(pdev);
  939                 pcisetpms(pdev, 0);
  940 
  941                 port = pdev->mem[0].bar;
  942                 size = pdev->mem[0].size;
  943 
  944                 if((port & 1) == 0){
  945                         print("vgbe: bar[0]=%#x is not io\n", port);
  946                         continue;
  947                 }
  948 
  949                 if(port > 0xff00){
  950                         print("vgbe: invalid port %#ux\n", port);
  951                         continue;
  952                 }
  953 
  954                 port &= 0xfffe;
  955 
  956                 if(size != 256){
  957                         print("vgbe: invalid io size: %d\n", size);
  958                         continue;
  959                 }
  960 
  961                 if(ioalloc(port, size, 0, "vge") < 0){
  962                         print("vgbe: port %#ux already in use\n", port);
  963                         continue;
  964                 }
  965 
  966                 ctlr = malloc(sizeof(Ctlr));
  967                 if(ctlr == nil){
  968                         print("vgbe: unable to alloc Ctlr\n");
  969                         iofree(port);
  970                         continue;
  971                 }
  972 
  973                 ctlr->pdev = pdev;
  974                 ctlr->port = port;
  975                 ctlr->inited = 0;
  976 
  977                 if(vgbehead != nil)
  978                         vgbetail->link = ctlr;
  979                 else
  980                         vgbehead = ctlr;
  981                 vgbetail = ctlr;
  982         }
  983 }
  984 
  985 static long
  986 vgbectl(Ether* edev, void* buf, long n)
  987 {
  988         Cmdbuf* cb;
  989         Ctlr* ctlr;
  990         ulong index;
  991         char* rptr;
  992         RxDesc* rd;
  993         TxDesc* td;
  994         uchar* p;
  995 
  996         ctlr = edev->ctlr;
  997 
  998         cb = parsecmd(buf, n);
  999         if(waserror()){
 1000                 free(cb);
 1001                 nexterror();
 1002         }
 1003 
 1004         if(cistrcmp(cb->f[0], "reset") == 0){
 1005                 vgbereset(ctlr);
 1006                 wiob(ctlr, Cr3S, Cr3_IntMask);
 1007                 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
 1008                 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
 1009         }
 1010         else if(cistrcmp(cb->f[0], "dumpintr") == 0){
 1011                 if(cb->nf < 2)
 1012                         error(Ecmdargs);
 1013 
 1014                 if(cistrcmp(cb->f[1], "on") == 0){
 1015                         ctlr->debugflags |= DumpIntr;
 1016                         ctlr->debugcount = ~0;
 1017                 }
 1018                 else if(cistrcmp(cb->f[1], "off") == 0)
 1019                         ctlr->debugflags &= ~DumpIntr;
 1020                 else{
 1021                         ulong count;
 1022                         char* rptr;
 1023 
 1024                         count = strtoul(cb->f[1], &rptr, 0);
 1025                         if(rptr == cb->f[1])
 1026                                 error("invalid control request");
 1027 
 1028                         ctlr->debugflags |= DumpIntr;
 1029                         ctlr->debugcount = count;
 1030 
 1031                         print("vgbe: debugcount set to %uld\n", count);
 1032                 }
 1033         }
 1034         else if(cistrcmp(cb->f[0], "dumprx") == 0){
 1035                 if(cb->nf < 2)
 1036                         error(Ecmdargs);
 1037 
 1038                 if(cistrcmp(cb->f[1], "on") == 0)
 1039                         ctlr->debugflags |= DumpRx;
 1040                 else if(cistrcmp(cb->f[1], "off") == 0)
 1041                         ctlr->debugflags &= ~DumpRx;
 1042                 else{
 1043                         index = strtoul(cb->f[1], &rptr, 0);
 1044                         if((rptr == cb->f[1]) || (index >= RxCount))
 1045                                 error("invalid control request");
 1046 
 1047                         rd = &ctlr->rx_ring[index];
 1048                         print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n",
 1049                                 index, rd->status, rd->control, rd->length);
 1050                 }
 1051         }
 1052         else if(cistrcmp(cb->f[0], "dumptx") == 0){
 1053                 if(cb->nf < 2)
 1054                         error(Ecmdargs);
 1055 
 1056                 if(cistrcmp(cb->f[1], "on") == 0)
 1057                         ctlr->debugflags |= DumpTx;
 1058                 else if(cistrcmp(cb->f[1], "off") == 0)
 1059                         ctlr->debugflags &= ~DumpTx;
 1060                 else{
 1061                         index = strtoul(cb->f[1], &rptr, 0);
 1062                         if((rptr == cb->f[1]) || (index >= TxCount))
 1063                                 error("invalid control request");
 1064 
 1065                         td = &ctlr->tx_ring[index];
 1066                         print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes",
 1067                                 index, td->status, td->control, td->frags[0].length);
 1068 
 1069                         p = (uchar*)td;
 1070                         for(index = 0; index < sizeof(TxDesc); index++){
 1071                                 if((index % 16) == 0)
 1072                                         print("\nvgbe: ");
 1073                                 else
 1074                                         print(" ");
 1075                                 print("%#02x", p[index]);
 1076                         }
 1077                 }
 1078         }
 1079         else if(cistrcmp(cb->f[0], "dumpall") == 0){
 1080                 if(cb->nf < 2)
 1081                         error(Ecmdargs);
 1082 
 1083                 if(cistrcmp(cb->f[1], "on") == 0){
 1084                         ctlr->debugflags = ~0;
 1085                         ctlr->debugcount = ~0;
 1086                 }
 1087                 else if(cistrcmp(cb->f[1], "off") == 0)
 1088                         ctlr->debugflags = 0;
 1089                 else error("invalid control request");
 1090         }
 1091         else
 1092                 error(Ebadctl);
 1093 
 1094         free(cb);
 1095         poperror();
 1096 
 1097         return n;
 1098 }
 1099 
 1100 static void
 1101 vgbepromiscuous(void* arg, int on)
 1102 {
 1103         USED(arg, on);
 1104 }
 1105 
 1106 /* multicast already on, don't need to do anything */
 1107 static void
 1108 vgbemulticast(void*, uchar*, int)
 1109 {
 1110 }
 1111 
 1112 static int
 1113 vgbepnp(Ether* edev)
 1114 {
 1115         Ctlr* ctlr;
 1116 
 1117 //      print("vgbe: pnp\n");
 1118 
 1119         if(vgbehead == nil)
 1120                 vgbepci();
 1121 
 1122         for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
 1123                 if(ctlr->active)
 1124                         continue;
 1125 
 1126                 if(edev->port == 0 || edev->port == ctlr->port){
 1127                         ctlr->active = 1;
 1128                         break;
 1129                 }
 1130         }
 1131 
 1132         if(ctlr == nil)
 1133                 return -1;
 1134 
 1135         vgbereset(ctlr);
 1136 
 1137         edev->ctlr = ctlr;
 1138         edev->port = ctlr->port;
 1139         edev->irq = ctlr->pdev->intl;
 1140         edev->tbdf = ctlr->pdev->tbdf;
 1141         edev->mbps = 1000;
 1142         memmove(edev->ea, ctlr->ea, Eaddrlen);
 1143         edev->attach = vgbeattach;
 1144         edev->transmit = vgbetransmit;
 1145         edev->interrupt = vgbeinterrupt;
 1146         edev->ifstat = vgbeifstat;
 1147 //      edev->promiscuous = vgbepromiscuous;
 1148         edev->multicast = vgbemulticast;
 1149 //      edev->shutdown = vgbeshutdown;
 1150         edev->ctl = vgbectl;
 1151 
 1152         edev->arg = edev;
 1153         return 0;
 1154 }
 1155 
 1156 void
 1157 ethervgbelink(void)
 1158 {
 1159         addethercard("vgbe", vgbepnp);
 1160 }

Cache object: f63ad863d8c74223117d833f54863ac4


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