Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
	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
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
471
noop(Block *)
472
{
473
}
474
 
475
static int
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
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
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
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
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
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
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
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
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
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
1110
vgbemulticast(void*, uchar*, int)
1111
{
1112
}
1113
 
1114
static void
1115
vgbeshutdown(Ether* ether)
1116
{
1117
	vgbereset(ether->ctlr);
1118
}
1119
 
1120
static int
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
1165
ethervgbelink(void)
1166
{
1167
	addethercard("vgbe", vgbepnp);
1168
}