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