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