xref: /plan9/sys/src/9/ppc/devether.c (revision d95be1c011c2cbadfb86cb2f56a061c3646d53ba)
1458db832SDavid du Colombier #include "u.h"
2458db832SDavid du Colombier #include "../port/lib.h"
3458db832SDavid du Colombier #include "mem.h"
4458db832SDavid du Colombier #include "dat.h"
5458db832SDavid du Colombier #include "fns.h"
6458db832SDavid du Colombier #include "io.h"
7458db832SDavid du Colombier #include "ureg.h"
8458db832SDavid du Colombier #include "../port/error.h"
9458db832SDavid du Colombier #include "../port/netif.h"
10458db832SDavid du Colombier 
11458db832SDavid du Colombier #include "etherif.h"
12458db832SDavid du Colombier 
13458db832SDavid du Colombier static Ether *etherxx[MaxEther];
144de34a7eSDavid du Colombier extern uchar etheraddr[];
15458db832SDavid du Colombier 
16458db832SDavid du Colombier Chan*
etherattach(char * spec)17458db832SDavid du Colombier etherattach(char* spec)
18458db832SDavid du Colombier {
19458db832SDavid du Colombier 	ulong ctlrno;
20458db832SDavid du Colombier 	char *p;
21458db832SDavid du Colombier 	Chan *chan;
22458db832SDavid du Colombier 
23458db832SDavid du Colombier 	ctlrno = 0;
24458db832SDavid du Colombier 	if(spec && *spec){
25458db832SDavid du Colombier 		ctlrno = strtoul(spec, &p, 0);
26458db832SDavid du Colombier 		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
27458db832SDavid du Colombier 			error(Ebadarg);
28458db832SDavid du Colombier 	}
29458db832SDavid du Colombier 	if(etherxx[ctlrno] == 0)
30458db832SDavid du Colombier 		error(Enodev);
31458db832SDavid du Colombier 
32458db832SDavid du Colombier 	chan = devattach('l', spec);
33458db832SDavid du Colombier 	chan->dev = ctlrno;
34458db832SDavid du Colombier 	if(etherxx[ctlrno]->attach)
35458db832SDavid du Colombier 		etherxx[ctlrno]->attach(etherxx[ctlrno]);
36458db832SDavid du Colombier 	return chan;
37458db832SDavid du Colombier }
38458db832SDavid du Colombier 
39458db832SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)40458db832SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
41458db832SDavid du Colombier {
42458db832SDavid du Colombier 	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
43458db832SDavid du Colombier }
44458db832SDavid du Colombier 
45458db832SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)46458db832SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
47458db832SDavid du Colombier {
48458db832SDavid du Colombier 	return netifstat(etherxx[chan->dev], chan, dp, n);
49458db832SDavid du Colombier }
50458db832SDavid du Colombier 
51458db832SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)52458db832SDavid du Colombier etheropen(Chan* chan, int omode)
53458db832SDavid du Colombier {
54458db832SDavid du Colombier 	return netifopen(etherxx[chan->dev], chan, omode);
55458db832SDavid du Colombier }
56458db832SDavid du Colombier 
57458db832SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)58458db832SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
59458db832SDavid du Colombier {
60458db832SDavid du Colombier }
61458db832SDavid du Colombier 
62458db832SDavid du Colombier static void
etherclose(Chan * chan)63458db832SDavid du Colombier etherclose(Chan* chan)
64458db832SDavid du Colombier {
65458db832SDavid du Colombier 	netifclose(etherxx[chan->dev], chan);
66458db832SDavid du Colombier }
67458db832SDavid du Colombier 
68458db832SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)69458db832SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
70458db832SDavid du Colombier {
71458db832SDavid du Colombier 	Ether *ether;
72458db832SDavid du Colombier 	ulong offset = off;
73458db832SDavid du Colombier 
74458db832SDavid du Colombier 	ether = etherxx[chan->dev];
75458db832SDavid du Colombier 	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
76458db832SDavid du Colombier 		/*
77458db832SDavid du Colombier 		 * With some controllers it is necessary to reach
78458db832SDavid du Colombier 		 * into the chip to extract statistics.
79458db832SDavid du Colombier 		 */
80458db832SDavid du Colombier 		if(NETTYPE(chan->qid.path) == Nifstatqid)
81458db832SDavid du Colombier 			return ether->ifstat(ether, buf, n, offset);
82458db832SDavid du Colombier 		else if(NETTYPE(chan->qid.path) == Nstatqid)
83458db832SDavid du Colombier 			ether->ifstat(ether, buf, 0, offset);
84458db832SDavid du Colombier 	}
85458db832SDavid du Colombier 
86458db832SDavid du Colombier 	return netifread(ether, chan, buf, n, offset);
87458db832SDavid du Colombier }
88458db832SDavid du Colombier 
89458db832SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)90458db832SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
91458db832SDavid du Colombier {
92458db832SDavid du Colombier 	return netifbread(etherxx[chan->dev], chan, n, offset);
93458db832SDavid du Colombier }
94458db832SDavid du Colombier 
95458db832SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)96458db832SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
97458db832SDavid du Colombier {
98458db832SDavid du Colombier 	return netifwstat(etherxx[chan->dev], chan, dp, n);
99458db832SDavid du Colombier }
100458db832SDavid du Colombier 
101458db832SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)102458db832SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
103458db832SDavid du Colombier {
104458db832SDavid du Colombier 	int i, n;
105458db832SDavid du Colombier 	Block *bp;
106458db832SDavid du Colombier 
107458db832SDavid du Colombier 	if(qwindow(f->in) <= 0)
108458db832SDavid du Colombier 		return;
109458db832SDavid du Colombier 	if(len > 58)
110458db832SDavid du Colombier 		n = 58;
111458db832SDavid du Colombier 	else
112458db832SDavid du Colombier 		n = len;
113458db832SDavid du Colombier 	bp = iallocb(64);
114458db832SDavid du Colombier 	if(bp == nil)
115458db832SDavid du Colombier 		return;
116458db832SDavid du Colombier 	memmove(bp->wp, pkt->d, n);
117458db832SDavid du Colombier 	i = TK2MS(MACHP(0)->ticks);
118458db832SDavid du Colombier 	bp->wp[58] = len>>8;
119458db832SDavid du Colombier 	bp->wp[59] = len;
120458db832SDavid du Colombier 	bp->wp[60] = i>>24;
121458db832SDavid du Colombier 	bp->wp[61] = i>>16;
122458db832SDavid du Colombier 	bp->wp[62] = i>>8;
123458db832SDavid du Colombier 	bp->wp[63] = i;
124458db832SDavid du Colombier 	bp->wp += 64;
125458db832SDavid du Colombier 	qpass(f->in, bp);
126458db832SDavid du Colombier }
127458db832SDavid du Colombier 
128458db832SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)129458db832SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
130458db832SDavid du Colombier {
131458db832SDavid du Colombier 	Etherpkt *pkt;
132458db832SDavid du Colombier 	ushort type;
133458db832SDavid du Colombier 	int len, multi, tome, fromme;
134458db832SDavid du Colombier 	Netfile **ep, *f, **fp, *fx;
135458db832SDavid du Colombier 	Block *xbp;
136458db832SDavid du Colombier 
137458db832SDavid du Colombier 	ether->inpackets++;
138458db832SDavid du Colombier 
139458db832SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
140458db832SDavid du Colombier 	len = BLEN(bp);
141458db832SDavid du Colombier 	type = (pkt->type[0]<<8)|pkt->type[1];
142458db832SDavid du Colombier 	fx = 0;
143458db832SDavid du Colombier 	ep = &ether->f[Ntypes];
144458db832SDavid du Colombier 
145458db832SDavid du Colombier 	multi = pkt->d[0] & 1;
146*d95be1c0SDavid du Colombier 	/* check for valid multicast addresses */
147458db832SDavid du Colombier 	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
148458db832SDavid du Colombier 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
149458db832SDavid du Colombier 			if(fromwire){
150458db832SDavid du Colombier 				freeb(bp);
151458db832SDavid du Colombier 				bp = 0;
152458db832SDavid du Colombier 			}
153458db832SDavid du Colombier 			return bp;
154458db832SDavid du Colombier 		}
155458db832SDavid du Colombier 	}
156458db832SDavid du Colombier 
157458db832SDavid du Colombier 	/* is it for me? */
158458db832SDavid du Colombier 	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
159458db832SDavid du Colombier 	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
160458db832SDavid du Colombier 
161458db832SDavid du Colombier 	/*
162458db832SDavid du Colombier 	 * Multiplex the packet to all the connections which want it.
163458db832SDavid du Colombier 	 * If the packet is not to be used subsequently (fromwire != 0),
164458db832SDavid du Colombier 	 * attempt to simply pass it into one of the connections, thereby
165458db832SDavid du Colombier 	 * saving a copy of the data (usual case hopefully).
166458db832SDavid du Colombier 	 */
167458db832SDavid du Colombier 	for(fp = ether->f; fp < ep; fp++){
168458db832SDavid du Colombier 		if(f = *fp)
169458db832SDavid du Colombier 		if(f->type == type || f->type < 0)
170458db832SDavid du Colombier 		if(tome || multi || f->prom){
171458db832SDavid du Colombier 			/* Don't want to hear bridged packets */
172458db832SDavid du Colombier 			if(f->bridge && !fromwire && !fromme)
173458db832SDavid du Colombier 				continue;
174458db832SDavid du Colombier 			if(!f->headersonly){
175458db832SDavid du Colombier 				if(fromwire && fx == 0)
176458db832SDavid du Colombier 					fx = f;
177458db832SDavid du Colombier 				else if(xbp = iallocb(len)){
178458db832SDavid du Colombier 					memmove(xbp->wp, pkt, len);
179458db832SDavid du Colombier 					xbp->wp += len;
180458db832SDavid du Colombier 					qpass(f->in, xbp);
181458db832SDavid du Colombier 				}
182458db832SDavid du Colombier 				else
183458db832SDavid du Colombier 					ether->soverflows++;
184458db832SDavid du Colombier 			}
185458db832SDavid du Colombier 			else
186458db832SDavid du Colombier 				etherrtrace(f, pkt, len);
187458db832SDavid du Colombier 		}
188458db832SDavid du Colombier 	}
189458db832SDavid du Colombier 
190458db832SDavid du Colombier 	if(fx){
191458db832SDavid du Colombier 		if(qpass(fx->in, bp) < 0)
192458db832SDavid du Colombier 			ether->soverflows++;
193458db832SDavid du Colombier 		return 0;
194458db832SDavid du Colombier 	}
195458db832SDavid du Colombier 	if(fromwire){
196458db832SDavid du Colombier 		freeb(bp);
197458db832SDavid du Colombier 		return 0;
198458db832SDavid du Colombier 	}
199458db832SDavid du Colombier 
200458db832SDavid du Colombier 	return bp;
201458db832SDavid du Colombier }
202458db832SDavid du Colombier 
203458db832SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)204458db832SDavid du Colombier etheroq(Ether* ether, Block* bp)
205458db832SDavid du Colombier {
206458db832SDavid du Colombier 	int len, loopback, s;
207458db832SDavid du Colombier 	Etherpkt *pkt;
208458db832SDavid du Colombier 
209458db832SDavid du Colombier 	ether->outpackets++;
210458db832SDavid du Colombier 	/*
211458db832SDavid du Colombier 	 * Check if the packet has to be placed back onto the input queue,
212458db832SDavid du Colombier 	 * i.e. if it's a loopback or broadcast packet or the interface is
213458db832SDavid du Colombier 	 * in promiscuous mode.
214458db832SDavid du Colombier 	 * If it's a loopback packet indicate to etheriq that the data isn't
215458db832SDavid du Colombier 	 * needed and return, etheriq will pass-on or free the block.
216458db832SDavid du Colombier 	 * To enable bridging to work, only packets that were originated
217458db832SDavid du Colombier 	 * by this interface are fed back.
218458db832SDavid du Colombier 	 */
219458db832SDavid du Colombier 	pkt = (Etherpkt*)bp->rp;
220458db832SDavid du Colombier 	len = BLEN(bp);
221458db832SDavid du Colombier 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
222458db832SDavid du Colombier 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
223458db832SDavid du Colombier 		s = splhi();
224458db832SDavid du Colombier 		etheriq(ether, bp, 0);
225458db832SDavid du Colombier 		splx(s);
226458db832SDavid du Colombier 	}
227458db832SDavid du Colombier 
228458db832SDavid du Colombier 	if(!loopback){
229458db832SDavid du Colombier 		qbwrite(ether->oq, bp);
230458db832SDavid du Colombier 		ether->transmit(ether);
231458db832SDavid du Colombier 	} else
232458db832SDavid du Colombier 		freeb(bp);
233458db832SDavid du Colombier 
234458db832SDavid du Colombier 	return len;
235458db832SDavid du Colombier }
236458db832SDavid du Colombier 
237458db832SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)238458db832SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
239458db832SDavid du Colombier {
240458db832SDavid du Colombier 	Ether *ether;
241458db832SDavid du Colombier 	Block *bp;
242458db832SDavid du Colombier 	int nn;
243458db832SDavid du Colombier 
244458db832SDavid du Colombier 	ether = etherxx[chan->dev];
245458db832SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid) {
246458db832SDavid du Colombier 		nn = netifwrite(ether, chan, buf, n);
247458db832SDavid du Colombier 		if(nn >= 0)
248458db832SDavid du Colombier 			return nn;
249458db832SDavid du Colombier 		if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
250458db832SDavid du Colombier 			qnoblock(ether->oq, 1);
251458db832SDavid du Colombier 			return n;
252458db832SDavid du Colombier 		}
253458db832SDavid du Colombier 		if(ether->ctl!=nil)
254458db832SDavid du Colombier 			return ether->ctl(ether,buf,n);
255458db832SDavid du Colombier 
256458db832SDavid du Colombier 		error(Ebadctl);
257458db832SDavid du Colombier 	}
258458db832SDavid du Colombier 
259458db832SDavid du Colombier 	if(n > ether->maxmtu)
260458db832SDavid du Colombier 		error(Etoobig);
261458db832SDavid du Colombier 	if(n < ether->minmtu)
262458db832SDavid du Colombier 		error(Etoosmall);
263458db832SDavid du Colombier 
264458db832SDavid du Colombier 	bp = allocb(n);
265458db832SDavid du Colombier 	if(waserror()){
266458db832SDavid du Colombier 		freeb(bp);
267458db832SDavid du Colombier 		nexterror();
268458db832SDavid du Colombier 	}
269458db832SDavid du Colombier 	memmove(bp->rp, buf, n);
270458db832SDavid du Colombier 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
271458db832SDavid du Colombier 	poperror();
272458db832SDavid du Colombier 	bp->wp += n;
273458db832SDavid du Colombier 
274458db832SDavid du Colombier 	return etheroq(ether, bp);
275458db832SDavid du Colombier }
276458db832SDavid du Colombier 
277458db832SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)278458db832SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
279458db832SDavid du Colombier {
280458db832SDavid du Colombier 	Ether *ether;
281458db832SDavid du Colombier 	long n;
282458db832SDavid du Colombier 
283458db832SDavid du Colombier 	n = BLEN(bp);
284458db832SDavid du Colombier 	if(NETTYPE(chan->qid.path) != Ndataqid){
285458db832SDavid du Colombier 		if(waserror()) {
286458db832SDavid du Colombier 			freeb(bp);
287458db832SDavid du Colombier 			nexterror();
288458db832SDavid du Colombier 		}
289458db832SDavid du Colombier 		n = etherwrite(chan, bp->rp, n, 0);
290458db832SDavid du Colombier 		poperror();
291458db832SDavid du Colombier 		freeb(bp);
292458db832SDavid du Colombier 		return n;
293458db832SDavid du Colombier 	}
294458db832SDavid du Colombier 	ether = etherxx[chan->dev];
295458db832SDavid du Colombier 
296458db832SDavid du Colombier 	if(n > ether->maxmtu){
297458db832SDavid du Colombier 		freeb(bp);
298458db832SDavid du Colombier 		error(Etoobig);
299458db832SDavid du Colombier 	}
300458db832SDavid du Colombier 	if(n < ether->minmtu){
301458db832SDavid du Colombier 		freeb(bp);
302458db832SDavid du Colombier 		error(Etoosmall);
303458db832SDavid du Colombier 	}
304458db832SDavid du Colombier 
305458db832SDavid du Colombier 	return etheroq(ether, bp);
306458db832SDavid du Colombier }
307458db832SDavid du Colombier 
308458db832SDavid du Colombier static struct {
309458db832SDavid du Colombier 	char*	type;
310458db832SDavid du Colombier 	int	(*reset)(Ether*);
311458db832SDavid du Colombier } cards[MaxEther+1];
312458db832SDavid du Colombier 
313458db832SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))314458db832SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
315458db832SDavid du Colombier {
316458db832SDavid du Colombier 	static int ncard;
317458db832SDavid du Colombier 
318458db832SDavid du Colombier 	if(ncard == MaxEther)
319458db832SDavid du Colombier 		panic("too many ether cards");
320458db832SDavid du Colombier 	cards[ncard].type = t;
321458db832SDavid du Colombier 	cards[ncard].reset = r;
322458db832SDavid du Colombier 	ncard++;
323458db832SDavid du Colombier }
324458db832SDavid du Colombier 
325458db832SDavid du Colombier int
parseether(uchar * to,char * from)326458db832SDavid du Colombier parseether(uchar *to, char *from)
327458db832SDavid du Colombier {
328458db832SDavid du Colombier 	char nip[4];
329458db832SDavid du Colombier 	char *p;
330458db832SDavid du Colombier 	int i;
331458db832SDavid du Colombier 
332458db832SDavid du Colombier 	p = from;
333458db832SDavid du Colombier 	for(i = 0; i < 6; i++){
334458db832SDavid du Colombier 		if(*p == 0)
335458db832SDavid du Colombier 			return -1;
336458db832SDavid du Colombier 		nip[0] = *p++;
337458db832SDavid du Colombier 		if(*p == 0)
338458db832SDavid du Colombier 			return -1;
339458db832SDavid du Colombier 		nip[1] = *p++;
340458db832SDavid du Colombier 		nip[2] = 0;
341458db832SDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
342458db832SDavid du Colombier 		if(*p == ':')
343458db832SDavid du Colombier 			p++;
344458db832SDavid du Colombier 	}
345458db832SDavid du Colombier 	return 0;
346458db832SDavid du Colombier }
347458db832SDavid du Colombier 
348458db832SDavid du Colombier static void
etherreset(void)349458db832SDavid du Colombier etherreset(void)
350458db832SDavid du Colombier {
351458db832SDavid du Colombier 	Ether *ether;
352458db832SDavid du Colombier 	int i, n, ctlrno;
353458db832SDavid du Colombier 	char name[32], buf[128];
354458db832SDavid du Colombier 
355458db832SDavid du Colombier 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
356458db832SDavid du Colombier 		if(ether == 0)
357458db832SDavid du Colombier 			ether = malloc(sizeof(Ether));
358458db832SDavid du Colombier 		memset(ether, 0, sizeof(Ether));
359458db832SDavid du Colombier 		ether->ctlrno = ctlrno;
360458db832SDavid du Colombier 		ether->tbdf = BUSUNKNOWN;
361458db832SDavid du Colombier 		ether->mbps = 10;
362458db832SDavid du Colombier 		ether->minmtu = ETHERMINTU;
363458db832SDavid du Colombier 		ether->maxmtu = ETHERMAXTU;
364458db832SDavid du Colombier 		if(isaconfig("ether", ctlrno, ether) == 0)
365458db832SDavid du Colombier 			continue;
366458db832SDavid du Colombier 		for(n = 0; cards[n].type; n++){
367458db832SDavid du Colombier 			if(cistrcmp(cards[n].type, ether->type))
368458db832SDavid du Colombier 				continue;
3694de34a7eSDavid du Colombier 			memmove(ether->ea, etheraddr, 6);
370458db832SDavid du Colombier 			for(i = 0; i < ether->nopt; i++){
371458db832SDavid du Colombier 				if(strncmp(ether->opt[i], "ea=", 3))
372458db832SDavid du Colombier 					continue;
373458db832SDavid du Colombier 				if(parseether(ether->ea, &ether->opt[i][3]) == -1)
374458db832SDavid du Colombier 					memset(ether->ea, 0, Eaddrlen);
375458db832SDavid du Colombier 			}
376458db832SDavid du Colombier 			if(cards[n].reset(ether))
377458db832SDavid du Colombier 				break;
378458db832SDavid du Colombier 
379458db832SDavid du Colombier 			/*
380458db832SDavid du Colombier 			 * IRQ2 doesn't really exist, it's used to gang the interrupt
381458db832SDavid du Colombier 			 * controllers together. A device set to IRQ2 will appear on
382458db832SDavid du Colombier 			 * the second interrupt controller as IRQ9.
383458db832SDavid du Colombier 			 */
384458db832SDavid du Colombier 			if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
385458db832SDavid du Colombier 				ether->irq = 9;
386458db832SDavid du Colombier 			snprint(name, sizeof(name), "ether%d", ctlrno);
387458db832SDavid du Colombier 
388458db832SDavid du Colombier 			/*
389458db832SDavid du Colombier 			 * If ether->irq is <0, it is a hack to indicate no interrupt
390458db832SDavid du Colombier 			 * used by ethersink.
391458db832SDavid du Colombier 			 */
392458db832SDavid du Colombier 			if(ether->irq >= 0)
393458db832SDavid du Colombier 				intrenable(ether->irq, ether->interrupt, ether, name);
394458db832SDavid du Colombier 			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
395458db832SDavid du Colombier 				ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
396458db832SDavid du Colombier 			if(ether->mem)
397458db832SDavid du Colombier 				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
398458db832SDavid du Colombier 			if(ether->size)
399458db832SDavid du Colombier 				i += sprint(buf+i, " size 0x%luX", ether->size);
4006063170eSDavid du Colombier 			i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
401458db832SDavid du Colombier 				ether->ea[0], ether->ea[1], ether->ea[2],
402458db832SDavid du Colombier 				ether->ea[3], ether->ea[4], ether->ea[5]);
403458db832SDavid du Colombier 			sprint(buf+i, "\n");
404458db832SDavid du Colombier 			print(buf);
405458db832SDavid du Colombier 
406458db832SDavid du Colombier 			if(ether->mbps >= 100){
407458db832SDavid du Colombier 				netifinit(ether, name, Ntypes, 256*1024);
408458db832SDavid du Colombier 				if(ether->oq == 0)
409458db832SDavid du Colombier 					ether->oq = qopen(256*1024, Qmsg, 0, 0);
410458db832SDavid du Colombier 			}
411458db832SDavid du Colombier 			else{
412458db832SDavid du Colombier 				netifinit(ether, name, Ntypes, 65*1024);
413458db832SDavid du Colombier 				if(ether->oq == 0)
414458db832SDavid du Colombier 					ether->oq = qopen(65*1024, Qmsg, 0, 0);
415458db832SDavid du Colombier 			}
416458db832SDavid du Colombier 			if(ether->oq == 0)
417458db832SDavid du Colombier 				panic("etherreset %s", name);
418458db832SDavid du Colombier 			ether->alen = Eaddrlen;
419458db832SDavid du Colombier 			memmove(ether->addr, ether->ea, Eaddrlen);
420458db832SDavid du Colombier 			memset(ether->bcast, 0xFF, Eaddrlen);
421458db832SDavid du Colombier 
422458db832SDavid du Colombier 			etherxx[ctlrno] = ether;
423458db832SDavid du Colombier 			ether = 0;
424458db832SDavid du Colombier 			break;
425458db832SDavid du Colombier 		}
426458db832SDavid du Colombier 	}
427458db832SDavid du Colombier 	if(ether)
428458db832SDavid du Colombier 		free(ether);
429458db832SDavid du Colombier }
430458db832SDavid du Colombier 
431458db832SDavid du Colombier #define POLY 0xedb88320
432458db832SDavid du Colombier 
433458db832SDavid du Colombier /* really slow 32 bit crc for ethers */
434458db832SDavid du Colombier ulong
ethercrc(uchar * p,int len)435458db832SDavid du Colombier ethercrc(uchar *p, int len)
436458db832SDavid du Colombier {
437458db832SDavid du Colombier 	int i, j;
438458db832SDavid du Colombier 	ulong crc, b;
439458db832SDavid du Colombier 
440458db832SDavid du Colombier 	crc = 0xffffffff;
441458db832SDavid du Colombier 	for(i = 0; i < len; i++){
442458db832SDavid du Colombier 		b = *p++;
443458db832SDavid du Colombier 		for(j = 0; j < 8; j++){
444458db832SDavid du Colombier 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
445458db832SDavid du Colombier 			b >>= 1;
446458db832SDavid du Colombier 		}
447458db832SDavid du Colombier 	}
448458db832SDavid du Colombier 	return crc;
449458db832SDavid du Colombier }
450458db832SDavid du Colombier 
451458db832SDavid du Colombier Dev etherdevtab = {
452458db832SDavid du Colombier 	'l',
453458db832SDavid du Colombier 	"ether",
454458db832SDavid du Colombier 
455458db832SDavid du Colombier 	etherreset,
456458db832SDavid du Colombier 	devinit,
457458db832SDavid du Colombier 	devshutdown,
458458db832SDavid du Colombier 	etherattach,
459458db832SDavid du Colombier 	etherwalk,
460458db832SDavid du Colombier 	etherstat,
461458db832SDavid du Colombier 	etheropen,
462458db832SDavid du Colombier 	ethercreate,
463458db832SDavid du Colombier 	etherclose,
464458db832SDavid du Colombier 	etherread,
465458db832SDavid du Colombier 	etherbread,
466458db832SDavid du Colombier 	etherwrite,
467458db832SDavid du Colombier 	etherbwrite,
468458db832SDavid du Colombier 	devremove,
469458db832SDavid du Colombier 	etherwstat,
470458db832SDavid du Colombier };
471