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"
32 #include "../port/etherif.h"
33 #include "../port/ethermii.h"
44 #define htole16(x) (x)
45 #define htole32(x) (x)
46 #define le32toh(x) (x)
57 /* Command registers. */
58 Cr0S = 0x08, /* Global command 0 (Set) */
59 Cr0C = 0x0c, /* Global command 0 (Clear) */
60 Cr0_Start = 0x01, /* - start MAC */
61 Cr0_Stop = 0x02, /* - stop MAC */
62 Cr0_EnableRx = 0x04, /* - turn on Rx engine */
63 Cr0_EnableTx = 0x08, /* - turn on Tx engine */
65 Cr1S = 0x09, /* Global command 1 (Set) */
66 Cr1C = 0x0d, /* Global command 1 (Clear) */
67 Cr1_NoPool = 0x08, /* - disable Rx/Tx desc pool */
68 Cr1_reset = 0x80, /* - software reset */
70 Cr2S = 0x0a, /* Global command 2 (Set) */
71 Cr2_XonEnable = 0x80, /* - 802.3x XON/XOFF flow control */
73 Cr3S = 0x0b, /* Global command 3 (Set) */
74 Cr3C = 0x0f, /* Global command 3 (Set) */
75 Cr3_IntMask = 0x02, /* - Mask all interrupts */
77 /* Eeprom registers. */
78 Eecsr = 0x93, /* EEPROM control/status */
79 Eecsr_Autold = 0x20, /* - trigger reload from EEPROM */
82 MiiStatus = 0x6D, /* MII port status */
83 MiiStatus_idle = 0x80, /* - idle */
85 MiiCmd = 0x70, /* MII command */
86 MiiCmd_write = 0x20, /* - write */
87 MiiCmd_read = 0x40, /* - read */
88 MiiCmd_auto = 0x80, /* - enable autopolling */
90 MiiAddr = 0x71, /* MII address */
91 MiiData = 0x72, /* MII data */
93 /* 64 bits related registers. */
97 /* Rx engine registers. */
98 RxDescLo = 0x38, /* Rx descriptor base address (lo 32 bits) */
99 RxCsrS = 0x32, /* Rx descriptor queue control/status (Set) */
100 RxCsrC = 0x36, /* Rx descriptor queue control/status (Clear) */
101 RxCsr_RunQueue = 0x01, /* - enable queue */
102 RxCsr_Active = 0x02, /* - queue active indicator */
103 RxCsr_Wakeup = 0x04, /* - wake up queue */
104 RxCsr_Dead = 0x08, /* - queue dead indicator */
105 RxNum = 0x50, /* Size of Rx desc ring */
106 RxDscIdx = 0x3c, /* Current Rx descriptor index */
107 RxResCnt = 0x5e, /* Rx descriptor residue count */
108 RxHostErr = 0x23, /* Rx host error status */
109 RxTimer = 0x3e, /* Rx queue timer pend */
110 RxControl = 0x06, /* MAC Rx control */
111 RxControl_BadFrame = 0x01, /* - accept CRC error frames */
112 RxControl_Runt = 0x02, /* - accept runts */
113 RxControl_MultiCast = 0x04, /* - accept multicasts */
114 RxControl_BroadCast = 0x08, /* - accept broadcasts */
115 RxControl_Promisc = 0x10, /* - promisc mode */
116 RxControl_Giant = 0x20, /* - accept VLAN tagged frames */
117 RxControl_UniCast = 0x40, /* - use perfect filtering */
118 RxControl_SymbolErr = 0x80, /* - accept symbol err packet */
119 RxConfig = 0x7e, /* MAC Rx config */
120 RxConfig_VlanFilter = 0x01, /* - filter VLAN ID mismatches */
121 RxConfig_VlanOpt0 = (0<<1), /* - TX: no tag insert, RX: all, no extr */
122 RxConfig_VlanOpt1 = (1<<1), /* - TX: no tag insert, RX: tagged pkts, no extr */
123 RxConfig_VlanOpt2 = (2<<1), /* - TX: tag insert, RX: all, extract tags */
124 RxConfig_VlanOpt3 = (3<<1), /* - TX: tag insert, RX: tagged pkts, with extr */
125 RxConfig_FifoLowWat = 0x08, /* - RX FIFO low watermark (7QW/15QW) */
126 RxConfig_FifoTh128 = (0<<4), /* - RX FIFO threshold 128 bytes */
127 RxConfig_FifoTh512 = (1<<4), /* - RX FIFO threshold 512 bytes */
128 RxConfig_FifoTh1024 = (2<<4), /* - RX FIFO threshold 1024 bytes */
129 RxConfig_FifoThFwd = (3<<4), /* - RX FIFO threshold ??? */
130 RxConfig_ArbPrio = 0x80, /* - arbitration priority */
132 /* Tx engine registers. */
133 TxDescLo = 0x40, /* Tx descriptor base address (lo 32 bits) */
134 TxCsrS = 0x30, /* Tx descriptor queue control/status (Set) */
135 TxCsrC = 0x38, /* Tx descriptor queue control/status (Clear) */
136 TxCsr_RunQueue = 0x01, /* - enable queue */
137 TxCsr_Active = 0x02, /* - queue active indicator */
138 TxCsr_Wakeup = 0x04, /* - wake up queue */
139 TxCsr_Dead = 0x08, /* - queue dead indicator */
140 TxNum = 0x52, /* Size of Tx desc ring */
141 TxDscIdx = 0x54, /* Current Tx descriptor index */
142 TxHostErr = 0x22, /* Tx host error status */
143 TxTimer = 0x3f, /* Tx queue timer pend */
144 TxControl = 0x07, /* MAC Rx control */
145 TxControl_LC_Off = (0<<0), /* - loopback control off */
146 TxControl_LC_Mac = (1<<0), /* - loopback control MAC internal */
147 TxControl_LC_Ext = (2<<0), /* - loopback control external */
148 TxControl_Coll16 = (0<<2), /* - one set of 16 retries */
149 TxControl_Coll32 = (1<<2), /* - two sets of 16 retries */
150 TxControl_Coll48 = (2<<2), /* - three sets of 16 retries */
151 TxControl_CollInf = (3<<2), /* - retry forever */
153 TxConfig = 0x7f, /* MAC Tx config */
154 TxConfig_SnapOpt = 0x01, /* - 1 == insert VLAN tag at 13th byte, */
155 /* 0 == insert VLAN tag after SNAP header (21st byte) */
156 TxConfig_NonBlk = 0x02, /* - priority TX/non-blocking mode */
157 TxConfig_Blk64 = (0<<3), /* - non-blocking threshold 64 packets */
158 TxConfig_Blk32 = (1<<3), /* - non-blocking threshold 32 packets */
159 TxConfig_Blk128 = (2<<3), /* - non-blocking threshold 128 packets */
160 TxConfig_Blk8 = (3<<3), /* - non-blocking threshold 8 packets */
161 TxConfig_ArbPrio = 0x80, /* - arbitration priority */
163 /* Timer registers. */
164 Timer0 = 0x74, /* single-shot timer */
165 Timer1 = 0x76, /* periodic timer */
167 /* Chip config registers. */
168 ChipCfgA = 0x78, /* chip config A */
169 ChipCfgB = 0x79, /* chip config B */
170 ChipCfgC = 0x7a, /* chip config C */
171 ChipCfgD = 0x7b, /* chip config D */
173 /* DMA config registers. */
174 DmaCfg0 = 0x7C, /* DMA config 0 */
175 DmaCfg1 = 0x7D, /* DMA config 1 */
177 /* Interrupt registers. */
178 IntCtl = 0x20, /* Interrupt control */
179 Imr = 0x28, /* Interrupt mask */
180 Isr = 0x24, /* Interrupt status */
181 Isr_RxHiPrio = (1<<0), /* - hi prio Rx int */
182 Isr_TxHiPrio = (1<<1), /* - hi prio Tx int */
183 Isr_RxComplete = (1<<2), /* - Rx queue completed */
184 Isr_TxComplete = (1<<3), /* - One of Tx queues completed */
186 Isr_TxComplete0 = (1<<4), /* - Tx queue 0 completed */
187 Isr_TxComplete1 = (1<<5), /* - Tx queue 1 completed */
188 Isr_TxComplete2 = (1<<6), /* - Tx queue 2 completed */
189 Isr_TxComplete3 = (1<<7), /* - Tx queue 3 completed */
191 Isr_Reserved8 = (1<<8), /* - reserved */
192 Isr_Reserver9 = (1<<9), /* - reserved */
193 Isr_RxCountOvflow = (1<<10), /* - Rx packet count overflow */
194 Isr_RxPause = (1<<11), /* - pause frame Rx */
196 Isr_RxFifoOvflow = (1<<12), /* - RX FIFO overflow */
197 Isr_RxNoDesc = (1<<13), /* - ran out of Rx descriptors */
198 Isr_RxNoDescWar = (1<<14), /* - running out of Rx descriptors */
199 Isr_LinkStatus = (1<<15), /* - link status change */
201 Isr_Timer0 = (1<<16), /* - one shot timer expired */
202 Isr_Timer1 = (1<<17), /* - periodic timer expired */
203 Isr_Power = (1<<18), /* - wake up power event */
204 Isr_PhyIntr = (1<<19), /* - PHY interrupt */
206 Isr_Stopped = (1<<20), /* - software shutdown complete */
207 Isr_MibOvflow = (1<<21), /* - MIB counter overflow warning */
208 Isr_SoftIntr = (1<<22), /* - software interrupt */
209 Isr_HoldOffReload = (1<<23), /* - reload hold timer */
211 Isr_RxDmaStall = (1<<24), /* - Rx DMA stall */
212 Isr_TxDmaStall = (1<<25), /* - Tx DMA stall */
213 Isr_Reserved26 = (1<<26), /* - reserved */
214 Isr_Reserved27 = (1<<27), /* - reserved */
216 Isr_Source0 = (1<<28), /* - interrupt source indication */
217 Isr_Source1 = (1<<29), /* - interrupt source indication */
218 Isr_Source2 = (1<<30), /* - interrupt source indication */
219 Isr_Source3 = (1<<31), /* - interrupt source indication */
221 Isr_Mask = Isr_TxComplete0|Isr_RxComplete|Isr_Stopped|
222 Isr_RxFifoOvflow|Isr_PhyIntr|Isr_LinkStatus|
223 Isr_RxNoDesc|Isr_RxDmaStall|Isr_TxDmaStall
226 typedef struct Frag Frag;
234 typedef struct RxDesc RxDesc;
242 typedef struct TxDesc TxDesc;
252 RxDesc_Status_VidMiss = (1<<0), /* VLAN tag filter miss */
253 RxDesc_Status_CrcErr = (1<<1), /* bad CRC error */
254 RxDesc_Status_FrAlErr = (1<<3), /* frame alignment error */
255 RxDesc_Status_CsumErr = (1<<3), /* bad TCP/IP checksum */
256 RxDesc_Status_RxLenErr = (1<<4), /* Rx length error */
257 RxDesc_Status_SymErr = (1<<5), /* PCS symbol error */
258 RxDesc_Status_SnTag = (1<<6), /* RX'ed tagged SNAP pkt */
259 RxDesc_Status_DeTag = (1<<7), /* VLAN tag extracted */
261 RxDesc_Status_OneFrag = (0<<8), /* only one fragment */
262 RxDesc_Status_FirstFrag = (1<<8), /* first frag in frame */
263 RxDesc_Status_LastFrag = (2<<8), /* last frag in frame */
264 RxDesc_Status_MidFrag = (3<<8), /* intermediate frag */
266 RxDesc_Status_Vtag = (1<<10), /* VLAN tag indicator */
267 RxDesc_Status_UniCast = (1<<11), /* unicast frame */
268 RxDesc_Status_BroadCast = (1<<12), /* broadcast frame */
269 RxDesc_Status_MultiCast = (1<<13), /* multicast frame */
270 RxDesc_Status_Perfect = (1<<14), /* perfect filter hit */
271 RxDesc_Status_Goodframe = (1<<15), /* frame is good. */
273 RxDesc_Status_SizShift = 16, /* received frame len shift */
274 RxDesc_Status_SizMask = 0x3FFF, /* received frame len mask */
276 RxDesc_Status_Shutdown = (1<<30), /* shutdown during RX */
277 RxDesc_Status_Own = (1<<31), /* own bit */
280 TxDesc_Status_Own = (1<<31), /* own bit */
283 TxDesc_Control_Intr = (1<<23), /* Tx intr request */
284 TxDesc_Control_Normal = (3<<24), /* normal frame */
287 typedef struct Stats Stats;
296 typedef struct Ctlr Ctlr;
314 Block* rx_blocks[RxCount];
318 Block* tx_blocks[TxCount];
324 static Ctlr* vgbehead;
325 static Ctlr* vgbetail;
327 #define riob(c, r) inb(c->port + r)
328 #define riow(c, r) ins(c->port + r)
329 #define riol(c, r) inl(c->port + r)
330 #define wiob(c, r, d) outb(c->port + r, d)
331 #define wiow(c, r, d) outs(c->port + r, d)
332 #define wiol(c, r, d) outl(c->port + r, d)
334 #define siob(c, r, b) wiob(c, r, riob(c, r) | b)
335 #define siow(c, r, b) wiow(c, r, riob(c, r) | b)
336 #define siol(c, r, b) wiol(c, r, riob(c, r) | b)
337 #define ciob(c, r, b) wiob(c, r, riob(c, r) & ~b)
338 #define ciow(c, r, b) wiow(c, r, riob(c, r) & ~b)
339 #define ciol(c, r, b) wiol(c, r, riob(c, r) & ~b)
342 vgbemiiw(Mii* mii, int phy, int addr, int data)
352 wiob(ctlr, MiiAddr, addr);
353 wiow(ctlr, MiiData, (ushort) data);
354 wiob(ctlr, MiiCmd, MiiCmd_write);
356 for(i = 0; i < Timeout; i++)
357 if((riob(ctlr, MiiCmd) & MiiCmd_write) == 0)
361 print("vgbe: miiw timeout\n");
369 vgbemiir(Mii* mii, int phy, int addr)
379 wiob(ctlr, MiiAddr, addr);
380 wiob(ctlr, MiiCmd, MiiCmd_read);
382 for(i = 0; i < Timeout; i++)
383 if((riob(ctlr, MiiCmd) & MiiCmd_read) == 0)
387 print("vgbe: miir timeout\n");
391 return riow(ctlr, MiiData);
395 vgbeifstat(Ether* edev, void* a, long n, ulong offset)
403 p = smalloc(READSTR);
405 l += snprint(p+l, READSTR-l, "tx: %uld\n", ctlr->stats.tx);
406 l += snprint(p+l, READSTR-l, "tx [errs]: %uld\n", ctlr->stats.txe);
407 l += snprint(p+l, READSTR-l, "rx: %uld\n", ctlr->stats.rx);
408 l += snprint(p+l, READSTR-l, "intr: %uld\n", ctlr->stats.intr);
409 snprint(p+l, READSTR-l, "\n");
411 n = readstr(offset, a, n, p);
417 static char* vgbeisr_info[] = {
420 "Rx queue completed",
421 "One of Tx queues completed",
422 "Tx queue 0 completed",
423 "Tx queue 1 completed",
424 "Tx queue 2 completed",
425 "Tx queue 3 completed",
428 "Rx packet count overflow",
431 "ran out of Rx descriptors",
432 "running out of Rx descriptors",
433 "link status change",
434 "one shot timer expired",
435 "periodic timer expired",
436 "wake up power event",
438 "software shutdown complete",
439 "MIB counter overflow warning",
440 "software interrupt",
446 "interrupt source indication 0",
447 "interrupt source indication 1",
448 "interrupt source indication 2",
449 "interrupt source indication 3",
453 vgbedumpisr(ulong isr)
457 for(i = 0; i < 32; i++){
462 print("vgbe: irq: - %02d : %c %s\n", i,
463 Isr_Mask & mask ? '*' : '-', vgbeisr_info[i]);
468 vgbenewrx(Ctlr* ctlr, int i)
473 block = iallocb(RxSize);
477 /* Remember that block. */
478 ctlr->rx_blocks[i] = block;
480 desc = &ctlr->rx_ring[i];
481 desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
482 desc->addr_hi = htole16(0);
483 desc->length = htole16(RxSize | 0x8000);
487 /* Initialize Rx descriptor. (TODO: 48/64 bits support ?) */
488 desc->status = htole32(RxDesc_Status_Own);
489 desc->control = htole32(0);
495 vgberxeof(Ether* edev)
500 ulong length, status;
505 if(ctlr->debugflags & DumpRx)
506 print("vgbe: rx_eof\n");
508 for(i = 0; i < RxCount; i++){
509 /* Remember that block. */
510 desc = &ctlr->rx_ring[i];
512 status = le32toh(desc->status);
514 if(status & RxDesc_Status_Own)
519 if(status & RxDesc_Status_Goodframe){
520 length = status >> RxDesc_Status_SizShift;
521 length &= RxDesc_Status_SizMask;
523 if(ctlr->debugflags & DumpRx)
524 print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n",
525 i, status, desc->control, length);
527 /* remember the block */
528 block = ctlr->rx_blocks[i];
530 /* plant new block, might fail if out of memory */
531 if(vgbenewrx(ctlr, i) == 0){
532 block->wp = block->rp + length;
533 etheriq(edev, block);
538 print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
539 i, status, desc->control);
542 desc->status = htole32(RxDesc_Status_Own);
543 desc->control = htole32(0);
546 if(ctlr->debugflags & DumpRx)
547 print("vgbe: rx_eof: done\n");
549 wiow(ctlr, RxResCnt, RxCount);
550 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
554 vgbetxeof(Ether* edev)
563 ilock(&ctlr->tx_lock);
565 if(ctlr->debugflags & DumpTx)
566 print("vgbe: tx_eof\n");
568 for(count = 0, i = 0; i < TxCount; i++){
569 block = ctlr->tx_blocks[i];
573 status = le32toh(ctlr->tx_ring[i].status);
574 if(status & TxDesc_Status_Own)
577 /* Todo add info if it failed */
580 if(ctlr->debugflags & DumpTx)
581 print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
584 ctlr->tx_blocks[i] = nil;
587 if(ctlr->debugflags & DumpTx)
588 print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
590 ctlr->tx_count -= count;
592 if(ctlr->debugflags & DumpTx)
593 print("vgbe: tx_eof: done [count=%d]\n", count);
595 iunlock(&ctlr->tx_lock);
598 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
602 vgbeinterrupt(Ureg *, void* arg)
608 edev = (Ether *) arg;
616 /* Mask interrupts. */
619 status = riol(ctlr, Isr);
625 wiol(ctlr, Isr, status);
627 if((status & Isr_Mask) == 0)
632 if(ctlr->debugflags & DumpIntr)
633 if(ctlr->debugcount){
634 print("vgbe: irq: status = %#08ulx\n", status);
639 if(status & Isr_RxComplete)
642 if(status & Isr_TxComplete0)
645 if(status & Isr_Stopped)
646 print("vgbe: irq: software shutdown complete\n");
648 if(status & Isr_RxFifoOvflow)
649 print("vgbe: irq: RX FIFO overflow\n");
651 if(status & Isr_PhyIntr)
652 print("vgbe: irq: PHY interrupt\n");
654 if(status & Isr_LinkStatus)
655 print("vgbe: irq: link status change\n");
657 if(status & Isr_RxNoDesc)
658 print("vgbe: irq: ran out of Rx descriptors\n");
660 if(status & Isr_RxDmaStall){
661 print("vgbe: irq: Rx DMA stall\n");
662 wiol(ctlr, Cr3C, Cr3_IntMask);
666 if(status & Isr_TxDmaStall){
667 print("vgbe: irq: Tx DMA stall\n");
668 wiol(ctlr, Cr3C, Cr3_IntMask);
673 /* Unmask interrupts. */
678 vgbetransmit(Ether* edev)
682 int i, index, start, count;
684 ulong status, length;
688 ilock(&ctlr->tx_lock);
690 start = riow(ctlr, TxDscIdx);
692 if(ctlr->debugflags & DumpTx)
693 print("vgbe: transmit (start=%d)\n", start);
695 /* find empty slot */
696 for(count = 0, i = 0; i < TxCount; i++){
697 index = (i + start) % TxCount;
699 if(ctlr->tx_blocks[index])
702 desc = &ctlr->tx_ring[index];
704 status = le32toh(desc->status);
705 if(status & TxDesc_Status_Own)
708 block = qget(edev->oq);
714 length = BLEN(block);
716 if(ctlr->debugflags & DumpTx)
717 print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block,
718 PCIWADDR(block->rp), length);
720 ctlr->tx_blocks[index] = block;
722 /* Initialize Tx descriptor. */
723 desc->status = htole32((length<<16)|TxDesc_Status_Own);
724 desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28));
726 desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp));
727 desc->frags[0].addr_hi = htole16(0);
728 desc->frags[0].length = htole16(length);
730 ctlr->tx_count += count;
732 if(ctlr->debugflags & DumpTx)
733 print("vgbe: transmit: done [count=%d]\n", count);
735 iunlock(&ctlr->tx_lock);
738 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
741 print("vgbe: transmit: no Tx entry available\n");
745 vgbeattach(Ether* edev)
754 lock(&ctlr->init_lock);
756 unlock(&ctlr->init_lock);
760 /* Allocate Rx/Tx ring. (TODO: Alignment ?) */
761 rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
763 print("vgbe: unable to alloc Rx ring\n");
764 txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
766 print("vgbe: unable to alloc Tx ring\n");
767 if(rxdesc == nil || txdesc == nil){
770 unlock(&ctlr->init_lock);
773 ctlr->rx_ring = rxdesc;
774 ctlr->tx_ring = txdesc;
776 /* Allocate Rx blocks, initialize Rx ring. */
777 for(i = 0; i < RxCount; i++)
781 wiob(ctlr, RxControl,
782 RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
783 wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
786 wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
787 wiow(ctlr, RxNum, RxCount - 1);
788 wiow(ctlr, RxDscIdx, 0);
789 wiow(ctlr, RxResCnt, RxCount);
792 wiob(ctlr, DmaCfg0, 4);
795 wiob(ctlr, TxControl, 0);
796 wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio);
799 wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc));
800 wiow(ctlr, TxNum, TxCount - 1);
801 wiow(ctlr, TxDscIdx, 0);
803 /* Enable Xon/Xoff */
804 wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable);
806 /* Enable Rx queue */
807 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
809 /* Enable Tx queue */
810 wiob(ctlr, TxCsrS, TxCsr_RunQueue);
814 unlock(&ctlr->init_lock);
816 /* Enable interrupts */
817 wiol(ctlr, Isr, 0xffffffff);
818 wiob(ctlr, Cr3S, Cr3_IntMask);
820 /* Wake up Rx queue */
821 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
825 vgbereset(Ctlr* ctlr)
830 // print("vgbe: reset\n");
832 /* Soft reset the controller. */
833 wiob(ctlr, Cr1S, Cr1_reset);
835 for(timeo = 0; timeo < Timeout; timeo++)
836 if((riob(ctlr, Cr1S) & Cr1_reset) == 0)
839 if(timeo >= Timeout){
840 print("vgbe: softreset timeout\n");
845 siob(ctlr, Eecsr, Eecsr_Autold);
847 for(timeo = 0; timeo < Timeout; timeo++)
848 if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0)
851 if(timeo >= Timeout){
852 print("vgbe: eeprom reload timeout\n");
856 /* Load the MAC address. */
857 for(i = 0; i < Eaddrlen; i++)
858 ctlr->ea[i] = riob(ctlr, EthAddr+i);
860 /* Initialize interrupts. */
861 wiol(ctlr, Isr, 0xffffffff);
862 wiol(ctlr, Imr, 0xffffffff);
864 /* Disable interrupts. */
865 wiol(ctlr, Cr3C, Cr3_IntMask);
867 /* 32 bits addresses only. (TODO: 64 bits ?) */
868 wiol(ctlr, TxDescHi, 0);
869 wiow(ctlr, DataBufHi, 0);
871 /* Enable MAC (turning off Rx/Tx engines for the moment). */
872 wiob(ctlr, Cr0C, Cr0_Stop|Cr0_EnableRx|Cr0_EnableTx);
873 wiob(ctlr, Cr0S, Cr0_Start);
875 /* Initialize Rx engine. */
876 wiow(ctlr, RxCsrC, RxCsr_RunQueue);
878 /* Initialize Tx engine. */
879 wiow(ctlr, TxCsrC, TxCsr_RunQueue);
881 /* Enable Rx/Tx engines. */
882 wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx);
884 /* Initialize link management. */
885 ctlr->mii = malloc(sizeof(Mii));
886 if(ctlr->mii == nil){
887 print("vgbe: unable to alloc Mii\n");
891 ctlr->mii->mir = vgbemiir;
892 ctlr->mii->miw = vgbemiiw;
893 ctlr->mii->ctlr = ctlr;
895 if(mii(ctlr->mii, 1<<1) == 0){
896 print("vgbe: no phy found\n");
900 // phy = ctlr->mii->curphy;
901 // print("vgbe: phy:oui %#x\n", phy->oui);
909 // print("vgbe: pci\n");
912 while(pdev = pcimatch(pdev, 0, 0)){
916 if(pdev->ccrb != 0x02 || pdev->ccru != 0)
919 switch((pdev->did<<16) | pdev->vid){
923 case (0x3119<<16)|0x1106: /* VIA Velocity (VT6122) */
927 if((pdev->pcr & 1) == 0){
928 print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr);
932 port = pdev->mem[0].bar;
933 size = pdev->mem[0].size;
936 print("vgbe: bar[0]=%#x is not io\n", port);
941 print("vgbe: invalid port %#ux\n", port);
948 print("vgbe: invalid io size: %d\n", size);
952 if(ioalloc(port, size, 0, "vge") < 0){
953 print("vgbe: port %#ux already in use\n", port);
957 ctlr = malloc(sizeof(Ctlr));
959 print("vgbe: unable to alloc Ctlr\n");
969 vgbetail->link = ctlr;
977 vgbectl(Ether* edev, void* buf, long n)
989 cb = parsecmd(buf, n);
995 if(cistrcmp(cb->f[0], "reset") == 0){
997 wiob(ctlr, Cr3S, Cr3_IntMask);
998 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
999 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
1001 else if(cistrcmp(cb->f[0], "dumpintr") == 0){
1005 if(cistrcmp(cb->f[1], "on") == 0){
1006 ctlr->debugflags |= DumpIntr;
1007 ctlr->debugcount = ~0;
1009 else if(cistrcmp(cb->f[1], "off") == 0)
1010 ctlr->debugflags &= ~DumpIntr;
1015 count = strtoul(cb->f[1], &rptr, 0);
1016 if(rptr == cb->f[1])
1017 error("invalid control request");
1019 ctlr->debugflags |= DumpIntr;
1020 ctlr->debugcount = count;
1022 print("vgbe: debugcount set to %uld\n", count);
1025 else if(cistrcmp(cb->f[0], "dumprx") == 0){
1029 if(cistrcmp(cb->f[1], "on") == 0)
1030 ctlr->debugflags |= DumpRx;
1031 else if(cistrcmp(cb->f[1], "off") == 0)
1032 ctlr->debugflags &= ~DumpRx;
1034 index = strtoul(cb->f[1], &rptr, 0);
1035 if((rptr == cb->f[1]) || (index >= RxCount))
1036 error("invalid control request");
1038 rd = &ctlr->rx_ring[index];
1039 print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n",
1040 index, rd->status, rd->control, rd->length);
1043 else if(cistrcmp(cb->f[0], "dumptx") == 0){
1047 if(cistrcmp(cb->f[1], "on") == 0)
1048 ctlr->debugflags |= DumpTx;
1049 else if(cistrcmp(cb->f[1], "off") == 0)
1050 ctlr->debugflags &= ~DumpTx;
1052 index = strtoul(cb->f[1], &rptr, 0);
1053 if((rptr == cb->f[1]) || (index >= TxCount))
1054 error("invalid control request");
1056 td = &ctlr->tx_ring[index];
1057 print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes",
1058 index, td->status, td->control, td->frags[0].length);
1061 for(index = 0; index < sizeof(TxDesc); index++){
1062 if((index % 16) == 0)
1066 print("%#02x", p[index]);
1070 else if(cistrcmp(cb->f[0], "dumpall") == 0){
1074 if(cistrcmp(cb->f[1], "on") == 0){
1075 ctlr->debugflags = ~0;
1076 ctlr->debugcount = ~0;
1078 else if(cistrcmp(cb->f[1], "off") == 0)
1079 ctlr->debugflags = 0;
1080 else error("invalid control request");
1092 vgbepromiscuous(void* arg, int on)
1097 /* multicast already on, don't need to do anything */
1099 vgbemulticast(void*, uchar*, int)
1104 vgbepnp(Ether* edev)
1108 // print("vgbe: pnp\n");
1113 for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
1117 if(edev->port == 0 || edev->port == ctlr->port){
1126 pcienable(ctlr->pdev);
1127 pcisetbme(ctlr->pdev);
1132 edev->port = ctlr->port;
1133 edev->irq = ctlr->pdev->intl;
1134 edev->tbdf = ctlr->pdev->tbdf;
1136 memmove(edev->ea, ctlr->ea, Eaddrlen);
1137 edev->attach = vgbeattach;
1138 edev->transmit = vgbetransmit;
1139 edev->ifstat = vgbeifstat;
1140 // edev->promiscuous = vgbepromiscuous;
1141 edev->multicast = vgbemulticast;
1142 // edev->shutdown = vgbeshutdown;
1143 edev->ctl = vgbectl;
1146 intrenable(edev->irq, vgbeinterrupt, edev, edev->tbdf, edev->name);
1154 addethercard("vgbe", vgbepnp);