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