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