xref: /plan9/sys/src/9/pc/ethervt6102.c (revision a8482e058adfb9039bb8aaa40ea4270fc64ff0a4)
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 	l = 0;
351 	for(i = 0; i < Nrxstats; i++){
352 		l += snprint(p+l, READSTR-l, "%s: %ud\n",
353 			rxstats[i], ctlr->rxstats[i]);
354 	}
355 	for(i = 0; i < Ntxstats; i++){
356 		if(txstats[i] == nil)
357 			continue;
358 		l += snprint(p+l, READSTR-l, "%s: %ud\n",
359 			txstats[i], ctlr->txstats[i]);
360 	}
361 	l += snprint(p+l, READSTR-l, "cls: %ud\n", ctlr->cls);
362 	l += snprint(p+l, READSTR-l, "intr: %ud\n", ctlr->intr);
363 	l += snprint(p+l, READSTR-l, "lintr: %ud\n", ctlr->lintr);
364 	l += snprint(p+l, READSTR-l, "lsleep: %ud\n", ctlr->lsleep);
365 	l += snprint(p+l, READSTR-l, "rintr: %ud\n", ctlr->rintr);
366 	l += snprint(p+l, READSTR-l, "tintr: %ud\n", ctlr->tintr);
367 	l += snprint(p+l, READSTR-l, "taligned: %ud\n", ctlr->taligned);
368 	l += snprint(p+l, READSTR-l, "tsplit: %ud\n", ctlr->tsplit);
369 	l += snprint(p+l, READSTR-l, "tcopied: %ud\n", ctlr->tcopied);
370 	l += snprint(p+l, READSTR-l, "txdw: %ud\n", ctlr->txdw);
371 	l += snprint(p+l, READSTR-l, "tft: %ud\n", ctlr->tft);
372 
373 	if(ctlr->mii != nil && ctlr->mii->curphy != nil){
374 		l += snprint(p+l, READSTR, "phy:   ");
375 		for(i = 0; i < NMiiPhyr; i++){
376 			if(i && ((i & 0x07) == 0))
377 				l += snprint(p+l, READSTR-l, "\n       ");
378 			r = miimir(ctlr->mii, i);
379 			l += snprint(p+l, READSTR-l, " %4.4uX", r);
380 		}
381 		snprint(p+l, READSTR-l, "\n");
382 	}
383 	snprint(p+l, READSTR-l, "\n");
384 
385 	n = readstr(offset, a, n, p);
386 	free(p);
387 
388 	return n;
389 }
390 
391 static void
392 vt6102promiscuous(void* arg, int on)
393 {
394 	int rcr;
395 	Ctlr *ctlr;
396 	Ether *edev;
397 
398 	edev = arg;
399 	ctlr = edev->ctlr;
400 	rcr = csr8r(ctlr, Rcr);
401 	if(on)
402 		rcr |= Prom;
403 	else
404 		rcr &= ~Prom;
405 	csr8w(ctlr, Rcr, rcr);
406 }
407 
408 static void
409 vt6102multicast(void* arg, uchar* addr, int on)
410 {
411 	/*
412 	 * For now Am is set in Rcr.
413 	 * Will need to interlock with promiscuous
414 	 * when this gets filled in.
415 	 */
416 	USED(arg, addr, on);
417 }
418 
419 static int
420 vt6102wakeup(void* v)
421 {
422 	return *((int*)v) != 0;
423 }
424 
425 static void
426 vt6102imr(Ctlr* ctlr, int imr)
427 {
428 	ilock(&ctlr->clock);
429 	ctlr->imr |= imr;
430 	csr16w(ctlr, Imr, ctlr->imr);
431 	iunlock(&ctlr->clock);
432 }
433 
434 static void
435 vt6102lproc(void* arg)
436 {
437 	Ctlr *ctlr;
438 	Ether *edev;
439 	MiiPhy *phy;
440 
441 	edev = arg;
442 	ctlr = edev->ctlr;
443 	for(;;){
444 		if(ctlr->mii == nil || ctlr->mii->curphy == nil)
445 			break;
446 		if(miistatus(ctlr->mii) < 0)
447 			goto enable;
448 
449 		phy = ctlr->mii->curphy;
450 		ilock(&ctlr->clock);
451 		if(phy->fd)
452 			ctlr->cr |= Fdx;
453 		else
454 			ctlr->cr &= ~Fdx;
455 		csr16w(ctlr, Cr, ctlr->cr);
456 		iunlock(&ctlr->clock);
457 enable:
458 		ctlr->lwakeup = 0;
459 		vt6102imr(ctlr, Srci);
460 
461 		ctlr->lsleep++;
462 		sleep(&ctlr->lrendez, vt6102wakeup, &ctlr->lwakeup);
463 
464 	}
465 	pexit("vt6102lproc: done", 1);
466 }
467 
468 static void
469 vt6102attach(Ether* edev)
470 {
471 	int i;
472 	Ctlr *ctlr;
473 	Ds *ds, *prev;
474 	uchar *alloc, *bounce;
475 	char name[KNAMELEN];
476 
477 	ctlr = edev->ctlr;
478 	qlock(&ctlr->alock);
479 	if(ctlr->alloc != nil){
480 		qunlock(&ctlr->alock);
481 		return;
482 	}
483 
484 	/*
485 	 * Descriptor and bounce-buffer space.
486 	 * Must all be aligned on a 4-byte boundary,
487 	 * but try to align on cache-lines.
488 	 */
489 	ctlr->nrd = Nrd;
490 	ctlr->ntd = Ntd;
491 	alloc = malloc((ctlr->nrd+ctlr->ntd)*ctlr->cls + ctlr->ntd*Txcopy + ctlr->cls-1);
492 	if(alloc == nil){
493 		qunlock(&ctlr->alock);
494 		return;
495 	}
496 	ctlr->alloc = alloc;
497 	alloc = (uchar*)ROUNDUP((ulong)alloc, ctlr->cls);
498 
499 	ctlr->rd = (Ds*)alloc;
500 
501 	if(waserror()){
502 		ds = ctlr->rd;
503 		for(i = 0; i < ctlr->nrd; i++){
504 			if(ds->bp != nil){
505 				freeb(ds->bp);
506 				ds->bp = nil;
507 			}
508 			if((ds = ds->next) == nil)
509 				break;
510 		}
511 		free(ctlr->alloc);
512 		ctlr->alloc = nil;
513 		qunlock(&ctlr->alock);
514 		nexterror();
515 	}
516 
517 	prev = ctlr->rd + ctlr->nrd-1;
518 	for(i = 0; i < ctlr->nrd; i++){
519 		ds = (Ds*)alloc;
520 		alloc += ctlr->cls;
521 
522 		ds->control = Rdbsz;
523 		ds->branch = PCIWADDR(alloc);
524 
525 		ds->bp = iallocb(Rdbsz+3);
526 		if(ds->bp == nil)
527 			error("vt6102: can't allocate receive ring\n");
528 		ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
529 		ds->addr = PCIWADDR(ds->bp->rp);
530 
531 		ds->next = (Ds*)alloc;
532 		ds->prev = prev;
533 		prev = ds;
534 
535 		ds->status = Own;
536 	}
537 	prev->branch = 0;
538 	prev->next = ctlr->rd;
539 	prev->status = 0;
540 	ctlr->rdh = ctlr->rd;
541 
542 	ctlr->td = (Ds*)alloc;
543 	prev = ctlr->td + ctlr->ntd-1;
544 	bounce = alloc + ctlr->ntd*ctlr->cls;
545 	for(i = 0; i < ctlr->ntd; i++){
546 		ds = (Ds*)alloc;
547 		alloc += ctlr->cls;
548 
549 		ds->bounce = bounce;
550 		bounce += Txcopy;
551 		ds->next = (Ds*)alloc;
552 		ds->prev = prev;
553 		prev = ds;
554 	}
555 	prev->next = ctlr->td;
556 	ctlr->tdh = ctlr->tdt = ctlr->td;
557 	ctlr->tdused = 0;
558 
559 	ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt;
560 	/*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
561 	ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
562 
563 	ilock(&ctlr->clock);
564 	csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
565 	csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
566 	csr16w(ctlr, Isr, ~0);
567 	csr16w(ctlr, Imr, ctlr->imr);
568 	csr16w(ctlr, Cr, ctlr->cr);
569 	iunlock(&ctlr->clock);
570 
571 	snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
572 	kproc(name, vt6102lproc, edev);
573 
574 	qunlock(&ctlr->alock);
575 	poperror();
576 }
577 
578 static void
579 vt6102transmit(Ether* edev)
580 {
581 	Block *bp;
582 	Ctlr *ctlr;
583 	Ds *ds, *next;
584 	int control, i, o, prefix, size, tdused, timeo;
585 
586 	ctlr = edev->ctlr;
587 
588 	ilock(&ctlr->tlock);
589 
590 	/*
591 	 * Free any completed packets
592 	 */
593 	ds = ctlr->tdh;
594 	for(tdused = ctlr->tdused; tdused > 0; tdused--){
595 		/*
596 		 * For some errors the chip will turn the Tx engine
597 		 * off. Wait for that to happen.
598 		 * Could reset and re-init the chip here if it doesn't
599 		 * play fair.
600 		 * To do: adjust Tx FIFO threshold on underflow.
601 		 */
602 		if(ds->status & (Abt|Tbuff|Udf)){
603 			for(timeo = 0; timeo < 1000; timeo++){
604 				if(!(csr16r(ctlr, Cr) & Txon))
605 					break;
606 				microdelay(1);
607 			}
608 			ds->status = Own;
609 			csr32w(ctlr, Txdaddr, PCIWADDR(ds));
610 		}
611 
612 		if(ds->status & Own)
613 			break;
614 		ds->addr = 0;
615 		ds->branch = 0;
616 
617 		if(ds->bp != nil){
618 			freeb(ds->bp);
619 			ds->bp = nil;
620 		}
621 		for(i = 0; i < Ntxstats-1; i++){
622 			if(ds->status & (1<<i))
623 				ctlr->txstats[i]++;
624 		}
625 		ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
626 
627 		ds = ds->next;
628 	}
629 	ctlr->tdh = ds;
630 
631 	/*
632 	 * Try to fill the ring back up.
633 	 */
634 	ds = ctlr->tdt;
635 	while(tdused < ctlr->ntd-2){
636 		if((bp = qget(edev->oq)) == nil)
637 			break;
638 		tdused++;
639 
640 		size = BLEN(bp);
641 		prefix = 0;
642 
643 		if(o = (((int)bp->rp) & 0x03)){
644 			prefix = Txcopy-o;
645 			if(prefix > size)
646 				prefix = size;
647 			memmove(ds->bounce, bp->rp, prefix);
648 			ds->addr = PCIWADDR(ds->bounce);
649 			bp->rp += prefix;
650 			size -= prefix;
651 		}
652 
653 		next = ds->next;
654 		ds->branch = PCIWADDR(ds->next);
655 
656 		if(size){
657 			if(prefix){
658 				next->bp = bp;
659 				next->addr = PCIWADDR(bp->rp);
660 				next->branch = PCIWADDR(next->next);
661 				next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK);
662 
663 				control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK);
664 
665 				next = next->next;
666 				tdused++;
667 				ctlr->tsplit++;
668 			}
669 			else{
670 				ds->bp = bp;
671 				ds->addr = PCIWADDR(bp->rp);
672 				control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
673 				ctlr->taligned++;
674 			}
675 		}
676 		else{
677 			freeb(bp);
678 			control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK);
679 			ctlr->tcopied++;
680 		}
681 
682 		ds->control = control;
683 		if(tdused >= ctlr->ntd-2){
684 			ds->control |= Ic;
685 			ctlr->txdw++;
686 		}
687 		coherence();
688 		ds->status = Own;
689 
690 		ds = next;
691 	}
692 	ctlr->tdt = ds;
693 	ctlr->tdused = tdused;
694 	if(ctlr->tdused)
695 		csr16w(ctlr, Cr, Tdmd|ctlr->cr);
696 
697 	iunlock(&ctlr->tlock);
698 }
699 
700 static void
701 vt6102receive(Ether* edev)
702 {
703 	Ds *ds;
704 	Block *bp;
705 	Ctlr *ctlr;
706 	int i, len;
707 
708 	ctlr = edev->ctlr;
709 
710 	ds = ctlr->rdh;
711 	while(!(ds->status & Own) && ds->status != 0){
712 		if(ds->status & Rerr){
713 			for(i = 0; i < Nrxstats; i++){
714 				if(ds->status & (1<<i))
715 					ctlr->rxstats[i]++;
716 			}
717 		}
718 		else if(bp = iallocb(Rdbsz+3)){
719 			len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
720 			ds->bp->wp = ds->bp->rp+len;
721 			etheriq(edev, ds->bp, 1);
722 			bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
723 			ds->addr = PCIWADDR(bp->rp);
724 			ds->bp = bp;
725 		}
726 		ds->control = Rdbsz;
727 		ds->branch = 0;
728 		ds->status = 0;
729 
730 		ds->prev->branch = PCIWADDR(ds);
731 		coherence();
732 		ds->prev->status = Own;
733 
734 		ds = ds->next;
735 	}
736 	ctlr->rdh = ds;
737 
738 	csr16w(ctlr, Cr, ctlr->cr);
739 }
740 
741 static void
742 vt6102interrupt(Ureg*, void* arg)
743 {
744 	Ctlr *ctlr;
745 	Ether *edev;
746 	int imr, isr, r, timeo;
747 
748 	edev = arg;
749 	ctlr = edev->ctlr;
750 
751 	ilock(&ctlr->clock);
752 	csr16w(ctlr, Imr, 0);
753 	imr = ctlr->imr;
754 	ctlr->intr++;
755 	for(;;){
756 		if((isr = csr16r(ctlr, Isr)) != 0)
757 			csr16w(ctlr, Isr, isr);
758 		if((isr & ctlr->imr) == 0)
759 			break;
760 
761 		if(isr & Srci){
762 			imr &= ~Srci;
763 			ctlr->lwakeup = isr & Srci;
764 			wakeup(&ctlr->lrendez);
765 			isr &= ~Srci;
766 			ctlr->lintr++;
767 		}
768 		if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
769 			vt6102receive(edev);
770 			isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
771 			ctlr->rintr++;
772 		}
773 		if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
774 			if(isr & (Abti|Udfi|Tu)){
775 				for(timeo = 0; timeo < 1000; timeo++){
776 					if(!(csr16r(ctlr, Cr) & Txon))
777 						break;
778 					microdelay(1);
779 				}
780 
781 				if((isr & Udfi) && ctlr->tft < CtftSAF){
782 					ctlr->tft += 1<<CtftSHIFT;
783 					r = csr8r(ctlr, Bcr1) & ~CtftMASK;
784 					csr8w(ctlr, Bcr1, r|ctlr->tft);
785 				}
786 			}
787 			vt6102transmit(edev);
788 			isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
789 			ctlr->tintr++;
790 		}
791 		if(isr)
792 			panic("vt6102: isr %4.4uX\n", isr);
793 	}
794 	ctlr->imr = imr;
795 	csr16w(ctlr, Imr, ctlr->imr);
796 	iunlock(&ctlr->clock);
797 }
798 
799 static int
800 vt6102miimicmd(Mii* mii, int pa, int ra, int cmd, int data)
801 {
802 	Ctlr *ctlr;
803 	int r, timeo;
804 
805 	ctlr = mii->ctlr;
806 
807 	csr8w(ctlr, Miicr, 0);
808 	r = csr8r(ctlr, Phyadr);
809 	csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
810 	csr8w(ctlr, Phyadr, pa);
811 	csr8w(ctlr, Miiadr, ra);
812 	if(cmd == Wcmd)
813 		csr16w(ctlr, Miidata, data);
814 	csr8w(ctlr, Miicr, cmd);
815 
816 	for(timeo = 0; timeo < 10000; timeo++){
817 		if(!(csr8r(ctlr, Miicr) & cmd))
818 			break;
819 		microdelay(1);
820 	}
821 	if(timeo >= 10000)
822 		return -1;
823 
824 	if(cmd == Wcmd)
825 		return 0;
826 	return csr16r(ctlr, Miidata);
827 }
828 
829 static int
830 vt6102miimir(Mii* mii, int pa, int ra)
831 {
832 	return vt6102miimicmd(mii, pa, ra, Rcmd, 0);
833 }
834 
835 static int
836 vt6102miimiw(Mii* mii, int pa, int ra, int data)
837 {
838 	return vt6102miimicmd(mii, pa, ra, Wcmd, data);
839 }
840 
841 static int
842 vt6102detach(Ctlr* ctlr)
843 {
844 	int revid, timeo;
845 
846 	/*
847 	 * Reset power management registers.
848 	 */
849 	revid = pcicfgr8(ctlr->pcidev, PciRID);
850 	if(revid >= 0x40){
851 		/* Set power state D0. */
852 		csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
853 
854 		/* Disable force PME-enable. */
855 		csr8w(ctlr, Wolcgclr, 0x80);
856 
857 		/* Clear WOL config and status bits. */
858 		csr8w(ctlr, Wolcrclr, 0xFF);
859 		csr8w(ctlr, Pwrcsrclr, 0xFF);
860 	}
861 
862 	/*
863 	 * Soft reset the controller.
864 	 */
865 	csr16w(ctlr, Cr, Stop);
866 	csr16w(ctlr, Cr, Stop|Sfrst);
867 	for(timeo = 0; timeo < 10000; timeo++){
868 		if(!(csr16r(ctlr, Cr) & Sfrst))
869 			break;
870 		microdelay(1);
871 	}
872 	if(timeo >= 1000)
873 		return -1;
874 
875 	return 0;
876 }
877 
878 static int
879 vt6102reset(Ctlr* ctlr)
880 {
881 	MiiPhy *phy;
882 	int i, r, timeo;
883 
884 	if(vt6102detach(ctlr) < 0)
885 		return -1;
886 
887 	/*
888 	 * Load the MAC address into the PAR[01]
889 	 * registers.
890 	 */
891 	r = csr8r(ctlr, Eecsr);
892 	csr8w(ctlr, Eecsr, Autold|r);
893 	for(timeo = 0; timeo < 100; timeo++){
894 		if(!(csr8r(ctlr, Cr) & Autold))
895 			break;
896 		microdelay(1);
897 	}
898 	if(timeo >= 100)
899 		return -1;
900 
901 	for(i = 0; i < Eaddrlen; i++)
902 		ctlr->par[i] = csr8r(ctlr, Par0+i);
903 
904 	/*
905 	 * Configure DMA and Rx/Tx thresholds.
906 	 * If the Rx/Tx threshold bits in Bcr[01] are 0 then
907 	 * the thresholds are determined by Rcr/Tcr.
908 	 */
909 	r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
910 	csr8w(ctlr, Bcr0, r|Crft64|Dma64);
911 	r = csr8r(ctlr, Bcr1) & ~CtftMASK;
912 	csr8w(ctlr, Bcr1, r|ctlr->tft);
913 
914 	r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
915 	csr8w(ctlr, Rcr, r|Ab|Am);
916 	csr32w(ctlr, Mcfilt0, ~0UL);	/* accept all multicast */
917 	csr32w(ctlr, Mcfilt1, ~0UL);
918 
919 	r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
920 	csr8w(ctlr, Tcr, r);
921 
922 	/*
923 	 * Link management.
924 	 */
925 	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
926 		return -1;
927 	ctlr->mii->mir = vt6102miimir;
928 	ctlr->mii->miw = vt6102miimiw;
929 	ctlr->mii->ctlr = ctlr;
930 
931 	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
932 		free(ctlr->mii);
933 		ctlr->mii = nil;
934 		return -1;
935 	}
936 	// print("oui %X phyno %d\n", phy->oui, phy->phyno);
937 	USED(phy);
938 
939 	//miiane(ctlr->mii, ~0, ~0, ~0);
940 
941 	return 0;
942 }
943 
944 static void
945 vt6102pci(void)
946 {
947 	Pcidev *p;
948 	Ctlr *ctlr;
949 	int cls, port;
950 
951 	p = nil;
952 	while(p = pcimatch(p, 0, 0)){
953 		if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
954 			continue;
955 
956 		switch((p->did<<16)|p->vid){
957 		default:
958 			continue;
959 		case (0x3065<<16)|0x1106:	/* Rhine II */
960 		case (0x3106<<16)|0x1106:	/* Rhine III */
961 			break;
962 		}
963 
964 		port = p->mem[0].bar & ~0x01;
965 		if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){
966 			print("vt6102: port 0x%uX in use\n", port);
967 			continue;
968 		}
969 		ctlr = malloc(sizeof(Ctlr));
970 		ctlr->port = port;
971 		ctlr->pcidev = p;
972 		ctlr->id = (p->did<<16)|p->vid;
973 		if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
974 			cls = 0x10;
975 		ctlr->cls = cls*4;
976 		if(ctlr->cls < sizeof(Ds)){
977 			print("vt6102: cls %d < sizeof(Ds)\n", ctlr->cls);
978 			iofree(port);
979 			free(ctlr);
980 			continue;
981 		}
982 		ctlr->tft = Ctft64;
983 
984 		if(vt6102reset(ctlr)){
985 			iofree(port);
986 			free(ctlr);
987 			continue;
988 		}
989 		pcisetbme(p);
990 
991 		if(vt6102ctlrhead != nil)
992 			vt6102ctlrtail->next = ctlr;
993 		else
994 			vt6102ctlrhead = ctlr;
995 		vt6102ctlrtail = ctlr;
996 	}
997 }
998 
999 static int
1000 vt6102pnp(Ether* edev)
1001 {
1002 	Ctlr *ctlr;
1003 
1004 	if(vt6102ctlrhead == nil)
1005 		vt6102pci();
1006 
1007 	/*
1008 	 * Any adapter matches if no edev->port is supplied,
1009 	 * otherwise the ports must match.
1010 	 */
1011 	for(ctlr = vt6102ctlrhead; ctlr != nil; ctlr = ctlr->next){
1012 		if(ctlr->active)
1013 			continue;
1014 		if(edev->port == 0 || edev->port == ctlr->port){
1015 			ctlr->active = 1;
1016 			break;
1017 		}
1018 	}
1019 	if(ctlr == nil)
1020 		return -1;
1021 
1022 	edev->ctlr = ctlr;
1023 	edev->port = ctlr->port;
1024 	edev->irq = ctlr->pcidev->intl;
1025 	edev->tbdf = ctlr->pcidev->tbdf;
1026 	edev->mbps = 100;
1027 	memmove(edev->ea, ctlr->par, Eaddrlen);
1028 
1029 	/*
1030 	 * Linkage to the generic ethernet driver.
1031 	 */
1032 	edev->attach = vt6102attach;
1033 	edev->transmit = vt6102transmit;
1034 	edev->interrupt = vt6102interrupt;
1035 	edev->ifstat = vt6102ifstat;
1036 	edev->ctl = nil;
1037 
1038 	edev->arg = edev;
1039 	edev->promiscuous = vt6102promiscuous;
1040 	edev->multicast = vt6102multicast;
1041 
1042 	return 0;
1043 }
1044 
1045 void
1046 ethervt6102link(void)
1047 {
1048 	addethercard("vt6102", vt6102pnp);
1049 	addethercard("rhine", vt6102pnp);
1050 }
1051