xref: /plan9-contrib/sys/src/9/loongson/devether.c (revision a81c3ea0c7f009a3088ab7fe55ea9013d9d77a74)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 
9 #include "../port/netif.h"
10 #include "etherif.h"
11 
12 extern int archether(unsigned ctlno, Ether *ether);
13 
14 static Ether *etherxx[MaxEther];
15 
16 Chan*
etherattach(char * spec)17 etherattach(char* spec)
18 {
19 	int ctlrno;
20 	char *p;
21 	Chan *chan;
22 
23 	ctlrno = 0;
24 	if(spec && *spec){
25 		ctlrno = strtoul(spec, &p, 0);
26 		if((ctlrno == 0 && p == spec) || *p != 0)
27 			error(Ebadarg);
28 		if(ctlrno < 0 || ctlrno >= MaxEther)
29 			error(Ebadarg);
30 	}
31 	if(etherxx[ctlrno] == 0)
32 		error(Enodev);
33 
34 	chan = devattach('l', spec);
35 	if(waserror()){
36 		chanfree(chan);
37 		nexterror();
38 	}
39 	chan->dev = ctlrno;
40 	if(etherxx[ctlrno]->attach)
41 		etherxx[ctlrno]->attach(etherxx[ctlrno]);
42 	poperror();
43 	return chan;
44 }
45 
46 static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)47 etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
48 {
49 	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
50 }
51 
52 static int
etherstat(Chan * chan,uchar * dp,int n)53 etherstat(Chan* chan, uchar* dp, int n)
54 {
55 	return netifstat(etherxx[chan->dev], chan, dp, n);
56 }
57 
58 static Chan*
etheropen(Chan * chan,int omode)59 etheropen(Chan* chan, int omode)
60 {
61 	return netifopen(etherxx[chan->dev], chan, omode);
62 }
63 
64 static void
ethercreate(Chan *,char *,int,ulong)65 ethercreate(Chan*, char*, int, ulong)
66 {
67 }
68 
69 static void
etherclose(Chan * chan)70 etherclose(Chan* chan)
71 {
72 	netifclose(etherxx[chan->dev], chan);
73 }
74 
75 static long
etherread(Chan * chan,void * buf,long n,vlong off)76 etherread(Chan* chan, void* buf, long n, vlong off)
77 {
78 	Ether *ether;
79 	ulong offset = off;
80 
81 	ether = etherxx[chan->dev];
82 	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83 		/*
84 		 * With some controllers it is necessary to reach
85 		 * into the chip to extract statistics.
86 		 */
87 		if(NETTYPE(chan->qid.path) == Nifstatqid)
88 			return ether->ifstat(ether, buf, n, offset);
89 		else if(NETTYPE(chan->qid.path) == Nstatqid)
90 			ether->ifstat(ether, buf, 0, offset);
91 	}
92 
93 	return netifread(ether, chan, buf, n, offset);
94 }
95 
96 static Block*
etherbread(Chan * chan,long n,ulong offset)97 etherbread(Chan* chan, long n, ulong offset)
98 {
99 	return netifbread(etherxx[chan->dev], chan, n, offset);
100 }
101 
102 static int
etherwstat(Chan * chan,uchar * dp,int n)103 etherwstat(Chan* chan, uchar* dp, int n)
104 {
105 	return netifwstat(etherxx[chan->dev], chan, dp, n);
106 }
107 
108 static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)109 etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110 {
111 	int i, n;
112 	Block *bp;
113 
114 	if(qwindow(f->in) <= 0)
115 		return;
116 	if(len > 58)
117 		n = 58;
118 	else
119 		n = len;
120 	bp = iallocb(64);
121 	if(bp == nil)
122 		return;
123 	memmove(bp->wp, pkt->d, n);
124 	i = TK2MS(MACHP(0)->ticks);
125 	bp->wp[58] = len>>8;
126 	bp->wp[59] = len;
127 	bp->wp[60] = i>>24;
128 	bp->wp[61] = i>>16;
129 	bp->wp[62] = i>>8;
130 	bp->wp[63] = i;
131 	bp->wp += 64;
132 	qpass(f->in, bp);
133 }
134 
135 Block*
etheriq(Ether * ether,Block * bp,int fromwire)136 etheriq(Ether* ether, Block* bp, int fromwire)
137 {
138 	Etherpkt *pkt;
139 	ushort type;
140 	int len, multi, tome, fromme;
141 	Netfile **ep, *f, **fp, *fx;
142 	Block *xbp;
143 
144 	ether->inpackets++;
145 
146 	pkt = (Etherpkt*)bp->rp;
147 	len = BLEN(bp);
148 	type = (pkt->type[0]<<8)|pkt->type[1];
149 	fx = 0;
150 	ep = &ether->f[Ntypes];
151 
152 	multi = pkt->d[0] & 1;
153 	/* check for valid multicast addresses */
154 	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
155 	    ether->prom == 0){
156 		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
157 			if(fromwire){
158 				freeb(bp);
159 				bp = 0;
160 			}
161 			return bp;
162 		}
163 	}
164 	/* is it for me? */
165 	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166 	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167 
168 	/*
169 	 * Multiplex the packet to all the connections which want it.
170 	 * If the packet is not to be used subsequently (fromwire != 0),
171 	 * attempt to simply pass it into one of the connections, thereby
172 	 * saving a copy of the data (usual case hopefully).
173 	 */
174 	for(fp = ether->f; fp < ep; fp++){
175 		if((f = *fp) != nil && (f->type == type || f->type < 0) &&
176 		    (tome || multi || f->prom)){
177 			/* Don't want to hear bridged packets */
178 			if(f->bridge && !fromwire && !fromme)
179 				continue;
180 			if(!f->headersonly){
181 				if(fromwire && fx == 0)
182 					fx = f;
183 				else if(xbp = iallocb(len)){
184 					memmove(xbp->wp, pkt, len);
185 					xbp->wp += len;
186 					if(qpass(f->in, xbp) < 0)
187 						ether->soverflows++;
188 				}
189 				else
190 					ether->soverflows++;
191 			}
192 			else
193 				etherrtrace(f, pkt, len);
194 		}
195 	}
196 
197 	if(fx){
198 		if(qpass(fx->in, bp) < 0)
199 			ether->soverflows++;
200 		return 0;
201 	}
202 	if(fromwire){
203 		freeb(bp);
204 		return 0;
205 	}
206 	return bp;
207 }
208 
209 static int
etheroq(Ether * ether,Block * bp)210 etheroq(Ether* ether, Block* bp)
211 {
212 	int len, loopback, s;
213 	Etherpkt *pkt;
214 
215 	ether->outpackets++;
216 
217 	/*
218 	 * Check if the packet has to be placed back onto the input queue,
219 	 * i.e. if it's a loopback or broadcast packet or the interface is
220 	 * in promiscuous mode.
221 	 * If it's a loopback packet indicate to etheriq that the data isn't
222 	 * needed and return, etheriq will pass-on or free the block.
223 	 * To enable bridging to work, only packets that were originated
224 	 * by this interface are fed back.
225 	 */
226 	pkt = (Etherpkt*)bp->rp;
227 	len = BLEN(bp);
228 	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
229 	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
230 		s = splhi();
231 		etheriq(ether, bp, 0);
232 		splx(s);
233 	}
234 
235 	if(!loopback){
236 		qbwrite(ether->oq, bp);
237 		if(ether->transmit != nil)
238 			ether->transmit(ether);
239 	} else
240 		freeb(bp);
241 
242 	return len;
243 }
244 
245 static long
etherwrite(Chan * chan,void * buf,long n,vlong)246 etherwrite(Chan* chan, void* buf, long n, vlong)
247 {
248 	Ether *ether;
249 	Block *bp;
250 	int nn, onoff;
251 	Cmdbuf *cb;
252 
253 	ether = etherxx[chan->dev];
254 	if(NETTYPE(chan->qid.path) != Ndataqid) {
255 		nn = netifwrite(ether, chan, buf, n);
256 		if(nn >= 0)
257 			return nn;
258 		cb = parsecmd(buf, n);
259 		if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
260 			if(cb->nf <= 1)
261 				onoff = 1;
262 			else
263 				onoff = atoi(cb->f[1]);
264 			qnoblock(ether->oq, onoff);
265 			free(cb);
266 			return n;
267 		}
268 		free(cb);
269 		if(ether->ctl!=nil)
270 			return ether->ctl(ether,buf,n);
271 
272 		error(Ebadctl);
273 	}
274 
275 	if(n > ether->maxmtu)
276 		error(Etoobig);
277 	if(n < ether->minmtu)
278 		error(Etoosmall);
279 
280 	bp = allocb(n);
281 	if(waserror()){
282 		freeb(bp);
283 		nexterror();
284 	}
285 	memmove(bp->rp, buf, n);
286 	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
287 	poperror();
288 	bp->wp += n;
289 
290 	return etheroq(ether, bp);
291 }
292 
293 static long
etherbwrite(Chan * chan,Block * bp,ulong)294 etherbwrite(Chan* chan, Block* bp, ulong)
295 {
296 	Ether *ether;
297 	long n;
298 
299 	n = BLEN(bp);
300 	if(NETTYPE(chan->qid.path) != Ndataqid){
301 		if(waserror()) {
302 			freeb(bp);
303 			nexterror();
304 		}
305 		n = etherwrite(chan, bp->rp, n, 0);
306 		poperror();
307 		freeb(bp);
308 		return n;
309 	}
310 	ether = etherxx[chan->dev];
311 
312 	if(n > ether->maxmtu){
313 		freeb(bp);
314 		error(Etoobig);
315 	}
316 	if(n < ether->minmtu){
317 		freeb(bp);
318 		error(Etoosmall);
319 	}
320 
321 	return etheroq(ether, bp);
322 }
323 
324 static struct {
325 	char*	type;
326 	int	(*reset)(Ether*);
327 } cards[MaxEther+1];
328 
329 void
addethercard(char * t,int (* r)(Ether *))330 addethercard(char* t, int (*r)(Ether*))
331 {
332 	static int ncard;
333 
334 	if(ncard == MaxEther)
335 		panic("too many ether cards");
336 	cards[ncard].type = t;
337 	cards[ncard].reset = r;
338 	ncard++;
339 }
340 
341 int
parseether(uchar * to,char * from)342 parseether(uchar *to, char *from)
343 {
344 	char nip[4];
345 	char *p;
346 	int i;
347 
348 	p = from;
349 	for(i = 0; i < Eaddrlen; i++){
350 		if(*p == 0)
351 			return -1;
352 		nip[0] = *p++;
353 		if(*p == 0)
354 			return -1;
355 		nip[1] = *p++;
356 		nip[2] = 0;
357 		to[i] = strtoul(nip, 0, 16);
358 		if(*p == ':')
359 			p++;
360 	}
361 	return 0;
362 }
363 
364 static void
etherreset(void)365 etherreset(void)
366 {
367 	Ether *ether;
368 	int i, n, ctlrno, subirq;
369 	char name[KNAMELEN], buf[128];
370 
371 	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
372 		if(ether == 0)
373 			ether = malloc(sizeof(Ether));
374 		memset(ether, 0, sizeof(Ether));
375 		ether->ctlrno = ctlrno;
376 		ether->mbps = 10;
377 		ether->minmtu = ETHERMINTU;
378 		ether->maxmtu = ETHERMAXTU;
379 
380 		if(archether(ctlrno, ether) <= 0)
381 			continue;
382 
383 		for(n = 0; cards[n].type; n++){
384 			if(cistrcmp(cards[n].type, ether->type))
385 				continue;
386 			for(i = 0; i < ether->nopt; i++)
387 				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
388 					if(parseether(ether->ea,
389 					    &ether->opt[i][3]) == -1)
390 						memset(ether->ea, 0, Eaddrlen);
391 				} else if(cistrcmp(ether->opt[i],
392 				    "100BASE-TXFD") == 0)
393 					ether->mbps = 100;
394 			if(cards[n].reset(ether))
395 				break;
396 			snprint(name, sizeof(name), "ether%d", ctlrno);
397 
398 			subirq = pcisubirq(ether->tbdf);
399 			if(ether->interrupt != nil && ether->irq >= 0)
400 				intrenable(ether->irq, ether->interrupt, ether, subirq);
401 
402 			i = snprint(buf, sizeof buf,
403 				"#l%d: %s: %dMbps port %#lux irq %d.%d",
404 				ctlrno, ether->type, ether->mbps, ether->port,
405 				ether->irq, subirq);
406 			if(ether->mem)
407 				i += snprint(buf+i, sizeof buf - i,
408 					" addr %#p", PADDR(ether->mem));
409 			if(ether->size)
410 				i += snprint(buf+i, sizeof buf - i,
411 					" size %#luX", ether->size);
412 			i += snprint(buf+i, sizeof buf - i,
413 				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
414 				ether->ea[0], ether->ea[1], ether->ea[2],
415 				ether->ea[3], ether->ea[4], ether->ea[5]);
416 			snprint(buf+i, sizeof buf - i, "\n");
417 			iprint("%s", buf);  /* it may be too early for print */
418 
419 			if(ether->mbps >= 1000)
420 				netifinit(ether, name, Ntypes, 4*1024*1024);
421 			else if(ether->mbps >= 100)
422 				netifinit(ether, name, Ntypes, 1024*1024);
423 			else
424 				netifinit(ether, name, Ntypes, 65*1024);
425 			if(ether->oq == 0)
426 				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
427 			if(ether->oq == 0)
428 				panic("etherreset %s", name);
429 			ether->alen = Eaddrlen;
430 			memmove(ether->addr, ether->ea, Eaddrlen);
431 			memset(ether->bcast, 0xFF, Eaddrlen);
432 
433 			etherxx[ctlrno] = ether;
434 			ether = 0;
435 			break;
436 		}
437 	}
438 	if(ether)
439 		free(ether);
440 }
441 
442 static void
ethershutdown(void)443 ethershutdown(void)
444 {
445 	Ether *ether;
446 	int i;
447 
448 	for(i = 0; i < MaxEther; i++){
449 		ether = etherxx[i];
450 		if(ether == nil)
451 			continue;
452 		if(ether->shutdown == nil) {
453 			print("#l%d: no shutdown function\n", i);
454 			continue;
455 		}
456 		(*ether->shutdown)(ether);
457 	}
458 }
459 
460 
461 #define POLY 0xedb88320
462 
463 /* really slow 32 bit crc for ethers */
464 ulong
ethercrc(uchar * p,int len)465 ethercrc(uchar *p, int len)
466 {
467 	int i, j;
468 	ulong crc, b;
469 
470 	crc = 0xffffffff;
471 	for(i = 0; i < len; i++){
472 		b = *p++;
473 		for(j = 0; j < 8; j++){
474 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
475 			b >>= 1;
476 		}
477 	}
478 	return crc;
479 }
480 
481 void
dumpoq(Queue * oq)482 dumpoq(Queue *oq)
483 {
484 	if (oq == nil)
485 		print("no outq! ");
486 	else if (qisclosed(oq))
487 		print("outq closed ");
488 	else if (qfull(oq))
489 		print("outq full ");
490 	else
491 		print("outq %d ", qlen(oq));
492 }
493 
494 void
dumpnetif(Netif * netif)495 dumpnetif(Netif *netif)
496 {
497 	print("netif %s ", netif->name);
498 	print("limit %d mbps %d link %d ",
499 		netif->limit, netif->mbps, netif->link);
500 	print("inpkts %lld outpkts %lld errs %d\n",
501 		netif->inpackets, netif->outpackets,
502 		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
503 		netif->buffs + netif->soverflows);
504 }
505 
506 Dev etherdevtab = {
507 	'l',
508 	"ether",
509 
510 	etherreset,
511 	devinit,
512 	ethershutdown,
513 	etherattach,
514 	etherwalk,
515 	etherstat,
516 	etheropen,
517 	ethercreate,
518 	etherclose,
519 	etherread,
520 	etherbread,
521 	etherwrite,
522 	etherbwrite,
523 	devremove,
524 	etherwstat,
525 };
526