FreeBSD/Linux Kernel Cross Reference
sys/pc/ethervgbe.c
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
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
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
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 l = 0;
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");
411
412 n = readstr(offset, a, n, p);
413 free(p);
414
415 return n;
416 }
417
418 static char* vgbeisr_info[] = {
419 "hi prio Rx int",
420 "hi prio Tx int",
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",
427 "reserved",
428 "reserved",
429 "Rx packet count overflow",
430 "pause frame Rx'ed",
431 "RX FIFO 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",
438 "PHY interrupt",
439 "software shutdown complete",
440 "MIB counter overflow warning",
441 "software interrupt",
442 "reload hold timer",
443 "Rx DMA stall",
444 "Tx DMA stall",
445 "reserved",
446 "reserved",
447 "interrupt source indication 0",
448 "interrupt source indication 1",
449 "interrupt source indication 2",
450 "interrupt source indication 3",
451 };
452
453 static void
454 vgbedumpisr(ulong isr)
455 {
456 int i;
457
458 for(i = 0; i < 32; i++){
459 ulong mask;
460
461 mask = 1<<i;
462 if(isr & mask)
463 print("vgbe: irq: - %02d : %c %s\n", i,
464 Isr_Mask & mask ? '*' : '-', vgbeisr_info[i]);
465 }
466 }
467
468 static void
469 noop(Block *)
470 {
471 }
472
473 static int
474 vgbenewrx(Ctlr* ctlr, int i)
475 {
476 Block* block;
477 RxDesc* desc;
478
479 /*
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.
483 */
484 block = allocb(RxSize);
485 block->free = noop;
486
487 /* Remember that block. */
488 ctlr->rx_blocks[i] = block;
489
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);
494
495 desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
496 desc->addr_hi = htole16(0);
497 desc->length = htole16(RxSize | 0x8000);
498
499 return 0;
500 }
501
502 static void
503 vgberxeof(Ether* edev)
504 {
505 Ctlr* ctlr;
506 int i;
507 Block* block;
508 ulong length, status;
509 RxDesc* desc;
510
511 ctlr = edev->ctlr;
512
513 if(ctlr->debugflags & DumpRx)
514 print("vgbe: rx_eof\n");
515
516 for(i = 0; i < RxCount; i++){
517 /* Remember that block. */
518 desc = &ctlr->rx_ring[i];
519
520 status = le32toh(desc->status);
521
522 if(status & RxDesc_Status_Own)
523 continue;
524
525 if(status & RxDesc_Status_Goodframe){
526 length = status >> RxDesc_Status_SizShift;
527 length &= RxDesc_Status_SizMask;
528
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);
532
533 block = ctlr->rx_blocks[i];
534 block->wp = block->rp + length;
535
536 ctlr->stats.rx++;
537 etheriq(edev, block, 1);
538 }
539 else
540 print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
541 i, status, desc->control);
542
543 /* reset packet ... */
544 desc->status = htole32(RxDesc_Status_Own);
545 desc->control = htole32(0);
546 }
547
548 if(ctlr->debugflags & DumpRx)
549 print("vgbe: rx_eof: done\n");
550
551 wiow(ctlr, RxResCnt, RxCount);
552 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
553 }
554
555 static void
556 vgbetxeof(Ether* edev)
557 {
558 Ctlr* ctlr;
559 int i, count;
560 Block* block;
561 ulong status;
562
563 ctlr = edev->ctlr;
564
565 ilock(&ctlr->tx_lock);
566
567 if(ctlr->debugflags & DumpTx)
568 print("vgbe: tx_eof\n");
569
570 for(count = 0, i = 0; i < TxCount; i++){
571 block = ctlr->tx_blocks[i];
572 if(block == nil)
573 continue;
574
575 status = le32toh(ctlr->tx_ring[i].status);
576 if(status & TxDesc_Status_Own)
577 continue;
578
579 /* Todo add info if it failed */
580 ctlr->stats.tx++;
581
582 if(ctlr->debugflags & DumpTx)
583 print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
584
585 count++;
586 ctlr->tx_blocks[i] = nil;
587 freeb(block);
588
589 if(ctlr->debugflags & DumpTx)
590 print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
591 }
592 ctlr->tx_count -= count;
593
594 if(ctlr->debugflags & DumpTx)
595 print("vgbe: tx_eof: done [count=%d]\n", count);
596
597 iunlock(&ctlr->tx_lock);
598
599 if(ctlr->tx_count)
600 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
601 }
602
603 static void
604 vgbeinterrupt(Ureg *, void* arg)
605 {
606 Ether* edev;
607 Ctlr* ctlr;
608 ulong status;
609
610 edev = (Ether *) arg;
611 if(edev == nil)
612 return;
613
614 ctlr = edev->ctlr;
615 if(ctlr == nil)
616 return;
617
618 /* Mask interrupts. */
619 wiol(ctlr, Imr, 0);
620
621 status = riol(ctlr, Isr);
622 if(status == 0xffff)
623 goto end;
624
625 /* acknowledge */
626 if(status)
627 wiol(ctlr, Isr, status);
628
629 if((status & Isr_Mask) == 0)
630 goto end;
631
632 ctlr->stats.intr++;
633
634 if(ctlr->debugflags & DumpIntr)
635 if(ctlr->debugcount){
636 print("vgbe: irq: status = %#08ulx\n", status);
637 vgbedumpisr(status);
638 ctlr->debugcount--;
639 }
640
641 if(status & Isr_RxComplete)
642 vgberxeof(edev);
643
644 if(status & Isr_TxComplete0)
645 vgbetxeof(edev);
646
647 if(status & Isr_Stopped)
648 print("vgbe: irq: software shutdown complete\n");
649
650 if(status & Isr_RxFifoOvflow)
651 print("vgbe: irq: RX FIFO overflow\n");
652
653 if(status & Isr_PhyIntr)
654 print("vgbe: irq: PHY interrupt\n");
655
656 if(status & Isr_LinkStatus)
657 print("vgbe: irq: link status change\n");
658
659 if(status & Isr_RxNoDesc)
660 print("vgbe: irq: ran out of Rx descriptors\n");
661
662 if(status & Isr_RxDmaStall){
663 print("vgbe: irq: Rx DMA stall\n");
664 wiol(ctlr, Cr3C, Cr3_IntMask);
665 return;
666 }
667
668 if(status & Isr_TxDmaStall){
669 print("vgbe: irq: Tx DMA stall\n");
670 wiol(ctlr, Cr3C, Cr3_IntMask);
671 return;
672 }
673
674 end:
675 /* Unmask interrupts. */
676 wiol(ctlr, Imr, ~0);
677 }
678
679 static void
680 vgbetransmit(Ether* edev)
681 {
682 Block* block;
683 Ctlr* ctlr;
684 int i, index, start, count;
685 TxDesc* desc;
686 ulong status, length;
687
688 ctlr = edev->ctlr;
689
690 ilock(&ctlr->tx_lock);
691
692 start = riow(ctlr, TxDscIdx);
693
694 if(ctlr->debugflags & DumpTx)
695 print("vgbe: transmit (start=%d)\n", start);
696
697 /* find empty slot */
698 for(count = 0, i = 0; i < TxCount; i++){
699 index = (i + start) % TxCount;
700
701 if(ctlr->tx_blocks[index])
702 continue;
703
704 desc = &ctlr->tx_ring[index];
705
706 status = le32toh(desc->status);
707 if(status & TxDesc_Status_Own)
708 continue;
709
710 block = qget(edev->oq);
711 if(block == nil)
712 break;
713
714 count++;
715
716 length = BLEN(block);
717
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);
721
722 ctlr->tx_blocks[index] = block;
723
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));
727
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);
731 }
732 ctlr->tx_count += count;
733
734 if(ctlr->debugflags & DumpTx)
735 print("vgbe: transmit: done [count=%d]\n", count);
736
737 iunlock(&ctlr->tx_lock);
738
739 if(ctlr->tx_count)
740 wiob(ctlr, TxCsrS, TxCsr_Wakeup);
741
742 if(count == 0)
743 print("vgbe: transmit: no Tx entry available\n");
744 }
745
746 static void
747 vgbeattach(Ether* edev)
748 {
749 Ctlr* ctlr;
750 RxDesc* rxdesc;
751 TxDesc* txdesc;
752 int i;
753
754 ctlr = edev->ctlr;
755
756 lock(&ctlr->init_lock);
757 if(ctlr->inited){
758 unlock(&ctlr->init_lock);
759 return;
760 }
761
762 // print("vgbe: attach\n");
763
764 /* Allocate Rx ring. (TODO: Alignment ?) */
765 rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
766 if(rxdesc == nil){
767 print("vgbe: unable to alloc Rx ring\n");
768 unlock(&ctlr->init_lock);
769 return;
770 }
771 ctlr->rx_ring = rxdesc;
772
773 /* Allocate Rx blocks, initialize Rx ring. */
774 for(i = 0; i < RxCount; i++)
775 vgbenewrx(ctlr, i);
776
777 /* Init Rx MAC. */
778 wiob(ctlr, RxControl,
779 RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
780 wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
781
782 /* Load Rx ring. */
783 wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
784 wiow(ctlr, RxNum, RxCount - 1);
785 wiow(ctlr, RxDscIdx, 0);
786 wiow(ctlr, RxResCnt, RxCount);
787
788 /* Allocate Tx ring. */
789 txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
790 if(txdesc == nil){
791 print("vgbe: unable to alloc Tx ring\n");
792 unlock(&ctlr->init_lock);
793 return;
794 }
795 ctlr->tx_ring = txdesc;
796
797 /* Init DMAs */
798 wiob(ctlr, DmaCfg0, 4);
799
800 /* Init Tx MAC. */
801 wiob(ctlr, TxControl, 0);
802 wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio);
803
804 /* Load Tx ring. */
805 wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc));
806 wiow(ctlr, TxNum, TxCount - 1);
807 wiow(ctlr, TxDscIdx, 0);
808
809 /* Enable Xon/Xoff */
810 wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable);
811
812 /* Enable Rx queue */
813 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
814
815 /* Enable Tx queue */
816 wiob(ctlr, TxCsrS, TxCsr_RunQueue);
817
818 /* Done */
819 ctlr->inited = 1;
820 unlock(&ctlr->init_lock);
821
822 /* Enable interrupts */
823 wiol(ctlr, Isr, 0xffffffff);
824 wiob(ctlr, Cr3S, Cr3_IntMask);
825
826 /* Wake up Rx queue */
827 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
828 }
829
830 static void
831 vgbereset(Ctlr* ctlr)
832 {
833 // MiiPhy* phy;
834 int timeo, i;
835
836 // print("vgbe: reset\n");
837
838 /* Soft reset the controller. */
839 wiob(ctlr, Cr1S, Cr1_reset);
840
841 for(timeo = 0; timeo < Timeout; timeo++)
842 if((riob(ctlr, Cr1S) & Cr1_reset) == 0)
843 break;
844
845 if(timeo >= Timeout){
846 print("vgbe: softreset timeout\n");
847 return;
848 }
849
850 /* Reload eeprom. */
851 siob(ctlr, Eecsr, Eecsr_Autold);
852
853 for(timeo = 0; timeo < Timeout; timeo++)
854 if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0)
855 break;
856
857 if(timeo >= Timeout){
858 print("vgbe: eeprom reload timeout\n");
859 return;
860 }
861
862 /* Load the MAC address. */
863 for(i = 0; i < Eaddrlen; i++)
864 ctlr->ea[i] = riob(ctlr, EthAddr+i);
865
866 /* Initialize interrupts. */
867 wiol(ctlr, Isr, 0xffffffff);
868 wiol(ctlr, Imr, 0xffffffff);
869
870 /* Disable interrupts. */
871 wiol(ctlr, Cr3C, Cr3_IntMask);
872
873 /* 32 bits addresses only. (TODO: 64 bits ?) */
874 wiol(ctlr, TxDescHi, 0);
875 wiow(ctlr, DataBufHi, 0);
876
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);
880
881 /* Initialize Rx engine. */
882 wiow(ctlr, RxCsrC, RxCsr_RunQueue);
883
884 /* Initialize Tx engine. */
885 wiow(ctlr, TxCsrC, TxCsr_RunQueue);
886
887 /* Enable Rx/Tx engines. */
888 wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx);
889
890 /* Initialize link management. */
891 ctlr->mii = malloc(sizeof(Mii));
892 if(ctlr->mii == nil){
893 print("vgbe: unable to alloc Mii\n");
894 return;
895 }
896
897 ctlr->mii->mir = vgbemiir;
898 ctlr->mii->miw = vgbemiiw;
899 ctlr->mii->ctlr = ctlr;
900
901 if(mii(ctlr->mii, 1<<1) == 0){
902 print("vgbe: no phy found\n");
903 return;
904 }
905
906 // phy = ctlr->mii->curphy;
907 // print("vgbe: phy:oui %#x\n", phy->oui);
908 }
909
910 static void
911 vgbepci(void)
912 {
913 Pcidev* pdev;
914
915 // print("vgbe: pci\n");
916
917 pdev = nil;
918 while(pdev = pcimatch(pdev, 0, 0)){
919 Ctlr* ctlr;
920 int port, size;
921
922 if(pdev->ccrb != 0x02 || pdev->ccru != 0)
923 continue;
924
925 switch((pdev->did<<16) | pdev->vid){
926 default:
927 continue;
928
929 case (0x3119<<16)|0x1106: /* VIA Velocity (VT6122) */
930 break;
931 }
932
933 if((pdev->pcr & 1) == 0){
934 print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr);
935 continue;
936 }
937
938 pcisetbme(pdev);
939 pcisetpms(pdev, 0);
940
941 port = pdev->mem[0].bar;
942 size = pdev->mem[0].size;
943
944 if((port & 1) == 0){
945 print("vgbe: bar[0]=%#x is not io\n", port);
946 continue;
947 }
948
949 if(port > 0xff00){
950 print("vgbe: invalid port %#ux\n", port);
951 continue;
952 }
953
954 port &= 0xfffe;
955
956 if(size != 256){
957 print("vgbe: invalid io size: %d\n", size);
958 continue;
959 }
960
961 if(ioalloc(port, size, 0, "vge") < 0){
962 print("vgbe: port %#ux already in use\n", port);
963 continue;
964 }
965
966 ctlr = malloc(sizeof(Ctlr));
967 if(ctlr == nil){
968 print("vgbe: unable to alloc Ctlr\n");
969 iofree(port);
970 continue;
971 }
972
973 ctlr->pdev = pdev;
974 ctlr->port = port;
975 ctlr->inited = 0;
976
977 if(vgbehead != nil)
978 vgbetail->link = ctlr;
979 else
980 vgbehead = ctlr;
981 vgbetail = ctlr;
982 }
983 }
984
985 static long
986 vgbectl(Ether* edev, void* buf, long n)
987 {
988 Cmdbuf* cb;
989 Ctlr* ctlr;
990 ulong index;
991 char* rptr;
992 RxDesc* rd;
993 TxDesc* td;
994 uchar* p;
995
996 ctlr = edev->ctlr;
997
998 cb = parsecmd(buf, n);
999 if(waserror()){
1000 free(cb);
1001 nexterror();
1002 }
1003
1004 if(cistrcmp(cb->f[0], "reset") == 0){
1005 vgbereset(ctlr);
1006 wiob(ctlr, Cr3S, Cr3_IntMask);
1007 wiob(ctlr, RxCsrS, RxCsr_RunQueue);
1008 wiob(ctlr, RxCsrS, RxCsr_Wakeup);
1009 }
1010 else if(cistrcmp(cb->f[0], "dumpintr") == 0){
1011 if(cb->nf < 2)
1012 error(Ecmdargs);
1013
1014 if(cistrcmp(cb->f[1], "on") == 0){
1015 ctlr->debugflags |= DumpIntr;
1016 ctlr->debugcount = ~0;
1017 }
1018 else if(cistrcmp(cb->f[1], "off") == 0)
1019 ctlr->debugflags &= ~DumpIntr;
1020 else{
1021 ulong count;
1022 char* rptr;
1023
1024 count = strtoul(cb->f[1], &rptr, 0);
1025 if(rptr == cb->f[1])
1026 error("invalid control request");
1027
1028 ctlr->debugflags |= DumpIntr;
1029 ctlr->debugcount = count;
1030
1031 print("vgbe: debugcount set to %uld\n", count);
1032 }
1033 }
1034 else if(cistrcmp(cb->f[0], "dumprx") == 0){
1035 if(cb->nf < 2)
1036 error(Ecmdargs);
1037
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;
1042 else{
1043 index = strtoul(cb->f[1], &rptr, 0);
1044 if((rptr == cb->f[1]) || (index >= RxCount))
1045 error("invalid control request");
1046
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);
1050 }
1051 }
1052 else if(cistrcmp(cb->f[0], "dumptx") == 0){
1053 if(cb->nf < 2)
1054 error(Ecmdargs);
1055
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;
1060 else{
1061 index = strtoul(cb->f[1], &rptr, 0);
1062 if((rptr == cb->f[1]) || (index >= TxCount))
1063 error("invalid control request");
1064
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);
1068
1069 p = (uchar*)td;
1070 for(index = 0; index < sizeof(TxDesc); index++){
1071 if((index % 16) == 0)
1072 print("\nvgbe: ");
1073 else
1074 print(" ");
1075 print("%#02x", p[index]);
1076 }
1077 }
1078 }
1079 else if(cistrcmp(cb->f[0], "dumpall") == 0){
1080 if(cb->nf < 2)
1081 error(Ecmdargs);
1082
1083 if(cistrcmp(cb->f[1], "on") == 0){
1084 ctlr->debugflags = ~0;
1085 ctlr->debugcount = ~0;
1086 }
1087 else if(cistrcmp(cb->f[1], "off") == 0)
1088 ctlr->debugflags = 0;
1089 else error("invalid control request");
1090 }
1091 else
1092 error(Ebadctl);
1093
1094 free(cb);
1095 poperror();
1096
1097 return n;
1098 }
1099
1100 static void
1101 vgbepromiscuous(void* arg, int on)
1102 {
1103 USED(arg, on);
1104 }
1105
1106 /* multicast already on, don't need to do anything */
1107 static void
1108 vgbemulticast(void*, uchar*, int)
1109 {
1110 }
1111
1112 static int
1113 vgbepnp(Ether* edev)
1114 {
1115 Ctlr* ctlr;
1116
1117 // print("vgbe: pnp\n");
1118
1119 if(vgbehead == nil)
1120 vgbepci();
1121
1122 for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
1123 if(ctlr->active)
1124 continue;
1125
1126 if(edev->port == 0 || edev->port == ctlr->port){
1127 ctlr->active = 1;
1128 break;
1129 }
1130 }
1131
1132 if(ctlr == nil)
1133 return -1;
1134
1135 vgbereset(ctlr);
1136
1137 edev->ctlr = ctlr;
1138 edev->port = ctlr->port;
1139 edev->irq = ctlr->pdev->intl;
1140 edev->tbdf = ctlr->pdev->tbdf;
1141 edev->mbps = 1000;
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;
1151
1152 edev->arg = edev;
1153 return 0;
1154 }
1155
1156 void
1157 ethervgbelink(void)
1158 {
1159 addethercard("vgbe", vgbepnp);
1160 }
Cache object: f63ad863d8c74223117d833f54863ac4
|