xref: /plan9/sys/src/9/ppc/etherfcc.c (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
1 /*
2  * FCCn ethernet
3  */
4 
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "imm.h"
12 #include "../port/error.h"
13 #include "../port/netif.h"
14 
15 #include "etherif.h"
16 #include "../ppc/ethermii.h"
17 
18 #define DBG 1
19 
20 enum {
21 	Nrdre		= 128,			/* receive descriptor ring entries */
22 	Ntdre		= 128,			/* transmit descriptor ring entries */
23 
24 	Rbsize		= ETHERMAXTU+4,		/* ring buffer size (+4 for CRC) */
25 	Bufsize		= Rbsize+CACHELINESZ,	/* extra room for alignment */
26 };
27 
28 enum {
29 
30 	/* ether-specific Rx BD bits */
31 	RxMiss=		SBIT(7),
32 	RxeLG=		SBIT(10),
33 	RxeNO=		SBIT(11),
34 	RxeSH=		SBIT(12),
35 	RxeCR=		SBIT(13),
36 	RxeOV=		SBIT(14),
37 	RxeCL=		SBIT(15),
38 	RxError=	(RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL),	/* various error flags */
39 
40 	/* ether-specific Tx BD bits */
41 	TxPad=		SBIT(1),	/* pad short frames */
42 	TxTC=		SBIT(5),	/* transmit CRC */
43 	TxeDEF=		SBIT(6),
44 	TxeHB=		SBIT(7),
45 	TxeLC=		SBIT(8),
46 	TxeRL=		SBIT(9),
47 	TxeUN=		SBIT(14),
48 	TxeCSL=		SBIT(15),
49 
50 	/* psmr */
51 	CRCE=		BIT(24),	/* Ethernet CRC */
52 	FCE=		BIT(10),	/* flow control */
53 	PRO=		BIT(9),		/* promiscuous mode */
54 	FDE=		BIT(5),		/* full duplex ethernet */
55 	LPB=		BIT(3),		/* local protect bit */
56 
57 	/* gfmr */
58 	ENET=		0xc,		/* ethernet mode */
59 	ENT=		BIT(27),
60 	ENR=		BIT(26),
61 	TCI=		BIT(2),
62 
63 	/* FCC function code register */
64 	GBL=		0x20,
65 	BO=		0x18,
66 	EB=		0x10,		/* Motorola byte order */
67 	TC2=		0x04,
68 	DTB=		0x02,
69 	BDB=		0x01,
70 
71 	/* FCC Event/Mask bits */
72 	GRA=		SBIT(8),
73 	RXC=		SBIT(9),
74 	TXC=		SBIT(10),
75 	TXE=		SBIT(11),
76 	RXF=		SBIT(12),
77 	BSY=		SBIT(13),
78 	TXB=		SBIT(14),
79 	RXB=		SBIT(15),
80 };
81 
82 enum {		/* Mcr */
83 	MDIread	=	0x60020000,	/* read opcode */
84 	MDIwrite =	0x50020000,	/* write opcode */
85 };
86 
87 typedef struct Etherparam Etherparam;
88 struct Etherparam {
89 /*0x00*/	FCCparam;
90 /*0x3c*/	ulong	stat_buf;
91 /*0x40*/	ulong	cam_ptr;
92 /*0x44*/	ulong	cmask;
93 /*0x48*/	ulong	cpres;
94 /*0x4c*/	ulong	crcec;
95 /*0x50*/	ulong	alec;
96 /*0x54*/	ulong	disfc;
97 /*0x58*/	ushort	retlim;
98 /*0x5a*/	ushort	retcnt;
99 /*0x5c*/	ushort	p_per;
100 /*0x5e*/	ushort	boff_cnt;
101 /*0x60*/	ulong	gaddr[2];
102 /*0x68*/	ushort	tfcstat;
103 /*0x6a*/	ushort	tfclen;
104 /*0x6c*/	ulong	tfcptr;
105 /*0x70*/	ushort	mflr;
106 /*0x72*/	ushort	paddr[3];
107 /*0x78*/	ushort	ibd_cnt;
108 /*0x7a*/	ushort	ibd_start;
109 /*0x7c*/	ushort	ibd_end;
110 /*0x7e*/	ushort	tx_len;
111 /*0x80*/	uchar	ibd_base[32];
112 /*0xa0*/	ulong	iaddr[2];
113 /*0xa8*/	ushort	minflr;
114 /*0xaa*/	ushort	taddr[3];
115 /*0xb0*/	ushort	padptr;
116 /*0xb2*/	ushort	Rsvdb2;
117 /*0xb4*/	ushort	cf_range;
118 /*0xb6*/	ushort	max_b;
119 /*0xb8*/	ushort	maxd1;
120 /*0xba*/	ushort	maxd2;
121 /*0xbc*/	ushort	maxd;
122 /*0xbe*/	ushort	dma_cnt;
123 /*0xc0*/	ulong	octc;
124 /*0xc4*/	ulong	colc;
125 /*0xc8*/	ulong	broc;
126 /*0xcc*/	ulong	mulc;
127 /*0xd0*/	ulong	uspc;
128 /*0xd4*/	ulong	frgc;
129 /*0xd8*/	ulong	ospc;
130 /*0xdc*/	ulong	jbrc;
131 /*0xe0*/	ulong	p64c;
132 /*0xe4*/	ulong	p65c;
133 /*0xe8*/	ulong	p128c;
134 /*0xec*/	ulong	p256c;
135 /*0xf0*/	ulong	p512c;
136 /*0xf4*/	ulong	p1024c;
137 /*0xf8*/	ulong	cam_buf;
138 /*0xfc*/	ulong	Rsvdfc;
139 /*0x100*/
140 };
141 
142 typedef struct Ctlr Ctlr;
143 struct Ctlr {
144 	Lock;
145 	int	fccid;
146 	int	port;
147 	ulong	pmdio;
148 	ulong	pmdck;
149 	int	init;
150 	int	active;
151 	int	duplex;		/* 1 == full */
152 	FCC*	fcc;
153 
154 	Ring;
155 	Block*	rcvbufs[Nrdre];
156 	Mii*	mii;
157 	Timer;
158 
159 	ulong	interrupts;	/* statistics */
160 	ulong	deferred;
161 	ulong	heartbeat;
162 	ulong	latecoll;
163 	ulong	retrylim;
164 	ulong	underrun;
165 	ulong	overrun;
166 	ulong	carrierlost;
167 	ulong	retrycount;
168 };
169 
170 static	int	fccirq[] = {0x20, 0x21, 0x22};
171 static	int	fccid[] = {FCC1ID, FCC2ID, FCC3ID};
172 
173 #ifdef DBG
174 ulong fccrhisto[16];
175 ulong fccthisto[16];
176 ulong fccrthisto[16];
177 ulong fcctrhisto[16];
178 ulong ehisto[0x80];
179 #endif
180 
181 static int fccmiimir(Mii*, int, int);
182 static int fccmiimiw(Mii*, int, int, int);
183 static void fccltimer(Ureg*, Timer*);
184 
185 static void
attach(Ether * ether)186 attach(Ether *ether)
187 {
188 	Ctlr *ctlr;
189 
190 	ctlr = ether->ctlr;
191 	ilock(ctlr);
192 	ctlr->active = 1;
193 	ctlr->fcc->gfmr |= ENR|ENT;
194 	iunlock(ctlr);
195 	ctlr->tmode = Tperiodic;
196 	ctlr->tf = fccltimer;
197 	ctlr->ta = ether;
198 	ctlr->tns = 5000000000LL;	/* 5 seconds */
199 	timeradd(ctlr);
200 }
201 
202 static void
closed(Ether * ether)203 closed(Ether *ether)
204 {
205 	Ctlr *ctlr;
206 
207 	ctlr = ether->ctlr;
208 	ilock(ctlr);
209 	ctlr->active = 0;
210 	ctlr->fcc->gfmr &= ~(ENR|ENT);
211 	iunlock(ctlr);
212 	print("Ether closed\n");
213 }
214 
215 static void
promiscuous(void * arg,int on)216 promiscuous(void* arg, int on)
217 {
218 	Ether *ether;
219 	Ctlr *ctlr;
220 
221 	ether = (Ether*)arg;
222 	ctlr = ether->ctlr;
223 
224 	ilock(ctlr);
225 	if(on || ether->nmaddr)
226 		ctlr->fcc->fpsmr |= PRO;
227 	else
228 		ctlr->fcc->fpsmr &= ~PRO;
229 	iunlock(ctlr);
230 }
231 
232 static void
multicast(void * arg,uchar * addr,int on)233 multicast(void* arg, uchar *addr, int on)
234 {
235 	Ether *ether;
236 	Ctlr *ctlr;
237 
238 	USED(addr, on);	/* if on, could SetGroupAddress; if !on, it's hard */
239 
240 	ether = (Ether*)arg;
241 	ctlr = ether->ctlr;
242 
243 	ilock(ctlr);
244 	if(ether->prom || ether->nmaddr)
245 		ctlr->fcc->fpsmr |= PRO;
246 	else
247 		ctlr->fcc->fpsmr &= ~PRO;
248 	iunlock(ctlr);
249 }
250 
251 static void
txstart(Ether * ether)252 txstart(Ether *ether)
253 {
254 	int len;
255 	Ctlr *ctlr;
256 	Block *b;
257 	BD *dre;
258 
259 	ctlr = ether->ctlr;
260 	if(ctlr->init)
261 		return;
262 	while(ctlr->ntq < Ntdre-1){
263 		b = qget(ether->oq);
264 		if(b == 0)
265 			break;
266 
267 		dre = &ctlr->tdr[ctlr->tdrh];
268 		dczap(dre, sizeof(BD));
269 		if(dre->status & BDReady)
270 			panic("ether: txstart");
271 
272 		/*
273 		 * Give ownership of the descriptor to the chip, increment the
274 		 * software ring descriptor pointer and tell the chip to poll.
275 		 */
276 		len = BLEN(b);
277 		if(ctlr->txb[ctlr->tdrh] != nil)
278 			panic("fcc/ether: txstart");
279 		ctlr->txb[ctlr->tdrh] = b;
280 		if((ulong)b->rp&1)
281 			panic("fcc/ether: txstart align");	/* TO DO: ensure alignment */
282 		dre->addr = PADDR(b->rp);
283 		dre->length = len;
284 		dcflush(b->rp, len);
285 		dcflush(dre, sizeof(BD));
286 		dre->status = (dre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC;
287 		dcflush(dre, sizeof(BD));
288 /*		ctlr->fcc->ftodr = 1<<15;	/* transmit now; Don't do this according to errata */
289 		ctlr->ntq++;
290 		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
291 	}
292 }
293 
294 static void
transmit(Ether * ether)295 transmit(Ether* ether)
296 {
297 	Ctlr *ctlr;
298 
299 	ctlr = ether->ctlr;
300 	ilock(ctlr);
301 	txstart(ether);
302 	iunlock(ctlr);
303 }
304 
305 static void
interrupt(Ureg *,void * arg)306 interrupt(Ureg*, void *arg)
307 {
308 	int len, status, rcvd, xmtd, restart;
309 	ushort events;
310 	Ctlr *ctlr;
311 	BD *dre;
312 	Block *b, *nb;
313 	Ether *ether = arg;
314 
315 	ctlr = ether->ctlr;
316 	if(!ctlr->active)
317 		return;	/* not ours */
318 
319 	/*
320 	 * Acknowledge all interrupts and whine about those that shouldn't
321 	 * happen.
322 	 */
323 	events = ctlr->fcc->fcce;
324 	ctlr->fcc->fcce = events;		/* clear events */
325 
326 #ifdef DBG
327 	ehisto[events & 0x7f]++;
328 #endif
329 
330 	ctlr->interrupts++;
331 
332 	if(events & BSY)
333 		ctlr->overrun++;
334 	if(events & TXE)
335 		ether->oerrs++;
336 
337 #ifdef DBG
338 	rcvd = xmtd = 0;
339 #endif
340 	/*
341 	 * Receiver interrupt: run round the descriptor ring logging
342 	 * errors and passing valid receive data up to the higher levels
343 	 * until we encounter a descriptor still owned by the chip.
344 	 */
345 	if(events & RXF){
346 		dre = &ctlr->rdr[ctlr->rdrx];
347 		dczap(dre, sizeof(BD));
348 		while(((status = dre->status) & BDEmpty) == 0){
349 			rcvd++;
350 			if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
351 				if(status & (RxeLG|RxeSH))
352 					ether->buffs++;
353 				if(status & RxeNO)
354 					ether->frames++;
355 				if(status & RxeCR)
356 					ether->crcs++;
357 				if(status & RxeOV)
358 					ether->overflows++;
359 				print("eth rx: %ux\n", status);
360 			}else{
361 				/*
362 				 * We have a packet. Read it in.
363 				 */
364 				len = dre->length-4;
365 				b = ctlr->rcvbufs[ctlr->rdrx];
366 				assert(dre->addr == PADDR(b->rp));
367 				dczap(b->rp, len);
368 				if(nb = iallocb(Bufsize)){
369 					b->wp += len;
370 					etheriq(ether, b, 1);
371 					b = nb;
372 					b->rp = (uchar*)(((ulong)b->rp + CACHELINESZ-1) & ~(CACHELINESZ-1));
373 					b->wp = b->rp;
374 					ctlr->rcvbufs[ctlr->rdrx] = b;
375 					ctlr->rdr[ctlr->rdrx].addr = PADDR(b->wp);
376 				}else
377 					ether->soverflows++;
378 			}
379 
380 			/*
381 			 * Finished with this descriptor, reinitialise it,
382 			 * give it back to the chip, then on to the next...
383 			 */
384 			dre->length = 0;
385 			dre->status = (status & BDWrap) | BDEmpty | BDInt;
386 			dcflush(dre, sizeof(BD));
387 
388 			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
389 			dre = &ctlr->rdr[ctlr->rdrx];
390 			dczap(dre, sizeof(BD));
391 		}
392 	}
393 
394 	/*
395 	 * Transmitter interrupt: handle anything queued for a free descriptor.
396 	 */
397 	if(events & (TXB|TXE)){
398 		ilock(ctlr);
399 		restart = 0;
400 		while(ctlr->ntq){
401 			dre = &ctlr->tdr[ctlr->tdri];
402 			dczap(dre, sizeof(BD));
403 			status = dre->status;
404 			if(status & BDReady)
405 				break;
406 			if(status & TxeDEF)
407 				ctlr->deferred++;
408 			if(status & TxeHB)
409 				ctlr->heartbeat++;
410 			if(status & TxeLC)
411 				ctlr->latecoll++;
412 			if(status & TxeRL)
413 				ctlr->retrylim++;
414 			if(status & TxeUN)
415 				ctlr->underrun++;
416 			if(status & TxeCSL)
417 				ctlr->carrierlost++;
418 			if(status & (TxeLC|TxeRL|TxeUN))
419 				restart = 1;
420 			ctlr->retrycount += (status>>2)&0xF;
421 			b = ctlr->txb[ctlr->tdri];
422 			if(b == nil)
423 				panic("fcce/interrupt: bufp");
424 			ctlr->txb[ctlr->tdri] = nil;
425 			freeb(b);
426 			ctlr->ntq--;
427 			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
428 			xmtd++;
429 		}
430 
431 		if(restart){
432 			ctlr->fcc->gfmr &= ~ENT;
433 			delay(10);
434 			ctlr->fcc->gfmr |= ENT;
435 			cpmop(RestartTx, ctlr->fccid, 0xc);
436 		}
437 		txstart(ether);
438 		iunlock(ctlr);
439 	}
440 #ifdef DBG
441 	if(rcvd >= nelem(fccrhisto))
442 		rcvd = nelem(fccrhisto) - 1;
443 	if(xmtd >= nelem(fccthisto))
444 		xmtd = nelem(fccthisto) - 1;
445 	if(rcvd)
446 		fcctrhisto[xmtd]++;
447 	else
448 		fccthisto[xmtd]++;
449 	if(xmtd)
450 		fccrthisto[rcvd]++;
451 	else
452 		fccrhisto[rcvd]++;
453 #endif
454 }
455 
456 static long
ifstat(Ether * ether,void * a,long n,ulong offset)457 ifstat(Ether* ether, void* a, long n, ulong offset)
458 {
459 	char *p;
460 	int len, i, r;
461 	Ctlr *ctlr;
462 	MiiPhy *phy;
463 
464 	if(n == 0)
465 		return 0;
466 
467 	ctlr = ether->ctlr;
468 
469 	p = malloc(READSTR);
470 	len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
471 	len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->carrierlost);
472 	len += snprint(p+len, READSTR-len, "heartbeat: %lud\n", ctlr->heartbeat);
473 	len += snprint(p+len, READSTR-len, "retrylimit: %lud\n", ctlr->retrylim);
474 	len += snprint(p+len, READSTR-len, "retrycount: %lud\n", ctlr->retrycount);
475 	len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->latecoll);
476 	len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->overrun);
477 	len += snprint(p+len, READSTR-len, "txunderruns: %lud\n", ctlr->underrun);
478 	len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->deferred);
479 	miistatus(ctlr->mii);
480 	phy = ctlr->mii->curphy;
481 	len += snprint(p+len, READSTR-len, "phy: link=%d, tfc=%d, rfc=%d, speed=%d, fd=%d\n",
482 		phy->link, phy->tfc, phy->rfc, phy->speed, phy->fd);
483 
484 #ifdef DBG
485 	if(ctlr->mii != nil && ctlr->mii->curphy != nil){
486 		len += snprint(p+len, READSTR, "phy:   ");
487 		for(i = 0; i < NMiiPhyr; i++){
488 			if(i && ((i & 0x07) == 0))
489 				len += snprint(p+len, READSTR-len, "\n       ");
490 			r = miimir(ctlr->mii, i);
491 			len += snprint(p+len, READSTR-len, " %4.4uX", r);
492 		}
493 		snprint(p+len, READSTR-len, "\n");
494 	}
495 #endif
496 	snprint(p+len, READSTR-len, "\n");
497 
498 	n = readstr(offset, a, n, p);
499 	free(p);
500 
501 	return n;
502 }
503 
504 IMM* imm;
505 
506 /*
507  * This follows the MPC8260 user guide: section28.9's initialisation sequence.
508  */
509 static int
fccsetup(Ctlr * ctlr,FCC * fcc,uchar * ea)510 fccsetup(Ctlr *ctlr, FCC *fcc, uchar *ea)
511 {
512 	int i;
513 	Etherparam *p;
514 	MiiPhy *phy;
515 
516 	/* Turn Ethernet off */
517 	fcc->gfmr &= ~(ENR | ENT);
518 
519 	ioplock();
520 	switch(ctlr->port) {
521 	default:
522 		iopunlock();
523 		return -1;
524 	case 0:
525 		/* Step 1 (Section 28.9), write the parallel ports */
526 		ctlr->pmdio = 0x01000000;
527 		ctlr->pmdck = 0x08000000;
528 		imm->port[0].pdir &= ~A1dir0;
529 		imm->port[0].pdir |= A1dir1;
530 		imm->port[0].psor &= ~A1psor0;
531 		imm->port[0].psor |= A1psor1;
532 		imm->port[0].ppar |= (A1dir0 | A1dir1);
533 		/* Step 2, Port C clocks */
534 		imm->port[2].psor &= ~0x00000c00;
535 		imm->port[2].pdir &= ~0x00000c00;
536 		imm->port[2].ppar |= 0x00000c00;
537 		imm->port[3].pdat |= (ctlr->pmdio | ctlr->pmdck);
538 		imm->port[3].podr |= ctlr->pmdio;
539 		imm->port[3].pdir |= (ctlr->pmdio | ctlr->pmdck);
540 		imm->port[3].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
541 		eieio();
542 		/* Step 3, Serial Interface clock routing */
543 		imm->cmxfcr &= ~0xff000000;	/* Clock mask */
544 		imm->cmxfcr |= 0x37000000;	/* Clock route */
545 		break;
546 
547 	case 1:
548 		/* Step 1 (Section 28.9), write the parallel ports */
549 		ctlr->pmdio = 0x00400000;
550 		ctlr->pmdck = 0x00200000;
551 		imm->port[1].pdir &= ~B2dir0;
552 		imm->port[1].pdir |= B2dir1;
553 		imm->port[1].psor &= ~B2psor0;
554 		imm->port[1].psor |= B2psor1;
555 		imm->port[1].ppar |= (B2dir0 | B2dir1);
556 		/* Step 2, Port C clocks */
557 		imm->port[2].psor &= ~0x00003000;
558 		imm->port[2].pdir &= ~0x00003000;
559 		imm->port[2].ppar |= 0x00003000;
560 
561 		imm->port[2].pdat |= (ctlr->pmdio | ctlr->pmdck);
562 		imm->port[2].podr |= ctlr->pmdio;
563 		imm->port[2].pdir |= (ctlr->pmdio | ctlr->pmdck);
564 		imm->port[2].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
565 		eieio();
566 		/* Step 3, Serial Interface clock routing */
567 		imm->cmxfcr &= ~0x00ff0000;
568 		imm->cmxfcr |= 0x00250000;
569 		break;
570 
571 	case 2:
572 		/* Step 1 (Section 28.9), write the parallel ports */
573 		imm->port[1].pdir &= ~B3dir0;
574 		imm->port[1].pdir |= B3dir1;
575 		imm->port[1].psor &= ~B3psor0;
576 		imm->port[1].psor |= B3psor1;
577 		imm->port[1].ppar |= (B3dir0 | B3dir1);
578 		/* Step 2, Port C clocks */
579 		imm->port[2].psor &= ~0x0000c000;
580 		imm->port[2].pdir &= ~0x0000c000;
581 		imm->port[2].ppar |= 0x0000c000;
582 		imm->port[3].pdat |= (ctlr->pmdio | ctlr->pmdck);
583 		imm->port[3].podr |= ctlr->pmdio;
584 		imm->port[3].pdir |= (ctlr->pmdio | ctlr->pmdck);
585 		imm->port[3].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
586 		eieio();
587 		/* Step 3, Serial Interface clock routing */
588 		imm->cmxfcr &= ~0x0000ff00;
589 		imm->cmxfcr |= 0x00003700;
590 		break;
591 	}
592 	iopunlock();
593 
594 	p = (Etherparam*)(m->immr->prmfcc + ctlr->port);
595 	memset(p, 0, sizeof(Etherparam));
596 
597 	/* Step 4 */
598 	fcc->gfmr |= ENET;
599 
600 	/* Step 5 */
601 	fcc->fpsmr = CRCE | FDE | LPB;	/* full duplex operation */
602 	ctlr->duplex = ~0;
603 
604 	/* Step 6 */
605 	fcc->fdsr = 0xd555;
606 
607 	/* Step 7, initialize parameter ram */
608 	p->rbase = PADDR(ctlr->rdr);
609 	p->tbase = PADDR(ctlr->tdr);
610 	p->rstate = (GBL | EB) << 24;
611 	p->tstate = (GBL | EB) << 24;
612 
613 	p->cmask = 0xdebb20e3;
614 	p->cpres = 0xffffffff;
615 
616 	p->retlim = 15;	/* retry limit */
617 
618 	p->mrblr = (Rbsize+0x1f)&~0x1f;		/* multiple of 32 */
619 	p->mflr = Rbsize;
620 	p->minflr = ETHERMINTU;
621 	p->maxd1 = (Rbsize+7) & ~7;
622 	p->maxd2 = (Rbsize+7) & ~7;
623 
624 	for(i=0; i<Eaddrlen; i+=2)
625 		p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i];
626 
627 	/* Step 7, initialize parameter ram, configuration-dependent values */
628 	p->riptr = m->immr->fccextra[ctlr->port].ri - (uchar*)IMMR;
629 	p->tiptr = m->immr->fccextra[ctlr->port].ti - (uchar*)IMMR;
630 	p->padptr = m->immr->fccextra[ctlr->port].pad - (uchar*)IMMR;
631 	memset(m->immr->fccextra[ctlr->port].pad, 0x88, 0x20);
632 
633 	/* Step 8, clear out events */
634 	fcc->fcce = ~0;
635 
636 	/* Step 9, Interrupt enable */
637 	fcc->fccm = TXE | RXF | TXB;
638 
639 	/* Step 10, Configure interrupt priority (not done here) */
640 	/* Step 11, Clear out current events */
641 	/* Step 12, Enable interrupts to the CP interrupt controller */
642 
643 	/* Step 13, Issue the Init Tx and Rx command, specifying 0xc for ethernet*/
644 	cpmop(InitRxTx, fccid[ctlr->port], 0xc);
645 
646 	/* Step 14, Link management */
647 	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
648 		return -1;
649 	ctlr->mii->mir = fccmiimir;
650 	ctlr->mii->miw = fccmiimiw;
651 	ctlr->mii->ctlr = ctlr;
652 
653 	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
654 		free(ctlr->mii);
655 		ctlr->mii = nil;
656 		return -1;
657 	}
658 	miiane(ctlr->mii, ~0, ~0, ~0);
659 #ifdef DBG
660 	print("oui=%X, phyno=%d, ", phy->oui, phy->phyno);
661 	print("anar=%ux, ", phy->anar);
662 	print("fc=%ux, ", phy->fc);
663 	print("mscr=%ux, ", phy->mscr);
664 
665 	print("link=%ux, ", phy->link);
666 	print("speed=%ux, ", phy->speed);
667 	print("fd=%ux, ", phy->fd);
668 	print("rfc=%ux, ", phy->rfc);
669 	print("tfc=%ux\n", phy->tfc);
670 #endif
671 	/* Step 15, Enable ethernet: done at attach time */
672 	return 0;
673 }
674 
675 static int
reset(Ether * ether)676 reset(Ether* ether)
677 {
678 	uchar ea[Eaddrlen];
679 	Ctlr *ctlr;
680 	FCC *fcc;
681 	Block *b;
682 	int i;
683 
684 	if(m->cpuhz < 24000000){
685 		print("%s ether: system speed must be >= 24MHz for ether use\n", ether->type);
686 		return -1;
687 	}
688 
689 	if(ether->port > 3){
690 		print("%s ether: no FCC port %ld\n", ether->type, ether->port);
691 		return -1;
692 	}
693 	ether->irq = fccirq[ether->port];
694 	ether->tbdf = BusPPC;
695 	fcc = imm->fcc + ether->port;
696 
697 	ctlr = malloc(sizeof(*ctlr));
698 	ether->ctlr = ctlr;
699 	memset(ctlr, 0, sizeof(*ctlr));
700 	ctlr->fcc = fcc;
701 	ctlr->port = ether->port;
702 	ctlr->fccid = fccid[ether->port];
703 
704 	/* Ioringinit will allocate the buffer descriptors in normal memory
705 	 * and NOT in Dual-Ported Ram, as prescribed by the MPC8260
706 	 * PowerQUICC II manual (Section 28.6).  When they are allocated
707 	 * in DPram and the Dcache is enabled, the processor will hang
708 	 */
709 	if(ioringinit(ctlr, Nrdre, Ntdre, 0) < 0)
710 		panic("etherfcc init");
711 	for(i = 0; i < Nrdre; i++){
712 		b = iallocb(Bufsize);
713 		b->rp = (uchar*)(((ulong)b->rp + CACHELINESZ-1) & ~(CACHELINESZ-1));
714 		b->wp = b->rp;
715 		ctlr->rcvbufs[i] = b;
716 		ctlr->rdr[i].addr = PADDR(b->wp);
717 	}
718 
719 	fccsetup(ctlr, fcc, ether->ea);
720 
721 	ether->mbps = 100;	/* TO DO: could be 10mbps */
722 	ether->attach = attach;
723 	ether->transmit = transmit;
724 	ether->interrupt = interrupt;
725 	ether->ifstat = ifstat;
726 
727 	ether->arg = ether;
728 	ether->promiscuous = promiscuous;
729 	ether->multicast = multicast;
730 
731 	/*
732 	 * Until we know where to find it, insist that the plan9.ini
733 	 * entry holds the Ethernet address.
734 	 */
735 	memset(ea, 0, Eaddrlen);
736 	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
737 		print("no ether address");
738 		return -1;
739 	}
740 
741 	return 0;
742 }
743 
744 void
etherfcclink(void)745 etherfcclink(void)
746 {
747 	addethercard("fcc", reset);
748 }
749 
750 static void
nanodelay(void)751 nanodelay(void)
752 {
753 	static int count;
754 	int i;
755 
756 	for(i = 0; i < 500; i++)
757 		count++;
758 	return;
759 }
760 
761 static
miiwriteloop(Ctlr * ctlr,Port * port,int cnt,ulong cmd)762 void miiwriteloop(Ctlr *ctlr, Port *port, int cnt, ulong cmd)
763 {
764 	int i;
765 
766 	for(i = 0; i < cnt; i++){
767 		port->pdat &= ~ctlr->pmdck;
768 		if(cmd & BIT(i))
769 			port->pdat |= ctlr->pmdio;
770 		else
771 			port->pdat &= ~ctlr->pmdio;
772 		nanodelay();
773 		port->pdat |= ctlr->pmdck;
774 		nanodelay();
775 	}
776 }
777 
778 static int
fccmiimiw(Mii * mii,int pa,int ra,int data)779 fccmiimiw(Mii *mii, int pa, int ra, int data)
780 {
781 	int x;
782 	Port *port;
783 	ulong cmd;
784 	Ctlr *ctlr;
785 
786 	/*
787 	 * MII Management Interface Write.
788 	 */
789 
790 	ctlr = mii->ctlr;
791 	port = imm->port + 3;
792 	cmd = MDIwrite | (pa<<(5+2+16))| (ra<<(2+16)) | (data & 0xffff);
793 
794 	x = splhi();
795 
796 	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
797 	nanodelay();
798 
799 	miiwriteloop(ctlr, port, 32, ~0);
800 	miiwriteloop(ctlr, port, 32, cmd);
801 
802 	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
803 	nanodelay();
804 
805 	miiwriteloop(ctlr, port, 32, ~0);
806 
807 	splx(x);
808 	return 1;
809 }
810 
811 static int
fccmiimir(Mii * mii,int pa,int ra)812 fccmiimir(Mii *mii, int pa, int ra)
813 {
814 	int data, i, x;
815 	Port *port;
816 	ulong cmd;
817 	Ctlr *ctlr;
818 
819 	ctlr = mii->ctlr;
820 	port = imm->port + 3;
821 
822 	cmd = MDIread | pa<<(5+2+16) | ra<<(2+16);
823 
824 	x = splhi();
825 	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
826 	nanodelay();
827 
828 	miiwriteloop(ctlr, port, 32, ~0);
829 
830 	/* Clock out the first 14 MS bits of the command */
831 	miiwriteloop(ctlr, port, 14, cmd);
832 
833 	/* Turn-around */
834 	port->pdat &= ~ctlr->pmdck;
835 	port->pdir &= ~ctlr->pmdio;
836 	nanodelay();
837 
838 	/* For read, clock in 18 bits, use 16 */
839 	data = 0;
840 	for(i=0; i<18; i++){
841 		data <<= 1;
842 		if(port->pdat & ctlr->pmdio)
843 			data |= 1;
844 		port->pdat |= ctlr->pmdck;
845 		nanodelay();
846 		port->pdat &= ~ctlr->pmdck;
847 		nanodelay();
848 	}
849 	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
850 	nanodelay();
851 	miiwriteloop(ctlr, port, 32, ~0);
852 	splx(x);
853 	return data & 0xffff;
854 }
855 
856 static void
fccltimer(Ureg *,Timer * t)857 fccltimer(Ureg*, Timer *t)
858 {
859 	Ether *ether;
860 	Ctlr *ctlr;
861 	MiiPhy *phy;
862 	ulong gfmr;
863 
864 	ether = t->ta;
865 	ctlr = ether->ctlr;
866 	if(ctlr->mii == nil || ctlr->mii->curphy == nil)
867 		return;
868 	phy = ctlr->mii->curphy;
869 	if(miistatus(ctlr->mii) < 0){
870 		print("miistatus failed\n");
871 		return;
872 	}
873 	if(phy->link == 0){
874 		print("link lost\n");
875 		return;
876 	}
877 	ether->mbps = phy->speed;
878 
879 	if(phy->fd != ctlr->duplex)
880 		print("set duplex\n");
881 	ilock(ctlr);
882 	gfmr = ctlr->fcc->gfmr;
883 	if(phy->fd != ctlr->duplex){
884 		ctlr->fcc->gfmr &= ~(ENR|ENT);
885 		if(phy->fd)
886 			ctlr->fcc->fpsmr |= FDE | LPB;		/* full duplex operation */
887 		else
888 			ctlr->fcc->fpsmr &= ~(FDE | LPB);	/* half duplex operation */
889 		ctlr->duplex = phy->fd;
890 	}
891 	ctlr->fcc->gfmr = gfmr;
892 	iunlock(ctlr);
893 }
894