Annotation of sys/arch/mac68k/dev/if_sn.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_sn.c,v 1.46 2007/01/12 16:31:21 martin Exp $ */
! 2: /* $NetBSD: if_sn.c,v 1.13 1997/04/25 03:40:10 briggs Exp $ */
! 3:
! 4: /*
! 5: * National Semiconductor DP8393X SONIC Driver
! 6: * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk)
! 7: * You may use, copy, and modify this program so long as you retain the
! 8: * copyright line.
! 9: *
! 10: * This driver has been substantially modified since Algorithmics donated
! 11: * it.
! 12: *
! 13: * Denton Gentry <denny1@home.com>
! 14: * and also
! 15: * Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>
! 16: * did the work to get this running on the Macintosh.
! 17: */
! 18:
! 19: #include <sys/param.h>
! 20: #include <sys/systm.h>
! 21: #include <sys/mbuf.h>
! 22: #include <sys/buf.h>
! 23: #include <sys/protosw.h>
! 24: #include <sys/socket.h>
! 25: #include <sys/syslog.h>
! 26: #include <sys/ioctl.h>
! 27: #include <sys/errno.h>
! 28: #include <sys/device.h>
! 29:
! 30: #include <net/if.h>
! 31: #include <net/if_dl.h>
! 32: #include <net/netisr.h>
! 33:
! 34: #ifdef INET
! 35: #include <netinet/in.h>
! 36: #include <netinet/in_systm.h>
! 37: #include <netinet/in_var.h>
! 38: #include <netinet/ip.h>
! 39: #include <netinet/if_ether.h>
! 40: #endif
! 41:
! 42: #include <uvm/uvm_extern.h>
! 43:
! 44: #include "bpfilter.h"
! 45: #if NBPFILTER > 0
! 46: #include <net/bpf.h>
! 47: #include <net/bpfdesc.h>
! 48: #endif
! 49:
! 50: #include <machine/bus.h>
! 51: #include <machine/cpu.h>
! 52: /* #include <machine/viareg.h> */
! 53: #include <mac68k/dev/if_snreg.h>
! 54: #include <mac68k/dev/if_snvar.h>
! 55:
! 56: static void snwatchdog(struct ifnet *);
! 57: static int sninit(struct sn_softc *);
! 58: static int snstop(struct sn_softc *);
! 59: static int snioctl(struct ifnet *, u_long, caddr_t);
! 60: static void snstart(struct ifnet *);
! 61: static void snreset(struct sn_softc *);
! 62:
! 63: static void caminitialise(struct sn_softc *);
! 64: static void camentry(struct sn_softc *, int, u_char *);
! 65: static void camprogram(struct sn_softc *);
! 66: static void initialise_tda(struct sn_softc *);
! 67: static void initialise_rda(struct sn_softc *);
! 68: static void initialise_rra(struct sn_softc *);
! 69: #ifdef SNDEBUG
! 70: static void camdump(struct sn_softc *);
! 71: #endif
! 72:
! 73: static void sonictxint(struct sn_softc *);
! 74: static void sonicrxint(struct sn_softc *);
! 75:
! 76: static __inline__ int sonicput(struct sn_softc *, struct mbuf *,
! 77: int);
! 78: static __inline__ int sonic_read(struct sn_softc *, caddr_t, int);
! 79: static __inline__ struct mbuf *sonic_get(struct sn_softc *, caddr_t, int);
! 80:
! 81: struct cfdriver sn_cd = {
! 82: NULL, "sn", DV_IFNET
! 83: };
! 84:
! 85: /*
! 86: * SONIC buffers need to be aligned 16 or 32 bit aligned.
! 87: * These macros calculate and verify alignment.
! 88: */
! 89: #define ROUNDUP(p, N) (((int) p + N - 1) & ~(N - 1))
! 90:
! 91: #define SOALIGN(m, array) (m ? (ROUNDUP(array, 4)) : (ROUNDUP(array, 2)))
! 92:
! 93: #define LOWER(x) ((unsigned)(x) & 0xffff)
! 94: #define UPPER(x) ((unsigned)(x) >> 16)
! 95:
! 96: /*
! 97: * Interface exists: make available by filling in network interface
! 98: * record. System will initialize the interface when it is ready
! 99: * to accept packets.
! 100: */
! 101: int
! 102: snsetup(struct sn_softc *sc, u_int8_t *lladdr)
! 103: {
! 104: struct ifnet *ifp = &sc->sc_if;
! 105: struct pglist pglist;
! 106: vm_page_t pg;
! 107: paddr_t phys;
! 108: vaddr_t p, pp;
! 109: int i, offset, error;
! 110:
! 111: /*
! 112: * XXX if_sn.c is intended to be MI. Should it allocate memory
! 113: * for its descriptor areas, or expect the MD attach code
! 114: * to do that?
! 115: */
! 116: TAILQ_INIT(&pglist);
! 117: error = uvm_pglistalloc(SN_NPAGES * PAGE_SIZE, 0, -PAGE_SIZE,
! 118: PAGE_SIZE, 0, &pglist, 1, 0);
! 119: if (error != 0) {
! 120: printf(": could not allocate descriptor memory\n");
! 121: return (error);
! 122: }
! 123:
! 124: /*
! 125: * Map the pages uncached.
! 126: */
! 127: sc->space = uvm_km_valloc(kernel_map, SN_NPAGES * PAGE_SIZE);
! 128: if (sc->space == NULL) {
! 129: printf(": could not map descriptor memory\n");
! 130: uvm_pglistfree(&pglist);
! 131: return (ENOMEM);
! 132: }
! 133:
! 134: phys = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist));
! 135: p = pp = sc->space;
! 136: TAILQ_FOREACH(pg, &pglist, pageq) {
! 137: pmap_enter_cache(pmap_kernel(), p, VM_PAGE_TO_PHYS(pg),
! 138: UVM_PROT_RW, UVM_PROT_RW | PMAP_WIRED, PG_CI);
! 139: p += PAGE_SIZE;
! 140: }
! 141: pmap_update(pmap_kernel());
! 142: p = pp;
! 143:
! 144: /*
! 145: * Put the pup in reset mode (sninit() will fix it later),
! 146: * stop the timer, disable all interrupts and clear any interrupts.
! 147: */
! 148: NIC_PUT(sc, SNR_CR, CR_STP);
! 149: wbflush();
! 150: NIC_PUT(sc, SNR_CR, CR_RST);
! 151: wbflush();
! 152: NIC_PUT(sc, SNR_IMR, 0);
! 153: wbflush();
! 154: NIC_PUT(sc, SNR_ISR, ISR_ALL);
! 155: wbflush();
! 156:
! 157: for (i = 0; i < NRRA; i++) {
! 158: sc->p_rra[i] = (void *)p;
! 159: sc->v_rra[i] = (p - sc->space) + phys;
! 160: p += RXRSRC_SIZE(sc);
! 161: }
! 162: sc->v_rea = (p - sc->space) + phys;
! 163:
! 164: p = SOALIGN(sc, p);
! 165:
! 166: sc->p_cda = (void *)(p);
! 167: sc->v_cda = (p - sc->space) + phys;
! 168: p += CDA_SIZE(sc);
! 169:
! 170: p = SOALIGN(sc, p);
! 171:
! 172: for (i = 0; i < NTDA; i++) {
! 173: struct mtd *mtdp = &sc->mtda[i];
! 174: mtdp->mtd_txp = (void *)p;
! 175: mtdp->mtd_vtxp = (p - sc->space) + phys;
! 176: p += TXP_SIZE(sc);
! 177: }
! 178:
! 179: p = SOALIGN(sc, p);
! 180:
! 181: #ifdef DIAGNOSTIC
! 182: if ((p - pp) > PAGE_SIZE) {
! 183: printf (": sizeof RRA (%ld) + CDA (%ld) +"
! 184: "TDA (%ld) > PAGE_SIZE (%d). Punt!\n",
! 185: (ulong)sc->p_cda - (ulong)sc->p_rra[0],
! 186: (ulong)sc->mtda[0].mtd_txp - (ulong)sc->p_cda,
! 187: (ulong)p - (ulong)sc->mtda[0].mtd_txp,
! 188: PAGE_SIZE);
! 189: return (EINVAL);
! 190: }
! 191: #endif
! 192:
! 193: p = pp + PAGE_SIZE;
! 194: pp = p;
! 195:
! 196: sc->sc_nrda = PAGE_SIZE / RXPKT_SIZE(sc);
! 197: sc->p_rda = (caddr_t)p;
! 198: sc->v_rda = (p - sc->space) + phys;
! 199:
! 200: p = pp + PAGE_SIZE;
! 201:
! 202: for (i = 0; i < NRBA; i++) {
! 203: sc->rbuf[i] = (caddr_t)p;
! 204: sc->rbuf_phys[i] = (p - sc->space) + phys;
! 205: p += PAGE_SIZE;
! 206: }
! 207:
! 208: pp = p;
! 209: offset = 0;
! 210: for (i = 0; i < NTDA; i++) {
! 211: struct mtd *mtdp = &sc->mtda[i];
! 212:
! 213: mtdp->mtd_buf = (caddr_t)p;
! 214: mtdp->mtd_vbuf = (p - sc->space) + phys;
! 215: offset += TXBSIZE;
! 216: if (offset < PAGE_SIZE - TXBSIZE) {
! 217: p += TXBSIZE;
! 218: } else {
! 219: p = pp + PAGE_SIZE;
! 220: pp = p;
! 221: offset = 0;
! 222: }
! 223: }
! 224:
! 225: #ifdef SNDEBUG
! 226: camdump(sc);
! 227: #endif
! 228: printf("address %s\n", ether_sprintf(lladdr));
! 229:
! 230: #ifdef SNDEBUG
! 231: printf("%s: buffers: rra=%p cda=%p rda=%p tda=%p\n",
! 232: sc->sc_dev.dv_xname, sc->p_rra[0], sc->p_cda,
! 233: sc->p_rda, sc->mtda[0].mtd_txp);
! 234: #endif
! 235:
! 236: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 237: bcopy(lladdr, sc->sc_enaddr, ETHER_ADDR_LEN);
! 238:
! 239: ifp->if_softc = sc;
! 240: ifp->if_ioctl = snioctl;
! 241: ifp->if_start = snstart;
! 242: ifp->if_flags =
! 243: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 244: ifp->if_watchdog = snwatchdog;
! 245: if_attach(ifp);
! 246: ether_ifattach(ifp);
! 247:
! 248: return (0);
! 249: }
! 250:
! 251: static int
! 252: snioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 253: {
! 254: struct ifaddr *ifa;
! 255: struct ifreq *ifr;
! 256: struct sn_softc *sc = ifp->if_softc;
! 257: int s = splnet(), err = 0;
! 258:
! 259: switch (cmd) {
! 260:
! 261: case SIOCSIFADDR:
! 262: ifa = (struct ifaddr *)data;
! 263: ifp->if_flags |= IFF_UP;
! 264: switch (ifa->ifa_addr->sa_family) {
! 265: #ifdef INET
! 266: case AF_INET:
! 267: (void)sninit(sc);
! 268: arp_ifinit(&sc->sc_arpcom, ifa);
! 269: break;
! 270: #endif
! 271: default:
! 272: (void)sninit(sc);
! 273: break;
! 274: }
! 275: break;
! 276:
! 277: case SIOCSIFFLAGS:
! 278: if ((ifp->if_flags & IFF_UP) == 0 &&
! 279: (ifp->if_flags & IFF_RUNNING) != 0) {
! 280: /*
! 281: * If interface is marked down and it is running,
! 282: * then stop it.
! 283: */
! 284: snstop(sc);
! 285: ifp->if_flags &= ~IFF_RUNNING;
! 286: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 287: (ifp->if_flags & IFF_RUNNING) == 0) {
! 288: /*
! 289: * If interface is marked up and it is stopped,
! 290: * then start it.
! 291: */
! 292: (void)sninit(sc);
! 293: } else {
! 294: /*
! 295: * reset the interface to pick up any other changes
! 296: * in flags
! 297: */
! 298: snreset(sc);
! 299: snstart(ifp);
! 300: }
! 301: break;
! 302:
! 303: case SIOCADDMULTI:
! 304: case SIOCDELMULTI:
! 305: ifr = (struct ifreq *) data;
! 306: if (cmd == SIOCADDMULTI)
! 307: err = ether_addmulti(ifr, &sc->sc_arpcom);
! 308: else
! 309: err = ether_delmulti(ifr, &sc->sc_arpcom);
! 310:
! 311: if (err == ENETRESET) {
! 312: /*
! 313: * Multicast list has changed; set the hardware
! 314: * filter accordingly. But remember UP flag!
! 315: */
! 316: if (ifp->if_flags & IFF_RUNNING)
! 317: snreset(sc);
! 318: err = 0;
! 319: }
! 320: break;
! 321: default:
! 322: err = EINVAL;
! 323: }
! 324: splx(s);
! 325: return (err);
! 326: }
! 327:
! 328: /*
! 329: * Encapsulate a packet of type family for the local net.
! 330: */
! 331: static void
! 332: snstart(struct ifnet *ifp)
! 333: {
! 334: struct sn_softc *sc = ifp->if_softc;
! 335: struct mbuf *m;
! 336: int mtd_next;
! 337:
! 338: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 339: return;
! 340:
! 341: outloop:
! 342: /* Check for room in the xmit buffer. */
! 343: if ((mtd_next = (sc->mtd_free + 1)) == NTDA)
! 344: mtd_next = 0;
! 345:
! 346: if (mtd_next == sc->mtd_hw) {
! 347: ifp->if_flags |= IFF_OACTIVE;
! 348: return;
! 349: }
! 350:
! 351: IF_DEQUEUE(&ifp->if_snd, m);
! 352: if (m == NULL)
! 353: return;
! 354:
! 355: /* We need the header for m_pkthdr.len. */
! 356: if ((m->m_flags & M_PKTHDR) == 0)
! 357: panic("%s: snstart: no header mbuf", sc->sc_dev.dv_xname);
! 358:
! 359: #if NBPFILTER > 0
! 360: /*
! 361: * If bpf is listening on this interface, let it
! 362: * see the packet before we commit it to the wire.
! 363: */
! 364: if (ifp->if_bpf)
! 365: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 366: #endif
! 367:
! 368: /*
! 369: * If there is nothing in the o/p queue, and there is room in
! 370: * the Tx ring, then send the packet directly. Otherwise append
! 371: * it to the o/p queue.
! 372: */
! 373: if ((sonicput(sc, m, mtd_next)) > 0) {
! 374: } else {
! 375: IF_PREPEND(&ifp->if_snd, m);
! 376: return;
! 377: }
! 378:
! 379: sc->mtd_prev = sc->mtd_free;
! 380: sc->mtd_free = mtd_next;
! 381:
! 382: ifp->if_opackets++; /* # of pkts */
! 383:
! 384: /* Jump back for possibly more punishment. */
! 385: goto outloop;
! 386: }
! 387:
! 388: /*
! 389: * reset and restart the SONIC. Called in case of fatal
! 390: * hardware/software errors.
! 391: */
! 392: static void
! 393: snreset(struct sn_softc *sc)
! 394: {
! 395: snstop(sc);
! 396: sninit(sc);
! 397: }
! 398:
! 399: static int
! 400: sninit(struct sn_softc *sc)
! 401: {
! 402: u_long s_rcr;
! 403: int s;
! 404:
! 405: if (sc->sc_if.if_flags & IFF_RUNNING)
! 406: /* already running */
! 407: return (0);
! 408:
! 409: s = splnet();
! 410:
! 411: NIC_PUT(sc, SNR_CR, CR_RST); /* DCR only accessible in reset mode! */
! 412:
! 413: /* config it */
! 414: NIC_PUT(sc, SNR_DCR, (sc->snr_dcr |
! 415: (sc->bitmode ? DCR_DW32 : DCR_DW16)));
! 416: NIC_PUT(sc, SNR_DCR2, sc->snr_dcr2);
! 417:
! 418: s_rcr = RCR_BRD | RCR_LBNONE;
! 419: if (sc->sc_if.if_flags & IFF_PROMISC)
! 420: s_rcr |= RCR_PRO;
! 421: if (sc->sc_if.if_flags & IFF_ALLMULTI)
! 422: s_rcr |= RCR_AMC;
! 423: NIC_PUT(sc, SNR_RCR, s_rcr);
! 424:
! 425: NIC_PUT(sc, SNR_IMR, (IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_LCDEN));
! 426:
! 427: /* clear pending interrupts */
! 428: NIC_PUT(sc, SNR_ISR, ISR_ALL);
! 429:
! 430: /* clear tally counters */
! 431: NIC_PUT(sc, SNR_CRCT, -1);
! 432: NIC_PUT(sc, SNR_FAET, -1);
! 433: NIC_PUT(sc, SNR_MPT, -1);
! 434:
! 435: initialise_tda(sc);
! 436: initialise_rda(sc);
! 437: initialise_rra(sc);
! 438:
! 439: /* enable the chip */
! 440: NIC_PUT(sc, SNR_CR, 0);
! 441: wbflush();
! 442:
! 443: /* program the CAM */
! 444: camprogram(sc);
! 445:
! 446: /* get it to read resource descriptors */
! 447: NIC_PUT(sc, SNR_CR, CR_RRRA);
! 448: wbflush();
! 449: while ((NIC_GET(sc, SNR_CR)) & CR_RRRA)
! 450: continue;
! 451:
! 452: /* enable rx */
! 453: NIC_PUT(sc, SNR_CR, CR_RXEN);
! 454: wbflush();
! 455:
! 456: /* flag interface as "running" */
! 457: sc->sc_if.if_flags |= IFF_RUNNING;
! 458: sc->sc_if.if_flags &= ~IFF_OACTIVE;
! 459:
! 460: splx(s);
! 461: return (0);
! 462: }
! 463:
! 464: /*
! 465: * close down an interface and free its buffers
! 466: * Called on final close of device, or if sninit() fails
! 467: * part way through.
! 468: */
! 469: static int
! 470: snstop(struct sn_softc *sc)
! 471: {
! 472: struct mtd *mtd;
! 473: int s = splnet();
! 474:
! 475: /* stick chip in reset */
! 476: NIC_PUT(sc, SNR_CR, CR_RST);
! 477: wbflush();
! 478:
! 479: /* free all receive buffers (currently static so nothing to do) */
! 480:
! 481: /* free all pending transmit mbufs */
! 482: while (sc->mtd_hw != sc->mtd_free) {
! 483: mtd = &sc->mtda[sc->mtd_hw];
! 484: if (mtd->mtd_mbuf)
! 485: m_freem(mtd->mtd_mbuf);
! 486: if (++sc->mtd_hw == NTDA) sc->mtd_hw = 0;
! 487: }
! 488:
! 489: sc->sc_if.if_timer = 0;
! 490: sc->sc_if.if_flags &= ~IFF_RUNNING;
! 491:
! 492: splx(s);
! 493: return (0);
! 494: }
! 495:
! 496: /*
! 497: * Called if any Tx packets remain unsent after 5 seconds,
! 498: * In all cases we just reset the chip, and any retransmission
! 499: * will be handled by higher level protocol timeouts.
! 500: */
! 501: static void
! 502: snwatchdog(struct ifnet *ifp)
! 503: {
! 504: struct sn_softc *sc = ifp->if_softc;
! 505: struct mtd *mtd;
! 506:
! 507: if (sc->mtd_hw != sc->mtd_free) {
! 508: /* something still pending for transmit */
! 509: mtd = &sc->mtda[sc->mtd_hw];
! 510: if (SRO(sc->bitmode, mtd->mtd_txp, TXP_STATUS) == 0)
! 511: log(LOG_ERR, "%s: Tx - timeout\n",
! 512: sc->sc_dev.dv_xname);
! 513: else
! 514: log(LOG_ERR, "%s: Tx - lost interrupt\n",
! 515: sc->sc_dev.dv_xname);
! 516: snreset(sc);
! 517: }
! 518: }
! 519:
! 520: /*
! 521: * stuff packet into sonic (at splnet)
! 522: */
! 523: static __inline__ int
! 524: sonicput(struct sn_softc *sc, struct mbuf *m0, int mtd_next)
! 525: {
! 526: struct mtd *mtdp;
! 527: struct mbuf *m;
! 528: u_char *buff;
! 529: void *txp;
! 530: u_int len = 0;
! 531: u_int totlen = 0;
! 532:
! 533: /* grab the replacement mtd */
! 534: mtdp = &sc->mtda[sc->mtd_free];
! 535:
! 536: buff = mtdp->mtd_buf;
! 537:
! 538: /* this packet goes to mtdnext fill in the TDA */
! 539: mtdp->mtd_mbuf = m0;
! 540: txp = mtdp->mtd_txp;
! 541:
! 542: /* Write to the config word. Every (NTDA/2)+1 packets we set an intr */
! 543: if (sc->mtd_pint == 0) {
! 544: sc->mtd_pint = NTDA/2;
! 545: SWO(sc->bitmode, txp, TXP_CONFIG, TCR_PINT);
! 546: } else {
! 547: sc->mtd_pint--;
! 548: SWO(sc->bitmode, txp, TXP_CONFIG, 0);
! 549: }
! 550:
! 551: for (m = m0; m; m = m->m_next) {
! 552: u_char *data = mtod(m, u_char *);
! 553: len = m->m_len;
! 554: totlen += len;
! 555: bcopy(data, buff, len);
! 556: buff += len;
! 557: }
! 558: if (totlen >= TXBSIZE) {
! 559: panic("%s: sonicput: packet overflow", sc->sc_dev.dv_xname);
! 560: }
! 561:
! 562: SWO(sc->bitmode, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRLO,
! 563: LOWER(mtdp->mtd_vbuf));
! 564: SWO(sc->bitmode, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRHI,
! 565: UPPER(mtdp->mtd_vbuf));
! 566:
! 567: if (totlen < ETHERMIN + ETHER_HDR_LEN) {
! 568: int pad = ETHERMIN + ETHER_HDR_LEN - totlen;
! 569: bzero(mtdp->mtd_buf + totlen, pad);
! 570: totlen = ETHERMIN + ETHER_HDR_LEN;
! 571: }
! 572:
! 573: SWO(sc->bitmode, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FSIZE,
! 574: totlen);
! 575: SWO(sc->bitmode, txp, TXP_FRAGCNT, 1);
! 576: SWO(sc->bitmode, txp, TXP_PKTSIZE, totlen);
! 577:
! 578: /* link onto the next mtd that will be used */
! 579: SWO(sc->bitmode, txp, TXP_FRAGOFF + (1 * TXP_FRAGSIZE) + TXP_FPTRLO,
! 580: LOWER(sc->mtda[mtd_next].mtd_vtxp) | EOL);
! 581:
! 582: /*
! 583: * The previous txp.tlink currently contains a pointer to
! 584: * our txp | EOL. Want to clear the EOL, so write our
! 585: * pointer to the previous txp.
! 586: */
! 587: SWO(sc->bitmode, sc->mtda[sc->mtd_prev].mtd_txp, sc->mtd_tlinko,
! 588: LOWER(mtdp->mtd_vtxp));
! 589:
! 590: /* make sure chip is running */
! 591: wbflush();
! 592: NIC_PUT(sc, SNR_CR, CR_TXP);
! 593: wbflush();
! 594: sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
! 595:
! 596: return (totlen);
! 597: }
! 598:
! 599: /*
! 600: * These are called from sonicioctl() when /etc/ifconfig is run to set
! 601: * the address or switch the i/f on.
! 602: */
! 603: /*
! 604: * CAM support
! 605: */
! 606: static void
! 607: caminitialise(struct sn_softc *sc)
! 608: {
! 609: void *p_cda = sc->p_cda;
! 610: int i;
! 611: int bitmode = sc->bitmode;
! 612: int camoffset;
! 613:
! 614: for (i = 0; i < MAXCAM; i++) {
! 615: camoffset = i * CDA_CAMDESC;
! 616: SWO(bitmode, p_cda, (camoffset + CDA_CAMEP), i);
! 617: SWO(bitmode, p_cda, (camoffset + CDA_CAMAP2), 0);
! 618: SWO(bitmode, p_cda, (camoffset + CDA_CAMAP1), 0);
! 619: SWO(bitmode, p_cda, (camoffset + CDA_CAMAP0), 0);
! 620: }
! 621: SWO(bitmode, p_cda, CDA_ENABLE, 0);
! 622: }
! 623:
! 624: static void
! 625: camentry(struct sn_softc *sc, int entry, u_char *ea)
! 626: {
! 627: void *p_cda = sc->p_cda;
! 628: int bitmode = sc->bitmode;
! 629: int camoffset = entry * CDA_CAMDESC;
! 630:
! 631: SWO(bitmode, p_cda, camoffset + CDA_CAMEP, entry);
! 632: SWO(bitmode, p_cda, camoffset + CDA_CAMAP2, (ea[5] << 8) | ea[4]);
! 633: SWO(bitmode, p_cda, camoffset + CDA_CAMAP1, (ea[3] << 8) | ea[2]);
! 634: SWO(bitmode, p_cda, camoffset + CDA_CAMAP0, (ea[1] << 8) | ea[0]);
! 635: SWO(bitmode, p_cda, CDA_ENABLE,
! 636: (SRO(bitmode, p_cda, CDA_ENABLE) | (1 << entry)));
! 637: }
! 638:
! 639: static void
! 640: camprogram(struct sn_softc *sc)
! 641: {
! 642: struct ether_multistep step;
! 643: struct ether_multi *enm;
! 644: struct ifnet *ifp;
! 645: int timeout;
! 646: int mcount = 0;
! 647:
! 648: caminitialise(sc);
! 649:
! 650: ifp = &sc->sc_if;
! 651:
! 652: /* Always load our own address first. */
! 653: camentry (sc, mcount, sc->sc_enaddr);
! 654: mcount++;
! 655:
! 656: /* Assume we won't need allmulti bit. */
! 657: ifp->if_flags &= ~IFF_ALLMULTI;
! 658:
! 659: /* Loop through multicast addresses */
! 660: ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
! 661: while (enm != NULL) {
! 662: if (mcount == MAXCAM) {
! 663: ifp->if_flags |= IFF_ALLMULTI;
! 664: break;
! 665: }
! 666:
! 667: if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
! 668: sizeof(enm->enm_addrlo)) != 0) {
! 669: /*
! 670: * SONIC's CAM is programmed with specific
! 671: * addresses. It has no way to specify a range.
! 672: * (Well, thats not exactly true. If the
! 673: * range is small one could program each addr
! 674: * within the range as a separate CAM entry)
! 675: */
! 676: ifp->if_flags |= IFF_ALLMULTI;
! 677: break;
! 678: }
! 679:
! 680: /* program the CAM with the specified entry */
! 681: camentry(sc, mcount, enm->enm_addrlo);
! 682: mcount++;
! 683:
! 684: ETHER_NEXT_MULTI(step, enm);
! 685: }
! 686:
! 687: NIC_PUT(sc, SNR_CDP, LOWER(sc->v_cda));
! 688: NIC_PUT(sc, SNR_CDC, MAXCAM);
! 689: NIC_PUT(sc, SNR_CR, CR_LCAM);
! 690: wbflush();
! 691:
! 692: timeout = 10000;
! 693: while ((NIC_GET(sc, SNR_CR) & CR_LCAM) && timeout--)
! 694: continue;
! 695: if (timeout == 0) {
! 696: /* XXX */
! 697: panic("%s: CAM initialisation failed", sc->sc_dev.dv_xname);
! 698: }
! 699: timeout = 10000;
! 700: while (((NIC_GET(sc, SNR_ISR) & ISR_LCD) == 0) && timeout--)
! 701: continue;
! 702:
! 703: if (NIC_GET(sc, SNR_ISR) & ISR_LCD)
! 704: NIC_PUT(sc, SNR_ISR, ISR_LCD);
! 705: else
! 706: printf("%s: CAM initialisation without interrupt\n",
! 707: sc->sc_dev.dv_xname);
! 708: }
! 709:
! 710: #ifdef SNDEBUG
! 711: static void
! 712: camdump(struct sn_softc *sc)
! 713: {
! 714: int i;
! 715:
! 716: printf("CAM entries:\n");
! 717: NIC_PUT(sc, SNR_CR, CR_RST);
! 718: wbflush();
! 719:
! 720: for (i = 0; i < 16; i++) {
! 721: ushort ap2, ap1, ap0;
! 722: NIC_PUT(sc, SNR_CEP, i);
! 723: wbflush();
! 724: ap2 = NIC_GET(sc, SNR_CAP2);
! 725: ap1 = NIC_GET(sc, SNR_CAP1);
! 726: ap0 = NIC_GET(sc, SNR_CAP0);
! 727: printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0);
! 728: }
! 729: printf("CAM enable 0x%x\n", NIC_GET(sc, SNR_CEP));
! 730:
! 731: NIC_PUT(sc, SNR_CR, 0);
! 732: wbflush();
! 733: }
! 734: #endif
! 735:
! 736: static void
! 737: initialise_tda(struct sn_softc *sc)
! 738: {
! 739: struct mtd *mtd;
! 740: int i;
! 741:
! 742: for (i = 0; i < NTDA; i++) {
! 743: mtd = &sc->mtda[i];
! 744: mtd->mtd_mbuf = 0;
! 745: }
! 746:
! 747: sc->mtd_hw = 0;
! 748: sc->mtd_prev = NTDA - 1;
! 749: sc->mtd_free = 0;
! 750: sc->mtd_tlinko = TXP_FRAGOFF + 1*TXP_FRAGSIZE + TXP_FPTRLO;
! 751: sc->mtd_pint = NTDA/2;
! 752:
! 753: NIC_PUT(sc, SNR_UTDA, UPPER(sc->mtda[0].mtd_vtxp));
! 754: NIC_PUT(sc, SNR_CTDA, LOWER(sc->mtda[0].mtd_vtxp));
! 755: }
! 756:
! 757: static void
! 758: initialise_rda(struct sn_softc *sc)
! 759: {
! 760: int bitmode = sc->bitmode;
! 761: int i;
! 762: caddr_t p_rda = 0;
! 763: u_int32_t v_rda = 0;
! 764:
! 765: /* link the RDA's together into a circular list */
! 766: for (i = 0; i < (sc->sc_nrda - 1); i++) {
! 767: p_rda = sc->p_rda + (i * RXPKT_SIZE(sc));
! 768: v_rda = sc->v_rda + ((i+1) * RXPKT_SIZE(sc));
! 769: SWO(bitmode, p_rda, RXPKT_RLINK, LOWER(v_rda));
! 770: SWO(bitmode, p_rda, RXPKT_INUSE, 1);
! 771: }
! 772: p_rda = sc->p_rda + ((sc->sc_nrda - 1) * RXPKT_SIZE(sc));
! 773: SWO(bitmode, p_rda, RXPKT_RLINK, LOWER(sc->v_rda) | EOL);
! 774: SWO(bitmode, p_rda, RXPKT_INUSE, 1);
! 775:
! 776: /* mark end of receive descriptor list */
! 777: sc->sc_rdamark = sc->sc_nrda - 1;
! 778:
! 779: sc->sc_rxmark = 0;
! 780:
! 781: NIC_PUT(sc, SNR_URDA, UPPER(sc->v_rda));
! 782: NIC_PUT(sc, SNR_CRDA, LOWER(sc->v_rda));
! 783: wbflush();
! 784: }
! 785:
! 786: static void
! 787: initialise_rra(struct sn_softc *sc)
! 788: {
! 789: int i;
! 790: u_int v;
! 791: int bitmode = sc->bitmode;
! 792:
! 793: if (bitmode)
! 794: NIC_PUT(sc, SNR_EOBC, RBASIZE(sc) / 2 - 2);
! 795: else
! 796: NIC_PUT(sc, SNR_EOBC, RBASIZE(sc) / 2 - 1);
! 797:
! 798: NIC_PUT(sc, SNR_URRA, UPPER(sc->v_rra[0]));
! 799: NIC_PUT(sc, SNR_RSA, LOWER(sc->v_rra[0]));
! 800: /* rea must point just past the end of the rra space */
! 801: NIC_PUT(sc, SNR_REA, LOWER(sc->v_rea));
! 802: NIC_PUT(sc, SNR_RRP, LOWER(sc->v_rra[0]));
! 803: NIC_PUT(sc, SNR_RSC, 0);
! 804:
! 805: /* fill up SOME of the rra with buffers */
! 806: for (i = 0; i < NRBA; i++) {
! 807: v = sc->rbuf_phys[i];
! 808: SWO(bitmode, sc->p_rra[i], RXRSRC_PTRHI, UPPER(v));
! 809: SWO(bitmode, sc->p_rra[i], RXRSRC_PTRLO, LOWER(v));
! 810: SWO(bitmode, sc->p_rra[i], RXRSRC_WCHI, UPPER(PAGE_SIZE/2));
! 811: SWO(bitmode, sc->p_rra[i], RXRSRC_WCLO, LOWER(PAGE_SIZE/2));
! 812: }
! 813: sc->sc_rramark = NRBA;
! 814: NIC_PUT(sc, SNR_RWP, LOWER(sc->v_rra[sc->sc_rramark]));
! 815: wbflush();
! 816: }
! 817:
! 818: int
! 819: snintr(void *arg)
! 820: {
! 821: struct sn_softc *sc = (struct sn_softc *)arg;
! 822: int isr;
! 823: int rv = 0;
! 824:
! 825: while ((isr = (NIC_GET(sc, SNR_ISR) & ISR_ALL)) != 0) {
! 826: rv = 1;
! 827: /* scrub the interrupts that we are going to service */
! 828: NIC_PUT(sc, SNR_ISR, isr);
! 829: wbflush();
! 830:
! 831: if (isr & (ISR_BR | ISR_LCD | ISR_TC))
! 832: printf("%s: unexpected interrupt status 0x%x\n",
! 833: sc->sc_dev.dv_xname, isr);
! 834:
! 835: if (isr & (ISR_TXDN | ISR_TXER | ISR_PINT))
! 836: sonictxint(sc);
! 837:
! 838: if (isr & ISR_PKTRX)
! 839: sonicrxint(sc);
! 840:
! 841: if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) {
! 842: if (isr & ISR_HBL)
! 843: /*
! 844: * The repeater is not providing a heartbeat.
! 845: * In itself this isn't harmful, lots of the
! 846: * cheap repeater hubs don't supply a heartbeat.
! 847: * So ignore the lack of heartbeat. Its only
! 848: * if we can't detect a carrier that we have a
! 849: * problem.
! 850: */
! 851: ;
! 852: if (isr & ISR_RDE)
! 853: printf("%s: receive descriptors exhausted\n",
! 854: sc->sc_dev.dv_xname);
! 855: if (isr & ISR_RBE)
! 856: printf("%s: receive buffers exhausted\n",
! 857: sc->sc_dev.dv_xname);
! 858: if (isr & ISR_RBAE)
! 859: printf("%s: receive buffer area exhausted\n",
! 860: sc->sc_dev.dv_xname);
! 861: if (isr & ISR_RFO)
! 862: printf("%s: receive FIFO overrun\n",
! 863: sc->sc_dev.dv_xname);
! 864: }
! 865: if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) {
! 866: #ifdef notdef
! 867: if (isr & ISR_CRC)
! 868: sc->sc_crctally++;
! 869: if (isr & ISR_FAE)
! 870: sc->sc_faetally++;
! 871: if (isr & ISR_MP)
! 872: sc->sc_mptally++;
! 873: #endif
! 874: }
! 875: snstart(&sc->sc_if);
! 876: }
! 877:
! 878: return (rv);
! 879: }
! 880:
! 881: /*
! 882: * Transmit interrupt routine
! 883: */
! 884: static void
! 885: sonictxint(struct sn_softc *sc)
! 886: {
! 887: struct mtd *mtd;
! 888: void *txp;
! 889: unsigned short txp_status;
! 890: int mtd_hw;
! 891: struct ifnet *ifp = &sc->sc_if;
! 892:
! 893: mtd_hw = sc->mtd_hw;
! 894:
! 895: if (mtd_hw == sc->mtd_free)
! 896: return;
! 897:
! 898: while (mtd_hw != sc->mtd_free) {
! 899: mtd = &sc->mtda[mtd_hw];
! 900:
! 901: txp = mtd->mtd_txp;
! 902:
! 903: if (SRO(sc->bitmode, txp, TXP_STATUS) == 0) {
! 904: break; /* it hasn't really gone yet */
! 905: }
! 906:
! 907: #ifdef SNDEBUG
! 908: {
! 909: struct ether_header *eh;
! 910:
! 911: eh = (struct ether_header *) mtd->mtd_buf;
! 912: printf("%s: xmit status=0x%x len=%d type=0x%x from %s",
! 913: sc->sc_dev.dv_xname,
! 914: SRO(sc->bitmode, txp, TXP_STATUS),
! 915: SRO(sc->bitmode, txp, TXP_PKTSIZE),
! 916: htons(eh->ether_type),
! 917: ether_sprintf(eh->ether_shost));
! 918: printf(" (to %s)\n", ether_sprintf(eh->ether_dhost));
! 919: }
! 920: #endif /* SNDEBUG */
! 921:
! 922: ifp->if_flags &= ~IFF_OACTIVE;
! 923:
! 924: if (mtd->mtd_mbuf != 0) {
! 925: m_freem(mtd->mtd_mbuf);
! 926: mtd->mtd_mbuf = 0;
! 927: }
! 928: if (++mtd_hw == NTDA) mtd_hw = 0;
! 929:
! 930: txp_status = SRO(sc->bitmode, txp, TXP_STATUS);
! 931:
! 932: ifp->if_collisions += (txp_status & TCR_EXC) ? 16 :
! 933: ((txp_status & TCR_NC) >> 12);
! 934:
! 935: if ((txp_status & TCR_PTX) == 0) {
! 936: ifp->if_oerrors++;
! 937:
! 938: /* XXX - DG This looks bogus */
! 939: if (mtd_hw != sc->mtd_free) {
! 940: mtd = &sc->mtda[mtd_hw];
! 941: NIC_PUT(sc, SNR_CTDA, LOWER(mtd->mtd_vtxp));
! 942: NIC_PUT(sc, SNR_CR, CR_TXP);
! 943: wbflush();
! 944: break;
! 945: }
! 946: }
! 947: }
! 948:
! 949: sc->mtd_hw = mtd_hw;
! 950: return;
! 951: }
! 952:
! 953: /*
! 954: * Receive interrupt routine
! 955: */
! 956: static void
! 957: sonicrxint(struct sn_softc *sc)
! 958: {
! 959: caddr_t rda;
! 960: int orra;
! 961: int len;
! 962: int rramark;
! 963: int rdamark;
! 964: int bitmode = sc->bitmode;
! 965: u_int16_t rxpkt_ptr;
! 966:
! 967: rda = sc->p_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
! 968:
! 969: while (SRO(bitmode, rda, RXPKT_INUSE) == 0) {
! 970: u_int status = SRO(bitmode, rda, RXPKT_STATUS);
! 971:
! 972: orra = RBASEQ(SRO(bitmode, rda, RXPKT_SEQNO)) & RRAMASK;
! 973: rxpkt_ptr = SRO(bitmode, rda, RXPKT_PTRLO);
! 974: len = SRO(bitmode, rda, RXPKT_BYTEC) - FCSSIZE;
! 975: if (status & RCR_PRX) {
! 976: caddr_t pkt = sc->rbuf[orra & RBAMASK] +
! 977: m68k_page_offset(rxpkt_ptr);
! 978: if (sonic_read(sc, pkt, len))
! 979: sc->sc_if.if_ipackets++;
! 980: else
! 981: sc->sc_if.if_ierrors++;
! 982: } else
! 983: sc->sc_if.if_ierrors++;
! 984:
! 985: /*
! 986: * give receive buffer area back to chip.
! 987: *
! 988: * If this was the last packet in the RRA, give the RRA to
! 989: * the chip again.
! 990: * If sonic read didnt copy it out then we would have to
! 991: * wait !!
! 992: * (dont bother add it back in again straight away)
! 993: *
! 994: * Really, we're doing p_rra[rramark] = p_rra[orra] but
! 995: * we have to use the macros because SONIC might be in
! 996: * 16 or 32 bit mode.
! 997: */
! 998: if (status & RCR_LPKT) {
! 999: void *tmp1, *tmp2;
! 1000:
! 1001: rramark = sc->sc_rramark;
! 1002: tmp1 = sc->p_rra[rramark];
! 1003: tmp2 = sc->p_rra[orra];
! 1004: SWO(bitmode, tmp1, RXRSRC_PTRLO,
! 1005: SRO(bitmode, tmp2, RXRSRC_PTRLO));
! 1006: SWO(bitmode, tmp1, RXRSRC_PTRHI,
! 1007: SRO(bitmode, tmp2, RXRSRC_PTRHI));
! 1008: SWO(bitmode, tmp1, RXRSRC_WCLO,
! 1009: SRO(bitmode, tmp2, RXRSRC_WCLO));
! 1010: SWO(bitmode, tmp1, RXRSRC_WCHI,
! 1011: SRO(bitmode, tmp2, RXRSRC_WCHI));
! 1012:
! 1013: /* zap old rra for fun */
! 1014: SWO(bitmode, tmp2, RXRSRC_WCHI, 0);
! 1015: SWO(bitmode, tmp2, RXRSRC_WCLO, 0);
! 1016:
! 1017: sc->sc_rramark = (++rramark) & RRAMASK;
! 1018: NIC_PUT(sc, SNR_RWP, LOWER(sc->v_rra[rramark]));
! 1019: wbflush();
! 1020: }
! 1021:
! 1022: /*
! 1023: * give receive descriptor back to chip simple
! 1024: * list is circular
! 1025: */
! 1026: rdamark = sc->sc_rdamark;
! 1027: SWO(bitmode, rda, RXPKT_INUSE, 1);
! 1028: SWO(bitmode, rda, RXPKT_RLINK,
! 1029: SRO(bitmode, rda, RXPKT_RLINK) | EOL);
! 1030: SWO(bitmode, (sc->p_rda + (rdamark * RXPKT_SIZE(sc))), RXPKT_RLINK,
! 1031: SRO(bitmode, (sc->p_rda + (rdamark * RXPKT_SIZE(sc))),
! 1032: RXPKT_RLINK) & ~EOL);
! 1033: sc->sc_rdamark = sc->sc_rxmark;
! 1034:
! 1035: if (++sc->sc_rxmark >= sc->sc_nrda)
! 1036: sc->sc_rxmark = 0;
! 1037: rda = sc->p_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
! 1038: }
! 1039: }
! 1040:
! 1041: /*
! 1042: * sonic_read -- pull packet off interface and forward to
! 1043: * appropriate protocol handler
! 1044: */
! 1045: static __inline__ int
! 1046: sonic_read(struct sn_softc *sc, caddr_t pkt, int len)
! 1047: {
! 1048: struct ifnet *ifp = &sc->sc_if;
! 1049: #ifdef SNDEBUG
! 1050: struct ether_header *et;
! 1051: #endif
! 1052: struct mbuf *m;
! 1053:
! 1054: #ifdef SNDEBUG
! 1055: /*
! 1056: * Get pointer to ethernet header (in input buffer).
! 1057: */
! 1058: et = (struct ether_header *)pkt;
! 1059:
! 1060: printf("%s: rcvd %p len=%d type=0x%x from %s",
! 1061: sc->sc_dev.dv_xname, et, len, htons(et->ether_type),
! 1062: ether_sprintf(et->ether_shost));
! 1063: printf(" (to %s)\n", ether_sprintf(et->ether_dhost));
! 1064: #endif /* SNDEBUG */
! 1065:
! 1066: if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN) ||
! 1067: len > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
! 1068: printf("%s: invalid packet length %d bytes\n",
! 1069: sc->sc_dev.dv_xname, len);
! 1070: return (0);
! 1071: }
! 1072:
! 1073: m = sonic_get(sc, pkt, len);
! 1074: if (m == NULL)
! 1075: return (0);
! 1076: #if NBPFILTER > 0
! 1077: /* Pass this up to any BPF listeners. */
! 1078: if (ifp->if_bpf)
! 1079: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1080: #endif
! 1081: ether_input_mbuf(ifp, m);
! 1082: return (1);
! 1083: }
! 1084:
! 1085: /*
! 1086: * munge the received packet into an mbuf chain
! 1087: */
! 1088: static __inline__ struct mbuf *
! 1089: sonic_get(struct sn_softc *sc, caddr_t pkt, int datalen)
! 1090: {
! 1091: struct mbuf *m, *top, **mp;
! 1092: int len;
! 1093:
! 1094: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1095: if (m == NULL)
! 1096: return (NULL);
! 1097:
! 1098: m->m_pkthdr.rcvif = &sc->sc_if;
! 1099: m->m_pkthdr.len = datalen;
! 1100: len = MHLEN;
! 1101: top = 0;
! 1102: mp = ⊤
! 1103:
! 1104: while (datalen > 0) {
! 1105: if (top) {
! 1106: MGET(m, M_DONTWAIT, MT_DATA);
! 1107: if (m == NULL) {
! 1108: m_freem(top);
! 1109: return (NULL);
! 1110: }
! 1111: len = MLEN;
! 1112: }
! 1113: if (datalen >= MINCLSIZE) {
! 1114: MCLGET(m, M_DONTWAIT);
! 1115: if ((m->m_flags & M_EXT) == 0) {
! 1116: if (top)
! 1117: m_freem(top);
! 1118: return (NULL);
! 1119: }
! 1120: len = MCLBYTES;
! 1121: }
! 1122: m->m_len = len = min(datalen, len);
! 1123:
! 1124: bcopy(pkt, mtod(m, caddr_t), (unsigned) len);
! 1125: pkt += len;
! 1126: datalen -= len;
! 1127: *mp = m;
! 1128: mp = &m->m_next;
! 1129: }
! 1130:
! 1131: return (top);
! 1132: }
! 1133:
! 1134: static u_char bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
! 1135: #define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf])
! 1136:
! 1137: void
! 1138: sn_get_enaddr(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
! 1139: u_char *dst)
! 1140: {
! 1141: int i, do_bbr;
! 1142: u_char b;
! 1143:
! 1144: /*
! 1145: * For reasons known only to Apple, MAC addresses in the ethernet
! 1146: * PROM are stored in Token Ring (IEEE 802.5) format, that is
! 1147: * with all of the bits in each byte reversed (canonical bit format).
! 1148: * When the address is read out it must be reversed to ethernet format
! 1149: * before use.
! 1150: *
! 1151: * Apple has been assigned OUI's 08:00:07 and 00:a0:40. All onboard
! 1152: * ethernet addresses on 68K machines should be in one of these
! 1153: * two ranges.
! 1154: *
! 1155: * Here is where it gets complicated.
! 1156: *
! 1157: * The PMac 7200, 7500, 8500, and 9500 accidentally had the PROM
! 1158: * written in standard ethernet format. The MacOS accounted for this
! 1159: * in these systems, and did not reverse the bytes. Some other
! 1160: * networking utilities were not so forgiving, and got confused.
! 1161: * "Some" of Apple's Nubus ethernet cards also had their bits
! 1162: * burned in ethernet format.
! 1163: *
! 1164: * Apple petitioned the IEEE and was granted the 00:05:02 (bit reversal
! 1165: * of 00:a0:40) as well. As of OpenTransport 1.1.1, Apple removed
! 1166: * their workaround and now reverses the bits regardless of
! 1167: * what kind of machine it is. So PMac systems and the affected
! 1168: * Nubus cards now use 00:05:02, instead of the 00:a0:40 for which they
! 1169: * were intended.
! 1170: *
! 1171: * See Apple Techinfo article TECHINFO-0020552, "OpenTransport 1.1.1
! 1172: * and MacOS System 7.5.3 FAQ (10/96)" for more details.
! 1173: */
! 1174: do_bbr = 0;
! 1175: b = bus_space_read_1(t, h, o);
! 1176: if (b == 0x10)
! 1177: do_bbr = 1;
! 1178: dst[0] = (do_bbr) ? bbr(b) : b;
! 1179:
! 1180: for (i = 1 ; i < ETHER_ADDR_LEN ; i++) {
! 1181: b = bus_space_read_1(t, h, o+i);
! 1182: dst[i] = (do_bbr) ? bbr(b) : b;
! 1183: }
! 1184: }
CVSweb