x86: one register_irq() for all types of buses
[akaros.git] / kern / drivers / dev / ether.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 #include <vfs.h>
17 #include <kfs.h>
18 #include <slab.h>
19 #include <kmalloc.h>
20 #include <kref.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #include <error.h>
25 #include <cpio.h>
26 #include <pmap.h>
27 #include <smp.h>
28 #include <ip.h>
29
30 enum {
31         Type8021Q = 0x8100,                     /* value of type field for 802.1[pQ] tags */
32 };
33
34 static struct ether *etherxx[MaxEther]; /* real controllers */
35 static struct ether *vlanalloc(struct ether *, int);
36 static void vlanoq(struct ether *, struct block *);
37
38 struct chan *etherattach(char *spec)
39 {
40         ERRSTACK(1);
41         uint32_t ctlrno;
42         char *p;
43         struct chan *chan;
44         struct ether *ether, *vlan;
45         int vlanid;
46
47         ctlrno = 0;
48         vlanid = 0;
49         if (spec && *spec) {
50                 ctlrno = strtoul(spec, &p, 0);
51                 /* somebody interpret this for me. */
52                 if (((ctlrno == 0) && (p == spec)) ||
53                         (ctlrno >= MaxEther) || ((*p) && (*p != '.')))
54                         error(Ebadarg);
55                 if (*p == '.') {        /* vlan */
56                         vlanid = strtoul(p + 1, &p, 0);
57                         if (vlanid <= 0 || vlanid > 0xFFF || *p)
58                                 error(Ebadarg);
59                 }
60         }
61         if ((ether = etherxx[ctlrno]) == 0)
62                 error(Enodev);
63         rlock(&ether->rwlock);
64         if (waserror()) {
65                 runlock(&ether->rwlock);
66                 nexterror();
67         }
68         if (vlanid) {
69                 if (ether->maxmtu < ETHERMAXTU + 4)
70                         error("interface cannot support 802.1 tags");
71                 vlan = vlanalloc(ether, vlanid);
72                 chan = devattach('l', spec);
73                 chan->dev = ctlrno + (vlanid << 8);
74                 chan->aux = vlan;
75                 poperror();
76                 runlock(&ether->rwlock);
77                 return chan;
78         }
79         chan = devattach('l', spec);
80         chan->dev = ctlrno;
81         chan->aux = ether;
82         if (ether->attach)
83                 ether->attach(ether);
84         poperror();
85         runlock(&ether->rwlock);
86         return chan;
87 }
88
89 static void ethershutdown(void)
90 {
91         struct ether *ether;
92         int i;
93
94         for (i = 0; i < MaxEther; i++) {
95                 ether = etherxx[i];
96                 if (ether != NULL && ether->detach != NULL)
97                         ether->detach(ether);
98         }
99 }
100
101 static struct walkqid *etherwalk(struct chan *chan, struct chan *nchan,
102                                                                  char **name, int nname)
103 {
104         ERRSTACK(1);
105         struct walkqid *wq;
106         struct ether *ether;
107
108         ether = chan->aux;
109         rlock(&ether->rwlock);
110         if (waserror()) {
111                 runlock(&ether->rwlock);
112                 nexterror();
113         }
114         wq = netifwalk(&ether->netif, chan, nchan, name, nname);
115         if (wq && wq->clone != NULL && wq->clone != chan)
116                 wq->clone->aux = ether;
117         poperror();
118         runlock(&ether->rwlock);
119         return wq;
120 }
121
122 static int etherstat(struct chan *chan, uint8_t * dp, int n)
123 {
124         ERRSTACK(1);
125         int s;
126         struct ether *ether;
127
128         ether = chan->aux;
129         rlock(&ether->rwlock);
130         if (waserror()) {
131                 runlock(&ether->rwlock);
132                 nexterror();
133         }
134         s = netifstat(&ether->netif, chan, dp, n);
135         poperror();
136         runlock(&ether->rwlock);
137         return s;
138 }
139
140 static struct chan *etheropen(struct chan *chan, int omode)
141 {
142         ERRSTACK(1);
143         struct chan *c;
144         struct ether *ether;
145
146         ether = chan->aux;
147         rlock(&ether->rwlock);
148         if (waserror()) {
149                 runlock(&ether->rwlock);
150                 nexterror();
151         }
152         c = netifopen(&ether->netif, chan, omode);
153         poperror();
154         runlock(&ether->rwlock);
155         return c;
156 }
157
158 static void etherclose(struct chan *chan)
159 {
160         ERRSTACK(1);
161         struct ether *ether;
162
163         ether = chan->aux;
164         rlock(&ether->rwlock);
165         if (waserror()) {
166                 runlock(&ether->rwlock);
167                 nexterror();
168         }
169         netifclose(&ether->netif, chan);
170         poperror();
171         runlock(&ether->rwlock);
172 }
173
174 static long etherread(struct chan *chan, void *buf, long n, int64_t off)
175 {
176         ERRSTACK(1);
177         struct ether *ether;
178         uint32_t offset = off;
179         long r;
180
181         ether = chan->aux;
182         rlock(&ether->rwlock);
183         if (waserror()) {
184                 runlock(&ether->rwlock);
185                 nexterror();
186         }
187         if ((chan->qid.type & QTDIR) == 0 && ether->ifstat) {
188                 /*
189                  * With some controllers it is necessary to reach
190                  * into the chip to extract statistics.
191                  */
192                 if (NETTYPE(chan->qid.path) == Nifstatqid) {
193                         r = ether->ifstat(ether, buf, n, offset);
194                         goto out;
195                 }
196                 if (NETTYPE(chan->qid.path) == Nstatqid)
197                         ether->ifstat(ether, buf, 0, offset);
198         }
199         r = netifread(&ether->netif, chan, buf, n, offset);
200 out:
201         poperror();
202         runlock(&ether->rwlock);
203         return r;
204 }
205
206 static struct block *etherbread(struct chan *chan, long n, uint32_t offset)
207 {
208         ERRSTACK(1);
209         struct block *b;
210         struct ether *ether;
211
212         ether = chan->aux;
213         rlock(&ether->rwlock);
214         if (waserror()) {
215                 runlock(&ether->rwlock);
216                 nexterror();
217         }
218         b = netifbread(&ether->netif, chan, n, offset);
219         poperror();
220         runlock(&ether->rwlock);
221         return b;
222 }
223
224 static int etherwstat(struct chan *chan, uint8_t * dp, int n)
225 {
226         ERRSTACK(1);
227         struct ether *ether;
228         int r;
229
230         ether = chan->aux;
231         rlock(&ether->rwlock);
232         if (waserror()) {
233                 runlock(&ether->rwlock);
234                 nexterror();
235         }
236         r = netifwstat(&ether->netif, chan, dp, n);
237         poperror();
238         runlock(&ether->rwlock);
239         return r;
240 }
241
242 static void etherrtrace(struct netfile *f, struct etherpkt *pkt, int len)
243 {
244         int i, n;
245         struct block *bp;
246
247         if (qwindow(f->in) <= 0)
248                 return;
249         if (len > 58)
250                 n = 58;
251         else
252                 n = len;
253         bp = iallocb(64);
254         if (bp == NULL)
255                 return;
256         memmove(bp->wp, pkt->d, n);
257         i = milliseconds();
258         bp->wp[58] = len >> 8;
259         bp->wp[59] = len;
260         bp->wp[60] = i >> 24;
261         bp->wp[61] = i >> 16;
262         bp->wp[62] = i >> 8;
263         bp->wp[63] = i;
264         bp->wp += 64;
265         qpass(f->in, bp);
266 }
267
268 struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
269 {
270         struct etherpkt *pkt;
271         uint16_t type;
272         int len, multi, tome, fromme, vlanid, i;
273         struct netfile **ep, *f, **fp, *fx;
274         struct block *xbp;
275         struct ether *vlan;
276
277         ether->netif.inpackets++;
278
279         pkt = (struct etherpkt *)bp->rp;
280         len = BLEN(bp);
281         type = (pkt->type[0] << 8) | pkt->type[1];
282         if (type == Type8021Q && ether->nvlan) {
283                 vlanid = nhgets(bp->rp + 2 * Eaddrlen + 2) & 0xFFF;
284                 if (vlanid) {
285                         for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
286                                 vlan = ether->vlans[i];
287                                 if (vlan != NULL && vlan->vlanid == vlanid) {
288                                         memmove(bp->rp + 4, bp->rp, 2 * Eaddrlen);
289                                         bp->rp += 4;
290                                         return etheriq(vlan, bp, fromwire);
291                                 }
292                         }
293                         /* allow normal type handling to accept or discard it */
294                 }
295         }
296
297         fx = 0;
298         ep = &ether->netif.f[Ntypes];
299
300         multi = pkt->d[0] & 1;
301         /* check for valid multcast addresses */
302         if (multi && memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) != 0
303                 && ether->netif.prom == 0) {
304                 if (!activemulti(&ether->netif, pkt->d, sizeof(pkt->d))) {
305                         if (fromwire) {
306                                 freeb(bp);
307                                 bp = 0;
308                         }
309                         return bp;
310                 }
311         }
312
313         /* is it for me? */
314         tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
315         fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
316
317         /*
318          * Multiplex the packet to all the connections which want it.
319          * If the packet is not to be used subsequently (fromwire != 0),
320          * attempt to simply pass it into one of the connections, thereby
321          * saving a copy of the data (usual case hopefully).
322          */
323         for (fp = ether->netif.f; fp < ep; fp++) {
324                 if ((f = *fp) && (f->type == type || f->type < 0))
325                         if (tome || multi || f->prom) {
326                                 /* Don't want to hear bridged packets */
327                                 if (f->bridge && !fromwire && !fromme)
328                                         continue;
329                                 if (!f->headersonly) {
330                                         if (fromwire && fx == 0)
331                                                 fx = f;
332                                         else if ((xbp = iallocb(len))) {
333                                                 memmove(xbp->wp, pkt, len);
334                                                 xbp->wp += len;
335                                                 if (qpass(f->in, xbp) < 0)
336                                                         ether->netif.soverflows++;
337                                         } else
338                                                 ether->netif.soverflows++;
339                                 } else
340                                         etherrtrace(f, pkt, len);
341                         }
342         }
343
344         if (fx) {
345                 if (qpass(fx->in, bp) < 0)
346                         ether->netif.soverflows++;
347                 return 0;
348         }
349         if (fromwire) {
350                 freeb(bp);
351                 return 0;
352         }
353
354         return bp;
355 }
356
357 static int etheroq(struct ether *ether, struct block *bp)
358 {
359         int len, loopback;
360         struct etherpkt *pkt;
361         int8_t irq_state = 0;
362
363         ether->netif.outpackets++;
364
365         /*
366          * Check if the packet has to be placed back onto the input queue,
367          * i.e. if it's a loopback or broadcast packet or the interface is
368          * in promiscuous mode.
369          * If it's a loopback packet indicate to etheriq that the data isn't
370          * needed and return, etheriq will pass-on or free the block.
371          * To enable bridging to work, only packets that were originated
372          * by this interface are fed back.
373          */
374         pkt = (struct etherpkt *)bp->rp;
375         len = BLEN(bp);
376         loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
377         if (loopback || memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) == 0
378                 || ether->netif.prom) {
379                 disable_irqsave(&irq_state);
380                 etheriq(ether, bp, 0);
381                 enable_irqsave(&irq_state);
382         }
383
384         if (!loopback) {
385                 if (ether->vlanid) {
386                         /* add tag */
387                         bp = padblock(bp, 2 + 2);
388                         memmove(bp->rp, bp->rp + 4, 2 * Eaddrlen);
389                         hnputs(bp->rp + 2 * Eaddrlen, Type8021Q);
390                         hnputs(bp->rp + 2 * Eaddrlen + 2, ether->vlanid & 0xFFF);       /* prio:3 0:1 vid:12 */
391                         ether = ether->ctlr;
392                 }
393                 qbwrite(ether->oq, bp);
394                 if (ether->transmit != NULL)
395                         ether->transmit(ether);
396         } else
397                 freeb(bp);
398
399         return len;
400 }
401
402 static long etherwrite(struct chan *chan, void *buf, long n, int64_t unused)
403 {
404         ERRSTACK(2);
405         struct ether *ether;
406         struct block *bp;
407         int onoff;
408         struct cmdbuf *cb;
409         long l;
410
411         ether = chan->aux;
412         rlock(&ether->rwlock);
413         if (waserror()) {
414                 runlock(&ether->rwlock);
415                 nexterror();
416         }
417         if (NETTYPE(chan->qid.path) != Ndataqid) {
418                 l = netifwrite(&ether->netif, chan, buf, n);
419                 if (l >= 0)
420                         goto out;
421                 cb = parsecmd(buf, n);
422                 if (strcmp(cb->f[0], "nonblocking") == 0) {
423                         if (cb->nf <= 1)
424                                 onoff = 1;
425                         else
426                                 onoff = atoi(cb->f[1]);
427                         if (ether->oq != NULL)
428                                 qnoblock(ether->oq, onoff);
429                         kfree(cb);
430                         goto out;
431                 }
432                 kfree(cb);
433                 if (ether->ctl != NULL) {
434                         l = ether->ctl(ether, buf, n);
435                         goto out;
436                 }
437                 error(Ebadctl);
438         }
439
440         if (n > ether->maxmtu)
441                 error(Etoobig);
442         if (n < ether->minmtu)
443                 error(Etoosmall);
444         bp = allocb(n);
445         if (waserror()) {
446                 freeb(bp);
447                 nexterror();
448         }
449         memmove(bp->rp, buf, n);
450         memmove(bp->rp + Eaddrlen, ether->ea, Eaddrlen);
451         bp->wp += n;
452         poperror();
453
454         l = etheroq(ether, bp);
455 out:
456         poperror();
457         runlock(&ether->rwlock);
458         return l;
459 }
460
461 static long etherbwrite(struct chan *chan, struct block *bp, uint32_t unused)
462 {
463         ERRSTACK(1);
464         struct ether *ether;
465         long n;
466
467         n = BLEN(bp);
468         if (NETTYPE(chan->qid.path) != Ndataqid) {
469                 if (waserror()) {
470                         freeb(bp);
471                         nexterror();
472                 }
473                 n = etherwrite(chan, bp->rp, n, 0);
474                 poperror();
475                 freeb(bp);
476                 return n;
477         }
478         ether = chan->aux;
479         rlock(&ether->rwlock);
480         if (waserror()) {
481                 runlock(&ether->rwlock);
482                 nexterror();
483         }
484         if (n > ether->maxmtu) {
485                 freeb(bp);
486                 error(Etoobig);
487         }
488         if (n < ether->minmtu) {
489                 freeb(bp);
490                 error(Etoosmall);
491         }
492         n = etheroq(ether, bp);
493         poperror();
494         runlock(&ether->rwlock);
495         return n;
496 }
497
498 static void nop(struct ether *unused)
499 {
500 }
501
502 static long vlanctl(struct ether *ether, void *buf, long n)
503 {
504         uint8_t ea[Eaddrlen];
505         struct ether *master;
506         struct cmdbuf *cb;
507         int i;
508
509         cb = parsecmd(buf, n);
510         if (cb->nf >= 2
511                 && strcmp(cb->f[0], "ea") == 0 && parseether(ea, cb->f[1]) == 0) {
512                 kfree(cb);
513                 memmove(ether->ea, ea, Eaddrlen);
514                 memmove(ether->netif.addr, ether->ea, Eaddrlen);
515                 return 0;
516         }
517         if (cb->nf == 1 && strcmp(cb->f[0], "disable") == 0) {
518                 master = ether->ctlr;
519                 qlock(&master->vlq);
520                 for (i = 0; i < ARRAY_SIZE(master->vlans); i++)
521                         if (master->vlans[i] == ether) {
522                                 ether->vlanid = 0;
523                                 master->nvlan--;
524                                 break;
525                         }
526                 qunlock(&master->vlq);
527                 kfree(cb);
528                 return 0;
529         }
530         kfree(cb);
531         error(Ebadctl);
532         return -1;      /* not reached */
533 }
534
535 static struct ether *vlanalloc(struct ether *ether, int id)
536 {
537         ERRSTACK(1);
538         struct ether *vlan;
539         int i, fid;
540         char name[KNAMELEN];
541
542         qlock(&ether->vlq);
543         if (waserror()) {
544                 qunlock(&ether->vlq);
545                 nexterror();
546         }
547         fid = -1;
548         for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
549                 vlan = ether->vlans[i];
550                 if (vlan != NULL && vlan->vlanid == id) {
551                         poperror();
552                         qunlock(&ether->vlq);
553                         return vlan;
554                 }
555                 if (fid < 0 && (vlan == NULL || vlan->vlanid == 0))
556                         fid = i;
557         }
558         if (fid < 0)
559                 error(Enoifc);
560         snprintf(name, sizeof(name), "ether%d.%d", ether->ctlrno, id);
561         vlan = ether->vlans[fid];
562         if (vlan == NULL) {
563                 vlan = kzmalloc(sizeof(struct ether), 1);
564                 if (vlan == NULL)
565                         error(Enovmem);
566                 rwinit(&vlan->rwlock);
567                 qlock_init(&vlan->vlq);
568                 netifinit(&vlan->netif, name, Ntypes, ether->netif.limit);
569                 ether->vlans[fid] = vlan;       /* id is still zero, can't be matched */
570                 ether->nvlan++;
571         } else
572                 memmove(vlan->netif.name, name, KNAMELEN - 1);
573         vlan->attach = nop;
574         vlan->transmit = NULL;
575         vlan->ctl = vlanctl;
576         vlan->irq = -1;
577         vlan->netif.promiscuous = ether->netif.promiscuous;
578         vlan->netif.multicast = ether->netif.multicast;
579         vlan->netif.arg = vlan;
580         vlan->netif.mbps = ether->netif.mbps;
581         vlan->fullduplex = ether->fullduplex;
582         vlan->encry = ether->encry;
583         vlan->minmtu = ether->minmtu;
584         vlan->maxmtu = ether->maxmtu;
585         vlan->ctlrno = ether->ctlrno;
586         vlan->vlanid = id;
587         vlan->netif.alen = Eaddrlen;
588         memmove(vlan->netif.addr, ether->netif.addr, sizeof(vlan->netif.addr));
589         memmove(vlan->netif.bcast, ether->netif.bcast, sizeof(ether->netif.bcast));
590         vlan->oq = NULL;
591         vlan->ctlr = ether;
592         vlan->vlanid = id;
593         poperror();
594         qunlock(&ether->vlq);
595         return vlan;
596 }
597
598 static struct {
599         char *type;
600         int (*reset) (struct ether *);
601 } cards[MaxEther + 1];
602
603 void addethercard(char *t, int (*r) (struct ether *))
604 {
605         static int ncard;
606
607         if (ncard == MaxEther)
608                 panic("too many ether cards");
609         cards[ncard].type = t;
610         cards[ncard].reset = r;
611         ncard++;
612 }
613
614 int parseether(uint8_t * to, char *from)
615 {
616         char nip[4];
617         char *p;
618         int i;
619
620         p = from;
621         for (i = 0; i < Eaddrlen; i++) {
622                 if (*p == 0)
623                         return -1;
624                 nip[0] = *p++;
625                 if (*p == 0)
626                         return -1;
627                 nip[1] = *p++;
628                 nip[2] = 0;
629                 to[i] = strtoul(nip, 0, 16);
630                 if (*p == ':')
631                         p++;
632         }
633         return 0;
634 }
635
636 static void etherreset(void)
637 {
638         struct ether *ether;
639         int i, n, ctlrno;
640         char name[KNAMELEN], buf[128];
641
642         for (ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++) {
643                 if (ether == 0)
644                         ether = kzmalloc(sizeof(struct ether), 0);
645                 memset(ether, 0, sizeof(struct ether));
646                 rwinit(&ether->rwlock);
647                 qlock_init(&ether->vlq);
648                 ether->ctlrno = ctlrno;
649                 ether->netif.mbps = 10;
650                 ether->minmtu = ETHERMINTU;
651                 ether->maxmtu = ETHERMAXTU;
652                 /* looked like irq type, we don't have these yet */
653                 //ether->netif.itype = -1;
654
655                 /* TODO: looks like they expected some init to be done here.  at the
656                  * very least, ether->type is 0 right now, and needs to be set.  looking
657                  * around online, it seems to find out ether config settings, so that we
658                  * can set some flags in the opt parseing below. */
659                 //if(archether(ctlrno, ether) <= 0)
660                 //  continue;
661
662                 for (n = 0; cards[n].type; n++) {
663 #if 0
664                         if (cistrcmp(cards[n].type, ether->type))
665                                 continue;
666                         for (i = 0; i < ether->nopt; i++) {
667                                 if (cistrncmp(ether->opt[i], "ea=", 3) == 0) {
668                                         if (parseether(ether->ea, &ether->opt[i][3]) == -1)
669                                                 memset(ether->ea, 0, Eaddrlen);
670                                 } else if (cistrcmp(ether->opt[i], "fullduplex") == 0 ||
671                                                    cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
672                                         ether->fullduplex = 1;
673                                 else if (cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
674                                         ether->mbps = 100;
675                         }
676 #endif
677                         if (cards[n].reset(ether))
678                                 continue;
679                         /* might be fucked a bit - reset() doesn't know the type.  might not
680                          * even matter, except for debugging. */
681                         ether->type = cards[n].type;
682                         snprintf(name, sizeof(name), "ether%d", ctlrno);
683
684                         if (ether->interrupt != NULL)
685                                 register_irq(ether->irq, ether->interrupt, ether, ether->tbdf);
686
687                         i = snprintf(buf, sizeof(buf),
688                                                  "#l%d: %s: %dMbps port 0x%x irq %u", ctlrno,
689                                                  ether->type, ether->netif.mbps, ether->port,
690                                                  ether->irq);
691                         /* Looks like this is for printing MMIO addrs */
692 #if 0
693                         if (ether->mem)
694                                 i += snprintf(buf + i, sizeof(buf) - i, " addr 0x%lx",
695                                                           PADDR(ether->mem));
696                         if (ether->size)
697                                 i += snprintf(buf + i, sizeof(buf) - i, " size 0x%lx",
698                                                           ether->size);
699 #endif
700                         i += snprintf(buf + i, sizeof(buf) - i,
701                                                   ": %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x",
702                                                   ether->ea[0], ether->ea[1], ether->ea[2],
703                                                   ether->ea[3], ether->ea[4], ether->ea[5]);
704                         snprintf(buf + i, sizeof(buf) - i, "\n");
705                         printk(buf);
706
707                         if (ether->netif.mbps == 100) {
708                                 netifinit(&ether->netif, name, Ntypes, 256 * 1024);
709                                 if (ether->oq == 0)
710                                         ether->oq = qopen(256 * 1024, Qmsg, 0, 0);
711                         } else {
712                                 netifinit(&ether->netif, name, Ntypes, 64 * 1024);
713                                 if (ether->oq == 0)
714                                         ether->oq = qopen(64 * 1024, Qmsg, 0, 0);
715                         }
716                         if (ether->oq == 0)
717                                 panic("etherreset %s", name);
718                         ether->netif.alen = Eaddrlen;
719                         memmove(ether->netif.addr, ether->ea, Eaddrlen);
720                         memset(ether->netif.bcast, 0xFF, Eaddrlen);
721
722                         etherxx[ctlrno] = ether;
723                         ether = 0;
724                         break;
725                 }
726         }
727         if (ether)
728                 kfree(ether);
729 }
730
731 static void etherpower(int on)
732 {
733         int i;
734         struct ether *ether;
735
736         /* TODO: fix etherpower.  locking and ether->readers are broken. */
737         warn("%s needs attention.  had a rough porting from inferno", __FUNCTION__);
738         for (i = 0; i < MaxEther; i++) {
739                 if ((ether = etherxx[i]) == NULL || ether->power == NULL)
740                         continue;
741                 if (on) {
742                         /* brho: not sure what they are doing.  there seem to be certain
743                          * assumptions about calling etherpower.  i think they are using
744                          * canrlock to see if the lock is currently writelocked.  and if it
745                          * was not lockable, they would assume they had the write lock and
746                          * could unlock.  this is super fucked up. */
747                         if (canrlock(&ether->rwlock)) {
748                                 runlock(&ether->rwlock);        // brho added this
749                                 continue;
750                         }
751                         if (ether->power != NULL)
752                                 ether->power(ether, on);
753                         wunlock(&ether->rwlock);
754                 } else {
755                         /* readers isn't in the ether struct...
756                            if(ether->readers)
757                            continue;
758                          */
759                         wlock(&ether->rwlock);
760                         if (ether->power != NULL)
761                                 ether->power(ether, on);
762                         /* Keep locked until power goes back on */
763                 }
764         }
765 }
766
767 #define ETHERPOLY 0xedb88320
768
769 /* really slow 32 bit crc for ethers */
770 uint32_t ethercrc(uint8_t * p, int len)
771 {
772         int i, j;
773         uint32_t crc, b;
774
775         crc = 0xffffffff;
776         for (i = 0; i < len; i++) {
777                 b = *p++;
778                 for (j = 0; j < 8; j++) {
779                         crc = (crc >> 1) ^ (((crc ^ b) & 1) ? ETHERPOLY : 0);
780                         b >>= 1;
781                 }
782         }
783         return crc;
784 }
785
786 struct dev etherdevtab __devtab = {
787         'l',
788         "ether",
789
790         etherreset,
791         devinit,
792         ethershutdown,
793         etherattach,
794         etherwalk,
795         etherstat,
796         etheropen,
797         devcreate,
798         etherclose,
799         etherread,
800         etherbread,
801         etherwrite,
802         etherbwrite,
803         devremove,
804         etherwstat,
805         etherpower,
806         devchaninfo,
807 };