2 * VIA Velocity gigabit ethernet.
3 * Register info has been stolen from FreeBSD driver.
6 * - VIA8237 (ABIT AV8): 100Mpbs Full duplex only.
7 * It works enough to run replica/pull, vncv, ...
13 * - dynamic ring sizing ??
14 * - link status change
21 * Philippe Anel, xigh@free.fr
25 #include "../port/lib.h"
30 #include "../port/error.h"
31 #include "../port/netif.h"
45 #define htole16(x) (x)
46 #define htole32(x) (x)
47 #define le32toh(x) (x)
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 */
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 */
71 Cr2S = 0x0a, /* Global command 2 (Set) */
72 Cr2_XonEnable = 0x80, /* - 802.3x XON/XOFF flow control */
74 Cr3S = 0x0b, /* Global command 3 (Set) */
75 Cr3C = 0x0f, /* Global command 3 (Set) */
76 Cr3_IntMask = 0x02, /* - Mask all interrupts */
78 /* Eeprom registers. */
79 Eecsr = 0x93, /* EEPROM control/status */
80 Eecsr_Autold = 0x20, /* - trigger reload from EEPROM */
83 MiiStatus = 0x6D, /* MII port status */
84 MiiStatus_idle = 0x80, /* - idle */
86 MiiCmd = 0x70, /* MII command */
87 MiiCmd_write = 0x20, /* - write */
88 MiiCmd_read = 0x40, /* - read */
89 MiiCmd_auto = 0x80, /* - enable autopolling */
91 MiiAddr = 0x71, /* MII address */
92 MiiData = 0x72, /* MII data */
94 /* 64 bits related registers. */
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 */
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 */
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 */
164 /* Timer registers. */
165 Timer0 = 0x74, /* single-shot timer */
166 Timer1 = 0x76, /* periodic timer */
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 */
174 /* DMA config registers. */
175 DmaCfg0 = 0x7C, /* DMA config 0 */
176 DmaCfg1 = 0x7D, /* DMA config 1 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
222 Isr_Mask = Isr_TxComplete0|Isr_RxComplete|Isr_Stopped|
223 Isr_RxFifoOvflow|Isr_PhyIntr|Isr_LinkStatus|
224 Isr_RxNoDesc|Isr_RxDmaStall|Isr_TxDmaStall
227 typedef struct Frag Frag;
235 typedef struct RxDesc RxDesc;
243 typedef struct TxDesc TxDesc;
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 */
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 */
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. */
274 RxDesc_Status_SizShift = 16, /* received frame len shift */
275 RxDesc_Status_SizMask = 0x3FFF, /* received frame len mask */
277 RxDesc_Status_Shutdown = (1<<30), /* shutdown during RX */
278 RxDesc_Status_Own = (1<<31), /* own bit */
281 TxDesc_Status_Own = (1<<31), /* own bit */
284 TxDesc_Control_Intr = (1<<23), /* Tx intr request */
285 TxDesc_Control_Normal = (3<<24), /* normal frame */
288 typedef struct Stats Stats;
297 typedef struct Ctlr Ctlr;
315 Block* rx_blocks[RxCount];
319 Block* tx_blocks[TxCount];
325 static Ctlr* vgbehead;
326 static Ctlr* vgbetail;
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)
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)
343 vgbemiiw(Mii* mii, int phy, int addr, int data)
353 wiob(ctlr, MiiAddr, addr);
354 wiow(ctlr, MiiData, (ushort) data);
355 wiob(ctlr, MiiCmd, MiiCmd_write);
357 for(i = 0; i < Timeout; i++)
358 if((riob(ctlr, MiiCmd) & MiiCmd_write) == 0)
362 print("vgbe: miiw timeout\n");
370 vgbemiir(Mii* mii, int phy, int addr)
380 wiob(ctlr, MiiAddr, addr);
381 wiob(ctlr, MiiCmd, MiiCmd_read);
383 for(i = 0; i < Timeout; i++)
384 if((riob(ctlr, MiiCmd) & MiiCmd_read) == 0)
388 print("vgbe: miir timeout\n");
392 return riow(ctlr, MiiData);
396 vgbeifstat(Ether* edev, void* a, long n, ulong offset)
404 p = smalloc(READSTR);
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");
412 n = readstr(offset, a, n, p);
418 static char* vgbeisr_info[] = {
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",
429 "Rx packet count 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",
439 "software shutdown complete",
440 "MIB counter overflow warning",
441 "software interrupt",
447 "interrupt source indication 0",
448 "interrupt source indication 1",
449 "interrupt source indication 2",
450 "interrupt source indication 3",
454 vgbedumpisr(ulong isr)
458 for(i = 0; i < 32; i++){
463 print("vgbe: irq: - %02d : %c %s\n", i,
464 Isr_Mask & mask ? '*' : '-', vgbeisr_info[i]);
469 vgbenewrx(Ctlr* ctlr, int i)
474 block = iallocb(RxSize);
478 /* Remember that block. */
479 ctlr->rx_blocks[i] = block;
481 desc = &ctlr->rx_ring[i];
482 desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
483 desc->addr_hi = htole16(0);
484 desc->length = htole16(RxSize | 0x8000);
488 /* Initialize Rx descriptor. (TODO: 48/64 bits support ?) */
489 desc->status = htole32(RxDesc_Status_Own);
490 desc->control = htole32(0);
496 vgberxeof(Ether* edev)
501 ulong length, status;
506 if(ctlr->debugflags & DumpRx)
507 print("vgbe: rx_eof\n");
509 for(i = 0; i < RxCount; i++){
510 /* Remember that block. */
511 desc = &ctlr->rx_ring[i];
513 status = le32toh(desc->status);
515 if(status & RxDesc_Status_Own)
520 if(status & RxDesc_Status_Goodframe){
521 length = status >> RxDesc_Status_SizShift;
522 length &= RxDesc_Status_SizMask;
524 if(ctlr->debugflags & DumpRx)
525 print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n",
526 i, status, desc->control, length);
528 /* remember the block */
529 block = ctlr->rx_blocks[i];
531 /* plant new block, might fail if out of memory */
532 if(vgbenewrx(ctlr, i) == 0){
533 block->wp = block->rp + length;
534 etheriq(edev, block, 1);
539 print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
540 i, status, desc->control);
543 desc->status = htole32(RxDesc_Status_Own);
544 desc->control = htole32(0);
547 if(ctlr->debugflags & DumpRx)
548 print("vgbe: rx_eof: done\n");
550 wiow(ctlr, RxResCnt, RxCount);
551 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
555 vgbetxeof(Ether* edev)
564 ilock(&ctlr->tx_lock);
566 if(ctlr->debugflags & DumpTx)
567 print("vgbe: tx_eof\n");
569 for(count = 0, i = 0; i < TxCount; i++){
570 block = ctlr->tx_blocks[i];
574 status = le32toh(ctlr->tx_ring[i].status);
575 if(status & TxDesc_Status_Own)
578 /* Todo add info if it failed */
581 if(ctlr->debugflags & DumpTx)
582 print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
585 ctlr->tx_blocks[i] = nil;
588 if(ctlr->debugflags & DumpTx)
589 print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
591 ctlr->tx_count -= count;
593 if(ctlr->debugflags & DumpTx)
594 print("vgbe: tx_eof: done [count=%d]\n", count);
596 iunlock(&ctlr->tx_lock);
599 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
603 vgbeinterrupt(Ureg *, void* arg)
609 edev = (Ether *) arg;
617 /* Mask interrupts. */
620 status = riol(ctlr, Isr);
626 wiol(ctlr, Isr, status);
628 if((status & Isr_Mask) == 0)
633 if(ctlr->debugflags & DumpIntr)
634 if(ctlr->debugcount){
635 print("vgbe: irq: status = %#08ulx\n", status);
640 if(status & Isr_RxComplete)
643 if(status & Isr_TxComplete0)
646 if(status & Isr_Stopped)
647 print("vgbe: irq: software shutdown complete\n");
649 if(status & Isr_RxFifoOvflow)
650 print("vgbe: irq: RX FIFO overflow\n");
652 if(status & Isr_PhyIntr)
653 print("vgbe: irq: PHY interrupt\n");
655 if(status & Isr_LinkStatus)
656 print("vgbe: irq: link status change\n");
658 if(status & Isr_RxNoDesc)
659 print("vgbe: irq: ran out of Rx descriptors\n");
661 if(status & Isr_RxDmaStall){
662 print("vgbe: irq: Rx DMA stall\n");
663 wiol(ctlr, Cr3C, Cr3_IntMask);
667 if(status & Isr_TxDmaStall){
668 print("vgbe: irq: Tx DMA stall\n");
669 wiol(ctlr, Cr3C, Cr3_IntMask);
674 /* Unmask interrupts. */
679 vgbetransmit(Ether* edev)
683 int i, index, start, count;
685 ulong status, length;
689 ilock(&ctlr->tx_lock);
691 start = riow(ctlr, TxDscIdx);
693 if(ctlr->debugflags & DumpTx)
694 print("vgbe: transmit (start=%d)\n", start);
696 /* find empty slot */
697 for(count = 0, i = 0; i < TxCount; i++){
698 index = (i + start) % TxCount;
700 if(ctlr->tx_blocks[index])
703 desc = &ctlr->tx_ring[index];
705 status = le32toh(desc->status);
706 if(status & TxDesc_Status_Own)
709 block = qget(edev->oq);
715 length = BLEN(block);
717 if(ctlr->debugflags & DumpTx)
718 print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block,
719 PCIWADDR(block->rp), length);
721 ctlr->tx_blocks[index] = block;
723 /* Initialize Tx descriptor. */
724 desc->status = htole32((length<<16)|TxDesc_Status_Own);
725 desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28));
727 desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp));
728 desc->frags[0].addr_hi = htole16(0);
729 desc->frags[0].length = htole16(length);
731 ctlr->tx_count += count;
733 if(ctlr->debugflags & DumpTx)
734 print("vgbe: transmit: done [count=%d]\n", count);
736 iunlock(&ctlr->tx_lock);
739 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
742 print("vgbe: transmit: no Tx entry available\n");
746 vgbeattach(Ether* edev)
755 lock(&ctlr->init_lock);
757 unlock(&ctlr->init_lock);
761 /* Allocate Rx/Tx ring. (TODO: Alignment ?) */
762 rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
764 print("vgbe: unable to alloc Rx ring\n");
765 txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
767 print("vgbe: unable to alloc Tx ring\n");
768 if(rxdesc == nil || txdesc == nil){
771 unlock(&ctlr->init_lock);
774 ctlr->rx_ring = rxdesc;
775 ctlr->tx_ring = txdesc;
777 /* Allocate Rx blocks, initialize Rx ring. */
778 for(i = 0; i < RxCount; i++)
782 wiob(ctlr, RxControl,
783 RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
784 wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
787 wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
788 wiow(ctlr, RxNum, RxCount - 1);
789 wiow(ctlr, RxDscIdx, 0);
790 wiow(ctlr, RxResCnt, RxCount);
793 wiob(ctlr, DmaCfg0, 4);
796 wiob(ctlr, TxControl, 0);
797 wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio);
800 wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc));
801 wiow(ctlr, TxNum, TxCount - 1);
802 wiow(ctlr, TxDscIdx, 0);
804 /* Enable Xon/Xoff */
805 wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable);
807 /* Enable Rx queue */
808 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
810 /* Enable Tx queue */
811 wiob(ctlr, TxCsrS, TxCsr_RunQueue);
815 unlock(&ctlr->init_lock);
817 /* Enable interrupts */
818 wiol(ctlr, Isr, 0xffffffff);
819 wiob(ctlr, Cr3S, Cr3_IntMask);
821 /* Wake up Rx queue */
822 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
826 vgbereset(Ctlr* ctlr)
831 // print("vgbe: reset\n");
833 /* Soft reset the controller. */
834 wiob(ctlr, Cr1S, Cr1_reset);
836 for(timeo = 0; timeo < Timeout; timeo++)
837 if((riob(ctlr, Cr1S) & Cr1_reset) == 0)
840 if(timeo >= Timeout){
841 print("vgbe: softreset timeout\n");
846 siob(ctlr, Eecsr, Eecsr_Autold);
848 for(timeo = 0; timeo < Timeout; timeo++)
849 if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0)
852 if(timeo >= Timeout){
853 print("vgbe: eeprom reload timeout\n");
857 /* Load the MAC address. */
858 for(i = 0; i < Eaddrlen; i++)
859 ctlr->ea[i] = riob(ctlr, EthAddr+i);
861 /* Initialize interrupts. */
862 wiol(ctlr, Isr, 0xffffffff);
863 wiol(ctlr, Imr, 0xffffffff);
865 /* Disable interrupts. */
866 wiol(ctlr, Cr3C, Cr3_IntMask);
868 /* 32 bits addresses only. (TODO: 64 bits ?) */
869 wiol(ctlr, TxDescHi, 0);
870 wiow(ctlr, DataBufHi, 0);
872 /* Enable MAC (turning off Rx/Tx engines for the moment). */
873 wiob(ctlr, Cr0C, Cr0_Stop|Cr0_EnableRx|Cr0_EnableTx);
874 wiob(ctlr, Cr0S, Cr0_Start);
876 /* Initialize Rx engine. */
877 wiow(ctlr, RxCsrC, RxCsr_RunQueue);
879 /* Initialize Tx engine. */
880 wiow(ctlr, TxCsrC, TxCsr_RunQueue);
882 /* Enable Rx/Tx engines. */
883 wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx);
885 /* Initialize link management. */
886 ctlr->mii = malloc(sizeof(Mii));
887 if(ctlr->mii == nil){
888 print("vgbe: unable to alloc Mii\n");
892 ctlr->mii->mir = vgbemiir;
893 ctlr->mii->miw = vgbemiiw;
894 ctlr->mii->ctlr = ctlr;
896 if(mii(ctlr->mii, 1<<1) == 0){
897 print("vgbe: no phy found\n");
901 // phy = ctlr->mii->curphy;
902 // print("vgbe: phy:oui %#x\n", phy->oui);
910 // print("vgbe: pci\n");
913 while(pdev = pcimatch(pdev, 0, 0)){
917 if(pdev->ccrb != 0x02 || pdev->ccru != 0)
920 switch((pdev->did<<16) | pdev->vid){
924 case (0x3119<<16)|0x1106: /* VIA Velocity (VT6122) */
928 if((pdev->pcr & 1) == 0){
929 print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr);
936 port = pdev->mem[0].bar;
937 size = pdev->mem[0].size;
940 print("vgbe: bar[0]=%#x is not io\n", port);
945 print("vgbe: invalid port %#ux\n", port);
952 print("vgbe: invalid io size: %d\n", size);
956 if(ioalloc(port, size, 0, "vge") < 0){
957 print("vgbe: port %#ux already in use\n", port);
961 ctlr = malloc(sizeof(Ctlr));
963 print("vgbe: unable to alloc Ctlr\n");
973 vgbetail->link = ctlr;
981 vgbectl(Ether* edev, void* buf, long n)
993 cb = parsecmd(buf, n);
999 if(cistrcmp(cb->f[0], "reset") == 0){
1001 wiob(ctlr, Cr3S, Cr3_IntMask);
1002 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
1003 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
1005 else if(cistrcmp(cb->f[0], "dumpintr") == 0){
1009 if(cistrcmp(cb->f[1], "on") == 0){
1010 ctlr->debugflags |= DumpIntr;
1011 ctlr->debugcount = ~0;
1013 else if(cistrcmp(cb->f[1], "off") == 0)
1014 ctlr->debugflags &= ~DumpIntr;
1019 count = strtoul(cb->f[1], &rptr, 0);
1020 if(rptr == cb->f[1])
1021 error("invalid control request");
1023 ctlr->debugflags |= DumpIntr;
1024 ctlr->debugcount = count;
1026 print("vgbe: debugcount set to %uld\n", count);
1029 else if(cistrcmp(cb->f[0], "dumprx") == 0){
1033 if(cistrcmp(cb->f[1], "on") == 0)
1034 ctlr->debugflags |= DumpRx;
1035 else if(cistrcmp(cb->f[1], "off") == 0)
1036 ctlr->debugflags &= ~DumpRx;
1038 index = strtoul(cb->f[1], &rptr, 0);
1039 if((rptr == cb->f[1]) || (index >= RxCount))
1040 error("invalid control request");
1042 rd = &ctlr->rx_ring[index];
1043 print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n",
1044 index, rd->status, rd->control, rd->length);
1047 else if(cistrcmp(cb->f[0], "dumptx") == 0){
1051 if(cistrcmp(cb->f[1], "on") == 0)
1052 ctlr->debugflags |= DumpTx;
1053 else if(cistrcmp(cb->f[1], "off") == 0)
1054 ctlr->debugflags &= ~DumpTx;
1056 index = strtoul(cb->f[1], &rptr, 0);
1057 if((rptr == cb->f[1]) || (index >= TxCount))
1058 error("invalid control request");
1060 td = &ctlr->tx_ring[index];
1061 print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes",
1062 index, td->status, td->control, td->frags[0].length);
1065 for(index = 0; index < sizeof(TxDesc); index++){
1066 if((index % 16) == 0)
1070 print("%#02x", p[index]);
1074 else if(cistrcmp(cb->f[0], "dumpall") == 0){
1078 if(cistrcmp(cb->f[1], "on") == 0){
1079 ctlr->debugflags = ~0;
1080 ctlr->debugcount = ~0;
1082 else if(cistrcmp(cb->f[1], "off") == 0)
1083 ctlr->debugflags = 0;
1084 else error("invalid control request");
1096 vgbepromiscuous(void* arg, int on)
1101 /* multicast already on, don't need to do anything */
1103 vgbemulticast(void*, uchar*, int)
1108 vgbepnp(Ether* edev)
1112 // print("vgbe: pnp\n");
1117 for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
1121 if(edev->port == 0 || edev->port == ctlr->port){
1133 edev->port = ctlr->port;
1134 edev->irq = ctlr->pdev->intl;
1135 edev->tbdf = ctlr->pdev->tbdf;
1137 memmove(edev->ea, ctlr->ea, Eaddrlen);
1138 edev->attach = vgbeattach;
1139 edev->transmit = vgbetransmit;
1140 edev->interrupt = vgbeinterrupt;
1141 edev->ifstat = vgbeifstat;
1142 // edev->promiscuous = vgbepromiscuous;
1143 edev->multicast = vgbemulticast;
1144 // edev->shutdown = vgbeshutdown;
1145 edev->ctl = vgbectl;
1154 addethercard("vgbe", vgbepnp);