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