Annotation of sys/arch/mac68k/dev/if_mc.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_mc.c,v 1.15 2007/01/12 16:31:21 martin Exp $ */
2: /* $NetBSD: if_mc.c,v 1.24 2004/10/30 18:08:34 thorpej Exp $ */
3:
4: /*-
5: * Copyright (c) 1997 David Huang <khym@azeotrope.org>
6: * All rights reserved.
7: *
8: * Portions of this code are based on code by Denton Gentry <denny1@home.com>,
9: * Charles M. Hannum, Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>, and
10: * Jason R. Thorpe.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. The name of the author may not be used to endorse or promote products
18: * derived from this software without specific prior written permission
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: *
31: */
32:
33: /*
34: * Driver for the AMD Am79C940 (MACE) ethernet chip, used for onboard
35: * ethernet on the Centris/Quadra 660av and Quadra 840av.
36: */
37:
38: #include <sys/param.h>
39: #include <sys/systm.h>
40: #include <sys/mbuf.h>
41: #include <sys/buf.h>
42: #include <sys/protosw.h>
43: #include <sys/socket.h>
44: #include <sys/syslog.h>
45: #include <sys/ioctl.h>
46: #include <sys/errno.h>
47: #include <sys/device.h>
48:
49: #include <net/if.h>
50: #include <net/if_dl.h>
51:
52: #ifdef INET
53: #include <netinet/in.h>
54: #include <netinet/if_ether.h>
55: #include <netinet/in_systm.h>
56: #include <netinet/in_var.h>
57: #include <netinet/ip.h>
58: #endif
59:
60: #include <uvm/uvm_extern.h>
61:
62: #include "bpfilter.h"
63: #if NBPFILTER > 0
64: #include <net/bpf.h>
65: #include <net/bpfdesc.h>
66: #endif
67:
68: #include <machine/bus.h>
69: #include <mac68k/dev/if_mcreg.h>
70: #include <mac68k/dev/if_mcvar.h>
71:
72: struct cfdriver mc_cd = {
73: NULL, "mc", DV_IFNET
74: };
75:
76: void mcwatchdog(struct ifnet *);
77: int mcinit(struct mc_softc *sc);
78: int mcstop(struct mc_softc *sc);
79: int mcioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
80: void mcstart(struct ifnet *ifp);
81: void mcreset(struct mc_softc *sc);
82:
83: u_int maceput(struct mc_softc *sc, struct mbuf *m0);
84: void mc_tint(struct mc_softc *sc);
85: void mace_read(struct mc_softc *, caddr_t, int);
86: struct mbuf *mace_get(struct mc_softc *, caddr_t, int);
87: static void mace_calcladrf(struct arpcom *ac, u_int8_t *af);
88: static inline u_int16_t ether_cmp(void *, void *);
89:
90:
91: /*
92: * Compare two Ether/802 addresses for equality, inlined and
93: * unrolled for speed. Use this like bcmp().
94: *
95: * XXX: Add <machine/inlines.h> for stuff like this?
96: * XXX: or maybe add it to libkern.h instead?
97: *
98: * "I'd love to have an inline assembler version of this."
99: * XXX: Who wanted that? mycroft? I wrote one, but this
100: * version in C is as good as hand-coded assembly. -gwr
101: *
102: * Please do NOT tweak this without looking at the actual
103: * assembly code generated before and after your tweaks!
104: */
105: static inline u_int16_t
106: ether_cmp(one, two)
107: void *one, *two;
108: {
109: register u_int16_t *a = (u_short *) one;
110: register u_int16_t *b = (u_short *) two;
111: register u_int16_t diff;
112:
113: #ifdef m68k
114: /*
115: * The post-increment-pointer form produces the best
116: * machine code for m68k. This was carefully tuned
117: * so it compiles to just 8 short (2-byte) op-codes!
118: */
119: diff = *a++ - *b++;
120: diff |= *a++ - *b++;
121: diff |= *a++ - *b++;
122: #else
123: /*
124: * Most modern CPUs do better with a single expresion.
125: * Note that short-cut evaluation is NOT helpful here,
126: * because it just makes the code longer, not faster!
127: */
128: diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
129: #endif
130:
131: return (diff);
132: }
133:
134: #define ETHER_CMP ether_cmp
135:
136: /*
137: * Interface exists: make available by filling in network interface
138: * record. System will initialize the interface when it is ready
139: * to accept packets.
140: */
141: int
142: mcsetup(sc, lladdr)
143: struct mc_softc *sc;
144: u_int8_t *lladdr;
145: {
146: struct ifnet *ifp = &sc->sc_if;
147:
148: /* reset the chip and disable all interrupts */
149: NIC_PUT(sc, MACE_BIUCC, SWRST);
150: DELAY(100);
151: NIC_PUT(sc, MACE_IMR, ~0);
152:
153: bcopy(lladdr, sc->sc_enaddr, ETHER_ADDR_LEN);
154: bcopy(sc->sc_enaddr, sc->sc_ethercom.ac_enaddr, ETHER_ADDR_LEN);
155: printf(": address %s\n", ether_sprintf(lladdr));
156:
157: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
158: ifp->if_softc = sc;
159: ifp->if_ioctl = mcioctl;
160: ifp->if_start = mcstart;
161: ifp->if_flags =
162: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
163: ifp->if_watchdog = mcwatchdog;
164: IFQ_SET_READY(&ifp->if_snd);
165:
166: if_attach(ifp);
167: ether_ifattach(ifp);
168:
169: return (0);
170: }
171:
172: int
173: mcioctl(ifp, cmd, data)
174: struct ifnet *ifp;
175: u_long cmd;
176: caddr_t data;
177: {
178: struct mc_softc *sc = ifp->if_softc;
179: struct ifaddr *ifa;
180: struct ifreq *ifr;
181:
182: int s = splnet(), err = 0;
183:
184: switch (cmd) {
185:
186: case SIOCSIFADDR:
187: ifa = (struct ifaddr *)data;
188: ifp->if_flags |= IFF_UP;
189: switch (ifa->ifa_addr->sa_family) {
190: #ifdef INET
191: case AF_INET:
192: mcinit(sc);
193: arp_ifinit(&sc->sc_ethercom, ifa);
194: break;
195: #endif
196: default:
197: mcinit(sc);
198: break;
199: }
200: break;
201:
202: case SIOCSIFFLAGS:
203: if ((ifp->if_flags & IFF_UP) == 0 &&
204: (ifp->if_flags & IFF_RUNNING) != 0) {
205: /*
206: * If interface is marked down and it is running,
207: * then stop it.
208: */
209: mcstop(sc);
210: ifp->if_flags &= ~IFF_RUNNING;
211: } else if ((ifp->if_flags & IFF_UP) != 0 &&
212: (ifp->if_flags & IFF_RUNNING) == 0) {
213: /*
214: * If interface is marked up and it is stopped,
215: * then start it.
216: */
217: (void)mcinit(sc);
218: } else {
219: /*
220: * reset the interface to pick up any other changes
221: * in flags
222: */
223: mcreset(sc);
224: mcstart(ifp);
225: }
226: break;
227:
228: case SIOCADDMULTI:
229: case SIOCDELMULTI:
230: ifr = (struct ifreq *) data;
231: err = (cmd == SIOCADDMULTI) ?
232: ether_addmulti(ifr, &sc->sc_ethercom) :
233: ether_delmulti(ifr, &sc->sc_ethercom);
234:
235: if (err == ENETRESET) {
236: /*
237: * Multicast list has changed; set the hardware
238: * filter accordingly. But remember UP flag!
239: */
240: if (ifp->if_flags & IFF_RUNNING)
241: mcreset(sc);
242: err = 0;
243: }
244: break;
245: default:
246: err = EINVAL;
247: }
248: splx(s);
249: return (err);
250: }
251:
252: /*
253: * Encapsulate a packet of type family for the local net.
254: */
255: void
256: mcstart(ifp)
257: struct ifnet *ifp;
258: {
259: struct mc_softc *sc = ifp->if_softc;
260: struct mbuf *m;
261:
262: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
263: return;
264:
265: while (1) {
266: if (ifp->if_flags & IFF_OACTIVE)
267: return;
268:
269: IFQ_DEQUEUE(&ifp->if_snd, m);
270: if (m == NULL)
271: return;
272:
273: #if NBPFILTER > 0
274: /*
275: * If bpf is listening on this interface, let it
276: * see the packet before we commit it to the wire.
277: */
278: if (ifp->if_bpf)
279: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
280: #endif
281:
282: /*
283: * Copy the mbuf chain into the transmit buffer.
284: */
285: ifp->if_flags |= IFF_OACTIVE;
286: maceput(sc, m);
287:
288: ifp->if_opackets++; /* # of pkts */
289: }
290: }
291:
292: /*
293: * reset and restart the MACE. Called in case of fatal
294: * hardware/software errors.
295: */
296: void
297: mcreset(sc)
298: struct mc_softc *sc;
299: {
300: mcstop(sc);
301: mcinit(sc);
302: }
303:
304: int
305: mcinit(sc)
306: struct mc_softc *sc;
307: {
308: int s;
309: u_int8_t maccc, ladrf[8];
310:
311: if (sc->sc_if.if_flags & IFF_RUNNING)
312: /* already running */
313: return (0);
314:
315: s = splnet();
316:
317: NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc);
318: NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc);
319: NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */
320: NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc);
321:
322: NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */
323:
324: /* set MAC address */
325: NIC_PUT(sc, MACE_IAC, ADDRCHG);
326: while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
327: ;
328: NIC_PUT(sc, MACE_IAC, PHYADDR);
329: bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR),
330: sc->sc_enaddr, ETHER_ADDR_LEN);
331:
332: /* set logical address filter */
333: mace_calcladrf(&sc->sc_ethercom, ladrf);
334:
335: NIC_PUT(sc, MACE_IAC, ADDRCHG);
336: while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
337: ;
338: NIC_PUT(sc, MACE_IAC, LOGADDR);
339: bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF),
340: ladrf, 8);
341:
342: NIC_PUT(sc, MACE_XMTFC, APADXMT);
343: /*
344: * No need to autostrip padding on receive... Ethernet frames
345: * don't have a length field, unlike 802.3 frames, so the MACE
346: * can't figure out the length of the packet anyways.
347: */
348: NIC_PUT(sc, MACE_RCVFC, 0);
349:
350: maccc = ENXMT | ENRCV;
351: if (sc->sc_if.if_flags & IFF_PROMISC)
352: maccc |= PROM;
353:
354: NIC_PUT(sc, MACE_MACCC, maccc);
355:
356: if (sc->sc_bus_init)
357: (*sc->sc_bus_init)(sc);
358:
359: /*
360: * Enable all interrupts except receive, since we use the DMA
361: * completion interrupt for that.
362: */
363: NIC_PUT(sc, MACE_IMR, RCVINTM);
364:
365: /* flag interface as "running" */
366: sc->sc_if.if_flags |= IFF_RUNNING;
367: sc->sc_if.if_flags &= ~IFF_OACTIVE;
368:
369: splx(s);
370: return (0);
371: }
372:
373: /*
374: * close down an interface and free its buffers
375: * Called on final close of device, or if mcinit() fails
376: * part way through.
377: */
378: int
379: mcstop(sc)
380: struct mc_softc *sc;
381: {
382: int s = splnet();
383:
384: NIC_PUT(sc, MACE_BIUCC, SWRST);
385: DELAY(100);
386:
387: sc->sc_if.if_timer = 0;
388: sc->sc_if.if_flags &= ~IFF_RUNNING;
389:
390: splx(s);
391: return (0);
392: }
393:
394: /*
395: * Called if any Tx packets remain unsent after 5 seconds,
396: * In all cases we just reset the chip, and any retransmission
397: * will be handled by higher level protocol timeouts.
398: */
399: void
400: mcwatchdog(ifp)
401: struct ifnet *ifp;
402: {
403: struct mc_softc *sc = ifp->if_softc;
404:
405: printf("mcwatchdog: resetting chip\n");
406: mcreset(sc);
407: }
408:
409: /*
410: * stuff packet into MACE (at splnet)
411: */
412: u_int
413: maceput(sc, m)
414: struct mc_softc *sc;
415: struct mbuf *m;
416: {
417: struct mbuf *n;
418: u_int len, totlen = 0;
419: u_char *buff;
420:
421: buff = sc->sc_txbuf;
422:
423: for (; m; m = n) {
424: u_char *data = mtod(m, u_char *);
425: len = m->m_len;
426: totlen += len;
427: bcopy(data, buff, len);
428: buff += len;
429: MFREE(m, n);
430: }
431:
432: if (totlen > PAGE_SIZE)
433: panic("%s: maceput: packet overflow", sc->sc_dev.dv_xname);
434:
435: #if 0
436: if (totlen < ETHERMIN + sizeof(struct ether_header)) {
437: int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
438: bzero(sc->sc_txbuf + totlen, pad);
439: totlen = ETHERMIN + sizeof(struct ether_header);
440: }
441: #endif
442:
443: (*sc->sc_putpacket)(sc, totlen);
444:
445: sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
446: return (totlen);
447: }
448:
449: void
450: mcintr(arg)
451: void *arg;
452: {
453: struct mc_softc *sc = arg;
454: u_int8_t ir;
455:
456: ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR);
457: if (ir & JAB) {
458: #ifdef MCDEBUG
459: printf("%s: jabber error\n", sc->sc_dev.dv_xname);
460: #endif
461: sc->sc_if.if_oerrors++;
462: }
463:
464: if (ir & BABL) {
465: #ifdef MCDEBUG
466: printf("%s: babble\n", sc->sc_dev.dv_xname);
467: #endif
468: sc->sc_if.if_oerrors++;
469: }
470:
471: if (ir & CERR) {
472: #ifdef MCDEBUG
473: printf("%s: collision error\n", sc->sc_dev.dv_xname);
474: #endif
475: sc->sc_if.if_collisions++;
476: }
477:
478: /*
479: * Pretend we have carrier; if we don't this will be cleared
480: * shortly.
481: */
482: sc->sc_havecarrier = 1;
483:
484: if (ir & XMTINT)
485: mc_tint(sc);
486:
487: if (ir & RCVINT)
488: mc_rint(sc);
489: }
490:
491: void
492: mc_tint(sc)
493: struct mc_softc *sc;
494: {
495: u_int8_t xmtrc, xmtfs;
496:
497: xmtrc = NIC_GET(sc, MACE_XMTRC);
498: xmtfs = NIC_GET(sc, MACE_XMTFS);
499:
500: if ((xmtfs & XMTSV) == 0)
501: return;
502:
503: if (xmtfs & UFLO) {
504: printf("%s: underflow\n", sc->sc_dev.dv_xname);
505: mcreset(sc);
506: return;
507: }
508:
509: if (xmtfs & LCOL) {
510: printf("%s: late collision\n", sc->sc_dev.dv_xname);
511: sc->sc_if.if_oerrors++;
512: sc->sc_if.if_collisions++;
513: }
514:
515: if (xmtfs & MORE)
516: /* Real number is unknown. */
517: sc->sc_if.if_collisions += 2;
518: else if (xmtfs & ONE)
519: sc->sc_if.if_collisions++;
520: else if (xmtfs & RTRY) {
521: printf("%s: excessive collisions\n", sc->sc_dev.dv_xname);
522: sc->sc_if.if_collisions += 16;
523: sc->sc_if.if_oerrors++;
524: }
525:
526: if (xmtfs & LCAR) {
527: sc->sc_havecarrier = 0;
528: printf("%s: lost carrier\n", sc->sc_dev.dv_xname);
529: sc->sc_if.if_oerrors++;
530: }
531:
532: sc->sc_if.if_flags &= ~IFF_OACTIVE;
533: sc->sc_if.if_timer = 0;
534: mcstart(&sc->sc_if);
535: }
536:
537: void
538: mc_rint(sc)
539: struct mc_softc *sc;
540: {
541: #define rxf sc->sc_rxframe
542: u_int len;
543:
544: len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4;
545:
546: #ifdef MCDEBUG
547: if (rxf.rx_rcvsts & 0xf0)
548: printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n",
549: sc->sc_dev.dv_xname, rxf.rx_rcvcnt, rxf.rx_rcvsts,
550: rxf.rx_rntpc, rxf.rx_rcvcc);
551: #endif
552:
553: if (rxf.rx_rcvsts & OFLO) {
554: #ifdef MCDEBUG
555: printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname);
556: #endif
557: sc->sc_if.if_ierrors++;
558: return;
559: }
560:
561: if (rxf.rx_rcvsts & CLSN)
562: sc->sc_if.if_collisions++;
563:
564: if (rxf.rx_rcvsts & FRAM) {
565: #ifdef MCDEBUG
566: printf("%s: framing error\n", sc->sc_dev.dv_xname);
567: #endif
568: sc->sc_if.if_ierrors++;
569: return;
570: }
571:
572: if (rxf.rx_rcvsts & FCS) {
573: #ifdef MCDEBUG
574: printf("%s: frame control checksum error\n", sc->sc_dev.dv_xname);
575: #endif
576: sc->sc_if.if_ierrors++;
577: return;
578: }
579:
580: mace_read(sc, rxf.rx_frame, len);
581: #undef rxf
582: }
583:
584: void
585: mace_read(sc, pkt, len)
586: struct mc_softc *sc;
587: caddr_t pkt;
588: int len;
589: {
590: struct ifnet *ifp = &sc->sc_if;
591: struct mbuf *m;
592:
593: if (len <= sizeof(struct ether_header) ||
594: len > ETHERMTU + sizeof(struct ether_header)) {
595: #ifdef MCDEBUG
596: printf("%s: invalid packet size %d; dropping\n",
597: sc->sc_dev.dv_xname, len);
598: #endif
599: ifp->if_ierrors++;
600: return;
601: }
602:
603: m = mace_get(sc, pkt, len);
604: if (m == NULL) {
605: ifp->if_ierrors++;
606: return;
607: }
608:
609: ifp->if_ipackets++;
610:
611: #if NBPFILTER > 0
612: /* Pass the packet to any BPF listeners. */
613: if (ifp->if_bpf)
614: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
615: #endif
616:
617: /* Pass the packet up. */
618: ether_input_mbuf(ifp, m);
619: }
620:
621: /*
622: * Pull data off an interface.
623: * Len is length of data, with local net header stripped.
624: * We copy the data into mbufs. When full cluster sized units are present
625: * we copy into clusters.
626: */
627: struct mbuf *
628: mace_get(sc, pkt, totlen)
629: struct mc_softc *sc;
630: caddr_t pkt;
631: int totlen;
632: {
633: register struct mbuf *m;
634: struct mbuf *top, **mp;
635: int len;
636:
637: MGETHDR(m, M_DONTWAIT, MT_DATA);
638: if (m == NULL)
639: return (NULL);
640:
641: m->m_pkthdr.rcvif = &sc->sc_if;
642: m->m_pkthdr.len = totlen;
643: len = MHLEN;
644: top = 0;
645: mp = ⊤
646:
647: while (totlen > 0) {
648: if (top) {
649: MGET(m, M_DONTWAIT, MT_DATA);
650: if (m == NULL) {
651: m_freem(top);
652: return (NULL);
653: }
654: len = MLEN;
655: }
656: if (totlen >= MINCLSIZE) {
657: MCLGET(m, M_DONTWAIT);
658: if ((m->m_flags & M_EXT) == 0) {
659: m_free(m);
660: m_freem(top);
661: return (NULL);
662: }
663: len = MCLBYTES;
664: }
665: m->m_len = len = min(totlen, len);
666: bcopy(pkt, mtod(m, caddr_t), len);
667: pkt += len;
668: totlen -= len;
669: *mp = m;
670: mp = &m->m_next;
671: }
672:
673: return (top);
674: }
675:
676: /*
677: * Go through the list of multicast addresses and calculate the logical
678: * address filter.
679: */
680: void
681: mace_calcladrf(ac, af)
682: struct arpcom *ac;
683: u_int8_t *af;
684: {
685: struct ifnet *ifp = &ac->ac_if;
686: struct ether_multi *enm;
687: register u_int32_t crc;
688: struct ether_multistep step;
689:
690: /*
691: * Set up multicast address filter by passing all multicast addresses
692: * through a crc generator, and then using the high order 6 bits as an
693: * index into the 64 bit logical address filter. The high order bit
694: * selects the word, while the rest of the bits select the bit within
695: * the word.
696: */
697:
698: *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0;
699: ETHER_FIRST_MULTI(step, ac, enm);
700: while (enm != NULL) {
701: if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
702: /*
703: * We must listen to a range of multicast addresses.
704: * For now, just accept all multicasts, rather than
705: * trying to set only those filter bits needed to match
706: * the range. (At this time, the only use of address
707: * ranges is for IP multicast routing, for which the
708: * range is big enough to require all bits set.)
709: */
710: goto allmulti;
711: }
712:
713: crc = ether_crc32_le(enm->enm_addrlo, sizeof(enm->enm_addrlo));
714:
715: /* Just want the 6 most significant bits. */
716: crc >>= 26;
717:
718: /* Set the corresponding bit in the filter. */
719: af[crc >> 3] |= 1 << (crc & 7);
720:
721: ETHER_NEXT_MULTI(step, enm);
722: }
723: ifp->if_flags &= ~IFF_ALLMULTI;
724: return;
725:
726: allmulti:
727: ifp->if_flags |= IFF_ALLMULTI;
728: *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0xffffffff;
729: }
730:
731: static u_char bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
732: #define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf])
733:
734: u_char
735: mc_get_enaddr(t, h, o, dst)
736: bus_space_tag_t t;
737: bus_space_handle_t h;
738: bus_size_t o;
739: u_char *dst;
740: {
741: int i;
742: u_char b, csum;
743:
744: /*
745: * The XOR of the 8 bytes of the ROM must be 0xff for it to be
746: * valid
747: */
748: for (i = 0, csum = 0; i < 8; i++) {
749: b = bus_space_read_1(t, h, o+16*i);
750: if (i < ETHER_ADDR_LEN)
751: dst[i] = bbr(b);
752: csum ^= b;
753: }
754:
755: return csum;
756: }
CVSweb