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