xref: /inferno-os/os/boot/pc/etherrhine.c (revision a60fa48ce2f27a689f276bea9538b5db2b74ff86)
1 /*
2 	Via Rhine driver, written for VT6102.
3 	Uses the ethermii to control PHY.
4 
5 	Currently always copies on both, tx and rx.
6 	rx side could be copy-free, and tx-side might be made
7 	(almost) copy-free by using (possibly) two descriptors (if it allows
8 	arbitrary tx lengths, which it should..): first for alignment and
9 	second for rest of the frame. Rx-part should be worth doing.
10  */
11 #include "u.h"
12 #include "lib.h"
13 #include "mem.h"
14 #include "dat.h"
15 #include "fns.h"
16 #include "io.h"
17 
18 typedef struct QLock { int r; } QLock;
19 #define qlock(i)	while(0)
20 #define qunlock(i)	while(0)
21 #define iprint		print
22 
23 #include "etherif.h"
24 #include "ethermii.h"
25 
26 enum {
27 	Ntxd = 4,
28 	Nrxd = 4,
29 	Nwait = 50,
30 	BIGSTR = 8192,
31 };
32 
33 typedef struct Desc Desc;
34 typedef struct Ctlr Ctlr;
35 
36 struct Desc {
37 	ulong	stat;
38 	ulong	size;
39 	ulong	addr;
40 	ulong	next;
41 	char	*buf;
42 	ulong	pad[3];
43 };
44 
45 struct Ctlr {
46 	Pcidev	*pci;
47 	int	attached;
48 	int	txused;
49 	int	txhead;
50 	int	txtail;
51 	int	rxtail;
52 	ulong	port;
53 
54 	Mii	mii;
55 
56 	Desc	*txd;		/* wants to be aligned on 16-byte boundary */
57 	Desc	*rxd;
58 
59 	QLock	attachlck;
60 	Lock	tlock;
61 };
62 
63 #define ior8(c, r)	(inb((c)->port+(r)))
64 #define iow8(c, r, b)	(outb((c)->port+(r), (int)(b)))
65 #define ior16(c, r)	(ins((c)->port+(r)))
66 #define ior32(c, r)	(inl((c)->port+(r)))
67 #define iow16(c, r, w)	(outs((c)->port+(r), (ushort)(w)))
68 #define iow32(c, r, l)	(outl((c)->port+(r), (ulong)(l)))
69 
70 /* names used everywhere else */
71 #define csr8r ior8
72 #define csr8w iow8
73 #define csr16r ior16
74 #define csr16w iow16
75 #define csr32r ior32
76 #define csr32w iow32
77 
78 enum Regs {
79 	Eaddr		= 0x0,
80 	Rcr		= 0x6,
81 	Tcr		= 0x7,
82 	Cr		= 0x8,
83 	Isr		= 0xc,
84 	Imr		= 0xe,
85 	McastAddr	= 0x10,
86 	RxdAddr		= 0x18,
87 	TxdAddr		= 0x1C,
88 	Bcr0		= 0x6E,		/* Bus Control */
89 	Bcr1		= 0x6F,
90 	RhineMiiPhy	= 0x6C,
91 	RhineMiiSr	= 0x6D,
92 	RhineMiiCr	= 0x70,
93 	RhineMiiAddr	= 0x71,
94 	RhineMiiData	= 0x72,
95 	Eecsr		= 0x74,
96 	ConfigB		= 0x79,
97 	ConfigD		= 0x7B,
98 	MiscCr		= 0x80,
99 	HwSticky	= 0x83,
100 	MiscIsr		= 0x84,
101 	MiscImr		= 0x86,
102 	WolCrSet	= 0xA0,
103 	WolCfgSet	= 0xA1,
104 	WolCgSet	= 0xA3,
105 	WolCrClr	= 0xA4,
106 	PwrCfgClr	= 0xA5,
107 	WolCgClr	= 0xA7,
108 };
109 
110 enum {					/* Rcr */
111 	Sep		= 0x01,		/* Accept Error Packets */
112 	Ar		= 0x02,		/* Accept Small Packets */
113 	Am		= 0x04,		/* Accept Multicast */
114 	Ab		= 0x08,		/* Accept Broadcast */
115 	RxBcast		= Ab,
116 	Prom		= 0x10,		/* Accept Physical Address Packets */
117 	RxProm		= Prom,
118 	RrftMASK	= 0xE0,		/* Receive FIFO Threshold */
119 	RrftSHIFT	= 5,
120 	Rrft64		= 0<<RrftSHIFT,
121 	Rrft32		= 1<<RrftSHIFT,
122 	Rrft128		= 2<<RrftSHIFT,
123 	Rrft256		= 3<<RrftSHIFT,
124 	Rrft512		= 4<<RrftSHIFT,
125 	Rrft768		= 5<<RrftSHIFT,
126 	Rrft1024	= 6<<RrftSHIFT,
127 	RrftSAF		= 7<<RrftSHIFT,
128 };
129 
130 enum {					/* Tcr */
131 	Lb0		= 0x02,		/* Loopback Mode */
132 	Lb1		= 0x04,
133 	Ofset		= 0x08,		/* Back-off Priority Selection */
134 	RtsfMASK	= 0xE0,		/* Transmit FIFO Threshold */
135 	RtsfSHIFT	= 5,
136 	Rtsf128		= 0<<RtsfSHIFT,
137 	Rtsf256		= 1<<RtsfSHIFT,
138 	Rtsf512		= 2<<RtsfSHIFT,
139 	Rtsf1024	= 3<<RtsfSHIFT,
140 	RtsfSAF		= 7<<RtsfSHIFT,
141 };
142 
143 enum Crbits {
144 	Init		= 1<<0,
145 	Start		= 1<<1,
146 	Stop		= 1<<2,
147 	RxOn		= 1<<3,
148 	TxOn		= 1<<4,
149 	Tdmd		= 1<<5,
150 	Rdmd		= 1<<6,
151 	EarlyRx		= 1<<8,
152 	Reserved0	= 1<<9,
153 	FullDuplex	= 1<<10,
154 	NoAutoPoll	= 1<<11,
155 	Reserved1	= 1<<12,
156 	Tdmd1		= 1<<13,
157 	Rdmd1		= 1<<14,
158 	Reset		= 1<<15,
159 };
160 
161 enum Isrbits {
162 	RxOk		= 1<<0,
163 	TxOk		= 1<<1,
164 	RxErr		= 1<<2,
165 	TxErr		= 1<<3,
166 	TxBufUdf	= 1<<4,
167 	RxBufLinkErr	= 1<<5,
168 	BusErr		= 1<<6,
169 	CrcOvf		= 1<<7,
170 	EarlyRxInt	= 1<<8,
171 	TxFifoUdf	= 1<<9,
172 	RxFifoOvf	= 1<<10,
173 	TxPktRace	= 1<<11,
174 	NoRxbuf		= 1<<12,
175 	TxCollision	= 1<<13,
176 	PortCh		= 1<<14,
177 	GPInt		= 1<<15,
178 };
179 
180 enum {					/* Bcr0 */
181 	DmaMASK		= 0x07,		/* DMA Length */
182 	DmaSHIFT	= 0,
183 	Dma32		= 0<<DmaSHIFT,
184 	Dma64		= 1<<DmaSHIFT,
185 	Dma128		= 2<<DmaSHIFT,
186 	Dma256		= 3<<DmaSHIFT,
187 	Dma512		= 4<<DmaSHIFT,
188 	Dma1024		= 5<<DmaSHIFT,
189 	DmaSAF		= 7<<DmaSHIFT,
190 	CrftMASK	= 0x38,		/* Rx FIFO Threshold */
191 	CrftSHIFT	= 3,
192 	Crft64		= 1<<CrftSHIFT,
193 	Crft128		= 2<<CrftSHIFT,
194 	Crft256		= 3<<CrftSHIFT,
195 	Crft512		= 4<<CrftSHIFT,
196 	Crft1024	= 5<<CrftSHIFT,
197 	CrftSAF		= 7<<CrftSHIFT,
198 	Extled		= 0x40,		/* Extra LED Support Control */
199 	Med2		= 0x80,		/* Medium Select Control */
200 };
201 
202 enum {					/* Bcr1 */
203 	PotMASK		= 0x07,		/* Polling Timer Interval */
204 	PotSHIFT	= 0,
205 	CtftMASK	= 0x38,		/* Tx FIFO Threshold */
206 	CtftSHIFT	= 3,
207 	Ctft64		= 1<<CtftSHIFT,
208 	Ctft128		= 2<<CtftSHIFT,
209 	Ctft256		= 3<<CtftSHIFT,
210 	Ctft512		= 4<<CtftSHIFT,
211 	Ctft1024	= 5<<CtftSHIFT,
212 	CtftSAF		= 7<<CtftSHIFT,
213 };
214 
215 
216 enum Eecsrbits {
217 	EeAutoLoad	= 1<<5,
218 };
219 
220 enum Descbits {
221 	OwnNic		= 1<<31,	/* stat */
222 	TxAbort		= 1<<8,		/* stat */
223 	TxError		= 1<<15,	/* stat */
224 	RxChainbuf	= 1<<10,	/* stat */
225 	RxChainStart	= 1<<9,		/* stat */
226 	RxChainEnd	= 1<<8,		/* stat */
227 	Chainbuf	= 1<<15,	/* size rx & tx*/
228 	TxDisableCrc	= 1<<16,	/* size */
229 	TxChainStart	= 1<<21,	/* size */
230 	TxChainEnd	= 1<<22,	/* size */
231 	TxInt		= 1<<23,	/* size */
232 };
233 
234 enum RhineMiiCrbits {
235 	Mdc	= 1<<0,
236 	Mdi	= 1<<1,
237 	Mdo	= 1<<2,
238 	Mdout	= 1<<3,
239 	Mdpm	= 1<<4,
240 	Wcmd	= 1<<5,
241 	Rcmd	= 1<<6,
242 	Mauto	= 1<<7,
243 };
244 
245 static void
246 attach(Ether *edev)
247 {
248 	Ctlr *ctlr;
249 	Desc *txd, *rxd, *td, *rd;
250 	Mii *mi;
251 	MiiPhy *phy;
252 	int i, s;
253 
254 	ctlr = edev->ctlr;
255 	qlock(&ctlr->attachlck);
256 	if (ctlr->attached == 0) {
257 		txd = ctlr->txd;
258 		rxd = ctlr->rxd;
259 		for (i = 0; i < Ntxd; ++i) {
260 			td = &txd[i];
261 			td->next = PCIWADDR(&txd[(i+1) % Ntxd]);
262 			td->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0);
263 			td->addr = PCIWADDR(td->buf);
264 			td->size = 0;
265 			coherence();
266 			td->stat = 0;
267 		}
268 		for (i = 0; i < Nrxd; ++i) {
269 			rd = &rxd[i];
270 			rd->next = PCIWADDR(&rxd[(i+1) % Nrxd]);
271 			rd->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0);
272 			rd->addr = PCIWADDR(rd->buf);
273 			rd->size = sizeof(Etherpkt)+4;
274 			coherence();
275 			rd->stat = OwnNic;
276 		}
277 
278 		ctlr->txhead = ctlr->txtail = ctlr->rxtail = 0;
279 		mi = &ctlr->mii;
280 		miistatus(mi);
281 		phy = mi->curphy;
282 		s = splhi();
283 		iow32(ctlr, TxdAddr, PCIWADDR(&txd[0]));
284 		iow32(ctlr, RxdAddr, PCIWADDR(&rxd[0]));
285 		iow16(ctlr, Cr, (phy->fd? FullDuplex: 0) | NoAutoPoll | TxOn |
286 			RxOn | Start | Rdmd);
287 		iow16(ctlr, Isr, 0xFFFF);
288 		iow16(ctlr, Imr, 0xFFFF);
289 		iow8(ctlr, MiscIsr, 0xFF);
290 		iow8(ctlr, MiscImr, ~(3<<5));
291 		splx(s);
292 		ctlr->attached = 1;
293 	}
294 	qunlock(&ctlr->attachlck);
295 }
296 
297 static void
298 txstart(Ether *edev)
299 {
300 	Ctlr *ctlr;
301 	Desc *txd, *td;
302 	int i, txused, n;
303 	RingBuf *tb;
304 
305 	ctlr = edev->ctlr;
306 	txd = ctlr->txd;
307 	i = ctlr->txhead;
308 	n = 0;
309 	for (txused = ctlr->txused; txused < Ntxd; txused++) {
310 		tb = &edev->tb[edev->ti];
311 		if(tb->owner != Interface)
312 			break;
313 
314 		td = &txd[i];
315 		memmove(td->buf, tb->pkt, tb->len);
316 		/* could reduce number of intrs here */
317 		td->size = tb->len | TxChainStart | TxChainEnd | TxInt;
318 		coherence();
319 		td->stat = OwnNic;
320 		i = (i + 1) % Ntxd;
321 		n++;
322 
323 		tb->owner = Host;
324 		edev->ti = NEXT(edev->ti, edev->ntb);
325 	}
326 	if (n)
327 		iow16(ctlr, Cr, ior16(ctlr, Cr) | Tdmd);
328 
329 	ctlr->txhead = i;
330 	ctlr->txused = txused;
331 }
332 
333 static void
334 transmit(Ether *edev)
335 {
336 	Ctlr *ctlr;
337 
338 	ctlr = edev->ctlr;
339 	ilock(&ctlr->tlock);
340 	txstart(edev);
341 	iunlock(&ctlr->tlock);
342 }
343 
344 static void
345 txcomplete(Ether *edev)
346 {
347 	Ctlr *ctlr;
348 	Desc *txd, *td;
349 	int i, txused;
350 	ulong stat;
351 
352 	ctlr = edev->ctlr;
353  	txd = ctlr->txd;
354 	i = ctlr->txtail;
355 	for (txused = ctlr->txused; txused > 0; txused--) {
356 		td = &txd[i];
357 		stat = td->stat;
358 		if (stat & OwnNic)
359 			break;
360 		i = (i + 1) % Ntxd;
361 	}
362 	ctlr->txused = txused;
363 	ctlr->txtail = i;
364 
365 	if (txused <= Ntxd/2)
366 		txstart(edev);
367 }
368 
369 static void
370 interrupt(Ureg *, void *arg)
371 {
372 	Ether *edev;
373 	Ctlr *ctlr;
374 	RingBuf *rb;
375 	ushort  isr, misr;
376 	ulong stat;
377 	Desc *rxd, *rd;
378 	int i, n, size;
379 
380 	edev = (Ether*)arg;
381 	ctlr = edev->ctlr;
382 	iow16(ctlr, Imr, 0);
383 	isr = ior16(ctlr, Isr);
384 	iow16(ctlr, Isr, 0xFFFF);
385 	/* don't care about used defined intrs */
386 	misr = ior16(ctlr, MiscIsr) & ~(3<<5);
387 
388 	if (isr & RxOk) {
389 		rxd = ctlr->rxd;
390 		i = ctlr->rxtail;
391 
392 		n = 0;
393 		while ((rxd[i].stat & OwnNic) == 0) {
394 			rd = &rxd[i];
395 			stat = rd->stat;
396 			if (stat & 0xFF)
397 				iprint("rx: %lux\n", stat & 0xFF);
398 			size = ((rd->stat>>16) & (2048-1)) - 4;
399 
400 			rb = &edev->rb[edev->ri];
401 			if(rb->owner == Interface){
402 				rb->owner = Host;
403 				rb->len = size;
404 				memmove(rb->pkt, rd->buf, size);
405 				edev->ri = NEXT(edev->ri, edev->nrb);
406 			}
407 
408 			rd->size = sizeof(Etherpkt)+4;
409 			coherence();
410 			rd->stat = OwnNic;
411 			i = (i + 1) % Nrxd;
412 			n++;
413 		}
414 		if (n)
415 			iow16(ctlr, Cr, ior16(ctlr, Cr) | Rdmd);
416 		ctlr->rxtail = i;
417 		isr &= ~RxOk;
418 	}
419 	if (isr & TxOk) {
420 		txcomplete(edev);
421 		isr &= ~TxOk;
422 	}
423 	if (isr | misr)
424 		iprint("etherrhine: unhandled irq(s). isr:%x misr:%x\n",
425 			isr, misr);
426 	iow16(ctlr, Imr, 0xFFFF);
427 }
428 
429 static int
430 miiread(Mii *mii, int phy, int reg)
431 {
432 	Ctlr *ctlr;
433 	int n;
434 
435 	ctlr = mii->ctlr;
436 
437 	n = Nwait;
438 	while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd))
439 		microdelay(1);
440 	if (n == Nwait)
441 		iprint("etherrhine: miiread: timeout\n");
442 
443 	iow8(ctlr, RhineMiiCr, 0);
444 	iow8(ctlr, RhineMiiPhy, phy);
445 	iow8(ctlr, RhineMiiAddr, reg);
446 	iow8(ctlr, RhineMiiCr, Rcmd);
447 
448 	n = Nwait;
449 	while (n-- && ior8(ctlr, RhineMiiCr) & Rcmd)
450 		microdelay(1);
451 	if (n == Nwait)
452 		iprint("etherrhine: miiread: timeout\n");
453 
454 	return ior16(ctlr, RhineMiiData);
455 }
456 
457 static int
458 miiwrite(Mii *mii, int phy, int reg, int data)
459 {
460 	int n;
461 	Ctlr *ctlr;
462 
463 	ctlr = mii->ctlr;
464 
465 	n = Nwait;
466 	while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd))
467 		microdelay(1);
468 	if (n == Nwait)
469 		iprint("etherrhine: miiwrite: timeout\n");
470 
471 	iow8(ctlr, RhineMiiCr, 0);
472 	iow8(ctlr, RhineMiiPhy, phy);
473 	iow8(ctlr, RhineMiiAddr, reg);
474 	iow16(ctlr, RhineMiiData, data);
475 	iow8(ctlr, RhineMiiCr, Wcmd);
476 
477 	n = Nwait;
478 	while (n-- && ior8(ctlr, RhineMiiCr) & Wcmd)
479 		microdelay(1);
480 	if (n == Nwait)
481 		iprint("etherrhine: miiwrite: timeout\n");
482 
483 	return 0;
484 }
485 
486 static void
487 reset(Ctlr* ctlr)
488 {
489 	int r, timeo;
490 
491 	/*
492 	 * Soft reset the controller.
493 	 */
494 	csr16w(ctlr, Cr, Stop);
495 	csr16w(ctlr, Cr, Stop|Reset);
496 	for(timeo = 0; timeo < 10000; timeo++){
497 		if(!(csr16r(ctlr, Cr) & Reset))
498 			break;
499 		microdelay(1);
500 	}
501 	if(timeo >= 1000)
502 		return;
503 
504 	/*
505 	 * Load the MAC address into the PAR[01]
506 	 * registers.
507 	 */
508 	r = csr8r(ctlr, Eecsr);
509 	csr8w(ctlr, Eecsr, EeAutoLoad|r);
510 	for(timeo = 0; timeo < 100; timeo++){
511 		if(!(csr8r(ctlr, Cr) & EeAutoLoad))
512 			break;
513 		microdelay(1);
514 	}
515 	if(timeo >= 100)
516 		return;
517 
518 	/*
519 	 * Configure DMA and Rx/Tx thresholds.
520 	 * If the Rx/Tx threshold bits in Bcr[01] are 0 then
521 	 * the thresholds are determined by Rcr/Tcr.
522 	 */
523 	r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
524 	csr8w(ctlr, Bcr0, r|Crft64|Dma64);
525 	r = csr8r(ctlr, Bcr1) & ~CtftMASK;
526 	csr8w(ctlr, Bcr1, r|Ctft64);
527 
528 	r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
529 	csr8w(ctlr, Rcr, r|Ab|Am);
530 
531 	r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
532 	csr8w(ctlr, Tcr, r);
533 }
534 
535 static void
536 detach(Ether* edev)
537 {
538 	reset(edev->ctlr);
539 }
540 
541 static void
542 init(Ether *edev)
543 {
544 	Ctlr *ctlr;
545 	int i;
546 
547 	ctlr = edev->ctlr;
548 	ilock(&ctlr->tlock);
549 
550 	pcisetbme(ctlr->pci);
551 	reset(ctlr);
552 
553 	iow8(ctlr, Eecsr, ior8(ctlr, Eecsr) | EeAutoLoad);
554 	for (i = 0; i < Nwait; ++i) {
555 		if ((ior8(ctlr, Eecsr) & EeAutoLoad) == 0)
556 			break;
557 		delay(5);
558 	}
559 	if (i >= Nwait)
560 		iprint("etherrhine: eeprom autoload timeout\n");
561 
562 	for (i = 0; i < Eaddrlen; ++i)
563 		edev->ea[i] = ior8(ctlr, Eaddr + i);
564 
565 	ctlr->mii.mir = miiread;
566 	ctlr->mii.miw = miiwrite;
567 	ctlr->mii.ctlr = ctlr;
568 
569 	if(mii(&ctlr->mii, ~0) == 0 || ctlr->mii.curphy == nil){
570 		iunlock(&ctlr->tlock);
571 		iprint("etherrhine: init mii failure\n");
572 		return;
573 	}
574 	for (i = 0; i < NMiiPhy; ++i)
575 		if (ctlr->mii.phy[i])
576 			if (ctlr->mii.phy[i]->oui != 0xFFFFF)
577 				ctlr->mii.curphy = ctlr->mii.phy[i];
578 	miistatus(&ctlr->mii);
579 
580 	iow16(ctlr, Imr, 0);
581 	iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop);
582 
583 	iunlock(&ctlr->tlock);
584 }
585 
586 static Pcidev *
587 rhinematch(ulong)
588 {
589 	static int nrhines = 0;
590 	int nfound = 0;
591 	Pcidev *p = nil;
592 
593 	while(p = pcimatch(p, 0x1106, 0)){
594 		if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
595 			continue;
596 		switch((p->did<<16)|p->vid){
597 		default:
598 			continue;
599 		case (0x3053<<16)|0x1106:	/* Rhine III vt6105m (Soekris) */
600 		case (0x3065<<16)|0x1106:	/* Rhine II */
601 		case (0x3106<<16)|0x1106:	/* Rhine III */
602 			if (++nfound > nrhines) {
603 				nrhines++;
604 				return p;
605 			}
606 			break;
607 		}
608 	}
609 	return p;
610 }
611 
612 int
613 rhinepnp(Ether *edev)
614 {
615 	Pcidev *p;
616 	Ctlr *ctlr;
617 	ulong port;
618 
619 	if (edev->attach)
620 		return 0;
621 	p = rhinematch(edev->port);
622 	if (p == nil)
623 		return -1;
624 
625 	port = p->mem[0].bar & ~1;
626 
627 	if ((ctlr = malloc(sizeof(Ctlr))) == nil) {
628 		print("etherrhine: couldn't allocate memory for ctlr\n");
629 		return -1;
630 	}
631 	memset(ctlr, 0, sizeof(Ctlr));
632 	ctlr->txd = xspanalloc(sizeof(Desc) * Ntxd, 16, 0);
633 	ctlr->rxd = xspanalloc(sizeof(Desc) * Nrxd, 16, 0);
634 
635 	ctlr->pci = p;
636 	ctlr->port = port;
637 
638 	edev->ctlr = ctlr;
639 	edev->port = ctlr->port;
640 	edev->irq = p->intl;
641 	edev->tbdf = p->tbdf;
642 
643 	init(edev);
644 
645 	edev->attach = attach;
646 	edev->transmit = transmit;
647 	edev->interrupt = interrupt;
648 	edev->detach = detach;
649 
650 	return 0;
651 }
652 
653 int
654 vt6102pnp(Ether *edev)
655 {
656 	return rhinepnp(edev);
657 }
658