xref: /plan9/sys/src/9/pc/ethervt6102.c (revision 6fbfa2f3a4bd5daf3b27fc86a6c02b39e9bc7b86)
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
vt6102ifstat(Ether * edev,void * a,long n,ulong offset)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
vt6102promiscuous(void * arg,int on)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
vt6102multicast(void * arg,uchar * addr,int on)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
vt6102wakeup(void * v)422 vt6102wakeup(void* v)
423 {
424 	return *((int*)v) != 0;
425 }
426 
427 static void
vt6102imr(Ctlr * ctlr,int imr)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
vt6102lproc(void * arg)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
vt6102attach(Ether * edev)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
vt6102transmit(Ether * edev)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
vt6102receive(Ether * edev)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
vt6102interrupt(Ureg *,void * arg)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
vt6102miimicmd(Mii * mii,int pa,int ra,int cmd,int data)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
vt6102miimir(Mii * mii,int pa,int ra)832 vt6102miimir(Mii* mii, int pa, int ra)
833 {
834 	return vt6102miimicmd(mii, pa, ra, Rcmd, 0);
835 }
836 
837 static int
vt6102miimiw(Mii * mii,int pa,int ra,int data)838 vt6102miimiw(Mii* mii, int pa, int ra, int data)
839 {
840 	return vt6102miimicmd(mii, pa, ra, Wcmd, data);
841 }
842 
843 static int
vt6102detach(Ctlr * ctlr)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
vt6102shutdown(Ether * ether)881 vt6102shutdown(Ether *ether)
882 {
883 	Ctlr *ctlr = ether->ctlr;
884 
885 	vt6102detach(ctlr);
886 }
887 
888 static int
vt6102reset(Ctlr * ctlr)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
vt6102pci(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
vt6102pnp(Ether * edev)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
ethervt6102link(void)1061 ethervt6102link(void)
1062 {
1063 	addethercard("vt6102", vt6102pnp);
1064 	addethercard("rhine", vt6102pnp);
1065 }
1066