]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devether.c
kernel: add portable sd mmc interface (from sources)
[plan9front.git] / sys / src / 9 / pc / devether.c
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 "pool.h"
8 #include "ureg.h"
9 #include "../port/error.h"
10 #include "../port/netif.h"
11
12 #include "etherif.h"
13
14 static Ether *etherxx[MaxEther];
15
16 Chan*
17 etherattach(char* spec)
18 {
19         ulong 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 || (ctlrno >= MaxEther))
27                         error(Ebadarg);
28         }
29         if(etherxx[ctlrno] == 0)
30                 error(Enodev);
31
32         chan = devattach('l', spec);
33         if(waserror()){
34                 chanfree(chan);
35                 nexterror();
36         }
37         chan->dev = ctlrno;
38         if(etherxx[ctlrno]->attach)
39                 etherxx[ctlrno]->attach(etherxx[ctlrno]);
40         poperror();
41         return chan;
42 }
43
44 static Walkqid*
45 etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
46 {
47         return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
48 }
49
50 static int
51 etherstat(Chan* chan, uchar* dp, int n)
52 {
53         return netifstat(etherxx[chan->dev], chan, dp, n);
54 }
55
56 static Chan*
57 etheropen(Chan* chan, int omode)
58 {
59         return netifopen(etherxx[chan->dev], chan, omode);
60 }
61
62 static Chan*
63 ethercreate(Chan*, char*, int, ulong)
64 {
65         error(Eperm);
66         return 0;
67 }
68
69 static void
70 etherclose(Chan* chan)
71 {
72         netifclose(etherxx[chan->dev], chan);
73 }
74
75 static long
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*
97 etherbread(Chan* chan, long n, ulong offset)
98 {
99         return netifbread(etherxx[chan->dev], chan, n, offset);
100 }
101
102 static int
103 etherwstat(Chan* chan, uchar* dp, int n)
104 {
105         return netifwstat(etherxx[chan->dev], chan, dp, n);
106 }
107
108 static void
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*
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 && ether->prom == 0){
155                 if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
156                         if(fromwire){
157                                 freeb(bp);
158                                 bp = 0;
159                         }
160                         return bp;
161                 }
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)
176                 if(f->type == type || f->type < 0)
177                 if(tome || multi || f->prom){
178                         /* Don't want to hear bridged packets */
179                         if(f->bridge && !fromwire && !fromme)
180                                 continue;
181                         if(!f->headersonly){
182                                 if(fromwire && fx == 0)
183                                         fx = f;
184                                 else if(xbp = iallocb(len)){
185                                         memmove(xbp->wp, pkt, len);
186                                         xbp->wp += len;
187                                         if(qpass(f->in, xbp) < 0) {
188                                                 // print("soverflow for f->in\n");
189                                                 ether->soverflows++;
190                                         }
191                                 }
192                                 else {
193                                         // print("soverflow iallocb\n");
194                                         ether->soverflows++;
195                                 }
196                         }
197                         else
198                                 etherrtrace(f, pkt, len);
199                 }
200         }
201
202         if(fx){
203                 if(qpass(fx->in, bp) < 0) {
204                         // print("soverflow for fx->in\n");
205                         ether->soverflows++;
206                 }
207                 return 0;
208         }
209         if(fromwire){
210                 freeb(bp);
211                 return 0;
212         }
213
214         return bp;
215 }
216
217 static int
218 etheroq(Ether* ether, Block* bp)
219 {
220         int len, loopback, s;
221         Etherpkt *pkt;
222
223         ether->outpackets++;
224
225         /*
226          * Check if the packet has to be placed back onto the input queue,
227          * i.e. if it's a loopback or broadcast packet or the interface is
228          * in promiscuous mode.
229          * If it's a loopback packet indicate to etheriq that the data isn't
230          * needed and return, etheriq will pass-on or free the block.
231          * To enable bridging to work, only packets that were originated
232          * by this interface are fed back.
233          */
234         pkt = (Etherpkt*)bp->rp;
235         len = BLEN(bp);
236         loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
237         if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
238                 s = splhi();
239                 etheriq(ether, bp, 0);
240                 splx(s);
241         }
242
243         if(!loopback){
244                 if(qfull(ether->oq))
245                         print("etheroq: WARNING: ether->oq full!\n");
246                 qbwrite(ether->oq, bp);
247                 if(ether->transmit != nil)
248                         ether->transmit(ether);
249         } else
250                 freeb(bp);
251
252         return len;
253 }
254
255 static long
256 etherwrite(Chan* chan, void* buf, long n, vlong)
257 {
258         Ether *ether;
259         Block *bp;
260         int nn, onoff;
261         Cmdbuf *cb;
262
263         ether = etherxx[chan->dev];
264         if(NETTYPE(chan->qid.path) != Ndataqid) {
265                 nn = netifwrite(ether, chan, buf, n);
266                 if(nn >= 0)
267                         return nn;
268                 cb = parsecmd(buf, n);
269                 if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
270                         if(cb->nf <= 1)
271                                 onoff = 1;
272                         else
273                                 onoff = atoi(cb->f[1]);
274                         qnoblock(ether->oq, onoff);
275                         free(cb);
276                         return n;
277                 }
278                 free(cb);
279                 if(ether->ctl!=nil)
280                         return ether->ctl(ether,buf,n);
281
282                 error(Ebadctl);
283         }
284
285         if(n > ether->maxmtu)
286                 error(Etoobig);
287         if(n < ether->minmtu)
288                 error(Etoosmall);
289
290         bp = allocb(n);
291         if(waserror()){
292                 freeb(bp);
293                 nexterror();
294         }
295         memmove(bp->rp, buf, n);
296         memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
297         poperror();
298         bp->wp += n;
299
300         return etheroq(ether, bp);
301 }
302
303 static long
304 etherbwrite(Chan* chan, Block* bp, ulong)
305 {
306         Ether *ether;
307         long n;
308
309         n = BLEN(bp);
310         if(NETTYPE(chan->qid.path) != Ndataqid){
311                 if(waserror()) {
312                         freeb(bp);
313                         nexterror();
314                 }
315                 n = etherwrite(chan, bp->rp, n, 0);
316                 poperror();
317                 freeb(bp);
318                 return n;
319         }
320         ether = etherxx[chan->dev];
321
322         if(n > ether->maxmtu){
323                 freeb(bp);
324                 error(Etoobig);
325         }
326         if(n < ether->minmtu){
327                 freeb(bp);
328                 error(Etoosmall);
329         }
330
331         return etheroq(ether, bp);
332 }
333
334 static struct {
335         char*   type;
336         int     (*reset)(Ether*);
337 } cards[MaxEther+1];
338
339 void
340 addethercard(char* t, int (*r)(Ether*))
341 {
342         static int ncard;
343
344         if(ncard == MaxEther)
345                 panic("too many ether cards");
346         cards[ncard].type = t;
347         cards[ncard].reset = r;
348         ncard++;
349 }
350
351 int
352 parseether(uchar *to, char *from)
353 {
354         char nip[4];
355         char *p;
356         int i;
357
358         p = from;
359         for(i = 0; i < Eaddrlen; i++){
360                 if(*p == 0)
361                         return -1;
362                 nip[0] = *p++;
363                 if(*p == 0)
364                         return -1;
365                 nip[1] = *p++;
366                 nip[2] = 0;
367                 to[i] = strtoul(nip, 0, 16);
368                 if(*p == ':')
369                         p++;
370         }
371         return 0;
372 }
373
374 static Ether*
375 etherprobe(int cardno, int ctlrno)
376 {
377         int i, lg;
378         ulong mb, bsz;
379         Ether *ether;
380         char buf[128], name[32];
381
382         ether = malloc(sizeof(Ether));
383         memset(ether, 0, sizeof(Ether));
384         ether->ctlrno = ctlrno;
385         ether->tbdf = BUSUNKNOWN;
386         ether->mbps = 10;
387         ether->minmtu = ETHERMINTU;
388         ether->maxmtu = ETHERMAXTU;
389
390         if(cardno < 0){
391                 if(isaconfig("ether", ctlrno, ether) == 0){
392                         free(ether);
393                         return nil;
394                 }
395                 for(cardno = 0; cards[cardno].type; cardno++){
396                         if(cistrcmp(cards[cardno].type, ether->type))
397                                 continue;
398                         for(i = 0; i < ether->nopt; i++){
399                                 if(strncmp(ether->opt[i], "ea=", 3))
400                                         continue;
401                                 if(parseether(ether->ea, &ether->opt[i][3]))
402                                         memset(ether->ea, 0, Eaddrlen);
403                         }
404                         break;
405                 }
406         }
407
408         if(cardno >= MaxEther || cards[cardno].type == nil){
409                 free(ether);
410                 return nil;
411         }
412         if(cards[cardno].reset(ether) < 0){
413                 free(ether);
414                 return nil;
415         }
416
417         /*
418          * IRQ2 doesn't really exist, it's used to gang the interrupt
419          * controllers together. A device set to IRQ2 will appear on
420          * the second interrupt controller as IRQ9.
421          */
422         if(ether->irq == 2)
423                 ether->irq = 9;
424         snprint(name, sizeof(name), "ether%d", ctlrno);
425
426         /*
427          * If ether->irq is <0, it is a hack to indicate no interrupt
428          * used by ethersink.
429          */
430         if(ether->irq >= 0)
431                 intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
432
433         i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
434                 ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
435         if(ether->mem)
436                 i += sprint(buf+i, " addr 0x%luX", ether->mem);
437         if(ether->size)
438                 i += sprint(buf+i, " size 0x%luX", ether->size);
439         i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
440                 ether->ea[0], ether->ea[1], ether->ea[2],
441                 ether->ea[3], ether->ea[4], ether->ea[5]);
442         sprint(buf+i, "\n");
443         print(buf);
444
445         /* compute log10(ether->mbps) into lg */
446         for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
447                 mb /= 10;
448         if (lg > 0)
449                 lg--;
450         if (lg > 14)                    /* 2^(14+17) = 2³¹ */
451                 lg = 14;
452         /* allocate larger output queues for higher-speed interfaces */
453         bsz = 1UL << (lg + 17);         /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
454         while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
455                 bsz /= 2;
456
457         netifinit(ether, name, Ntypes, bsz);
458         if(ether->oq == nil) {
459                 ether->oq = qopen(bsz, Qmsg, 0, 0);
460                 ether->limit = bsz;
461         }
462         if(ether->oq == nil)
463                 panic("etherreset %s: can't allocate output queue of %ld bytes",
464                         name, bsz);
465         ether->alen = Eaddrlen;
466         memmove(ether->addr, ether->ea, Eaddrlen);
467         memset(ether->bcast, 0xFF, Eaddrlen);
468
469         return ether;
470 }
471
472 static void
473 etherreset(void)
474 {
475         Ether *ether;
476         int cardno, ctlrno;
477
478         for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
479                 if((ether = etherprobe(-1, ctlrno)) == nil)
480                         continue;
481                 etherxx[ctlrno] = ether;
482         }
483
484         if(getconf("*noetherprobe"))
485                 return;
486
487         cardno = ctlrno = 0;
488         while(cards[cardno].type != nil && ctlrno < MaxEther){
489                 if(etherxx[ctlrno] != nil){
490                         ctlrno++;
491                         continue;
492                 }
493                 if((ether = etherprobe(cardno, ctlrno)) == nil){
494                         cardno++;
495                         continue;
496                 }
497                 etherxx[ctlrno] = ether;
498                 ctlrno++;
499         }
500 }
501
502 static void
503 ethershutdown(void)
504 {
505         Ether *ether;
506         int i;
507
508         for(i = 0; i < MaxEther; i++){
509                 ether = etherxx[i];
510                 if(ether == nil)
511                         continue;
512                 if(ether->shutdown == nil) {
513                         print("#l%d: no shutdown fuction\n", i);
514                         continue;
515                 }
516                 (*ether->shutdown)(ether);
517         }
518 }
519
520
521 #define POLY 0xedb88320
522
523 /* really slow 32 bit crc for ethers */
524 ulong
525 ethercrc(uchar *p, int len)
526 {
527         int i, j;
528         ulong crc, b;
529
530         crc = 0xffffffff;
531         for(i = 0; i < len; i++){
532                 b = *p++;
533                 for(j = 0; j < 8; j++){
534                         crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
535                         b >>= 1;
536                 }
537         }
538         return crc;
539 }
540
541 Dev etherdevtab = {
542         'l',
543         "ether",
544
545         etherreset,
546         devinit,
547         ethershutdown,
548         etherattach,
549         etherwalk,
550         etherstat,
551         etheropen,
552         ethercreate,
553         etherclose,
554         etherread,
555         etherbread,
556         etherwrite,
557         etherbwrite,
558         devremove,
559         etherwstat,
560 };