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