[BACK]Return to if_sn.c CVS log [TXT][DIR] Up to [local] / sys / arch / mac68k / dev

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 = &top;
        !          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