xref: /plan9/sys/src/9/pc/ether79c970.c (revision aa72973a2891ccbd3fb042462446761159389e19)
1 /*
2  * AMD79C970
3  * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
4  * To do:
5  *	finish this rewrite
6  */
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/error.h"
14 #include "../port/netif.h"
15 
16 #include "etherif.h"
17 
18 enum {
19 	Lognrdre	= 6,
20 	Nrdre		= (1<<Lognrdre),/* receive descriptor ring entries */
21 	Logntdre	= 4,
22 	Ntdre		= (1<<Logntdre),/* transmit descriptor ring entries */
23 
24 	Rbsize		= ETHERMAXTU+4,	/* ring buffer size (+4 for CRC) */
25 };
26 
27 enum {					/* DWIO I/O resource map */
28 	Aprom		= 0x0000,	/* physical address */
29 	Rdp		= 0x0010,	/* register data port */
30 	Rap		= 0x0014,	/* register address port */
31 	Sreset		= 0x0018,	/* software reset */
32 	Bdp		= 0x001C,	/* bus configuration register data port */
33 };
34 
35 enum {					/* CSR0 */
36 	Init		= 0x0001,	/* begin initialisation */
37 	Strt		= 0x0002,	/* enable chip */
38 	Stop		= 0x0004,	/* disable chip */
39 	Tdmd		= 0x0008,	/* transmit demand */
40 	Txon		= 0x0010,	/* transmitter on */
41 	Rxon		= 0x0020,	/* receiver on */
42 	Iena		= 0x0040,	/* interrupt enable */
43 	Intr		= 0x0080,	/* interrupt flag */
44 	Idon		= 0x0100,	/* initialisation done */
45 	Tint		= 0x0200,	/* transmit interrupt */
46 	Rint		= 0x0400,	/* receive interrupt */
47 	Merr		= 0x0800,	/* memory error */
48 	Miss		= 0x1000,	/* missed frame */
49 	Cerr		= 0x2000,	/* collision */
50 	Babl		= 0x4000,	/* transmitter timeout */
51 	Err		= 0x8000,	/* Babl|Cerr|Miss|Merr */
52 };
53 
54 enum {					/* CSR3 */
55 	Bswp		= 0x0004,	/* byte swap */
56 	Emba		= 0x0008,	/* enable modified back-off algorithm */
57 	Dxmt2pd		= 0x0010,	/* disable transmit two part deferral */
58 	Lappen		= 0x0020,	/* look-ahead packet processing enable */
59 };
60 
61 enum {					/* CSR4 */
62 	ApadXmt		= 0x0800,	/* auto pad transmit */
63 };
64 
65 enum {					/* CSR15 */
66 	Prom		= 0x8000,	/* promiscuous mode */
67 };
68 
69 typedef struct Iblock Iblock;
70 struct Iblock {			/* Initialisation Block */
71 	ushort	mode;
72 	uchar	rlen;			/* upper 4 bits */
73 	uchar	tlen;			/* upper 4 bits */
74 	uchar	padr[6];
75 	uchar	res[2];
76 	uchar	ladr[8];
77 	ulong	rdra;
78 	ulong	tdra;
79 };
80 
81 typedef struct Dre Dre;
82 struct Dre {			/* descriptor ring entry */
83 	ulong	addr;
84 	ulong	md1;			/* status|bcnt */
85 	ulong	md2;			/* rcc|rpc|mcnt */
86 	Block*	bp;
87 };
88 
89 enum {					/* md1 */
90 	Enp		= 0x01000000,	/* end of packet */
91 	Stp		= 0x02000000,	/* start of packet */
92 	RxBuff		= 0x04000000,	/* buffer error */
93 	Def		= 0x04000000,	/* deferred */
94 	Crc		= 0x08000000,	/* CRC error */
95 	One		= 0x08000000,	/* one retry needed */
96 	Oflo		= 0x10000000,	/* overflow error */
97 	More		= 0x10000000,	/* more than one retry needed */
98 	Fram		= 0x20000000,	/* framing error */
99 	RxErr		= 0x40000000,	/* Fram|Oflo|Crc|RxBuff */
100 	TxErr		= 0x40000000,	/* Uflo|Lcol|Lcar|Rtry */
101 	Own		= 0x80000000,
102 };
103 
104 enum {					/* md2 */
105 	Rtry		= 0x04000000,	/* failed after repeated retries */
106 	Lcar		= 0x08000000,	/* loss of carrier */
107 	Lcol		= 0x10000000,	/* late collision */
108 	Uflo		= 0x40000000,	/* underflow error */
109 	TxBuff		= 0x80000000,	/* buffer error */
110 };
111 
112 typedef struct Ctlr Ctlr;
113 struct Ctlr {
114 	Lock;
115 	int	port;
116 	Pcidev*	pcidev;
117 	Ctlr*	next;
118 	int	active;
119 
120 	int	init;			/* initialisation in progress */
121 	Iblock	iblock;
122 
123 	Dre*	rdr;			/* receive descriptor ring */
124 	int	rdrx;
125 
126 	Dre*	tdr;			/* transmit descriptor ring */
127 	int	tdrh;			/* host index into tdr */
128 	int	tdri;			/* interface index into tdr */
129 	int	ntq;			/* descriptors active */
130 
131 	ulong	rxbuff;			/* receive statistics */
132 	ulong	crc;
133 	ulong	oflo;
134 	ulong	fram;
135 
136 	ulong	rtry;			/* transmit statistics */
137 	ulong	lcar;
138 	ulong	lcol;
139 	ulong	uflo;
140 	ulong	txbuff;
141 
142 	ulong	merr;			/* bobf is such a whiner */
143 	ulong	miss;
144 	ulong	babl;
145 
146 	int	(*ior)(Ctlr*, int);
147 	void	(*iow)(Ctlr*, int, int);
148 };
149 
150 static Ctlr* ctlrhead;
151 static Ctlr* ctlrtail;
152 
153 /*
154  * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above.
155  * To get to 16-bit offsets, scale down with 0x10 staying the same.
156  */
157 static int
io16r(Ctlr * c,int r)158 io16r(Ctlr *c, int r)
159 {
160 	if(r >= Rdp)
161 		r = (r-Rdp)/2+Rdp;
162 	return ins(c->port+r);
163 }
164 
165 static void
io16w(Ctlr * c,int r,int v)166 io16w(Ctlr *c, int r, int v)
167 {
168 	if(r >= Rdp)
169 		r = (r-Rdp)/2+Rdp;
170 	outs(c->port+r, v);
171 }
172 
173 static int
io32r(Ctlr * c,int r)174 io32r(Ctlr *c, int r)
175 {
176 	return inl(c->port+r);
177 }
178 
179 static void
io32w(Ctlr * c,int r,int v)180 io32w(Ctlr *c, int r, int v)
181 {
182 	outl(c->port+r, v);
183 }
184 
185 static void
attach(Ether *)186 attach(Ether*)
187 {
188 }
189 
190 static long
ifstat(Ether * ether,void * a,long n,ulong offset)191 ifstat(Ether* ether, void* a, long n, ulong offset)
192 {
193 	char *p;
194 	int len;
195 	Ctlr *ctlr;
196 
197 	ctlr = ether->ctlr;
198 
199 	ether->crcs = ctlr->crc;
200 	ether->frames = ctlr->fram;
201 	ether->buffs = ctlr->rxbuff+ctlr->txbuff;
202 	ether->overflows = ctlr->oflo;
203 
204 	if(n == 0)
205 		return 0;
206 
207 	p = malloc(READSTR);
208 	if(p == nil)
209 		error(Enomem);
210 	len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff);
211 	len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc);
212 	len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo);
213 	len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram);
214 	len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry);
215 	len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar);
216 	len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol);
217 	len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo);
218 	len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
219 	len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr);
220 	len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss);
221 	snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl);
222 
223 	n = readstr(offset, a, n, p);
224 	free(p);
225 
226 	return n;
227 }
228 
229 static void
ringinit(Ctlr * ctlr)230 ringinit(Ctlr* ctlr)
231 {
232 	Dre *dre;
233 
234 	/*
235 	 * Initialise the receive and transmit buffer rings.
236 	 * The ring entries must be aligned on 16-byte boundaries.
237 	 *
238 	 * This routine is protected by ctlr->init.
239 	 */
240 	if(ctlr->rdr == 0){
241 		ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0);
242 		for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){
243 			dre->bp = iallocb(Rbsize);
244 			if(dre->bp == nil)
245 				panic("can't allocate ethernet receive ring\n");
246 			dre->addr = PADDR(dre->bp->rp);
247 			dre->md2 = 0;
248 			dre->md1 = Own|(-Rbsize & 0xFFFF);
249 		}
250 	}
251 	ctlr->rdrx = 0;
252 
253 	if(ctlr->tdr == 0)
254 		ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
255 	memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
256 	ctlr->tdrh = ctlr->tdri = 0;
257 }
258 
259 static void
promiscuous(void * arg,int on)260 promiscuous(void* arg, int on)
261 {
262 	Ether *ether;
263 	int x;
264 	Ctlr *ctlr;
265 
266 	ether = arg;
267 	ctlr = ether->ctlr;
268 
269 	/*
270 	 * Put the chip into promiscuous mode. First must wait until
271 	 * anyone transmitting is done, then stop the chip and put
272 	 * it in promiscuous mode. Restarting is made harder by the chip
273 	 * reloading the transmit and receive descriptor pointers with their
274 	 * base addresses when Strt is set (unlike the older Lance chip),
275 	 * so the rings must be re-initialised.
276 	 */
277 	ilock(ctlr);
278 	if(ctlr->init){
279 		iunlock(ctlr);
280 		return;
281 	}
282 	ctlr->init = 1;
283 	iunlock(ctlr);
284 
285 	while(ctlr->ntq)
286 		;
287 
288 	ctlr->iow(ctlr, Rdp, Stop);
289 
290 	ctlr->iow(ctlr, Rap, 15);
291 	x = ctlr->ior(ctlr, Rdp) & ~Prom;
292 	if(on)
293 		x |= Prom;
294 	ctlr->iow(ctlr, Rdp, x);
295 	ctlr->iow(ctlr, Rap, 0);
296 
297 	ringinit(ctlr);
298 
299 	ilock(ctlr);
300 	ctlr->init = 0;
301 	ctlr->iow(ctlr, Rdp, Iena|Strt);
302 	iunlock(ctlr);
303 }
304 
305 static void
multicast(void * arg,uchar *,int)306 multicast(void* arg, uchar*, int)
307 {
308 	promiscuous(arg, 1);
309 }
310 
311 static void
shutdown(Ether * ether)312 shutdown(Ether *ether)
313 {
314 	Ctlr *ctlr;
315 
316 	ctlr = ether->ctlr;
317 	ilock(ctlr);
318 	io32r(ctlr, Sreset);
319 	io16r(ctlr, Sreset);
320 	iunlock(ctlr);
321 }
322 
323 static void
txstart(Ether * ether)324 txstart(Ether* ether)
325 {
326 	Ctlr *ctlr;
327 	Block *bp;
328 	Dre *dre;
329 
330 	ctlr = ether->ctlr;
331 
332 	if(ctlr->init)
333 		return;
334 
335 	while(ctlr->ntq < (Ntdre-1)){
336 		bp = qget(ether->oq);
337 		if(bp == nil)
338 			break;
339 
340 		/*
341 		 * Give ownership of the descriptor to the chip,
342 		 * increment the software ring descriptor pointer
343 		 * and tell the chip to poll.
344 		 * There's no need to pad to ETHERMINTU
345 		 * here as ApadXmt is set in CSR4.
346 		 */
347 		dre = &ctlr->tdr[ctlr->tdrh];
348 		dre->bp = bp;
349 		dre->addr = PADDR(bp->rp);
350 		dre->md2 = 0;
351 		dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
352 		ctlr->ntq++;
353 		ctlr->iow(ctlr, Rdp, Iena|Tdmd);
354 		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
355 	}
356 }
357 
358 static void
transmit(Ether * ether)359 transmit(Ether* ether)
360 {
361 	Ctlr *ctlr;
362 
363 	ctlr = ether->ctlr;
364 	ilock(ctlr);
365 	txstart(ether);
366 	iunlock(ctlr);
367 }
368 
369 static void
interrupt(Ureg *,void * arg)370 interrupt(Ureg*, void* arg)
371 {
372 	Ctlr *ctlr;
373 	Ether *ether;
374 	int csr0, len;
375 	Dre *dre;
376 	Block *bp;
377 
378 	ether = arg;
379 	ctlr = ether->ctlr;
380 
381 	/*
382 	 * Acknowledge all interrupts and whine about those that shouldn't
383 	 * happen.
384 	 */
385 intrloop:
386 	csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
387 	ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
388 	if(csr0 & Merr)
389 		ctlr->merr++;
390 	if(csr0 & Miss)
391 		ctlr->miss++;
392 	if(csr0 & Babl)
393 		ctlr->babl++;
394 	//if(csr0 & (Babl|Miss|Merr))
395 	//	print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
396 	if(!(csr0 & (Rint|Tint)))
397 		return;
398 
399 	/*
400 	 * Receiver interrupt: run round the descriptor ring logging
401 	 * errors and passing valid receive data up to the higher levels
402 	 * until a descriptor is encountered still owned by the chip.
403 	 */
404 	if(csr0 & Rint){
405 		dre = &ctlr->rdr[ctlr->rdrx];
406 		while(!(dre->md1 & Own)){
407 			if(dre->md1 & RxErr){
408 				if(dre->md1 & RxBuff)
409 					ctlr->rxbuff++;
410 				if(dre->md1 & Crc)
411 					ctlr->crc++;
412 				if(dre->md1 & Oflo)
413 					ctlr->oflo++;
414 				if(dre->md1 & Fram)
415 					ctlr->fram++;
416 			}
417 			else if(bp = iallocb(Rbsize)){
418 				len = (dre->md2 & 0x0FFF)-4;
419 				dre->bp->wp = dre->bp->rp+len;
420 				etheriq(ether, dre->bp, 1);
421 				dre->bp = bp;
422 				dre->addr = PADDR(bp->rp);
423 			}
424 
425 			/*
426 			 * Finished with this descriptor, reinitialise it,
427 			 * give it back to the chip, then on to the next...
428 			 */
429 			dre->md2 = 0;
430 			dre->md1 = Own|(-Rbsize & 0xFFFF);
431 
432 			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
433 			dre = &ctlr->rdr[ctlr->rdrx];
434 		}
435 	}
436 
437 	/*
438 	 * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
439 	 */
440 	if(csr0 & Tint){
441 		lock(ctlr);
442 		while(ctlr->ntq){
443 			dre = &ctlr->tdr[ctlr->tdri];
444 			if(dre->md1 & Own)
445 				break;
446 
447 			if(dre->md1 & TxErr){
448 				if(dre->md2 & Rtry)
449 					ctlr->rtry++;
450 				if(dre->md2 & Lcar)
451 					ctlr->lcar++;
452 				if(dre->md2 & Lcol)
453 					ctlr->lcol++;
454 				if(dre->md2 & Uflo)
455 					ctlr->uflo++;
456 				if(dre->md2 & TxBuff)
457 					ctlr->txbuff++;
458 				ether->oerrs++;
459 			}
460 
461 			freeb(dre->bp);
462 
463 			ctlr->ntq--;
464 			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
465 		}
466 		txstart(ether);
467 		unlock(ctlr);
468 	}
469 	goto intrloop;
470 }
471 
472 static void
amd79c970pci(void)473 amd79c970pci(void)
474 {
475 	int port;
476 	Ctlr *ctlr;
477 	Pcidev *p;
478 
479 	p = nil;
480 	while(p = pcimatch(p, 0x1022, 0x2000)){
481 		port = p->mem[0].bar & ~0x01;
482 		if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
483 			print("amd79c970: port 0x%uX in use\n", port);
484 			continue;
485 		}
486 		ctlr = malloc(sizeof(Ctlr));
487 		if(ctlr == nil)
488 			error(Enomem);
489 		ctlr->port = p->mem[0].bar & ~0x01;
490 		ctlr->pcidev = p;
491 
492 		if(ctlrhead != nil)
493 			ctlrtail->next = ctlr;
494 		else
495 			ctlrhead = ctlr;
496 		ctlrtail = ctlr;
497 	}
498 }
499 
500 static int
reset(Ether * ether)501 reset(Ether* ether)
502 {
503 	int x;
504 	uchar ea[Eaddrlen];
505 	Ctlr *ctlr;
506 
507 	if(ctlrhead == nil)
508 		amd79c970pci();
509 
510 	/*
511 	 * Any adapter matches if no port is supplied,
512 	 * otherwise the ports must match.
513 	 */
514 	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
515 		if(ctlr->active)
516 			continue;
517 		if(ether->port == 0 || ether->port == ctlr->port){
518 			ctlr->active = 1;
519 			break;
520 		}
521 	}
522 	if(ctlr == nil)
523 		return -1;
524 
525 	/*
526 	 * Allocate a controller structure and start to initialise it.
527 	 */
528 	ether->ctlr = ctlr;
529 	ether->port = ctlr->port;
530 	ether->irq = ctlr->pcidev->intl;
531 	ether->tbdf = ctlr->pcidev->tbdf;
532 	pcisetbme(ctlr->pcidev);
533 	shutdown(ether);
534 	ilock(ctlr);
535 	ctlr->init = 1;
536 
537 	if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
538 		ctlr->ior = io16r;
539 		ctlr->iow = io16w;
540 	}else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
541 		ctlr->ior = io32r;
542 		ctlr->iow = io32w;
543 	}else{
544 		print("#l%d: card doesn't talk right\n", ether->ctlrno);
545 		iunlock(ctlr);
546 		return -1;
547 	}
548 
549 	ctlr->iow(ctlr, Rap, 88);
550 	x = ctlr->ior(ctlr, Rdp);
551 	ctlr->iow(ctlr, Rap, 89);
552 	x |= ctlr->ior(ctlr, Rdp)<<16;
553 
554 	switch(x&0xFFFFFFF){
555 	case 0x2420003:	/* PCnet/PCI 79C970 */
556 	case 0x2621003:	/* PCnet/PCI II 79C970A */
557 	case 0x2625003:	/* PCnet-FAST III 79C973 */
558 		break;
559 	default:
560 		print("#l%d: unknown PCnet card version 0x%.7ux\n",
561 			ether->ctlrno, x&0xFFFFFFF);
562 		iunlock(ctlr);
563 		return -1;
564 	}
565 
566 	/*
567 	 * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
568 	 * Set the auto pad transmit in CSR4.
569 	 */
570 	ctlr->iow(ctlr, Rap, 20);
571 	ctlr->iow(ctlr, Bdp, 0x0002);
572 
573 	ctlr->iow(ctlr, Rap, 4);
574 	x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
575 	ctlr->iow(ctlr, Rdp, ApadXmt|x);
576 
577 	ctlr->iow(ctlr, Rap, 0);
578 
579 	/*
580 	 * Check if the adapter's station address is to be overridden.
581 	 * If not, read it from the I/O-space and set in ether->ea prior to
582 	 * loading the station address in the initialisation block.
583 	 */
584 	memset(ea, 0, Eaddrlen);
585 	if(!memcmp(ea, ether->ea, Eaddrlen)){
586 		x = ctlr->ior(ctlr, Aprom);
587 		ether->ea[0] = x;
588 		ether->ea[1] = x>>8;
589 		if(ctlr->ior == io16r)
590 			x = ctlr->ior(ctlr, Aprom+2);
591 		else
592 			x >>= 16;
593 		ether->ea[2] = x;
594 		ether->ea[3] = x>>8;
595 		x = ctlr->ior(ctlr, Aprom+4);
596 		ether->ea[4] = x;
597 		ether->ea[5] = x>>8;
598 	}
599 
600 	/*
601 	 * Start to fill in the initialisation block
602 	 * (must be DWORD aligned).
603 	 */
604 	ctlr->iblock.rlen = Lognrdre<<4;
605 	ctlr->iblock.tlen = Logntdre<<4;
606 	memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));
607 
608 	ringinit(ctlr);
609 	ctlr->iblock.rdra = PADDR(ctlr->rdr);
610 	ctlr->iblock.tdra = PADDR(ctlr->tdr);
611 
612 	/*
613 	 * Point the chip at the initialisation block and tell it to go.
614 	 * Mask the Idon interrupt and poll for completion. Strt and interrupt
615 	 * enables will be set later when attaching to the network.
616 	 */
617 	x = PADDR(&ctlr->iblock);
618 	ctlr->iow(ctlr, Rap, 1);
619 	ctlr->iow(ctlr, Rdp, x & 0xFFFF);
620 	ctlr->iow(ctlr, Rap, 2);
621 	ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
622 	ctlr->iow(ctlr, Rap, 3);
623 	ctlr->iow(ctlr, Rdp, Idon);
624 	ctlr->iow(ctlr, Rap, 0);
625 	ctlr->iow(ctlr, Rdp, Init);
626 
627 	while(!(ctlr->ior(ctlr, Rdp) & Idon))
628 		;
629 
630 	/*
631 	 * We used to set CSR0 to Idon|Stop here, and then
632 	 * in attach change it to Iena|Strt.  Apparently the simulated
633 	 * 79C970 in VMware never enables after a write of Idon|Stop,
634 	 * so we enable the device here now.
635 	 */
636 	ctlr->iow(ctlr, Rdp, Iena|Strt);
637 	ctlr->init = 0;
638 	iunlock(ctlr);
639 
640 	/*
641 	 * Linkage to the generic ethernet driver.
642 	 */
643 	ether->attach = attach;
644 	ether->transmit = transmit;
645 	ether->interrupt = interrupt;
646 	ether->ifstat = ifstat;
647 
648 	ether->arg = ether;
649 	ether->promiscuous = promiscuous;
650 	ether->multicast = multicast;
651 	ether->shutdown = shutdown;
652 
653 	return 0;
654 }
655 
656 void
ether79c970link(void)657 ether79c970link(void)
658 {
659 	addethercard("AMD79C970",  reset);
660 }
661