xref: /inferno-os/os/mpc/etherscc.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 /*
2  * SCCn ethernet
3  */
4 
5 #include "u.h"
6 #include "lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
13 
14 #include "etherif.h"
15 
16 enum {
17 	Nrdre		= 16,	/* receive descriptor ring entries */
18 	Ntdre		= 16,	/* transmit descriptor ring entries */
19 
20 	Rbsize		= ETHERMAXTU+4,		/* ring buffer size (+4 for CRC) */
21 	Bufsize		= (Rbsize+7)&~7,	/* aligned */
22 };
23 
24 enum {
25 	/* ether-specific Rx BD bits */
26 	RxMiss=		1<<8,
27 	RxeLG=		1<<5,
28 	RxeNO=		1<<4,
29 	RxeSH=		1<<3,
30 	RxeCR=		1<<2,
31 	RxeOV=		1<<1,
32 	RxeCL=		1<<0,
33 	RxError=		(RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL),	/* various error flags */
34 
35 	/* ether-specific Tx BD bits */
36 	TxPad=		1<<14,	/* pad short frames */
37 	TxTC=		1<<10,	/* transmit CRC */
38 	TxeDEF=		1<<9,
39 	TxeHB=		1<<8,
40 	TxeLC=		1<<7,
41 	TxeRL=		1<<6,
42 	TxeUN=		1<<1,
43 	TxeCSL=		1<<0,
44 
45 	/* scce */
46 	RXB=	1<<0,
47 	TXB=	1<<1,
48 	BSY=		1<<2,
49 	RXF=		1<<3,
50 	TXE=		1<<4,
51 
52 	/* psmr */
53 	PRO=	1<<9,	/* promiscuous mode */
54 
55 	/* gsmrl */
56 	ENR=	1<<5,
57 	ENT=	1<<4,
58 
59 	/* port A */
60 	RXD1=	SIBIT(15),
61 	TXD1=	SIBIT(14),
62 
63 	/* port B */
64 	RTS1=	IBIT(19),
65 
66 	/* port C */
67 	CTS1=	SIBIT(11),
68 	CD1=	SIBIT(10),
69 };
70 
71 typedef struct Etherparam Etherparam;
72 struct Etherparam {
73 	SCCparam;
74 	ulong	c_pres;		/* preset CRC */
75 	ulong	c_mask;		/* constant mask for CRC */
76 	ulong	crcec;		/* CRC error counter */
77 	ulong	alec;		/* alighnment error counter */
78 	ulong	disfc;		/* discard frame counter */
79 	ushort	pads;		/* short frame PAD characters */
80 	ushort	ret_lim;	/* retry limit threshold */
81 	ushort	ret_cnt;	/* retry limit counter */
82 	ushort	mflr;		/* maximum frame length reg */
83 	ushort	minflr;		/* minimum frame length reg */
84 	ushort	maxd1;		/* maximum DMA1 length reg */
85 	ushort	maxd2;		/* maximum DMA2 length reg */
86 	ushort	maxd;		/* rx max DMA */
87 	ushort	dma_cnt;	/* rx dma counter */
88 	ushort	max_b;		/* max bd byte count */
89 	ushort	gaddr[4];		/* group address filter */
90 	ulong	tbuf0_data0;	/* save area 0 - current frm */
91 	ulong	tbuf0_data1;	/* save area 1 - current frm */
92 	ulong	tbuf0_rba0;
93 	ulong	tbuf0_crc;
94 	ushort	tbuf0_bcnt;
95 	ushort	paddr[3];	/* physical address LSB to MSB increasing */
96 	ushort	p_per;		/* persistence */
97 	ushort	rfbd_ptr;	/* rx first bd pointer */
98 	ushort	tfbd_ptr;	/* tx first bd pointer */
99 	ushort	tlbd_ptr;	/* tx last bd pointer */
100 	ulong	tbuf1_data0;	/* save area 0 - next frame */
101 	ulong	tbuf1_data1;	/* save area 1 - next frame */
102 	ulong	tbuf1_rba0;
103 	ulong	tbuf1_crc;
104 	ushort	tbuf1_bcnt;
105 	ushort	tx_len;		/* tx frame length counter */
106 	ushort	iaddr[4];		/* individual address filter*/
107 	ushort	boff_cnt;	/* back-off counter */
108 	ushort	taddr[3];	/* temp address */
109 };
110 
111 typedef struct {
112 	Lock;
113 	int	port;
114 	int	init;
115 	int	active;
116 	SCC*	scc;
117 	CPMdev*	cpm;
118 
119 	Ring;
120 
121 	ulong	interrupts;			/* statistics */
122 	ulong	deferred;
123 	ulong	heartbeat;
124 	ulong	latecoll;
125 	ulong	retrylim;
126 	ulong	underrun;
127 	ulong	overrun;
128 	ulong	carrierlost;
129 	ulong	retrycount;
130 } Ctlr;
131 
132 static	int	sccid[] = {-1, CPscc1, CPscc2, CPscc3, CPscc4};
133 
134 static void
135 attach(Ether *ether)
136 {
137 	Ctlr *ctlr;
138 
139 	ctlr = ether->ctlr;
140 	ctlr->active = 1;
141 	ctlr->scc->gsmrl |= ENR|ENT;
142 	eieio();
143 }
144 
145 static void
146 closed(Ether *ether)
147 {
148 	Ctlr *ctlr;
149 
150 	ctlr = ether->ctlr;
151 	if(ctlr->active){
152 		sccxstop(ctlr->cpm);
153 		ilock(ctlr);
154 		ctlr->active = 0;
155 		iunlock(ctlr);
156 	}
157 }
158 
159 static void
160 promiscuous(void* arg, int on)
161 {
162 	Ether *ether;
163 	Ctlr *ctlr;
164 
165 	ether = (Ether*)arg;
166 	ctlr = ether->ctlr;
167 
168 	ilock(ctlr);
169 	if(on || ether->nmaddr)
170 		ctlr->scc->psmr |= PRO;
171 	else
172 		ctlr->scc->psmr &= ~PRO;
173 	iunlock(ctlr);
174 }
175 
176 static void
177 multicast(void* arg, uchar *addr, int on)
178 {
179 	Ether *ether;
180 	Ctlr *ctlr;
181 
182 	USED(addr, on);	/* if on, could SetGroupAddress; if !on, it's hard */
183 
184 	ether = (Ether*)arg;
185 	ctlr = ether->ctlr;
186 
187 	ilock(ctlr);
188 	if(ether->prom || ether->nmaddr)
189 		ctlr->scc->psmr |= PRO;
190 	else
191 		ctlr->scc->psmr &= ~PRO;
192 	iunlock(ctlr);
193 }
194 
195 static void
196 txstart(Ether *ether)
197 {
198 	int len;
199 	Ctlr *ctlr;
200 	Block *b;
201 	BD *dre;
202 
203 	ctlr = ether->ctlr;
204 	while(ctlr->ntq < Ntdre-1){
205 		b = qget(ether->oq);
206 		if(b == 0)
207 			break;
208 
209 		dre = &ctlr->tdr[ctlr->tdrh];
210 		if(dre->status & BDReady)
211 			panic("ether: txstart");
212 
213 		/*
214 		 * Give ownership of the descriptor to the chip, increment the
215 		 * software ring descriptor pointer and tell the chip to poll.
216 		 */
217 		len = BLEN(b);
218 		dcflush(b->rp, len);
219 		if(ctlr->txb[ctlr->tdrh] != nil)
220 			panic("scc/ether: txstart");
221 		ctlr->txb[ctlr->tdrh] = b;
222 		if((ulong)b->rp&1)
223 			panic("scc/ether: txstart align");	/* TO DO: ensure alignment */
224 		dre->addr = PADDR(b->rp);
225 		dre->length = len;
226 		eieio();
227 		dre->status = (dre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC;
228 		eieio();
229 		ctlr->scc->todr = 1<<15;	/* transmit now */
230 		eieio();
231 		ctlr->ntq++;
232 		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
233 	}
234 }
235 
236 static void
237 transmit(Ether* ether)
238 {
239 	Ctlr *ctlr;
240 
241 	ctlr = ether->ctlr;
242 	ilock(ctlr);
243 	txstart(ether);
244 	iunlock(ctlr);
245 }
246 
247 static void
248 interrupt(Ureg*, void *arg)
249 {
250 	Ether *ether;
251 	int len, events, status;
252 	Ctlr *ctlr;
253 	BD *dre;
254 	Block *b;
255 
256 	ether = arg;
257 	ctlr = ether->ctlr;
258 	if(!ctlr->active)
259 		return;	/* not ours */
260 
261 	/*
262 	 * Acknowledge all interrupts and whine about those that shouldn't
263 	 * happen.
264 	 */
265 	events = ctlr->scc->scce;
266 	eieio();
267 	ctlr->scc->scce = events;
268 	eieio();
269 	ctlr->interrupts++;
270 
271 	if(events & (TXE|BSY|RXB)){
272 		if(events & RXB)
273 			ctlr->overrun++;
274 		if(events & TXE)
275 			ether->oerrs++;
276 		if(0 || events & TXE)
277 			print("ETHER.SCC#%d: scce = 0x%uX\n", ether->ctlrno, events);
278 	}
279 	/*
280 	 * Receiver interrupt: run round the descriptor ring logging
281 	 * errors and passing valid receive data up to the higher levels
282 	 * until we encounter a descriptor still owned by the chip.
283 	 */
284 	if(events & (RXF|RXB) || 1){
285 		dre = &ctlr->rdr[ctlr->rdrx];
286 		while(((status = dre->status) & BDEmpty) == 0){
287 			if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
288 				if(status & (RxeLG|RxeSH))
289 					ether->buffs++;
290 				if(status & RxeNO)
291 					ether->frames++;
292 				if(status & RxeCR)
293 					ether->crcs++;
294 				if(status & RxeOV)
295 					ether->overflows++;
296 				//print("eth rx: %ux\n", status);
297 			}
298 			else{
299 				/*
300 				 * We have a packet. Read it in.
301 				 */
302 				len = dre->length-4;
303 				if((b = iallocb(len)) != 0){
304 					dcinval(KADDR(dre->addr), len);
305 					memmove(b->wp, KADDR(dre->addr), len);
306 					b->wp += len;
307 					etheriq(ether, b, 1);
308 				}else
309 					ether->soverflows++;
310 			}
311 
312 			/*
313 			 * Finished with this descriptor, reinitialise it,
314 			 * give it back to the chip, then on to the next...
315 			 */
316 			dre->length = 0;
317 			dre->status = (status & BDWrap) | BDEmpty | BDInt;
318 			eieio();
319 
320 			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
321 			dre = &ctlr->rdr[ctlr->rdrx];
322 		}
323 	}
324 
325 	/*
326 	 * Transmitter interrupt: handle anything queued for a free descriptor.
327 	 */
328 	if(events & TXB){
329 		lock(ctlr);
330 		while(ctlr->ntq){
331 			dre = &ctlr->tdr[ctlr->tdri];
332 			status = dre->status;
333 			if(status & BDReady)
334 				break;
335 			if(status & TxeDEF)
336 				ctlr->deferred++;
337 			if(status & TxeHB)
338 				ctlr->heartbeat++;
339 			if(status & TxeLC)
340 				ctlr->latecoll++;
341 			if(status & TxeRL)
342 				ctlr->retrylim++;
343 			if(status & TxeUN)
344 				ctlr->underrun++;
345 			if(status & TxeCSL)
346 				ctlr->carrierlost++;
347 			ctlr->retrycount += (status>>2)&0xF;
348 			b = ctlr->txb[ctlr->tdri];
349 			if(b == nil)
350 				panic("scce/interrupt: bufp");
351 			ctlr->txb[ctlr->tdri] = nil;
352 			freeb(b);
353 			ctlr->ntq--;
354 			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
355 		}
356 		txstart(ether);
357 		unlock(ctlr);
358 	}
359 	if(events & TXE)
360 		cpmop(ctlr->cpm, RestartTx, 0);
361 }
362 
363 static long
364 ifstat(Ether* ether, void* a, long n, ulong offset)
365 {
366 	char *p;
367 	int len;
368 	Ctlr *ctlr;
369 
370 	if(n == 0)
371 		return 0;
372 
373 	ctlr = ether->ctlr;
374 
375 	p = malloc(READSTR);
376 	len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
377 	len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->carrierlost);
378 	len += snprint(p+len, READSTR-len, "heartbeat: %lud\n", ctlr->heartbeat);
379 	len += snprint(p+len, READSTR-len, "retrylimit: %lud\n", ctlr->retrylim);
380 	len += snprint(p+len, READSTR-len, "retrycount: %lud\n", ctlr->retrycount);
381 	len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->latecoll);
382 	len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->overrun);
383 	len += snprint(p+len, READSTR-len, "txunderruns: %lud\n", ctlr->underrun);
384 	snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->deferred);
385 	n = readstr(offset, a, n, p);
386 	free(p);
387 
388 	return n;
389 }
390 
391 /*
392  * This follows the MPC823 user guide: section16.9.23.7's initialisation sequence,
393  * except that it sets the right bits for the MPC823ADS board when SCC2 is used,
394  * and those for the 860/821 development board for SCC1.
395  */
396 static void
397 sccsetup(Ctlr *ctlr, SCC *scc, Ether *ether)
398 {
399 	int i, rcs, tcs, w;
400 	Etherparam *p;
401 	IMM *io;
402 
403 
404 	i = 2*(ctlr->port-1);
405 	io = ioplock();
406 	w = (TXD1|RXD1)<<i;	/* TXDn and RXDn in port A */
407 	io->papar |= w;	/* enable TXDn and RXDn pins */
408 	io->padir &= ~w;
409 	io->paodr &= ~w;	/* not open drain */
410 
411 	w = (CD1|CTS1)<<i;	/* CLSN and RENA: CDn and CTSn in port C */
412 	io->pcpar &= ~w;	/* enable CLSN (CTSn) and RENA (CDn) */
413 	io->pcdir &= ~w;
414 	io->pcso |= w;
415 	iopunlock();
416 
417 	/* clocks and transceiver control: details depend on the board's wiring */
418 	archetherenable(sccid[ctlr->port], &rcs, &tcs, ether->mbps, ether->fullduplex);
419 
420 	sccnmsi(ctlr->port, rcs, tcs);	/* connect the clocks */
421 
422 	p = ctlr->cpm->param;
423 	memset(p, 0, sizeof(*p));
424 	p->rfcr = 0x18;
425 	p->tfcr = 0x18;
426 	p->mrblr = Bufsize;
427 	p->rbase = PADDR(ctlr->rdr);
428 	p->tbase = PADDR(ctlr->tdr);
429 
430 	cpmop(ctlr->cpm, InitRxTx, 0);
431 
432 	p->c_pres = ~0;
433 	p->c_mask = 0xDEBB20E3;
434 	p->crcec = 0;
435 	p->alec = 0;
436 	p->disfc = 0;
437 	p->pads = 0x8888;
438 	p->ret_lim = 0xF;
439 	p->mflr = Rbsize;
440 	p->minflr = ETHERMINTU+4;
441 	p->maxd1 = Bufsize;
442 	p->maxd2 = Bufsize;
443 	p->p_per = 0;	/* only moderate aggression */
444 
445 	for(i=0; i<Eaddrlen; i+=2)
446 		p->paddr[2-i/2] = (ether->ea[i+1]<<8)|ether->ea[i];	/* it's not the obvious byte order */
447 
448 	scc->psmr = (2<<10)|(5<<1);	/* 32-bit CRC, ignore 22 bits before SFD */
449 	scc->dsr = 0xd555;
450 	scc->gsmrh = 0;	/* normal operation */
451 	scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC;	/* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */
452 	eieio();
453 	scc->scce = ~0;	/* clear all events */
454 	eieio();
455 	scc->sccm = TXE | RXF | TXB;	/* enable interrupts */
456 	eieio();
457 
458 	io = ioplock();
459 	w = RTS1<<(ctlr->port-1);	/* enable TENA pin (RTSn) */
460 	io->pbpar |= w;
461 	io->pbdir |= w;
462 	iopunlock();
463 
464 	/* gsmrl enable is deferred until attach */
465 }
466 
467 static int
468 reset(Ether* ether)
469 {
470 	uchar ea[Eaddrlen];
471 	CPMdev *cpm;
472 	Ctlr *ctlr;
473 	SCC *scc;
474 
475 	if(m->speed < 24){
476 		print("%s ether: system speed must be >= 24MHz for ether use\n", ether->type);
477 		return -1;
478 	}
479 
480 	if(!(ether->port >= 1 && ether->port <= 4)){
481 		print("%s ether: no SCC port %lud\n", ether->type, ether->port);
482 		return -1;
483 	}
484 
485 	/*
486 	 * Insist that the platform-specific code provide the Ethernet address
487 	 */
488 	memset(ea, 0, Eaddrlen);
489 	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
490 		print("no ether address");
491 		return -1;
492 	}
493 
494 	cpm = cpmdev(sccid[ether->port]);
495 	if(cpm == nil)
496 		return -1;
497 	ether->irq = VectorCPIC + cpm->irq;
498 	scc = cpm->regs;
499 	ctlr = malloc(sizeof(*ctlr));
500 	ether->ctlr = ctlr;
501 	memset(ctlr, 0, sizeof(*ctlr));
502 	ctlr->cpm = cpm;
503 	ctlr->scc = scc;
504 	ctlr->port = ether->port;
505 
506 	if(ioringinit(ctlr, Nrdre, Ntdre, Bufsize) < 0)
507 		panic("etherscc init");
508 
509 	sccsetup(ctlr, scc, ether);
510 
511 	ether->attach = attach;
512 	ether->closed = closed;
513 	ether->transmit = transmit;
514 	ether->interrupt = interrupt;
515 	ether->ifstat = ifstat;
516 
517 	ether->arg = ether;
518 	ether->promiscuous = promiscuous;
519 	ether->multicast = multicast;
520 
521 	return 0;
522 }
523 
524 void
525 etherscclink(void)
526 {
527 	addethercard("SCC", reset);
528 }
529