1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168 |
- /*
- * VIA Velocity gigabit ethernet.
- * Register info has been stolen from FreeBSD driver.
- *
- * Has been tested on:
- * - VIA8237 (ABIT AV8): 100Mpbs Full duplex only.
- * It works enough to run replica/pull, vncv, ...
- *
- * To do:
- * - 64/48 bits
- * - autonegotiation
- * - thresholds
- * - dynamic ring sizing ??
- * - link status change
- * - shutdown
- * - promiscuous
- * - report error
- * - Rx/Tx Csum
- * - Jumbo frames
- *
- * Philippe Anel, xigh@free.fr
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "../port/error.h"
- #include "../port/netif.h"
- #include "etherif.h"
- #include "ethermii.h"
- #define DEBUG
- enum
- {
- DumpIntr = (1<<0),
- DumpRx = (1<<1),
- DumpTx = (1<<2),
- };
- #define htole16(x) (x)
- #define htole32(x) (x)
- #define le32toh(x) (x)
- enum
- {
- Timeout = 50000,
- RxCount = 256,
- TxCount = 256,
- RxSize = 2048,
- EthAddr = 0x00,
- /* Command registers. */
- Cr0S = 0x08, /* Global command 0 (Set) */
- Cr0C = 0x0c, /* Global command 0 (Clear) */
- Cr0_Start = 0x01, /* - start MAC */
- Cr0_Stop = 0x02, /* - stop MAC */
- Cr0_EnableRx = 0x04, /* - turn on Rx engine */
- Cr0_EnableTx = 0x08, /* - turn on Tx engine */
- Cr1S = 0x09, /* Global command 1 (Set) */
- Cr1C = 0x0d, /* Global command 1 (Clear) */
- Cr1_NoPool = 0x08, /* - disable Rx/Tx desc pool */
- Cr1_reset = 0x80, /* - software reset */
- Cr2S = 0x0a, /* Global command 2 (Set) */
- Cr2_XonEnable = 0x80, /* - 802.3x XON/XOFF flow control */
- Cr3S = 0x0b, /* Global command 3 (Set) */
- Cr3C = 0x0f, /* Global command 3 (Set) */
- Cr3_IntMask = 0x02, /* - Mask all interrupts */
- /* Eeprom registers. */
- Eecsr = 0x93, /* EEPROM control/status */
- Eecsr_Autold = 0x20, /* - trigger reload from EEPROM */
- /* Mii registers. */
- MiiStatus = 0x6D, /* MII port status */
- MiiStatus_idle = 0x80, /* - idle */
- MiiCmd = 0x70, /* MII command */
- MiiCmd_write = 0x20, /* - write */
- MiiCmd_read = 0x40, /* - read */
- MiiCmd_auto = 0x80, /* - enable autopolling */
- MiiAddr = 0x71, /* MII address */
- MiiData = 0x72, /* MII data */
- /* 64 bits related registers. */
- TxDescHi = 0x18,
- DataBufHi = 0x1d,
- /* Rx engine registers. */
- RxDescLo = 0x38, /* Rx descriptor base address (lo 32 bits) */
- RxCsrS = 0x32, /* Rx descriptor queue control/status (Set) */
- RxCsrC = 0x36, /* Rx descriptor queue control/status (Clear) */
- RxCsr_RunQueue = 0x01, /* - enable queue */
- RxCsr_Active = 0x02, /* - queue active indicator */
- RxCsr_Wakeup = 0x04, /* - wake up queue */
- RxCsr_Dead = 0x08, /* - queue dead indicator */
- RxNum = 0x50, /* Size of Rx desc ring */
- RxDscIdx = 0x3c, /* Current Rx descriptor index */
- RxResCnt = 0x5e, /* Rx descriptor residue count */
- RxHostErr = 0x23, /* Rx host error status */
- RxTimer = 0x3e, /* Rx queue timer pend */
- RxControl = 0x06, /* MAC Rx control */
- RxControl_BadFrame = 0x01, /* - accept CRC error frames */
- RxControl_Runt = 0x02, /* - accept runts */
- RxControl_MultiCast = 0x04, /* - accept multicasts */
- RxControl_BroadCast = 0x08, /* - accept broadcasts */
- RxControl_Promisc = 0x10, /* - promisc mode */
- RxControl_Giant = 0x20, /* - accept VLAN tagged frames */
- RxControl_UniCast = 0x40, /* - use perfect filtering */
- RxControl_SymbolErr = 0x80, /* - accept symbol err packet */
- RxConfig = 0x7e, /* MAC Rx config */
- RxConfig_VlanFilter = 0x01, /* - filter VLAN ID mismatches */
- RxConfig_VlanOpt0 = (0<<1), /* - TX: no tag insert, RX: all, no extr */
- RxConfig_VlanOpt1 = (1<<1), /* - TX: no tag insert, RX: tagged pkts, no extr */
- RxConfig_VlanOpt2 = (2<<1), /* - TX: tag insert, RX: all, extract tags */
- RxConfig_VlanOpt3 = (3<<1), /* - TX: tag insert, RX: tagged pkts, with extr */
- RxConfig_FifoLowWat = 0x08, /* - RX FIFO low watermark (7QW/15QW) */
- RxConfig_FifoTh128 = (0<<4), /* - RX FIFO threshold 128 bytes */
- RxConfig_FifoTh512 = (1<<4), /* - RX FIFO threshold 512 bytes */
- RxConfig_FifoTh1024 = (2<<4), /* - RX FIFO threshold 1024 bytes */
- RxConfig_FifoThFwd = (3<<4), /* - RX FIFO threshold ??? */
- RxConfig_ArbPrio = 0x80, /* - arbitration priority */
- /* Tx engine registers. */
- TxDescLo = 0x40, /* Tx descriptor base address (lo 32 bits) */
- TxCsrS = 0x30, /* Tx descriptor queue control/status (Set) */
- TxCsrC = 0x38, /* Tx descriptor queue control/status (Clear) */
- TxCsr_RunQueue = 0x01, /* - enable queue */
- TxCsr_Active = 0x02, /* - queue active indicator */
- TxCsr_Wakeup = 0x04, /* - wake up queue */
- TxCsr_Dead = 0x08, /* - queue dead indicator */
- TxNum = 0x52, /* Size of Tx desc ring */
- TxDscIdx = 0x54, /* Current Tx descriptor index */
- TxHostErr = 0x22, /* Tx host error status */
- TxTimer = 0x3f, /* Tx queue timer pend */
- TxControl = 0x07, /* MAC Rx control */
- TxControl_LC_Off = (0<<0), /* - loopback control off */
- TxControl_LC_Mac = (1<<0), /* - loopback control MAC internal */
- TxControl_LC_Ext = (2<<0), /* - loopback control external */
- TxControl_Coll16 = (0<<2), /* - one set of 16 retries */
- TxControl_Coll32 = (1<<2), /* - two sets of 16 retries */
- TxControl_Coll48 = (2<<2), /* - three sets of 16 retries */
- TxControl_CollInf = (3<<2), /* - retry forever */
- TxConfig = 0x7f, /* MAC Tx config */
- TxConfig_SnapOpt = 0x01, /* - 1 == insert VLAN tag at 13th byte, */
- /* 0 == insert VLAN tag after SNAP header (21st byte) */
- TxConfig_NonBlk = 0x02, /* - priority TX/non-blocking mode */
- TxConfig_Blk64 = (0<<3), /* - non-blocking threshold 64 packets */
- TxConfig_Blk32 = (1<<3), /* - non-blocking threshold 32 packets */
- TxConfig_Blk128 = (2<<3), /* - non-blocking threshold 128 packets */
- TxConfig_Blk8 = (3<<3), /* - non-blocking threshold 8 packets */
- TxConfig_ArbPrio = 0x80, /* - arbitration priority */
- /* Timer registers. */
- Timer0 = 0x74, /* single-shot timer */
- Timer1 = 0x76, /* periodic timer */
- /* Chip config registers. */
- ChipCfgA = 0x78, /* chip config A */
- ChipCfgB = 0x79, /* chip config B */
- ChipCfgC = 0x7a, /* chip config C */
- ChipCfgD = 0x7b, /* chip config D */
- /* DMA config registers. */
- DmaCfg0 = 0x7C, /* DMA config 0 */
- DmaCfg1 = 0x7D, /* DMA config 1 */
- /* Interrupt registers. */
- IntCtl = 0x20, /* Interrupt control */
- Imr = 0x28, /* Interrupt mask */
- Isr = 0x24, /* Interrupt status */
- Isr_RxHiPrio = (1<<0), /* - hi prio Rx int */
- Isr_TxHiPrio = (1<<1), /* - hi prio Tx int */
- Isr_RxComplete = (1<<2), /* - Rx queue completed */
- Isr_TxComplete = (1<<3), /* - One of Tx queues completed */
- Isr_TxComplete0 = (1<<4), /* - Tx queue 0 completed */
- Isr_TxComplete1 = (1<<5), /* - Tx queue 1 completed */
- Isr_TxComplete2 = (1<<6), /* - Tx queue 2 completed */
- Isr_TxComplete3 = (1<<7), /* - Tx queue 3 completed */
- Isr_Reserved8 = (1<<8), /* - reserved */
- Isr_Reserver9 = (1<<9), /* - reserved */
- Isr_RxCountOvflow = (1<<10), /* - Rx packet count overflow */
- Isr_RxPause = (1<<11), /* - pause frame Rx */
- Isr_RxFifoOvflow = (1<<12), /* - RX FIFO overflow */
- Isr_RxNoDesc = (1<<13), /* - ran out of Rx descriptors */
- Isr_RxNoDescWar = (1<<14), /* - running out of Rx descriptors */
- Isr_LinkStatus = (1<<15), /* - link status change */
- Isr_Timer0 = (1<<16), /* - one shot timer expired */
- Isr_Timer1 = (1<<17), /* - periodic timer expired */
- Isr_Power = (1<<18), /* - wake up power event */
- Isr_PhyIntr = (1<<19), /* - PHY interrupt */
- Isr_Stopped = (1<<20), /* - software shutdown complete */
- Isr_MibOvflow = (1<<21), /* - MIB counter overflow warning */
- Isr_SoftIntr = (1<<22), /* - software interrupt */
- Isr_HoldOffReload = (1<<23), /* - reload hold timer */
- Isr_RxDmaStall = (1<<24), /* - Rx DMA stall */
- Isr_TxDmaStall = (1<<25), /* - Tx DMA stall */
- Isr_Reserved26 = (1<<26), /* - reserved */
- Isr_Reserved27 = (1<<27), /* - reserved */
- Isr_Source0 = (1<<28), /* - interrupt source indication */
- Isr_Source1 = (1<<29), /* - interrupt source indication */
- Isr_Source2 = (1<<30), /* - interrupt source indication */
- Isr_Source3 = (1<<31), /* - interrupt source indication */
- Isr_Mask = Isr_TxComplete0|Isr_RxComplete|Isr_Stopped|
- Isr_RxFifoOvflow|Isr_PhyIntr|Isr_LinkStatus|
- Isr_RxNoDesc|Isr_RxDmaStall|Isr_TxDmaStall
- };
- typedef struct Frag Frag;
- struct Frag
- {
- ulong addr_lo;
- ushort addr_hi;
- ushort length;
- };
- typedef struct RxDesc RxDesc;
- struct RxDesc
- {
- ulong status;
- ulong control;
- Frag;
- };
- typedef struct TxDesc TxDesc;
- struct TxDesc
- {
- ulong status;
- ulong control;
- Frag frags[7];
- };
- enum
- {
- RxDesc_Status_VidMiss = (1<<0), /* VLAN tag filter miss */
- RxDesc_Status_CrcErr = (1<<1), /* bad CRC error */
- RxDesc_Status_FrAlErr = (1<<3), /* frame alignment error */
- RxDesc_Status_CsumErr = (1<<3), /* bad TCP/IP checksum */
- RxDesc_Status_RxLenErr = (1<<4), /* Rx length error */
- RxDesc_Status_SymErr = (1<<5), /* PCS symbol error */
- RxDesc_Status_SnTag = (1<<6), /* RX'ed tagged SNAP pkt */
- RxDesc_Status_DeTag = (1<<7), /* VLAN tag extracted */
- RxDesc_Status_OneFrag = (0<<8), /* only one fragment */
- RxDesc_Status_FirstFrag = (1<<8), /* first frag in frame */
- RxDesc_Status_LastFrag = (2<<8), /* last frag in frame */
- RxDesc_Status_MidFrag = (3<<8), /* intermediate frag */
- RxDesc_Status_Vtag = (1<<10), /* VLAN tag indicator */
- RxDesc_Status_UniCast = (1<<11), /* unicast frame */
- RxDesc_Status_BroadCast = (1<<12), /* broadcast frame */
- RxDesc_Status_MultiCast = (1<<13), /* multicast frame */
- RxDesc_Status_Perfect = (1<<14), /* perfect filter hit */
- RxDesc_Status_Goodframe = (1<<15), /* frame is good. */
- RxDesc_Status_SizShift = 16, /* received frame len shift */
- RxDesc_Status_SizMask = 0x3FFF, /* received frame len mask */
- RxDesc_Status_Shutdown = (1<<30), /* shutdown during RX */
- RxDesc_Status_Own = (1<<31), /* own bit */
- /* ... */
- TxDesc_Status_Own = (1<<31), /* own bit */
- /* ... */
- TxDesc_Control_Intr = (1<<23), /* Tx intr request */
- TxDesc_Control_Normal = (3<<24), /* normal frame */
- };
- typedef struct Stats Stats;
- struct Stats
- {
- ulong rx;
- ulong tx;
- ulong txe;
- ulong intr;
- };
- typedef struct Ctlr Ctlr;
- struct Ctlr
- {
- Ctlr* link;
- Pcidev* pdev;
- int port;
- int inited;
- Lock init_lock;
- ulong debugflags;
- ulong debugcount;
- Mii* mii;
- int active;
- uchar ea[6];
- RxDesc* rx_ring;
- Block* rx_blocks[RxCount];
- Lock tx_lock;
- TxDesc* tx_ring;
- Block* tx_blocks[TxCount];
- ulong tx_count;
- Stats stats;
- };
- static Ctlr* vgbehead;
- static Ctlr* vgbetail;
- #define riob(c, r) inb(c->port + r)
- #define riow(c, r) ins(c->port + r)
- #define riol(c, r) inl(c->port + r)
- #define wiob(c, r, d) outb(c->port + r, d)
- #define wiow(c, r, d) outs(c->port + r, d)
- #define wiol(c, r, d) outl(c->port + r, d)
- #define siob(c, r, b) wiob(c, r, riob(c, r) | b)
- #define siow(c, r, b) wiow(c, r, riob(c, r) | b)
- #define siol(c, r, b) wiol(c, r, riob(c, r) | b)
- #define ciob(c, r, b) wiob(c, r, riob(c, r) & ~b)
- #define ciow(c, r, b) wiow(c, r, riob(c, r) & ~b)
- #define ciol(c, r, b) wiol(c, r, riob(c, r) & ~b)
- static int
- vgbemiiw(Mii* mii, int phy, int addr, int data)
- {
- Ctlr* ctlr;
- int i;
- if(phy != 1)
- return -1;
- ctlr = mii->ctlr;
- wiob(ctlr, MiiAddr, addr);
- wiow(ctlr, MiiData, (ushort) data);
- wiob(ctlr, MiiCmd, MiiCmd_write);
- for(i = 0; i < Timeout; i++)
- if((riob(ctlr, MiiCmd) & MiiCmd_write) == 0)
- break;
- if(i >= Timeout){
- print("vgbe: miiw timeout\n");
- return -1;
- }
- return 0;
- }
- static int
- vgbemiir(Mii* mii, int phy, int addr)
- {
- Ctlr* ctlr;
- int i;
- if(phy != 1)
- return -1;
- ctlr = mii->ctlr;
- wiob(ctlr, MiiAddr, addr);
- wiob(ctlr, MiiCmd, MiiCmd_read);
- for(i = 0; i < Timeout; i++)
- if((riob(ctlr, MiiCmd) & MiiCmd_read) == 0)
- break;
- if(i >= Timeout){
- print("vgbe: miir timeout\n");
- return -1;
- }
- return riow(ctlr, MiiData);
- }
- static long
- vgbeifstat(Ether* edev, void* a, long n, ulong offset)
- {
- char* p;
- Ctlr* ctlr;
- int l;
- ctlr = edev->ctlr;
- p = malloc(READSTR);
- if(p == nil)
- error(Enomem);
- l = 0;
- l += snprint(p+l, READSTR-l, "tx: %uld\n", ctlr->stats.tx);
- l += snprint(p+l, READSTR-l, "tx [errs]: %uld\n", ctlr->stats.txe);
- l += snprint(p+l, READSTR-l, "rx: %uld\n", ctlr->stats.rx);
- l += snprint(p+l, READSTR-l, "intr: %uld\n", ctlr->stats.intr);
- snprint(p+l, READSTR-l, "\n");
- n = readstr(offset, a, n, p);
- free(p);
- return n;
- }
- static char* vgbeisr_info[] = {
- "hi prio Rx int",
- "hi prio Tx int",
- "Rx queue completed",
- "One of Tx queues completed",
- "Tx queue 0 completed",
- "Tx queue 1 completed",
- "Tx queue 2 completed",
- "Tx queue 3 completed",
- "reserved",
- "reserved",
- "Rx packet count overflow",
- "pause frame Rx'ed",
- "RX FIFO overflow",
- "ran out of Rx descriptors",
- "running out of Rx descriptors",
- "link status change",
- "one shot timer expired",
- "periodic timer expired",
- "wake up power event",
- "PHY interrupt",
- "software shutdown complete",
- "MIB counter overflow warning",
- "software interrupt",
- "reload hold timer",
- "Rx DMA stall",
- "Tx DMA stall",
- "reserved",
- "reserved",
- "interrupt source indication 0",
- "interrupt source indication 1",
- "interrupt source indication 2",
- "interrupt source indication 3",
- };
- static void
- vgbedumpisr(ulong isr)
- {
- int i;
- for(i = 0; i < 32; i++){
- ulong mask;
- mask = 1<<i;
- if(isr & mask)
- print("vgbe: irq: - %02d : %c %s\n", i,
- Isr_Mask & mask ? '*' : '-', vgbeisr_info[i]);
- }
- }
- static void
- noop(Block *)
- {
- }
- static int
- vgbenewrx(Ctlr* ctlr, int i)
- {
- Block* block;
- RxDesc* desc;
- /*
- * allocate a receive Block. we're maintaining
- * a private pool of Blocks, so we don't want freeb
- * to actually free them, thus we set block->free.
- */
- block = allocb(RxSize);
- block->free = noop;
- /* Remember that block. */
- ctlr->rx_blocks[i] = block;
- /* Initialize Rx descriptor. (TODO: 48/64 bits support ?) */
- desc = &ctlr->rx_ring[i];
- desc->status = htole32(RxDesc_Status_Own);
- desc->control = htole32(0);
- desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
- desc->addr_hi = htole16(0);
- desc->length = htole16(RxSize | 0x8000);
- return 0;
- }
- static void
- vgberxeof(Ether* edev)
- {
- Ctlr* ctlr;
- int i;
- Block* block;
- ulong length, status;
- RxDesc* desc;
- ctlr = edev->ctlr;
- if(ctlr->debugflags & DumpRx)
- print("vgbe: rx_eof\n");
- for(i = 0; i < RxCount; i++){
- /* Remember that block. */
- desc = &ctlr->rx_ring[i];
- status = le32toh(desc->status);
- if(status & RxDesc_Status_Own)
- continue;
- if(status & RxDesc_Status_Goodframe){
- length = status >> RxDesc_Status_SizShift;
- length &= RxDesc_Status_SizMask;
- if(ctlr->debugflags & DumpRx)
- print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n",
- i, status, desc->control, length);
- block = ctlr->rx_blocks[i];
- block->wp = block->rp + length;
- ctlr->stats.rx++;
- etheriq(edev, block, 1);
- }
- else
- print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
- i, status, desc->control);
- /* reset packet ... */
- desc->status = htole32(RxDesc_Status_Own);
- desc->control = htole32(0);
- }
- if(ctlr->debugflags & DumpRx)
- print("vgbe: rx_eof: done\n");
- wiow(ctlr, RxResCnt, RxCount);
- wiob(ctlr, RxCsrS, RxCsr_Wakeup);
- }
- static void
- vgbetxeof(Ether* edev)
- {
- Ctlr* ctlr;
- int i, count;
- Block* block;
- ulong status;
- ctlr = edev->ctlr;
- ilock(&ctlr->tx_lock);
- if(ctlr->debugflags & DumpTx)
- print("vgbe: tx_eof\n");
- for(count = 0, i = 0; i < TxCount; i++){
- block = ctlr->tx_blocks[i];
- if(block == nil)
- continue;
- status = le32toh(ctlr->tx_ring[i].status);
- if(status & TxDesc_Status_Own)
- continue;
- /* Todo add info if it failed */
- ctlr->stats.tx++;
- if(ctlr->debugflags & DumpTx)
- print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
- count++;
- ctlr->tx_blocks[i] = nil;
- freeb(block);
- if(ctlr->debugflags & DumpTx)
- print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
- }
- ctlr->tx_count -= count;
- if(ctlr->debugflags & DumpTx)
- print("vgbe: tx_eof: done [count=%d]\n", count);
- iunlock(&ctlr->tx_lock);
- if(ctlr->tx_count)
- wiob(ctlr, TxCsrS, TxCsr_Wakeup);
- }
- static void
- vgbeinterrupt(Ureg *, void* arg)
- {
- Ether* edev;
- Ctlr* ctlr;
- ulong status;
- edev = (Ether *) arg;
- if(edev == nil)
- return;
- ctlr = edev->ctlr;
- if(ctlr == nil)
- return;
- /* Mask interrupts. */
- wiol(ctlr, Imr, 0);
- status = riol(ctlr, Isr);
- if(status == 0xffff)
- goto end;
- /* acknowledge */
- if(status)
- wiol(ctlr, Isr, status);
- if((status & Isr_Mask) == 0)
- goto end;
- ctlr->stats.intr++;
- if(ctlr->debugflags & DumpIntr)
- if(ctlr->debugcount){
- print("vgbe: irq: status = %#08ulx\n", status);
- vgbedumpisr(status);
- ctlr->debugcount--;
- }
- if(status & Isr_RxComplete)
- vgberxeof(edev);
- if(status & Isr_TxComplete0)
- vgbetxeof(edev);
- if(status & Isr_Stopped)
- print("vgbe: irq: software shutdown complete\n");
- if(status & Isr_RxFifoOvflow)
- print("vgbe: irq: RX FIFO overflow\n");
- if(status & Isr_PhyIntr)
- print("vgbe: irq: PHY interrupt\n");
- if(status & Isr_LinkStatus)
- print("vgbe: irq: link status change\n");
- if(status & Isr_RxNoDesc)
- print("vgbe: irq: ran out of Rx descriptors\n");
- if(status & Isr_RxDmaStall){
- print("vgbe: irq: Rx DMA stall\n");
- wiol(ctlr, Cr3C, Cr3_IntMask);
- return;
- }
- if(status & Isr_TxDmaStall){
- print("vgbe: irq: Tx DMA stall\n");
- wiol(ctlr, Cr3C, Cr3_IntMask);
- return;
- }
- end:
- /* Unmask interrupts. */
- wiol(ctlr, Imr, ~0);
- }
- static void
- vgbetransmit(Ether* edev)
- {
- Block* block;
- Ctlr* ctlr;
- int i, index, start, count;
- TxDesc* desc;
- ulong status, length;
- ctlr = edev->ctlr;
- ilock(&ctlr->tx_lock);
- start = riow(ctlr, TxDscIdx);
- if(ctlr->debugflags & DumpTx)
- print("vgbe: transmit (start=%d)\n", start);
- /* find empty slot */
- for(count = 0, i = 0; i < TxCount; i++){
- index = (i + start) % TxCount;
- if(ctlr->tx_blocks[index])
- continue;
- desc = &ctlr->tx_ring[index];
- status = le32toh(desc->status);
- if(status & TxDesc_Status_Own)
- continue;
- block = qget(edev->oq);
- if(block == nil)
- break;
- count++;
- length = BLEN(block);
- if(ctlr->debugflags & DumpTx)
- print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block,
- PCIWADDR(block->rp), length);
- ctlr->tx_blocks[index] = block;
- /* Initialize Tx descriptor. */
- desc->status = htole32((length<<16)|TxDesc_Status_Own);
- desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28));
- desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp));
- desc->frags[0].addr_hi = htole16(0);
- desc->frags[0].length = htole16(length);
- }
- ctlr->tx_count += count;
- if(ctlr->debugflags & DumpTx)
- print("vgbe: transmit: done [count=%d]\n", count);
- iunlock(&ctlr->tx_lock);
- if(ctlr->tx_count)
- wiob(ctlr, TxCsrS, TxCsr_Wakeup);
- if(count == 0)
- print("vgbe: transmit: no Tx entry available\n");
- }
- static void
- vgbeattach(Ether* edev)
- {
- Ctlr* ctlr;
- RxDesc* rxdesc;
- TxDesc* txdesc;
- int i;
- ctlr = edev->ctlr;
- lock(&ctlr->init_lock);
- if(ctlr->inited){
- unlock(&ctlr->init_lock);
- return;
- }
- // print("vgbe: attach\n");
- /* Allocate Rx ring. (TODO: Alignment ?) */
- rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
- if(rxdesc == nil){
- print("vgbe: unable to alloc Rx ring\n");
- unlock(&ctlr->init_lock);
- return;
- }
- ctlr->rx_ring = rxdesc;
- /* Allocate Rx blocks, initialize Rx ring. */
- for(i = 0; i < RxCount; i++)
- vgbenewrx(ctlr, i);
- /* Init Rx MAC. */
- wiob(ctlr, RxControl,
- RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
- wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
- /* Load Rx ring. */
- wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
- wiow(ctlr, RxNum, RxCount - 1);
- wiow(ctlr, RxDscIdx, 0);
- wiow(ctlr, RxResCnt, RxCount);
- /* Allocate Tx ring. */
- txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
- if(txdesc == nil){
- print("vgbe: unable to alloc Tx ring\n");
- unlock(&ctlr->init_lock);
- return;
- }
- ctlr->tx_ring = txdesc;
- /* Init DMAs */
- wiob(ctlr, DmaCfg0, 4);
- /* Init Tx MAC. */
- wiob(ctlr, TxControl, 0);
- wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio);
- /* Load Tx ring. */
- wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc));
- wiow(ctlr, TxNum, TxCount - 1);
- wiow(ctlr, TxDscIdx, 0);
- /* Enable Xon/Xoff */
- wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable);
- /* Enable Rx queue */
- wiob(ctlr, RxCsrS, RxCsr_RunQueue);
- /* Enable Tx queue */
- wiob(ctlr, TxCsrS, TxCsr_RunQueue);
- /* Done */
- ctlr->inited = 1;
- unlock(&ctlr->init_lock);
- /* Enable interrupts */
- wiol(ctlr, Isr, 0xffffffff);
- wiob(ctlr, Cr3S, Cr3_IntMask);
- /* Wake up Rx queue */
- wiob(ctlr, RxCsrS, RxCsr_Wakeup);
- }
- static void
- vgbereset(Ctlr* ctlr)
- {
- // MiiPhy* phy;
- int timeo, i;
- // print("vgbe: reset\n");
- /* Soft reset the controller. */
- wiob(ctlr, Cr1S, Cr1_reset);
- for(timeo = 0; timeo < Timeout; timeo++)
- if((riob(ctlr, Cr1S) & Cr1_reset) == 0)
- break;
- if(timeo >= Timeout){
- print("vgbe: softreset timeout\n");
- return;
- }
- /* Reload eeprom. */
- siob(ctlr, Eecsr, Eecsr_Autold);
- for(timeo = 0; timeo < Timeout; timeo++)
- if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0)
- break;
- if(timeo >= Timeout){
- print("vgbe: eeprom reload timeout\n");
- return;
- }
- /* Load the MAC address. */
- for(i = 0; i < Eaddrlen; i++)
- ctlr->ea[i] = riob(ctlr, EthAddr+i);
- /* Initialize interrupts. */
- wiol(ctlr, Isr, 0xffffffff);
- wiol(ctlr, Imr, 0xffffffff);
- /* Disable interrupts. */
- wiol(ctlr, Cr3C, Cr3_IntMask);
- /* 32 bits addresses only. (TODO: 64 bits ?) */
- wiol(ctlr, TxDescHi, 0);
- wiow(ctlr, DataBufHi, 0);
- /* Enable MAC (turning off Rx/Tx engines for the moment). */
- wiob(ctlr, Cr0C, Cr0_Stop|Cr0_EnableRx|Cr0_EnableTx);
- wiob(ctlr, Cr0S, Cr0_Start);
- /* Initialize Rx engine. */
- wiow(ctlr, RxCsrC, RxCsr_RunQueue);
- /* Initialize Tx engine. */
- wiow(ctlr, TxCsrC, TxCsr_RunQueue);
- /* Enable Rx/Tx engines. */
- wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx);
- /* Initialize link management. */
- ctlr->mii = malloc(sizeof(Mii));
- if(ctlr->mii == nil){
- print("vgbe: unable to alloc Mii\n");
- return;
- }
- ctlr->mii->mir = vgbemiir;
- ctlr->mii->miw = vgbemiiw;
- ctlr->mii->ctlr = ctlr;
- if(mii(ctlr->mii, 1<<1) == 0){
- print("vgbe: no phy found\n");
- return;
- }
- // phy = ctlr->mii->curphy;
- // print("vgbe: phy:oui %#x\n", phy->oui);
- }
- static void
- vgbepci(void)
- {
- Pcidev* pdev;
- // print("vgbe: pci\n");
- pdev = nil;
- while(pdev = pcimatch(pdev, 0, 0)){
- Ctlr* ctlr;
- int port, size;
- if(pdev->ccrb != 0x02 || pdev->ccru != 0)
- continue;
- switch((pdev->did<<16) | pdev->vid){
- default:
- continue;
- case (0x3119<<16)|0x1106: /* VIA Velocity (VT6122) */
- break;
- }
- if((pdev->pcr & 1) == 0){
- print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr);
- continue;
- }
- pcisetbme(pdev);
- pcisetpms(pdev, 0);
- port = pdev->mem[0].bar;
- size = pdev->mem[0].size;
- if((port & 1) == 0){
- print("vgbe: bar[0]=%#x is not io\n", port);
- continue;
- }
- if(port > 0xff00){
- print("vgbe: invalid port %#ux\n", port);
- continue;
- }
- port &= 0xfffe;
- if(size != 256){
- print("vgbe: invalid io size: %d\n", size);
- continue;
- }
- if(ioalloc(port, size, 0, "vge") < 0){
- print("vgbe: port %#ux already in use\n", port);
- continue;
- }
- ctlr = malloc(sizeof(Ctlr));
- if(ctlr == nil){
- print("vgbe: unable to alloc Ctlr\n");
- iofree(port);
- continue;
- }
- ctlr->pdev = pdev;
- ctlr->port = port;
- ctlr->inited = 0;
- if(vgbehead != nil)
- vgbetail->link = ctlr;
- else
- vgbehead = ctlr;
- vgbetail = ctlr;
- }
- }
- static long
- vgbectl(Ether* edev, void* buf, long n)
- {
- Cmdbuf* cb;
- Ctlr* ctlr;
- ulong index;
- char* rptr;
- RxDesc* rd;
- TxDesc* td;
- uchar* p;
- ctlr = edev->ctlr;
- cb = parsecmd(buf, n);
- if(waserror()){
- free(cb);
- nexterror();
- }
- if(cistrcmp(cb->f[0], "reset") == 0){
- vgbereset(ctlr);
- wiob(ctlr, Cr3S, Cr3_IntMask);
- wiob(ctlr, RxCsrS, RxCsr_RunQueue);
- wiob(ctlr, RxCsrS, RxCsr_Wakeup);
- }
- else if(cistrcmp(cb->f[0], "dumpintr") == 0){
- if(cb->nf < 2)
- error(Ecmdargs);
- if(cistrcmp(cb->f[1], "on") == 0){
- ctlr->debugflags |= DumpIntr;
- ctlr->debugcount = ~0;
- }
- else if(cistrcmp(cb->f[1], "off") == 0)
- ctlr->debugflags &= ~DumpIntr;
- else{
- ulong count;
- char* rptr;
- count = strtoul(cb->f[1], &rptr, 0);
- if(rptr == cb->f[1])
- error("invalid control request");
- ctlr->debugflags |= DumpIntr;
- ctlr->debugcount = count;
- print("vgbe: debugcount set to %uld\n", count);
- }
- }
- else if(cistrcmp(cb->f[0], "dumprx") == 0){
- if(cb->nf < 2)
- error(Ecmdargs);
- if(cistrcmp(cb->f[1], "on") == 0)
- ctlr->debugflags |= DumpRx;
- else if(cistrcmp(cb->f[1], "off") == 0)
- ctlr->debugflags &= ~DumpRx;
- else{
- index = strtoul(cb->f[1], &rptr, 0);
- if((rptr == cb->f[1]) || (index >= RxCount))
- error("invalid control request");
- rd = &ctlr->rx_ring[index];
- print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n",
- index, rd->status, rd->control, rd->length);
- }
- }
- else if(cistrcmp(cb->f[0], "dumptx") == 0){
- if(cb->nf < 2)
- error(Ecmdargs);
- if(cistrcmp(cb->f[1], "on") == 0)
- ctlr->debugflags |= DumpTx;
- else if(cistrcmp(cb->f[1], "off") == 0)
- ctlr->debugflags &= ~DumpTx;
- else{
- index = strtoul(cb->f[1], &rptr, 0);
- if((rptr == cb->f[1]) || (index >= TxCount))
- error("invalid control request");
- td = &ctlr->tx_ring[index];
- print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes",
- index, td->status, td->control, td->frags[0].length);
- p = (uchar*)td;
- for(index = 0; index < sizeof(TxDesc); index++){
- if((index % 16) == 0)
- print("\nvgbe: ");
- else
- print(" ");
- print("%#02x", p[index]);
- }
- }
- }
- else if(cistrcmp(cb->f[0], "dumpall") == 0){
- if(cb->nf < 2)
- error(Ecmdargs);
- if(cistrcmp(cb->f[1], "on") == 0){
- ctlr->debugflags = ~0;
- ctlr->debugcount = ~0;
- }
- else if(cistrcmp(cb->f[1], "off") == 0)
- ctlr->debugflags = 0;
- else error("invalid control request");
- }
- else
- error(Ebadctl);
- free(cb);
- poperror();
- return n;
- }
- static void
- vgbepromiscuous(void* arg, int on)
- {
- USED(arg, on);
- }
- /* multicast already on, don't need to do anything */
- static void
- vgbemulticast(void*, uchar*, int)
- {
- }
- static void
- vgbeshutdown(Ether* ether)
- {
- vgbereset(ether->ctlr);
- }
- static int
- vgbepnp(Ether* edev)
- {
- Ctlr* ctlr;
- // print("vgbe: pnp\n");
- if(vgbehead == nil)
- vgbepci();
- for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
- if(ctlr->active)
- continue;
- if(edev->port == 0 || edev->port == ctlr->port){
- ctlr->active = 1;
- break;
- }
- }
- if(ctlr == nil)
- return -1;
- vgbereset(ctlr);
- edev->ctlr = ctlr;
- edev->port = ctlr->port;
- edev->irq = ctlr->pdev->intl;
- edev->tbdf = ctlr->pdev->tbdf;
- edev->mbps = 1000;
- memmove(edev->ea, ctlr->ea, Eaddrlen);
- edev->attach = vgbeattach;
- edev->transmit = vgbetransmit;
- edev->interrupt = vgbeinterrupt;
- edev->ifstat = vgbeifstat;
- // edev->promiscuous = vgbepromiscuous;
- edev->multicast = vgbemulticast;
- edev->shutdown = vgbeshutdown;
- edev->ctl = vgbectl;
- edev->arg = edev;
- return 0;
- }
- void
- ethervgbelink(void)
- {
- addethercard("vgbe", vgbepnp);
- }
|