Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * VIA VT6102 Fast Ethernet Controller (Rhine II).
3
 * To do:
4
 *	cache-line size alignments - done
5
 *	reduce tx interrupts
6
 *	use 2 descriptors on tx for alignment - done
7
 *	reorganise initialisation/shutdown/reset
8
 *	adjust Tx FIFO threshold on underflow - untested
9
 *	why does the link status never cause an interrupt?
10
 *	use the lproc as a periodic timer for stalls, etc.
11
 */
12
#include "u.h"
13
#include "../port/lib.h"
14
#include "mem.h"
15
#include "dat.h"
16
#include "fns.h"
17
#include "io.h"
18
#include "../port/error.h"
19
#include "../port/netif.h"
20
 
21
#include "etherif.h"
22
#include "ethermii.h"
23
 
24
enum {
25
	Par0		= 0x00,		/* Ethernet Address */
26
	Rcr		= 0x06,		/* Receive Configuration */
27
	Tcr		= 0x07,		/* Transmit Configuration */
28
	Cr		= 0x08,		/* Control */
29
	Isr		= 0x0C,		/* Interrupt Status */
30
	Imr		= 0x0E,		/* Interrupt Mask */
31
	Mcfilt0		= 0x10,		/* Multicast Filter 0 */
32
	Mcfilt1		= 0x14,		/* Multicast Filter 1 */
33
	Rxdaddr		= 0x18,		/* Current Rx Descriptor Address */
34
	Txdaddr		= 0x1C,		/* Current Tx Descriptor Address */
35
	Phyadr		= 0x6C,		/* Phy Address */
36
	Miisr		= 0x6D,		/* MII Status */
37
	Bcr0		= 0x6E,		/* Bus Control */
38
	Bcr1		= 0x6F,
39
	Miicr		= 0x70,		/* MII Control */
40
	Miiadr		= 0x71,		/* MII Address */
41
	Miidata		= 0x72,		/* MII Data */
42
	Eecsr		= 0x74,		/* EEPROM Control and Status */
43
	Stickhw		= 0x83,		/* Sticky Hardware Control */
44
	Wolcrclr	= 0xA4,
45
	Wolcgclr	= 0xA7,
46
	Pwrcsrclr	= 0xAC,
47
};
48
 
49
enum {					/* Rcr */
50
	Sep		= 0x01,		/* Accept Error Packets */
51
	Ar		= 0x02,		/* Accept Small Packets */
52
	Am		= 0x04,		/* Accept Multicast */
53
	Ab		= 0x08,		/* Accept Broadcast */
54
	Prom		= 0x10,		/* Accept Physical Address Packets */
55
	RrftMASK	= 0xE0,		/* Receive FIFO Threshold */
56
	RrftSHIFT	= 5,
57
	Rrft64		= 0<<RrftSHIFT,
58
	Rrft32		= 1<<RrftSHIFT,
59
	Rrft128		= 2<<RrftSHIFT,
60
	Rrft256		= 3<<RrftSHIFT,
61
	Rrft512		= 4<<RrftSHIFT,
62
	Rrft768		= 5<<RrftSHIFT,
63
	Rrft1024	= 6<<RrftSHIFT,
64
	RrftSAF		= 7<<RrftSHIFT,
65
};
66
 
67
enum {					/* Tcr */
68
	Lb0		= 0x02,		/* Loopback Mode */
69
	Lb1		= 0x04,
70
	Ofset		= 0x08,		/* Back-off Priority Selection */
71
	RtsfMASK	= 0xE0,		/* Transmit FIFO Threshold */
72
	RtsfSHIFT	= 5,
73
	Rtsf128		= 0<<RtsfSHIFT,
74
	Rtsf256		= 1<<RtsfSHIFT,
75
	Rtsf512		= 2<<RtsfSHIFT,
76
	Rtsf1024	= 3<<RtsfSHIFT,
77
	RtsfSAF		= 7<<RtsfSHIFT,
78
};
79
 
80
enum {					/* Cr */
81
	Init		= 0x0001,	/* INIT Process Begin */
82
	Strt		= 0x0002,	/* Start NIC */
83
	Stop		= 0x0004,	/* Stop NIC */
84
	Rxon		= 0x0008,	/* Turn on Receive Process */
85
	Txon		= 0x0010,	/* Turn on Transmit Process */
86
	Tdmd		= 0x0020,	/* Transmit Poll Demand */
87
	Rdmd		= 0x0040,	/* Receive Poll Demand */
88
	Eren		= 0x0100,	/* Early Receive Enable */
89
	Fdx		= 0x0400,	/* Set MAC to Full Duplex Mode */
90
	Dpoll		= 0x0800,	/* Disable Td/Rd Auto Polling */
91
	Tdmd1		= 0x2000,	/* Transmit Poll Demand 1 */
92
	Rdmd1		= 0x4000,	/* Receive Poll Demand 1 */
93
	Sfrst		= 0x8000,	/* Software Reset */
94
};
95
 
96
enum {					/* Isr/Imr */
97
	Prx		= 0x0001,	/* Received Packet Successfully */
98
	Ptx		= 0x0002,	/* Transmitted Packet Successfully */
99
	Rxe		= 0x0004,	/* Receive Error */
100
	Txe		= 0x0008,	/* Transmit Error */
101
	Tu		= 0x0010,	/* Transmit Buffer Underflow */
102
	Ru		= 0x0020,	/* Receive Buffer Link Error */
103
	Be		= 0x0040,	/* PCI Bus Error */
104
	Cnt		= 0x0080,	/* Counter Overflow */
105
	Eri		= 0x0100,	/* Early Receive Interrupt */
106
	Udfi		= 0x0200,	/* Tx FIFO Underflow */
107
	Ovfi		= 0x0400,	/* Receive FIFO Overflow */
108
	Pktrace		= 0x0800,	/* Hmmm... */
109
	Norbf		= 0x1000,	/* No Receive Buffers */
110
	Abti		= 0x2000,	/* Transmission Abort */
111
	Srci		= 0x4000,	/* Port State Change */
112
	Geni		= 0x8000,	/* General Purpose Interrupt */
113
};
114
 
115
enum {					/* Phyadr */
116
	PhyadMASK	= 0x1F,		/* PHY Address */
117
	PhyadSHIFT	= 0,
118
	Mfdc		= 0x20,		/* Accelerate MDC Speed */
119
	Mpo0		= 0x40,		/* MII Polling Timer Interval */
120
	Mpo1		= 0x80,
121
};
122
 
123
enum {					/* Bcr0 */
124
	DmaMASK		= 0x07,		/* DMA Length */
125
	DmaSHIFT	= 0,
126
	Dma32		= 0<<DmaSHIFT,
127
	Dma64		= 1<<DmaSHIFT,
128
	Dma128		= 2<<DmaSHIFT,
129
	Dma256		= 3<<DmaSHIFT,
130
	Dma512		= 4<<DmaSHIFT,
131
	Dma1024		= 5<<DmaSHIFT,
132
	DmaSAF		= 7<<DmaSHIFT,
133
	CrftMASK	= 0x38,		/* Rx FIFO Threshold */
134
	CrftSHIFT	= 3,
135
	Crft64		= 1<<CrftSHIFT,
136
	Crft128		= 2<<CrftSHIFT,
137
	Crft256		= 3<<CrftSHIFT,
138
	Crft512		= 4<<CrftSHIFT,
139
	Crft1024	= 5<<CrftSHIFT,
140
	CrftSAF		= 7<<CrftSHIFT,
141
	Extled		= 0x40,		/* Extra LED Support Control */
142
	Med2		= 0x80,		/* Medium Select Control */
143
};
144
 
145
enum {					/* Bcr1 */
146
	PotMASK		= 0x07,		/* Polling Timer Interval */
147
	PotSHIFT	= 0,
148
	CtftMASK	= 0x38,		/* Tx FIFO Threshold */
149
	CtftSHIFT	= 3,
150
	Ctft64		= 1<<CtftSHIFT,
151
	Ctft128		= 2<<CtftSHIFT,
152
	Ctft256		= 3<<CtftSHIFT,
153
	Ctft512		= 4<<CtftSHIFT,
154
	Ctft1024	= 5<<CtftSHIFT,
155
	CtftSAF		= 7<<CtftSHIFT,
156
};
157
 
158
enum {					/* Miicr */
159
	Mdc		= 0x01,		/* Clock */
160
	Mdi		= 0x02,		/* Data In */
161
	Mdo		= 0x04,		/* Data Out */
162
	Mout		= 0x08,		/* Output Enable */
163
	Mdpm		= 0x10,		/* Direct Program Mode Enable */
164
	Wcmd		= 0x20,		/* Write Enable */
165
	Rcmd		= 0x40,		/* Read Enable */
166
	Mauto		= 0x80,		/* Auto Polling Enable */
167
};
168
 
169
enum {					/* Miiadr */
170
	MadMASK		= 0x1F,		/* MII Port Address */
171
	MadSHIFT	= 0,
172
	Mdone		= 0x20,		/* Accelerate MDC Speed */
173
	Msrcen		= 0x40,		/* MII Polling Timer Interval */
174
	Midle		= 0x80,
175
};
176
 
177
enum {					/* Eecsr */
178
	Edo		= 0x01,		/* Data Out */
179
	Edi		= 0x02,		/* Data In */
180
	Eck		= 0x04,		/* Clock */
181
	Ecs		= 0x08,		/* Chip Select */
182
	Dpm		= 0x10,		/* Direct Program Mode Enable */
183
	Autold		= 0x20,		/* Dynamic Reload */
184
	Embp		= 0x40,		/* Embedded Program Enable */
185
	Eepr		= 0x80,		/* Programmed */
186
};
187
 
188
/*
189
 * Ring descriptor. The space allocated for each
190
 * of these will be rounded up to a cache-line boundary.
191
 * The first 4 elements are known to the hardware.
192
 */
193
typedef struct Ds Ds;
194
typedef struct Ds {
195
	uint	status;
196
	uint	control;
197
	uint	addr;
198
	uint	branch;
199
 
200
	Block*	bp;
201
	void*	bounce;
202
	Ds*	next;
203
	Ds*	prev;
204
} Ds;
205
 
206
enum {					/* Rx Ds status */
207
	Rerr		= 0x00000001,	/* Receiver Error */
208
	Crc		= 0x00000002,	/* CRC Error */
209
	Fae		= 0x00000004,	/* Frame Alignment Error */
210
	Fov		= 0x00000008,	/* FIFO Overflow */
211
	Long		= 0x00000010,	/* A Long Packet */
212
	Runt		= 0x00000020,	/* A Runt Packet */
213
	Rxserr		= 0x00000040,	/* System Error */
214
	Buff		= 0x00000080,	/* Buffer Underflow Error */
215
	Rxedp		= 0x00000100,	/* End of Packet Buffer */
216
	Rxstp		= 0x00000200,	/* Packet Start */
217
	Chn		= 0x00000400,	/* Chain Buffer */
218
	Phy		= 0x00000800,	/* Physical Address Packet */
219
	Bar		= 0x00001000,	/* Broadcast Packet */
220
	Mar		= 0x00002000,	/* Multicast Packet */
221
	Rxok		= 0x00008000,	/* Packet Received Successfully */
222
	LengthMASK	= 0x07FF0000,	/* Received Packet Length */
223
	LengthSHIFT	= 16,
224
 
225
	Own		= 0x80000000,	/* Descriptor Owned by NIC */
226
};
227
 
228
enum {					/* Tx Ds status */
229
	NcrMASK		= 0x0000000F,	/* Collision Retry Count */
230
	NcrSHIFT	= 0,
231
	Cols		= 0x00000010,	/* Experienced Collisions */
232
	Cdh		= 0x00000080,	/* CD Heartbeat */
233
	Abt		= 0x00000100,	/* Aborted after Excessive Collisions */
234
	Owc		= 0x00000200,	/* Out of Window Collision Seen */
235
	Crs		= 0x00000400,	/* Carrier Sense Lost */
236
	Udf		= 0x00000800,	/* FIFO Underflow */
237
	Tbuff		= 0x00001000,	/* Invalid Td */
238
	Txserr		= 0x00002000,	/* System Error */
239
	Terr		= 0x00008000,	/* Excessive Collisions */
240
};
241
 
242
enum {					/* Tx Ds control */
243
	TbsMASK		= 0x000007FF,	/* Tx Buffer Size */
244
	TbsSHIFT	= 0,
245
	Chain		= 0x00008000,	/* Chain Buffer */
246
	Crcdisable	= 0x00010000,	/* Disable CRC generation */
247
	Stp		= 0x00200000,	/* Start of Packet */
248
	Edp		= 0x00400000,	/* End of Packet */
249
	Ic		= 0x00800000,	/* Assert Interrupt Immediately */
250
};
251
 
252
enum {
253
	Nrd		= 64,
254
	Ntd		= 64,
255
	Rdbsz		= ROUNDUP(ETHERMAXTU+4, 4),
256
 
257
	Nrxstats	= 8,
258
	Ntxstats	= 9,
259
 
260
	Txcopy		= 128,
261
};
262
 
263
typedef struct Ctlr Ctlr;
264
typedef struct Ctlr {
265
	int	port;
266
	Pcidev*	pcidev;
267
	Ctlr*	next;
268
	int	active;
269
	int	id;
270
	uchar	par[Eaddrlen];
271
 
272
	QLock	alock;			/* attach */
273
	void*	alloc;			/* receive/transmit descriptors */
274
	int	cls;			/* alignment */
275
	int	nrd;
276
	int	ntd;
277
 
278
	Ds*	rd;
279
	Ds*	rdh;
280
 
281
	Lock	tlock;
282
	Ds*	td;
283
	Ds*	tdh;
284
	Ds*	tdt;
285
	int	tdused;
286
 
287
	Lock	clock;			/*  */
288
	int	cr;
289
	int	imr;
290
	int	tft;			/* Tx threshold */
291
 
292
	Mii*	mii;
293
	Rendez	lrendez;
294
	int	lwakeup;
295
 
296
	uint	rxstats[Nrxstats];	/* statistics */
297
	uint	txstats[Ntxstats];
298
	uint	intr;
299
	uint	lintr;
300
	uint	lsleep;
301
	uint	rintr;
302
	uint	tintr;
303
	uint	taligned;
304
	uint	tsplit;
305
	uint	tcopied;
306
	uint	txdw;
307
} Ctlr;
308
 
309
static Ctlr* vt6102ctlrhead;
310
static Ctlr* vt6102ctlrtail;
311
 
312
#define csr8r(c, r)	(inb((c)->port+(r)))
313
#define csr16r(c, r)	(ins((c)->port+(r)))
314
#define csr32r(c, r)	(inl((c)->port+(r)))
315
#define csr8w(c, r, b)	(outb((c)->port+(r), (int)(b)))
316
#define csr16w(c, r, w)	(outs((c)->port+(r), (ushort)(w)))
317
#define csr32w(c, r, w)	(outl((c)->port+(r), (ulong)(w)))
318
 
319
static char* rxstats[Nrxstats] = {
320
	"Receiver Error",
321
	"CRC Error",
322
	"Frame Alignment Error",
323
	"FIFO Overflow",
324
	"Long Packet",
325
	"Runt Packet",
326
	"System Error",
327
	"Buffer Underflow Error",
328
};
329
static char* txstats[Ntxstats] = {
330
	"Aborted after Excessive Collisions",
331
	"Out of Window Collision Seen",
332
	"Carrier Sense Lost",
333
	"FIFO Underflow",
334
	"Invalid Td",
335
	"System Error",
336
	nil,
337
	"Excessive Collisions",
338
};
339
 
340
static long
341
vt6102ifstat(Ether* edev, void* a, long n, ulong offset)
342
{
343
	char *p;
344
	Ctlr *ctlr;
345
	int i, l, r;
346
 
347
	ctlr = edev->ctlr;
348
 
349
	p = malloc(READSTR);
350
	if(p == nil)
351
		error(Enomem);
352
	l = 0;
353
	for(i = 0; i < Nrxstats; i++){
354
		l += snprint(p+l, READSTR-l, "%s: %ud\n",
355
			rxstats[i], ctlr->rxstats[i]);
356
	}
357
	for(i = 0; i < Ntxstats; i++){
358
		if(txstats[i] == nil)
359
			continue;
360
		l += snprint(p+l, READSTR-l, "%s: %ud\n",
361
			txstats[i], ctlr->txstats[i]);
362
	}
363
	l += snprint(p+l, READSTR-l, "cls: %ud\n", ctlr->cls);
364
	l += snprint(p+l, READSTR-l, "intr: %ud\n", ctlr->intr);
365
	l += snprint(p+l, READSTR-l, "lintr: %ud\n", ctlr->lintr);
366
	l += snprint(p+l, READSTR-l, "lsleep: %ud\n", ctlr->lsleep);
367
	l += snprint(p+l, READSTR-l, "rintr: %ud\n", ctlr->rintr);
368
	l += snprint(p+l, READSTR-l, "tintr: %ud\n", ctlr->tintr);
369
	l += snprint(p+l, READSTR-l, "taligned: %ud\n", ctlr->taligned);
370
	l += snprint(p+l, READSTR-l, "tsplit: %ud\n", ctlr->tsplit);
371
	l += snprint(p+l, READSTR-l, "tcopied: %ud\n", ctlr->tcopied);
372
	l += snprint(p+l, READSTR-l, "txdw: %ud\n", ctlr->txdw);
373
	l += snprint(p+l, READSTR-l, "tft: %ud\n", ctlr->tft);
374
 
375
	if(ctlr->mii != nil && ctlr->mii->curphy != nil){
376
		l += snprint(p+l, READSTR, "phy:   ");
377
		for(i = 0; i < NMiiPhyr; i++){
378
			if(i && ((i & 0x07) == 0))
379
				l += snprint(p+l, READSTR-l, "\n       ");
380
			r = miimir(ctlr->mii, i);
381
			l += snprint(p+l, READSTR-l, " %4.4uX", r);
382
		}
383
		snprint(p+l, READSTR-l, "\n");
384
	}
385
	snprint(p+l, READSTR-l, "\n");
386
 
387
	n = readstr(offset, a, n, p);
388
	free(p);
389
 
390
	return n;
391
}
392
 
393
static void
394
vt6102promiscuous(void* arg, int on)
395
{
396
	int rcr;
397
	Ctlr *ctlr;
398
	Ether *edev;
399
 
400
	edev = arg;
401
	ctlr = edev->ctlr;
402
	rcr = csr8r(ctlr, Rcr);
403
	if(on)
404
		rcr |= Prom;
405
	else
406
		rcr &= ~Prom;
407
	csr8w(ctlr, Rcr, rcr);
408
}
409
 
410
static void
411
vt6102multicast(void* arg, uchar* addr, int on)
412
{
413
	/*
414
	 * For now Am is set in Rcr.
415
	 * Will need to interlock with promiscuous
416
	 * when this gets filled in.
417
	 */
418
	USED(arg, addr, on);
419
}
420
 
421
static int
422
vt6102wakeup(void* v)
423
{
424
	return *((int*)v) != 0;
425
}
426
 
427
static void
428
vt6102imr(Ctlr* ctlr, int imr)
429
{
430
	ilock(&ctlr->clock);
431
	ctlr->imr |= imr;
432
	csr16w(ctlr, Imr, ctlr->imr);
433
	iunlock(&ctlr->clock);
434
}
435
 
436
static void
437
vt6102lproc(void* arg)
438
{
439
	Ctlr *ctlr;
440
	Ether *edev;
441
	MiiPhy *phy;
442
 
443
	edev = arg;
444
	ctlr = edev->ctlr;
445
	for(;;){
446
		if(ctlr->mii == nil || ctlr->mii->curphy == nil)
447
			break;
448
		if(miistatus(ctlr->mii) < 0)
449
			goto enable;
450
 
451
		phy = ctlr->mii->curphy;
452
		ilock(&ctlr->clock);
453
		if(phy->fd)
454
			ctlr->cr |= Fdx;
455
		else
456
			ctlr->cr &= ~Fdx;
457
		csr16w(ctlr, Cr, ctlr->cr);
458
		iunlock(&ctlr->clock);
459
enable:
460
		ctlr->lwakeup = 0;
461
		vt6102imr(ctlr, Srci);
462
 
463
		ctlr->lsleep++;
464
		sleep(&ctlr->lrendez, vt6102wakeup, &ctlr->lwakeup);
465
 
466
	}
467
	pexit("vt6102lproc: done", 1);
468
}
469
 
470
static void
471
vt6102attach(Ether* edev)
472
{
473
	int i;
474
	Ctlr *ctlr;
475
	Ds *ds, *prev;
476
	uchar *alloc, *bounce;
477
	char name[KNAMELEN];
478
 
479
	ctlr = edev->ctlr;
480
	qlock(&ctlr->alock);
481
	if(ctlr->alloc != nil){
482
		qunlock(&ctlr->alock);
483
		return;
484
	}
485
 
486
	/*
487
	 * Descriptor and bounce-buffer space.
488
	 * Must all be aligned on a 4-byte boundary,
489
	 * but try to align on cache-lines.
490
	 */
491
	ctlr->nrd = Nrd;
492
	ctlr->ntd = Ntd;
493
	alloc = malloc((ctlr->nrd+ctlr->ntd)*ctlr->cls + ctlr->ntd*Txcopy + ctlr->cls-1);
494
	if(alloc == nil){
495
		qunlock(&ctlr->alock);
496
		error(Enomem);
497
	}
498
	ctlr->alloc = alloc;
499
	alloc = (uchar*)ROUNDUP((ulong)alloc, ctlr->cls);
500
 
501
	ctlr->rd = (Ds*)alloc;
502
 
503
	if(waserror()){
504
		ds = ctlr->rd;
505
		for(i = 0; i < ctlr->nrd; i++){
506
			if(ds->bp != nil){
507
				freeb(ds->bp);
508
				ds->bp = nil;
509
			}
510
			if((ds = ds->next) == nil)
511
				break;
512
		}
513
		free(ctlr->alloc);
514
		ctlr->alloc = nil;
515
		qunlock(&ctlr->alock);
516
		nexterror();
517
	}
518
 
519
	prev = ctlr->rd + ctlr->nrd-1;
520
	for(i = 0; i < ctlr->nrd; i++){
521
		ds = (Ds*)alloc;
522
		alloc += ctlr->cls;
523
 
524
		ds->control = Rdbsz;
525
		ds->branch = PCIWADDR(alloc);
526
 
527
		ds->bp = iallocb(Rdbsz+3);
528
		if(ds->bp == nil)
529
			error("vt6102: can't allocate receive ring\n");
530
		ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
531
		ds->addr = PCIWADDR(ds->bp->rp);
532
 
533
		ds->next = (Ds*)alloc;
534
		ds->prev = prev;
535
		prev = ds;
536
 
537
		ds->status = Own;
538
	}
539
	prev->branch = 0;
540
	prev->next = ctlr->rd;
541
	prev->status = 0;
542
	ctlr->rdh = ctlr->rd;
543
 
544
	ctlr->td = (Ds*)alloc;
545
	prev = ctlr->td + ctlr->ntd-1;
546
	bounce = alloc + ctlr->ntd*ctlr->cls;
547
	for(i = 0; i < ctlr->ntd; i++){
548
		ds = (Ds*)alloc;
549
		alloc += ctlr->cls;
550
 
551
		ds->bounce = bounce;
552
		bounce += Txcopy;
553
		ds->next = (Ds*)alloc;
554
		ds->prev = prev;
555
		prev = ds;
556
	}
557
	prev->next = ctlr->td;
558
	ctlr->tdh = ctlr->tdt = ctlr->td;
559
	ctlr->tdused = 0;
560
 
561
	ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt;
562
	/*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
563
	ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
564
 
565
	ilock(&ctlr->clock);
566
	csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
567
	csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
568
	csr16w(ctlr, Isr, ~0);
569
	csr16w(ctlr, Imr, ctlr->imr);
570
	csr16w(ctlr, Cr, ctlr->cr);
571
	iunlock(&ctlr->clock);
572
 
573
	snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
574
	kproc(name, vt6102lproc, edev);
575
 
576
	qunlock(&ctlr->alock);
577
	poperror();
578
}
579
 
580
static void
581
vt6102transmit(Ether* edev)
582
{
583
	Block *bp;
584
	Ctlr *ctlr;
585
	Ds *ds, *next;
586
	int control, i, o, prefix, size, tdused, timeo;
587
 
588
	ctlr = edev->ctlr;
589
 
590
	ilock(&ctlr->tlock);
591
 
592
	/*
593
	 * Free any completed packets
594
	 */
595
	ds = ctlr->tdh;
596
	for(tdused = ctlr->tdused; tdused > 0; tdused--){
597
		/*
598
		 * For some errors the chip will turn the Tx engine
599
		 * off. Wait for that to happen.
600
		 * Could reset and re-init the chip here if it doesn't
601
		 * play fair.
602
		 * To do: adjust Tx FIFO threshold on underflow.
603
		 */
604
		if(ds->status & (Abt|Tbuff|Udf)){
605
			for(timeo = 0; timeo < 1000; timeo++){
606
				if(!(csr16r(ctlr, Cr) & Txon))
607
					break;
608
				microdelay(1);
609
			}
610
			ds->status = Own;
611
			csr32w(ctlr, Txdaddr, PCIWADDR(ds));
612
		}
613
 
614
		if(ds->status & Own)
615
			break;
616
		ds->addr = 0;
617
		ds->branch = 0;
618
 
619
		if(ds->bp != nil){
620
			freeb(ds->bp);
621
			ds->bp = nil;
622
		}
623
		for(i = 0; i < Ntxstats-1; i++){
624
			if(ds->status & (1<<i))
625
				ctlr->txstats[i]++;
626
		}
627
		ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
628
 
629
		ds = ds->next;
630
	}
631
	ctlr->tdh = ds;
632
 
633
	/*
634
	 * Try to fill the ring back up.
635
	 */
636
	ds = ctlr->tdt;
637
	while(tdused < ctlr->ntd-2){
638
		if((bp = qget(edev->oq)) == nil)
639
			break;
640
		tdused++;
641
 
642
		size = BLEN(bp);
643
		prefix = 0;
644
 
645
		if(o = (((int)bp->rp) & 0x03)){
646
			prefix = Txcopy-o;
647
			if(prefix > size)
648
				prefix = size;
649
			memmove(ds->bounce, bp->rp, prefix);
650
			ds->addr = PCIWADDR(ds->bounce);
651
			bp->rp += prefix;
652
			size -= prefix;
653
		}
654
 
655
		next = ds->next;
656
		ds->branch = PCIWADDR(ds->next);
657
 
658
		if(size){
659
			if(prefix){
660
				next->bp = bp;
661
				next->addr = PCIWADDR(bp->rp);
662
				next->branch = PCIWADDR(next->next);
663
				next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK);
664
 
665
				control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK);
666
 
667
				next = next->next;
668
				tdused++;
669
				ctlr->tsplit++;
670
			}
671
			else{
672
				ds->bp = bp;
673
				ds->addr = PCIWADDR(bp->rp);
674
				control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
675
				ctlr->taligned++;
676
			}
677
		}
678
		else{
679
			freeb(bp);
680
			control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK);
681
			ctlr->tcopied++;
682
		}
683
 
684
		ds->control = control;
685
		if(tdused >= ctlr->ntd-2){
686
			ds->control |= Ic;
687
			ctlr->txdw++;
688
		}
689
		coherence();
690
		ds->status = Own;
691
 
692
		ds = next;
693
	}
694
	ctlr->tdt = ds;
695
	ctlr->tdused = tdused;
696
	if(ctlr->tdused)
697
		csr16w(ctlr, Cr, Tdmd|ctlr->cr);
698
 
699
	iunlock(&ctlr->tlock);
700
}
701
 
702
static void
703
vt6102receive(Ether* edev)
704
{
705
	Ds *ds;
706
	Block *bp;
707
	Ctlr *ctlr;
708
	int i, len;
709
 
710
	ctlr = edev->ctlr;
711
 
712
	ds = ctlr->rdh;
713
	while(!(ds->status & Own) && ds->status != 0){
714
		if(ds->status & Rerr){
715
			for(i = 0; i < Nrxstats; i++){
716
				if(ds->status & (1<<i))
717
					ctlr->rxstats[i]++;
718
			}
719
		}
720
		else if(bp = iallocb(Rdbsz+3)){
721
			len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
722
			ds->bp->wp = ds->bp->rp+len;
723
			etheriq(edev, ds->bp, 1);
724
			bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
725
			ds->addr = PCIWADDR(bp->rp);
726
			ds->bp = bp;
727
		}
728
		ds->control = Rdbsz;
729
		ds->branch = 0;
730
		ds->status = 0;
731
 
732
		ds->prev->branch = PCIWADDR(ds);
733
		coherence();
734
		ds->prev->status = Own;
735
 
736
		ds = ds->next;
737
	}
738
	ctlr->rdh = ds;
739
 
740
	csr16w(ctlr, Cr, ctlr->cr);
741
}
742
 
743
static void
744
vt6102interrupt(Ureg*, void* arg)
745
{
746
	Ctlr *ctlr;
747
	Ether *edev;
748
	int imr, isr, r, timeo;
749
 
750
	edev = arg;
751
	ctlr = edev->ctlr;
752
 
753
	ilock(&ctlr->clock);
754
	csr16w(ctlr, Imr, 0);
755
	imr = ctlr->imr;
756
	ctlr->intr++;
757
	for(;;){
758
		if((isr = csr16r(ctlr, Isr)) != 0)
759
			csr16w(ctlr, Isr, isr);
760
		if((isr & ctlr->imr) == 0)
761
			break;
762
 
763
		if(isr & Srci){
764
			imr &= ~Srci;
765
			ctlr->lwakeup = isr & Srci;
766
			wakeup(&ctlr->lrendez);
767
			isr &= ~Srci;
768
			ctlr->lintr++;
769
		}
770
		if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
771
			vt6102receive(edev);
772
			isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
773
			ctlr->rintr++;
774
		}
775
		if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
776
			if(isr & (Abti|Udfi|Tu)){
777
				for(timeo = 0; timeo < 1000; timeo++){
778
					if(!(csr16r(ctlr, Cr) & Txon))
779
						break;
780
					microdelay(1);
781
				}
782
 
783
				if((isr & Udfi) && ctlr->tft < CtftSAF){
784
					ctlr->tft += 1<<CtftSHIFT;
785
					r = csr8r(ctlr, Bcr1) & ~CtftMASK;
786
					csr8w(ctlr, Bcr1, r|ctlr->tft);
787
				}
788
			}
789
			vt6102transmit(edev);
790
			isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
791
			ctlr->tintr++;
792
		}
793
		if(isr)
794
			panic("vt6102: isr %4.4uX\n", isr);
795
	}
796
	ctlr->imr = imr;
797
	csr16w(ctlr, Imr, ctlr->imr);
798
	iunlock(&ctlr->clock);
799
}
800
 
801
static int
802
vt6102miimicmd(Mii* mii, int pa, int ra, int cmd, int data)
803
{
804
	Ctlr *ctlr;
805
	int r, timeo;
806
 
807
	ctlr = mii->ctlr;
808
 
809
	csr8w(ctlr, Miicr, 0);
810
	r = csr8r(ctlr, Phyadr);
811
	csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
812
	csr8w(ctlr, Phyadr, pa);
813
	csr8w(ctlr, Miiadr, ra);
814
	if(cmd == Wcmd)
815
		csr16w(ctlr, Miidata, data);
816
	csr8w(ctlr, Miicr, cmd);
817
 
818
	for(timeo = 0; timeo < 10000; timeo++){
819
		if(!(csr8r(ctlr, Miicr) & cmd))
820
			break;
821
		microdelay(1);
822
	}
823
	if(timeo >= 10000)
824
		return -1;
825
 
826
	if(cmd == Wcmd)
827
		return 0;
828
	return csr16r(ctlr, Miidata);
829
}
830
 
831
static int
832
vt6102miimir(Mii* mii, int pa, int ra)
833
{
834
	return vt6102miimicmd(mii, pa, ra, Rcmd, 0);
835
}
836
 
837
static int
838
vt6102miimiw(Mii* mii, int pa, int ra, int data)
839
{
840
	return vt6102miimicmd(mii, pa, ra, Wcmd, data);
841
}
842
 
843
static int
844
vt6102detach(Ctlr* ctlr)
845
{
846
	int revid, timeo;
847
 
848
	/*
849
	 * Reset power management registers.
850
	 */
851
	revid = pcicfgr8(ctlr->pcidev, PciRID);
852
	if(revid >= 0x40){
853
		/* Set power state D0. */
854
		csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
855
 
856
		/* Disable force PME-enable. */
857
		csr8w(ctlr, Wolcgclr, 0x80);
858
 
859
		/* Clear WOL config and status bits. */
860
		csr8w(ctlr, Wolcrclr, 0xFF);
861
		csr8w(ctlr, Pwrcsrclr, 0xFF);
862
	}
863
 
864
	/*
865
	 * Soft reset the controller.
866
	 */
867
	csr16w(ctlr, Cr, Stop);
868
	csr16w(ctlr, Cr, Stop|Sfrst);
869
	for(timeo = 0; timeo < 10000; timeo++){
870
		if(!(csr16r(ctlr, Cr) & Sfrst))
871
			break;
872
		microdelay(1);
873
	}
874
	if(timeo >= 1000)
875
		return -1;
876
 
877
	return 0;
878
}
879
 
880
static void
881
vt6102shutdown(Ether *ether)
882
{
883
	Ctlr *ctlr = ether->ctlr;
884
 
885
	vt6102detach(ctlr);
886
}
887
 
888
static int
889
vt6102reset(Ctlr* ctlr)
890
{
891
	MiiPhy *phy;
892
	int i, r, timeo;
893
 
894
	if(vt6102detach(ctlr) < 0)
895
		return -1;
896
 
897
	/*
898
	 * Load the MAC address into the PAR[01]
899
	 * registers.
900
	 */
901
	r = csr8r(ctlr, Eecsr);
902
	csr8w(ctlr, Eecsr, Autold|r);
903
	for(timeo = 0; timeo < 100; timeo++){
904
		if(!(csr8r(ctlr, Cr) & Autold))
905
			break;
906
		microdelay(1);
907
	}
908
	if(timeo >= 100)
909
		return -1;
910
 
911
	for(i = 0; i < Eaddrlen; i++)
912
		ctlr->par[i] = csr8r(ctlr, Par0+i);
913
 
914
	/*
915
	 * Configure DMA and Rx/Tx thresholds.
916
	 * If the Rx/Tx threshold bits in Bcr[01] are 0 then
917
	 * the thresholds are determined by Rcr/Tcr.
918
	 */
919
	r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
920
	csr8w(ctlr, Bcr0, r|Crft64|Dma64);
921
	r = csr8r(ctlr, Bcr1) & ~CtftMASK;
922
	csr8w(ctlr, Bcr1, r|ctlr->tft);
923
 
924
	r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
925
	csr8w(ctlr, Rcr, r|Ab|Am);
926
	csr32w(ctlr, Mcfilt0, ~0UL);	/* accept all multicast */
927
	csr32w(ctlr, Mcfilt1, ~0UL);
928
 
929
	r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
930
	csr8w(ctlr, Tcr, r);
931
 
932
	/*
933
	 * Link management.
934
	 */
935
	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
936
		return -1;
937
	ctlr->mii->mir = vt6102miimir;
938
	ctlr->mii->miw = vt6102miimiw;
939
	ctlr->mii->ctlr = ctlr;
940
 
941
	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
942
		free(ctlr->mii);
943
		ctlr->mii = nil;
944
		return -1;
945
	}
946
	// print("oui %X phyno %d\n", phy->oui, phy->phyno);
947
	USED(phy);
948
 
949
	//miiane(ctlr->mii, ~0, ~0, ~0);
950
 
951
	return 0;
952
}
953
 
954
static void
955
vt6102pci(void)
956
{
957
	Pcidev *p;
958
	Ctlr *ctlr;
959
	int cls, port;
960
 
961
	p = nil;
962
	while(p = pcimatch(p, 0, 0)){
963
		if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
964
			continue;
965
 
966
		switch((p->did<<16)|p->vid){
967
		default:
968
			continue;
969
		case (0x3065<<16)|0x1106:	/* Rhine II */
970
		case (0x3106<<16)|0x1106:	/* Rhine III */
971
			break;
972
		}
973
 
974
		port = p->mem[0].bar & ~0x01;
975
		if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){
976
			print("vt6102: port 0x%uX in use\n", port);
977
			continue;
978
		}
979
		ctlr = malloc(sizeof(Ctlr));
980
		if(ctlr == nil) {
981
			iofree(port);
982
			error(Enomem);
983
		}
984
		ctlr->port = port;
985
		ctlr->pcidev = p;
986
		ctlr->id = (p->did<<16)|p->vid;
987
		if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
988
			cls = 0x10;
989
		ctlr->cls = cls*4;
990
		if(ctlr->cls < sizeof(Ds)){
991
			print("vt6102: cls %d < sizeof(Ds)\n", ctlr->cls);
992
			iofree(port);
993
			free(ctlr);
994
			continue;
995
		}
996
		ctlr->tft = Ctft64;
997
 
998
		if(vt6102reset(ctlr)){
999
			iofree(port);
1000
			free(ctlr);
1001
			continue;
1002
		}
1003
		pcisetbme(p);
1004
 
1005
		if(vt6102ctlrhead != nil)
1006
			vt6102ctlrtail->next = ctlr;
1007
		else
1008
			vt6102ctlrhead = ctlr;
1009
		vt6102ctlrtail = ctlr;
1010
	}
1011
}
1012
 
1013
static int
1014
vt6102pnp(Ether* edev)
1015
{
1016
	Ctlr *ctlr;
1017
 
1018
	if(vt6102ctlrhead == nil)
1019
		vt6102pci();
1020
 
1021
	/*
1022
	 * Any adapter matches if no edev->port is supplied,
1023
	 * otherwise the ports must match.
1024
	 */
1025
	for(ctlr = vt6102ctlrhead; ctlr != nil; ctlr = ctlr->next){
1026
		if(ctlr->active)
1027
			continue;
1028
		if(edev->port == 0 || edev->port == ctlr->port){
1029
			ctlr->active = 1;
1030
			break;
1031
		}
1032
	}
1033
	if(ctlr == nil)
1034
		return -1;
1035
 
1036
	edev->ctlr = ctlr;
1037
	edev->port = ctlr->port;
1038
	edev->irq = ctlr->pcidev->intl;
1039
	edev->tbdf = ctlr->pcidev->tbdf;
1040
	edev->mbps = 100;
1041
	memmove(edev->ea, ctlr->par, Eaddrlen);
1042
 
1043
	/*
1044
	 * Linkage to the generic ethernet driver.
1045
	 */
1046
	edev->attach = vt6102attach;
1047
	edev->transmit = vt6102transmit;
1048
	edev->interrupt = vt6102interrupt;
1049
	edev->ifstat = vt6102ifstat;
1050
	edev->shutdown = vt6102shutdown;
1051
	edev->ctl = nil;
1052
 
1053
	edev->arg = edev;
1054
	edev->promiscuous = vt6102promiscuous;
1055
	edev->multicast = vt6102multicast;
1056
 
1057
	return 0;
1058
}
1059
 
1060
void
1061
ethervt6102link(void)
1062
{
1063
	addethercard("vt6102", vt6102pnp);
1064
	addethercard("rhine", vt6102pnp);
1065
}