xref: /plan9-contrib/sys/src/9/pc/ethervgbe.c (revision 906943f9f6b8411972abb5e3a03ed19f74be7ccc)
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 int
469 vgbenewrx(Ctlr* ctlr, int i)
470 {
471 	Block* block;
472 	RxDesc* desc;
473 
474 	/* Allocate Rx block. (TODO: Alignment ?) */
475 	block = allocb(RxSize);
476 
477 	/* Remember that block. */
478 	ctlr->rx_blocks[i] = block;
479 
480 	/* Initialize Rx descriptor. (TODO: 48/64 bits support ?) */
481 	desc = &ctlr->rx_ring[i];
482 	desc->status = htole32(RxDesc_Status_Own);
483 	desc->control = htole32(0);
484 
485 	desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
486 	desc->addr_hi = htole16(0);
487 	desc->length = htole16(RxSize | 0x8000);
488 
489 	return 0;
490 }
491 
492 static void
493 vgberxeof(Ether* edev)
494 {
495 	Ctlr* ctlr;
496 	int i;
497 	Block* block;
498 	ulong length, status;
499 	RxDesc* desc;
500 
501 	ctlr = edev->ctlr;
502 
503 	if(ctlr->debugflags & DumpRx)
504 		print("vgbe: rx_eof\n");
505 
506 	for(i = 0; i < RxCount; i++){
507 		/* Remember that block. */
508 		desc = &ctlr->rx_ring[i];
509 
510 		status = le32toh(desc->status);
511 
512 		if(status & RxDesc_Status_Own)
513 			continue;
514 
515 		if(status & RxDesc_Status_Goodframe){
516 			length = status >> RxDesc_Status_SizShift;
517 			length &= RxDesc_Status_SizMask;
518 
519 			if(ctlr->debugflags & DumpRx)
520 				print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n",
521 					i, status, desc->control, length);
522 
523 			block = ctlr->rx_blocks[i];
524 			block->wp = block->rp + length;
525 
526 			ctlr->stats.rx++;
527 			/*
528 			 * the packet actually *is* from the wire, but
529 			 * we're maintaining a private array of Blocks,
530 			 * so can't have etheriq free block.
531 			 */
532 			etheriq(edev, block, 0);
533 		}
534 		else
535 			print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
536 				i, status, desc->control);
537 
538 		/* reset packet ... */
539 		desc->status = htole32(RxDesc_Status_Own);
540 		desc->control = htole32(0);
541 	}
542 
543 	if(ctlr->debugflags & DumpRx)
544 		print("vgbe: rx_eof: done\n");
545 
546 	wiow(ctlr, RxResCnt, RxCount);
547 	wiob(ctlr, RxCsrS, RxCsr_Wakeup);
548 }
549 
550 static void
551 vgbetxeof(Ether* edev)
552 {
553 	Ctlr* ctlr;
554 	int i, count;
555 	Block* block;
556 	ulong status;
557 
558 	ctlr = edev->ctlr;
559 
560 	ilock(&ctlr->tx_lock);
561 
562 	if(ctlr->debugflags & DumpTx)
563 		print("vgbe: tx_eof\n");
564 
565 	for(count = 0, i = 0; i < TxCount; i++){
566 		block = ctlr->tx_blocks[i];
567 		if(block == nil)
568 			continue;
569 
570 		status = le32toh(ctlr->tx_ring[i].status);
571 		if(status & TxDesc_Status_Own)
572 			continue;
573 
574 		/* Todo add info if it failed */
575 		ctlr->stats.tx++;
576 
577 		if(ctlr->debugflags & DumpTx)
578 			print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
579 
580 		count++;
581 		ctlr->tx_blocks[i] = nil;
582 		freeb(block);
583 
584 		if(ctlr->debugflags & DumpTx)
585 			print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
586 	}
587 	ctlr->tx_count -= count;
588 
589 	if(ctlr->debugflags & DumpTx)
590 		print("vgbe: tx_eof: done [count=%d]\n", count);
591 
592 	iunlock(&ctlr->tx_lock);
593 
594 	if(ctlr->tx_count)
595 		wiob(ctlr, TxCsrS, TxCsr_Wakeup);
596 }
597 
598 static void
599 vgbeinterrupt(Ureg *, void* arg)
600 {
601 	Ether* edev;
602 	Ctlr* ctlr;
603 	ulong status;
604 
605 	edev = (Ether *) arg;
606 	if(edev == nil)
607 		return;
608 
609 	ctlr = edev->ctlr;
610 	if(ctlr == nil)
611 		return;
612 
613 	/* Mask interrupts. */
614 	wiol(ctlr, Imr, 0);
615 
616 	status = riol(ctlr, Isr);
617 	if(status == 0xffff)
618 		goto end;
619 
620 	/* acknowledge */
621 	if(status)
622 		wiol(ctlr, Isr, status);
623 
624 	if((status & Isr_Mask) == 0)
625 		goto end;
626 
627 	ctlr->stats.intr++;
628 
629 	if(ctlr->debugflags & DumpIntr)
630 		if(ctlr->debugcount){
631 			print("vgbe: irq: status = %#08ulx\n", status);
632 			vgbedumpisr(status);
633 			ctlr->debugcount--;
634 		}
635 
636 	if(status & Isr_RxComplete)
637 		vgberxeof(edev);
638 
639 	if(status & Isr_TxComplete0)
640 		vgbetxeof(edev);
641 
642 	if(status & Isr_Stopped)
643 		print("vgbe: irq: software shutdown complete\n");
644 
645 	if(status & Isr_RxFifoOvflow)
646 		print("vgbe: irq: RX FIFO overflow\n");
647 
648 	if(status & Isr_PhyIntr)
649 		print("vgbe: irq: PHY interrupt\n");
650 
651 	if(status & Isr_LinkStatus)
652 		print("vgbe: irq: link status change\n");
653 
654 	if(status & Isr_RxNoDesc)
655 		print("vgbe: irq: ran out of Rx descriptors\n");
656 
657 	if(status & Isr_RxDmaStall){
658 		print("vgbe: irq: Rx DMA stall\n");
659 		wiol(ctlr, Cr3C, Cr3_IntMask);
660 		return;
661 	}
662 
663 	if(status & Isr_TxDmaStall){
664 		print("vgbe: irq: Tx DMA stall\n");
665 		wiol(ctlr, Cr3C, Cr3_IntMask);
666 		return;
667 	}
668 
669 end:
670 	/* Unmask interrupts. */
671 	wiol(ctlr, Imr, ~0);
672 }
673 
674 static void
675 vgbetransmit(Ether* edev)
676 {
677 	Block* block;
678 	Ctlr* ctlr;
679 	int i, index, start, count;
680 	TxDesc* desc;
681 	ulong status, length;
682 
683 	ctlr = edev->ctlr;
684 
685 	ilock(&ctlr->tx_lock);
686 
687 	start = riow(ctlr, TxDscIdx);
688 
689 	if(ctlr->debugflags & DumpTx)
690 		print("vgbe: transmit (start=%d)\n", start);
691 
692 	/* find empty slot */
693 	for(count = 0, i = 0; i < TxCount; i++){
694 		index = (i + start) % TxCount;
695 
696 		if(ctlr->tx_blocks[index])
697 			continue;
698 
699 		desc = &ctlr->tx_ring[index];
700 
701 		status = le32toh(desc->status);
702 		if(status & TxDesc_Status_Own)
703 			continue;
704 
705 		block = qget(edev->oq);
706 		if(block == nil)
707 			break;
708 
709 		count++;
710 
711 		length = BLEN(block);
712 
713 		if(ctlr->debugflags & DumpTx)
714 			print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block,
715 				PCIWADDR(block->rp), length);
716 
717 		ctlr->tx_blocks[index] = block;
718 
719 		/* Initialize Tx descriptor. */
720 		desc->status = htole32((length<<16)|TxDesc_Status_Own);
721 		desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28));
722 
723 		desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp));
724 		desc->frags[0].addr_hi = htole16(0);
725 		desc->frags[0].length = htole16(length);
726 	}
727 	ctlr->tx_count += count;
728 
729 	if(ctlr->debugflags & DumpTx)
730 		print("vgbe: transmit: done [count=%d]\n", count);
731 
732 	iunlock(&ctlr->tx_lock);
733 
734 	if(ctlr->tx_count)
735 		wiob(ctlr, TxCsrS, TxCsr_Wakeup);
736 
737 	if(count == 0)
738 		print("vgbe: transmit: no Tx entry available\n");
739 }
740 
741 static void
742 vgbeattach(Ether* edev)
743 {
744 	Ctlr* ctlr;
745 	RxDesc* rxdesc;
746 	TxDesc* txdesc;
747 	int i;
748 
749 	ctlr = edev->ctlr;
750 
751 	lock(&ctlr->init_lock);
752 	if(ctlr->inited){
753 		unlock(&ctlr->init_lock);
754 		return;
755 	}
756 
757 //	print("vgbe: attach\n");
758 
759 	/* Allocate Rx ring.  (TODO: Alignment ?) */
760 	rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
761 	if(rxdesc == nil){
762 		print("vgbe: unable to alloc Rx ring\n");
763 		unlock(&ctlr->init_lock);
764 		return;
765 	}
766 	ctlr->rx_ring = rxdesc;
767 
768 	/* Allocate Rx blocks, initialize Rx ring. */
769 	for(i = 0; i < RxCount; i++)
770 		vgbenewrx(ctlr, i);
771 
772 	/* Init Rx MAC. */
773 	wiob(ctlr, RxControl,
774 		RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
775 	wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
776 
777 	/* Load Rx ring. */
778 	wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
779 	wiow(ctlr, RxNum, RxCount - 1);
780 	wiow(ctlr, RxDscIdx, 0);
781 	wiow(ctlr, RxResCnt, RxCount);
782 
783 	/* Allocate Tx ring. */
784 	txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
785 	if(txdesc == nil){
786 		print("vgbe: unable to alloc Tx ring\n");
787 		unlock(&ctlr->init_lock);
788 		return;
789 	}
790 	ctlr->tx_ring = txdesc;
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 		pcisetbme(pdev);
934 		pcisetpms(pdev, 0);
935 
936 		port = pdev->mem[0].bar;
937 		size = pdev->mem[0].size;
938 
939 		if((port & 1) == 0){
940 			print("vgbe: bar[0]=%#x is not io\n", port);
941 			continue;
942 		}
943 
944 		if(port > 0xff00){
945 			print("vgbe: invalid port %#ux\n", port);
946 			continue;
947 		}
948 
949 		port &= 0xfffe;
950 
951 		if(size != 256){
952 			print("vgbe: invalid io size: %d\n", size);
953 			continue;
954 		}
955 
956 		if(ioalloc(port, size, 0, "vge") < 0){
957 			print("vgbe: port %#ux already in use\n", port);
958 			continue;
959 		}
960 
961 		ctlr = malloc(sizeof(Ctlr));
962 		if(ctlr == nil){
963 			print("vgbe: unable to alloc Ctlr\n");
964 			iofree(port);
965 			continue;
966 		}
967 
968 		ctlr->pdev = pdev;
969 		ctlr->port = port;
970 		ctlr->inited = 0;
971 
972 		if(vgbehead != nil)
973 			vgbetail->link = ctlr;
974 		else
975 			vgbehead = ctlr;
976 		vgbetail = ctlr;
977 	}
978 }
979 
980 static long
981 vgbectl(Ether* edev, void* buf, long n)
982 {
983 	Cmdbuf* cb;
984 	Ctlr* ctlr;
985 	ulong index;
986 	char* rptr;
987 	RxDesc* rd;
988 	TxDesc* td;
989 	uchar* p;
990 
991 	ctlr = edev->ctlr;
992 
993 	cb = parsecmd(buf, n);
994 	if(waserror()){
995 		free(cb);
996 		nexterror();
997 	}
998 
999 	if(cistrcmp(cb->f[0], "reset") == 0){
1000 		vgbereset(ctlr);
1001 		wiob(ctlr, Cr3S, Cr3_IntMask);
1002 		wiob(ctlr, RxCsrS, RxCsr_RunQueue);
1003 		wiob(ctlr, RxCsrS, RxCsr_Wakeup);
1004 	}
1005 	else if(cistrcmp(cb->f[0], "dumpintr") == 0){
1006 		if(cb->nf < 2)
1007 			error(Ecmdargs);
1008 
1009 		if(cistrcmp(cb->f[1], "on") == 0){
1010 			ctlr->debugflags |= DumpIntr;
1011 			ctlr->debugcount = ~0;
1012 		}
1013 		else if(cistrcmp(cb->f[1], "off") == 0)
1014 			ctlr->debugflags &= ~DumpIntr;
1015 		else{
1016 			ulong count;
1017 			char* rptr;
1018 
1019 			count = strtoul(cb->f[1], &rptr, 0);
1020 			if(rptr == cb->f[1])
1021 				error("invalid control request");
1022 
1023 			ctlr->debugflags |= DumpIntr;
1024 			ctlr->debugcount = count;
1025 
1026 			print("vgbe: debugcount set to %uld\n", count);
1027 		}
1028 	}
1029 	else if(cistrcmp(cb->f[0], "dumprx") == 0){
1030 		if(cb->nf < 2)
1031 			error(Ecmdargs);
1032 
1033 		if(cistrcmp(cb->f[1], "on") == 0)
1034 			ctlr->debugflags |= DumpRx;
1035 		else if(cistrcmp(cb->f[1], "off") == 0)
1036 			ctlr->debugflags &= ~DumpRx;
1037 		else{
1038 			index = strtoul(cb->f[1], &rptr, 0);
1039 			if((rptr == cb->f[1]) || (index >= RxCount))
1040 				error("invalid control request");
1041 
1042 			rd = &ctlr->rx_ring[index];
1043 			print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n",
1044 				index, rd->status, rd->control, rd->length);
1045 		}
1046 	}
1047 	else if(cistrcmp(cb->f[0], "dumptx") == 0){
1048 		if(cb->nf < 2)
1049 			error(Ecmdargs);
1050 
1051 		if(cistrcmp(cb->f[1], "on") == 0)
1052 			ctlr->debugflags |= DumpTx;
1053 		else if(cistrcmp(cb->f[1], "off") == 0)
1054 			ctlr->debugflags &= ~DumpTx;
1055 		else{
1056 			index = strtoul(cb->f[1], &rptr, 0);
1057 			if((rptr == cb->f[1]) || (index >= TxCount))
1058 				error("invalid control request");
1059 
1060 			td = &ctlr->tx_ring[index];
1061 			print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes",
1062 				index, td->status, td->control, td->frags[0].length);
1063 
1064 			p = (uchar*)td;
1065 			for(index = 0; index < sizeof(TxDesc); index++){
1066 				if((index % 16) == 0)
1067 					print("\nvgbe: ");
1068 				else
1069 					print(" ");
1070 				print("%#02x", p[index]);
1071 			}
1072 		}
1073 	}
1074 	else if(cistrcmp(cb->f[0], "dumpall") == 0){
1075 		if(cb->nf < 2)
1076 			error(Ecmdargs);
1077 
1078 		if(cistrcmp(cb->f[1], "on") == 0){
1079 			ctlr->debugflags = ~0;
1080 			ctlr->debugcount = ~0;
1081 		}
1082 		else if(cistrcmp(cb->f[1], "off") == 0)
1083 			ctlr->debugflags = 0;
1084 		else error("invalid control request");
1085 	}
1086 	else
1087 		error(Ebadctl);
1088 
1089 	free(cb);
1090 	poperror();
1091 
1092 	return n;
1093 }
1094 
1095 static void
1096 vgbepromiscuous(void* arg, int on)
1097 {
1098 	USED(arg, on);
1099 }
1100 
1101 /* multicast already on, don't need to do anything */
1102 static void
1103 vgbemulticast(void*, uchar*, int)
1104 {
1105 }
1106 
1107 static int
1108 vgbepnp(Ether* edev)
1109 {
1110 	Ctlr* ctlr;
1111 
1112 //	print("vgbe: pnp\n");
1113 
1114 	if(vgbehead == nil)
1115 		vgbepci();
1116 
1117 	for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
1118 		if(ctlr->active)
1119 			continue;
1120 
1121 		if(edev->port == 0 || edev->port == ctlr->port){
1122 			ctlr->active = 1;
1123 			break;
1124 		}
1125 	}
1126 
1127 	if(ctlr == nil)
1128 		return -1;
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->interrupt = vgbeinterrupt;
1141 	edev->ifstat = vgbeifstat;
1142 //	edev->promiscuous = vgbepromiscuous;
1143 	edev->multicast = vgbemulticast;
1144 //	edev->shutdown = vgbeshutdown;
1145 	edev->ctl = vgbectl;
1146 
1147 	edev->arg = edev;
1148 	return 0;
1149 }
1150 
1151 void
1152 ethervgbelink(void)
1153 {
1154 	addethercard("vgbe", vgbepnp);
1155 }
1156