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