Annotation of sys/arch/mac68k/dev/if_mc.c, Revision 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