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)
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]);
474 vgbenewrx(Ctlr* ctlr, int i)
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.
484 block = allocb(RxSize);
487 /* Remember that block. */
488 ctlr->rx_blocks[i] = block;
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);
495 desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
496 desc->addr_hi = htole16(0);
497 desc->length = htole16(RxSize | 0x8000);
503 vgberxeof(Ether* edev)
508 ulong length, status;
513 if(ctlr->debugflags & DumpRx)
514 print("vgbe: rx_eof\n");
516 for(i = 0; i < RxCount; i++){
517 /* Remember that block. */
518 desc = &ctlr->rx_ring[i];
520 status = le32toh(desc->status);
522 if(status & RxDesc_Status_Own)
525 if(status & RxDesc_Status_Goodframe){
526 length = status >> RxDesc_Status_SizShift;
527 length &= RxDesc_Status_SizMask;
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);
533 block = ctlr->rx_blocks[i];
534 block->wp = block->rp + length;
537 etheriq(edev, block, 1);
540 print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
541 i, status, desc->control);
543 /* reset packet ... */
544 desc->status = htole32(RxDesc_Status_Own);
545 desc->control = htole32(0);
548 if(ctlr->debugflags & DumpRx)
549 print("vgbe: rx_eof: done\n");
551 wiow(ctlr, RxResCnt, RxCount);
552 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
556 vgbetxeof(Ether* edev)
565 ilock(&ctlr->tx_lock);
567 if(ctlr->debugflags & DumpTx)
568 print("vgbe: tx_eof\n");
570 for(count = 0, i = 0; i < TxCount; i++){
571 block = ctlr->tx_blocks[i];
575 status = le32toh(ctlr->tx_ring[i].status);
576 if(status & TxDesc_Status_Own)
579 /* Todo add info if it failed */
582 if(ctlr->debugflags & DumpTx)
583 print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
586 ctlr->tx_blocks[i] = nil;
589 if(ctlr->debugflags & DumpTx)
590 print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
592 ctlr->tx_count -= count;
594 if(ctlr->debugflags & DumpTx)
595 print("vgbe: tx_eof: done [count=%d]\n", count);
597 iunlock(&ctlr->tx_lock);
600 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
604 vgbeinterrupt(Ureg *, void* arg)
610 edev = (Ether *) arg;
618 /* Mask interrupts. */
621 status = riol(ctlr, Isr);
627 wiol(ctlr, Isr, status);
629 if((status & Isr_Mask) == 0)
634 if(ctlr->debugflags & DumpIntr)
635 if(ctlr->debugcount){
636 print("vgbe: irq: status = %#08ulx\n", status);
641 if(status & Isr_RxComplete)
644 if(status & Isr_TxComplete0)
647 if(status & Isr_Stopped)
648 print("vgbe: irq: software shutdown complete\n");
650 if(status & Isr_RxFifoOvflow)
651 print("vgbe: irq: RX FIFO overflow\n");
653 if(status & Isr_PhyIntr)
654 print("vgbe: irq: PHY interrupt\n");
656 if(status & Isr_LinkStatus)
657 print("vgbe: irq: link status change\n");
659 if(status & Isr_RxNoDesc)
660 print("vgbe: irq: ran out of Rx descriptors\n");
662 if(status & Isr_RxDmaStall){
663 print("vgbe: irq: Rx DMA stall\n");
664 wiol(ctlr, Cr3C, Cr3_IntMask);
668 if(status & Isr_TxDmaStall){
669 print("vgbe: irq: Tx DMA stall\n");
670 wiol(ctlr, Cr3C, Cr3_IntMask);
675 /* Unmask interrupts. */
680 vgbetransmit(Ether* edev)
684 int i, index, start, count;
686 ulong status, length;
690 ilock(&ctlr->tx_lock);
692 start = riow(ctlr, TxDscIdx);
694 if(ctlr->debugflags & DumpTx)
695 print("vgbe: transmit (start=%d)\n", start);
697 /* find empty slot */
698 for(count = 0, i = 0; i < TxCount; i++){
699 index = (i + start) % TxCount;
701 if(ctlr->tx_blocks[index])
704 desc = &ctlr->tx_ring[index];
706 status = le32toh(desc->status);
707 if(status & TxDesc_Status_Own)
710 block = qget(edev->oq);
716 length = BLEN(block);
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);
722 ctlr->tx_blocks[index] = block;
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));
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);
732 ctlr->tx_count += count;
734 if(ctlr->debugflags & DumpTx)
735 print("vgbe: transmit: done [count=%d]\n", count);
737 iunlock(&ctlr->tx_lock);
740 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
743 print("vgbe: transmit: no Tx entry available\n");
747 vgbeattach(Ether* edev)
756 lock(&ctlr->init_lock);
758 unlock(&ctlr->init_lock);
762 // print("vgbe: attach\n");
764 /* Allocate Rx ring. (TODO: Alignment ?) */
765 rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
767 print("vgbe: unable to alloc Rx ring\n");
768 unlock(&ctlr->init_lock);
771 ctlr->rx_ring = rxdesc;
773 /* Allocate Rx blocks, initialize Rx ring. */
774 for(i = 0; i < RxCount; i++)
778 wiob(ctlr, RxControl,
779 RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
780 wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
783 wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
784 wiow(ctlr, RxNum, RxCount - 1);
785 wiow(ctlr, RxDscIdx, 0);
786 wiow(ctlr, RxResCnt, RxCount);
788 /* Allocate Tx ring. */
789 txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
791 print("vgbe: unable to alloc Tx ring\n");
792 unlock(&ctlr->init_lock);
795 ctlr->tx_ring = txdesc;
798 wiob(ctlr, DmaCfg0, 4);
801 wiob(ctlr, TxControl, 0);
802 wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio);
805 wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc));
806 wiow(ctlr, TxNum, TxCount - 1);
807 wiow(ctlr, TxDscIdx, 0);
809 /* Enable Xon/Xoff */
810 wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable);
812 /* Enable Rx queue */
813 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
815 /* Enable Tx queue */
816 wiob(ctlr, TxCsrS, TxCsr_RunQueue);
820 unlock(&ctlr->init_lock);
822 /* Enable interrupts */
823 wiol(ctlr, Isr, 0xffffffff);
824 wiob(ctlr, Cr3S, Cr3_IntMask);
826 /* Wake up Rx queue */
827 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
831 vgbereset(Ctlr* ctlr)
836 // print("vgbe: reset\n");
838 /* Soft reset the controller. */
839 wiob(ctlr, Cr1S, Cr1_reset);
841 for(timeo = 0; timeo < Timeout; timeo++)
842 if((riob(ctlr, Cr1S) & Cr1_reset) == 0)
845 if(timeo >= Timeout){
846 print("vgbe: softreset timeout\n");
851 siob(ctlr, Eecsr, Eecsr_Autold);
853 for(timeo = 0; timeo < Timeout; timeo++)
854 if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0)
857 if(timeo >= Timeout){
858 print("vgbe: eeprom reload timeout\n");
862 /* Load the MAC address. */
863 for(i = 0; i < Eaddrlen; i++)
864 ctlr->ea[i] = riob(ctlr, EthAddr+i);
866 /* Initialize interrupts. */
867 wiol(ctlr, Isr, 0xffffffff);
868 wiol(ctlr, Imr, 0xffffffff);
870 /* Disable interrupts. */
871 wiol(ctlr, Cr3C, Cr3_IntMask);
873 /* 32 bits addresses only. (TODO: 64 bits ?) */
874 wiol(ctlr, TxDescHi, 0);
875 wiow(ctlr, DataBufHi, 0);
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);
881 /* Initialize Rx engine. */
882 wiow(ctlr, RxCsrC, RxCsr_RunQueue);
884 /* Initialize Tx engine. */
885 wiow(ctlr, TxCsrC, TxCsr_RunQueue);
887 /* Enable Rx/Tx engines. */
888 wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx);
890 /* Initialize link management. */
891 ctlr->mii = malloc(sizeof(Mii));
892 if(ctlr->mii == nil){
893 print("vgbe: unable to alloc Mii\n");
897 ctlr->mii->mir = vgbemiir;
898 ctlr->mii->miw = vgbemiiw;
899 ctlr->mii->ctlr = ctlr;
901 if(mii(ctlr->mii, 1<<1) == 0){
902 print("vgbe: no phy found\n");
906 // phy = ctlr->mii->curphy;
907 // print("vgbe: phy:oui %#x\n", phy->oui);
915 // print("vgbe: pci\n");
918 while(pdev = pcimatch(pdev, 0, 0)){
922 if(pdev->ccrb != 0x02 || pdev->ccru != 0)
925 switch((pdev->did<<16) | pdev->vid){
929 case (0x3119<<16)|0x1106: /* VIA Velocity (VT6122) */
933 if((pdev->pcr & 1) == 0){
934 print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr);
941 port = pdev->mem[0].bar;
942 size = pdev->mem[0].size;
945 print("vgbe: bar[0]=%#x is not io\n", port);
950 print("vgbe: invalid port %#ux\n", port);
957 print("vgbe: invalid io size: %d\n", size);
961 if(ioalloc(port, size, 0, "vge") < 0){
962 print("vgbe: port %#ux already in use\n", port);
966 ctlr = malloc(sizeof(Ctlr));
968 print("vgbe: unable to alloc Ctlr\n");
978 vgbetail->link = ctlr;
986 vgbectl(Ether* edev, void* buf, long n)
998 cb = parsecmd(buf, n);
1004 if(cistrcmp(cb->f[0], "reset") == 0){
1006 wiob(ctlr, Cr3S, Cr3_IntMask);
1007 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
1008 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
1010 else if(cistrcmp(cb->f[0], "dumpintr") == 0){
1014 if(cistrcmp(cb->f[1], "on") == 0){
1015 ctlr->debugflags |= DumpIntr;
1016 ctlr->debugcount = ~0;
1018 else if(cistrcmp(cb->f[1], "off") == 0)
1019 ctlr->debugflags &= ~DumpIntr;
1024 count = strtoul(cb->f[1], &rptr, 0);
1025 if(rptr == cb->f[1])
1026 error("invalid control request");
1028 ctlr->debugflags |= DumpIntr;
1029 ctlr->debugcount = count;
1031 print("vgbe: debugcount set to %uld\n", count);
1034 else if(cistrcmp(cb->f[0], "dumprx") == 0){
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;
1043 index = strtoul(cb->f[1], &rptr, 0);
1044 if((rptr == cb->f[1]) || (index >= RxCount))
1045 error("invalid control request");
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);
1052 else if(cistrcmp(cb->f[0], "dumptx") == 0){
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;
1061 index = strtoul(cb->f[1], &rptr, 0);
1062 if((rptr == cb->f[1]) || (index >= TxCount))
1063 error("invalid control request");
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);
1070 for(index = 0; index < sizeof(TxDesc); index++){
1071 if((index % 16) == 0)
1075 print("%#02x", p[index]);
1079 else if(cistrcmp(cb->f[0], "dumpall") == 0){
1083 if(cistrcmp(cb->f[1], "on") == 0){
1084 ctlr->debugflags = ~0;
1085 ctlr->debugcount = ~0;
1087 else if(cistrcmp(cb->f[1], "off") == 0)
1088 ctlr->debugflags = 0;
1089 else error("invalid control request");
1101 vgbepromiscuous(void* arg, int on)
1106 /* multicast already on, don't need to do anything */
1108 vgbemulticast(void*, uchar*, int)
1113 vgbepnp(Ether* edev)
1117 // print("vgbe: pnp\n");
1122 for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
1126 if(edev->port == 0 || edev->port == ctlr->port){
1138 edev->port = ctlr->port;
1139 edev->irq = ctlr->pdev->intl;
1140 edev->tbdf = ctlr->pdev->tbdf;
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;
1159 addethercard("vgbe", vgbepnp);