]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/ethervgbe.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / 9 / 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 }