[BACK]Return to smc91cxx.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/smc91cxx.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: smc91cxx.c,v 1.26 2006/06/23 06:27:11 miod Exp $      */
        !             2: /*     $NetBSD: smc91cxx.c,v 1.11 1998/08/08 23:51:41 mycroft Exp $    */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1997 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
        !            10:  * NASA Ames Research Center.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *     This product includes software developed by the NetBSD
        !            23:  *     Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: /*
        !            42:  * Copyright (c) 1996 Gardner Buchanan <gbuchanan@shl.com>
        !            43:  * All rights reserved.
        !            44:  *
        !            45:  * Redistribution and use in source and binary forms, with or without
        !            46:  * modification, are permitted provided that the following conditions
        !            47:  * are met:
        !            48:  * 1. Redistributions of source code must retain the above copyright
        !            49:  *    notice, this list of conditions and the following disclaimer.
        !            50:  * 2. Redistributions in binary form must reproduce the above copyright
        !            51:  *    notice, this list of conditions and the following disclaimer in the
        !            52:  *    documentation and/or other materials provided with the distribution.
        !            53:  * 3. All advertising materials mentioning features or use of this software
        !            54:  *    must display the following acknowledgement:
        !            55:  *     This product includes software developed by Gardner Buchanan.
        !            56:  * 4. The name of Gardner Buchanan may not be used to endorse or promote
        !            57:  *    products derived from this software without specific prior written
        !            58:  *    permission.
        !            59:  *
        !            60:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            61:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            62:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            63:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            64:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            65:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            66:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            67:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            68:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            69:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            70:  *
        !            71:  *   from FreeBSD Id: if_sn.c,v 1.4 1996/03/18 15:47:16 gardner Exp
        !            72:  */
        !            73:
        !            74: /*
        !            75:  * Core driver for the SMC 91Cxx family of Ethernet chips.
        !            76:  *
        !            77:  * Memory allocation interrupt logic is drived from an SMC 91C90 driver
        !            78:  * written for NetBSD/amiga by Michael Hitch.
        !            79:  */
        !            80:
        !            81: #include "bpfilter.h"
        !            82:
        !            83: #include <sys/param.h>
        !            84: #include <sys/systm.h>
        !            85: #include <sys/mbuf.h>
        !            86: #include <sys/syslog.h>
        !            87: #include <sys/socket.h>
        !            88: #include <sys/device.h>
        !            89: #include <sys/timeout.h>
        !            90: #include <sys/kernel.h>
        !            91: #include <sys/malloc.h>
        !            92: #include <sys/ioctl.h>
        !            93: #include <sys/errno.h>
        !            94:
        !            95: #include <machine/bus.h>
        !            96: #include <machine/intr.h>
        !            97:
        !            98: #include <net/if.h>
        !            99: #include <net/if_dl.h>
        !           100: #include <net/if_media.h>
        !           101:
        !           102: #ifdef INET
        !           103: #include <netinet/in.h>
        !           104: #include <netinet/if_ether.h>
        !           105: #include <netinet/in_systm.h>
        !           106: #include <netinet/in_var.h>
        !           107: #include <netinet/ip.h>
        !           108: #endif
        !           109:
        !           110: #if NBPFILTER > 0
        !           111: #include <net/bpf.h>
        !           112: #endif
        !           113:
        !           114: #include <dev/mii/mii.h>
        !           115: #include <dev/mii/miivar.h>
        !           116: #include <dev/mii/mii_bitbang.h>
        !           117:
        !           118: #include <dev/ic/smc91cxxreg.h>
        !           119: #include <dev/ic/smc91cxxvar.h>
        !           120:
        !           121: #ifndef __BUS_SPACE_HAS_STREAM_METHODS
        !           122: #define bus_space_write_multi_stream_2 bus_space_write_multi_2
        !           123: #define bus_space_write_multi_stream_4 bus_space_write_multi_4
        !           124: #define bus_space_read_multi_stream_2  bus_space_read_multi_2
        !           125: #define bus_space_read_multi_stream_4  bus_space_read_multi_4
        !           126: #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
        !           127:
        !           128: /* XXX Hardware padding doesn't work yet(?) */
        !           129: #define        SMC91CXX_SW_PAD
        !           130:
        !           131: const char *smc91cxx_idstrs[] = {
        !           132:        NULL,                           /* 0 */
        !           133:        NULL,                           /* 1 */
        !           134:        NULL,                           /* 2 */
        !           135:        "SMC91C90/91C92",               /* 3 */
        !           136:        "SMC91C94/91C96",               /* 4 */
        !           137:        "SMC91C95",                     /* 5 */
        !           138:        NULL,                           /* 6 */
        !           139:        "SMC91C100",                    /* 7 */
        !           140:        "SMC91C100FD",                  /* 8 */
        !           141:        NULL,                           /* 9 */
        !           142:        NULL,                           /* 10 */
        !           143:        NULL,                           /* 11 */
        !           144:        NULL,                           /* 12 */
        !           145:        NULL,                           /* 13 */
        !           146:        NULL,                           /* 14 */
        !           147:        NULL,                           /* 15 */
        !           148: };
        !           149:
        !           150: /* Supported media types. */
        !           151: const int smc91cxx_media[] = {
        !           152:        IFM_ETHER|IFM_10_T,
        !           153:        IFM_ETHER|IFM_10_5,
        !           154: };
        !           155: #define        NSMC91CxxMEDIA  (sizeof(smc91cxx_media) / sizeof(smc91cxx_media[0]))
        !           156:
        !           157: /*
        !           158:  * MII bit-bang glue.
        !           159:  */
        !           160: u_int32_t smc91cxx_mii_bitbang_read(struct device *);
        !           161: void smc91cxx_mii_bitbang_write(struct device *, u_int32_t);
        !           162:
        !           163: const struct mii_bitbang_ops smc91cxx_mii_bitbang_ops = {
        !           164:        smc91cxx_mii_bitbang_read,
        !           165:        smc91cxx_mii_bitbang_write,
        !           166:        {
        !           167:                MR_MDO,         /* MII_BIT_MDO */
        !           168:                MR_MDI,         /* MII_BIT_MDI */
        !           169:                MR_MCLK,        /* MII_BIT_MDC */
        !           170:                MR_MDOE,        /* MII_BIT_DIR_HOST_PHY */
        !           171:                0,              /* MII_BIT_DIR_PHY_HOST */
        !           172:        }
        !           173: };
        !           174:
        !           175: struct cfdriver sm_cd = {
        !           176:        NULL, "sm", DV_IFNET
        !           177: };
        !           178:
        !           179: /* MII callbacks */
        !           180: int    smc91cxx_mii_readreg(struct device *, int, int);
        !           181: void   smc91cxx_mii_writereg(struct device *, int, int, int);
        !           182: void   smc91cxx_statchg(struct device *);
        !           183: void   smc91cxx_tick(void *);
        !           184:
        !           185: int    smc91cxx_mediachange(struct ifnet *);
        !           186: void   smc91cxx_mediastatus(struct ifnet *, struct ifmediareq *);
        !           187:
        !           188: int    smc91cxx_set_media(struct smc91cxx_softc *, int);
        !           189:
        !           190: void   smc91cxx_read(struct smc91cxx_softc *);
        !           191: void   smc91cxx_reset(struct smc91cxx_softc *);
        !           192: void   smc91cxx_start(struct ifnet *);
        !           193: void   smc91cxx_resume(struct smc91cxx_softc *);
        !           194: void   smc91cxx_watchdog(struct ifnet *);
        !           195: int    smc91cxx_ioctl(struct ifnet *, u_long, caddr_t);
        !           196:
        !           197: static __inline int ether_cmp(void *, void *);
        !           198: static __inline int
        !           199: ether_cmp(va, vb)
        !           200:        void *va, *vb;
        !           201: {
        !           202:        u_int8_t *a = va;
        !           203:        u_int8_t *b = vb;
        !           204:
        !           205:        return ((a[5] != b[5]) || (a[4] != b[4]) || (a[3] != b[3]) ||
        !           206:                (a[2] != b[2]) || (a[1] != b[1]) || (a[0] != b[0]));
        !           207: }
        !           208:
        !           209: void
        !           210: smc91cxx_attach(sc, myea)
        !           211:        struct smc91cxx_softc *sc;
        !           212:        u_int8_t *myea;
        !           213: {
        !           214:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           215:        bus_space_tag_t bst = sc->sc_bst;
        !           216:        bus_space_handle_t bsh = sc->sc_bsh;
        !           217:        struct ifmedia *ifm = &sc->sc_mii.mii_media;
        !           218:        u_int32_t miicapabilities;
        !           219:        u_int16_t tmp;
        !           220:        int i, aui;
        !           221:        const char *idstr;
        !           222:
        !           223:        /* Make sure the chip is stopped. */
        !           224:        smc91cxx_stop(sc);
        !           225:
        !           226:        SMC_SELECT_BANK(sc, 3);
        !           227:        tmp = bus_space_read_2(bst, bsh, REVISION_REG_W);
        !           228:        sc->sc_chipid = RR_ID(tmp);
        !           229:        /* check magic number */
        !           230:        if ((tmp & BSR_DETECT_MASK) != BSR_DETECT_VALUE) {
        !           231:                idstr = NULL;
        !           232:                printf("%s: invalid BSR 0x%04x\n", sc->sc_dev.dv_xname, tmp);
        !           233:        } else
        !           234:                idstr = smc91cxx_idstrs[RR_ID(tmp)];
        !           235: #ifdef SMC_DEBUG
        !           236:        printf("\n%s: ", sc->sc_dev.dv_xname);
        !           237:        if (idstr != NULL)
        !           238:                printf("%s, ", idstr);
        !           239:        else
        !           240:                printf("unknown chip id %d, ", sc->sc_chipid);
        !           241:        printf("revision %d", RR_REV(tmp));
        !           242: #endif
        !           243:
        !           244:        /* Read the station address from the chip. */
        !           245:        SMC_SELECT_BANK(sc, 1);
        !           246:        if (myea == NULL) {
        !           247:                for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
        !           248:                        tmp = bus_space_read_2(bst, bsh, IAR_ADDR0_REG_W + i);
        !           249:                        sc->sc_arpcom.ac_enaddr[i + 1] = (tmp >>8) & 0xff;
        !           250:                        sc->sc_arpcom.ac_enaddr[i] = tmp & 0xff;
        !           251:                }
        !           252:        } else {
        !           253:                bcopy(myea, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
        !           254:        }
        !           255:
        !           256:        printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
        !           257:
        !           258:        /* Initialize the ifnet structure. */
        !           259:        bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
        !           260:        ifp->if_softc = sc;
        !           261:        ifp->if_start = smc91cxx_start;
        !           262:        ifp->if_ioctl = smc91cxx_ioctl;
        !           263:        ifp->if_watchdog = smc91cxx_watchdog;
        !           264:        ifp->if_flags =
        !           265:            IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
        !           266:        IFQ_SET_READY(&ifp->if_snd);
        !           267:
        !           268:        /* Attach the interface. */
        !           269:        if_attach(ifp);
        !           270:        ether_ifattach(ifp);
        !           271:
        !           272:        /*
        !           273:         * Initialize our media structures and MII info.  We will
        !           274:         * probe the MII if we are on the SMC91Cxx
        !           275:         */
        !           276:        sc->sc_mii.mii_ifp = ifp;
        !           277:        sc->sc_mii.mii_readreg = smc91cxx_mii_readreg;
        !           278:        sc->sc_mii.mii_writereg = smc91cxx_mii_writereg;
        !           279:        sc->sc_mii.mii_statchg = smc91cxx_statchg;
        !           280:        ifmedia_init(ifm, 0, smc91cxx_mediachange, smc91cxx_mediastatus);
        !           281:
        !           282:        SMC_SELECT_BANK(sc, 1);
        !           283:        tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
        !           284:
        !           285:        miicapabilities = BMSR_MEDIAMASK|BMSR_ANEG;
        !           286:        switch (sc->sc_chipid) {
        !           287:        case CHIP_91100:
        !           288:                /*
        !           289:                 * The 91100 does not have full-duplex capabilities,
        !           290:                 * even if the PHY does.
        !           291:                 */
        !           292:                miicapabilities &= ~(BMSR_100TXFDX | BMSR_10TFDX);
        !           293:        case CHIP_91100FD:
        !           294:                if (tmp & CR_MII_SELECT) {
        !           295: #ifdef SMC_DEBUG
        !           296:                        printf("%s: default media MII\n",
        !           297:                            sc->sc_dev.dv_xname);
        !           298: #endif
        !           299:                        mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff,
        !           300:                            MII_PHY_ANY, MII_OFFSET_ANY, 0);
        !           301:                        if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
        !           302:                                ifmedia_add(&sc->sc_mii.mii_media,
        !           303:                                    IFM_ETHER|IFM_NONE, 0, NULL);
        !           304:                                ifmedia_set(&sc->sc_mii.mii_media,
        !           305:                                    IFM_ETHER|IFM_NONE);
        !           306:                        } else {
        !           307:                                ifmedia_set(&sc->sc_mii.mii_media,
        !           308:                                    IFM_ETHER|IFM_AUTO);
        !           309:                        }
        !           310:                        sc->sc_flags |= SMC_FLAGS_HAS_MII;
        !           311:                        break;
        !           312:                }
        !           313:                /*FALLTHROUGH*/
        !           314:        default:
        !           315:                aui = tmp & CR_AUI_SELECT;
        !           316: #ifdef SMC_DEBUG
        !           317:                printf("%s: default media %s\n", sc->sc_dev.dv_xname,
        !           318:                        aui ? "AUI" : "UTP");
        !           319: #endif
        !           320:                for (i = 0; i < NSMC91CxxMEDIA; i++)
        !           321:                        ifmedia_add(ifm, smc91cxx_media[i], 0, NULL);
        !           322:                ifmedia_set(ifm, IFM_ETHER | (aui ? IFM_10_5 : IFM_10_T));
        !           323:                break;
        !           324:        }
        !           325:
        !           326:        /* The attach is successful. */
        !           327:        sc->sc_flags |= SMC_FLAGS_ATTACHED;
        !           328: }
        !           329:
        !           330: /*
        !           331:  * Change media according to request.
        !           332:  */
        !           333: int
        !           334: smc91cxx_mediachange(ifp)
        !           335:        struct ifnet *ifp;
        !           336: {
        !           337:        struct smc91cxx_softc *sc = ifp->if_softc;
        !           338:
        !           339:        return (smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_media));
        !           340: }
        !           341:
        !           342: int
        !           343: smc91cxx_set_media(sc, media)
        !           344:        struct smc91cxx_softc *sc;
        !           345:        int media;
        !           346: {
        !           347:        bus_space_tag_t bst = sc->sc_bst;
        !           348:        bus_space_handle_t bsh = sc->sc_bsh;
        !           349:        u_int16_t tmp;
        !           350:
        !           351:        /*
        !           352:         * If the interface is not currently powered on, just return.
        !           353:         * When it is enabled later, smc91cxx_init() will properly set
        !           354:         * up the media for us.
        !           355:         */
        !           356:        if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0)
        !           357:                return (0);
        !           358:
        !           359:        if (IFM_TYPE(media) != IFM_ETHER)
        !           360:                return (EINVAL);
        !           361:
        !           362:        if (sc->sc_flags & SMC_FLAGS_HAS_MII)
        !           363:                return (mii_mediachg(&sc->sc_mii));
        !           364:
        !           365:        switch (IFM_SUBTYPE(media)) {
        !           366:        case IFM_10_T:
        !           367:        case IFM_10_5:
        !           368:                SMC_SELECT_BANK(sc, 1);
        !           369:                tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
        !           370:                if (IFM_SUBTYPE(media) == IFM_10_5)
        !           371:                        tmp |= CR_AUI_SELECT;
        !           372:                else
        !           373:                        tmp &= ~CR_AUI_SELECT;
        !           374:                bus_space_write_2(bst, bsh, CONFIG_REG_W, tmp);
        !           375:                delay(20000);   /* XXX is this needed? */
        !           376:                break;
        !           377:
        !           378:        default:
        !           379:                return (EINVAL);
        !           380:        }
        !           381:
        !           382:        return (0);
        !           383: }
        !           384:
        !           385: /*
        !           386:  * Notify the world which media we're using.
        !           387:  */
        !           388: void
        !           389: smc91cxx_mediastatus(ifp, ifmr)
        !           390:        struct ifnet *ifp;
        !           391:        struct ifmediareq *ifmr;
        !           392: {
        !           393:        struct smc91cxx_softc *sc = ifp->if_softc;
        !           394:        bus_space_tag_t bst = sc->sc_bst;
        !           395:        bus_space_handle_t bsh = sc->sc_bsh;
        !           396:        u_int16_t tmp;
        !           397:
        !           398:        if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) {
        !           399:                ifmr->ifm_active = IFM_ETHER | IFM_NONE;
        !           400:                ifmr->ifm_status = 0;
        !           401:                return;
        !           402:        }
        !           403:
        !           404:        /*
        !           405:         * If we have MII, go ask the PHY what's going on.
        !           406:         */
        !           407:        if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
        !           408:                mii_pollstat(&sc->sc_mii);
        !           409:                ifmr->ifm_active = sc->sc_mii.mii_media_active;
        !           410:                ifmr->ifm_status = sc->sc_mii.mii_media_status;
        !           411:                return;
        !           412:        }
        !           413:
        !           414:        SMC_SELECT_BANK(sc, 1);
        !           415:        tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
        !           416:        ifmr->ifm_active =
        !           417:            IFM_ETHER | ((tmp & CR_AUI_SELECT) ? IFM_10_5 : IFM_10_T);
        !           418: }
        !           419:
        !           420: /*
        !           421:  * Reset and initialize the chip.
        !           422:  */
        !           423: void
        !           424: smc91cxx_init(sc)
        !           425:        struct smc91cxx_softc *sc;
        !           426: {
        !           427:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           428:        bus_space_tag_t bst = sc->sc_bst;
        !           429:        bus_space_handle_t bsh = sc->sc_bsh;
        !           430:        u_int16_t tmp;
        !           431:        int s, i;
        !           432:
        !           433:        s = splnet();
        !           434:
        !           435:        /*
        !           436:         * This resets the registers mostly to defaults, but doesn't
        !           437:         * affect the EEPROM.  After the reset cycle, we pause briefly
        !           438:         * for the chip to recover.
        !           439:         *
        !           440:         * XXX how long are we really supposed to delay?  --thorpej
        !           441:         */
        !           442:        SMC_SELECT_BANK(sc, 0);
        !           443:        bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, RCR_SOFTRESET);
        !           444:        delay(100);
        !           445:        bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
        !           446:        delay(200);
        !           447:
        !           448:        bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
        !           449:
        !           450:        /* Set the Ethernet address. */
        !           451:        SMC_SELECT_BANK(sc, 1);
        !           452:        for (i = 0; i < ETHER_ADDR_LEN; i++ )
        !           453:                bus_space_write_1(bst, bsh, IAR_ADDR0_REG_W + i,
        !           454:                    sc->sc_arpcom.ac_enaddr[i]);
        !           455:
        !           456:        /*
        !           457:         * Set the control register to automatically release successfully
        !           458:         * transmitted packets (making the best use of our limited memory)
        !           459:         * and enable the EPH interrupt on certain TX errors.
        !           460:         */
        !           461:        bus_space_write_2(bst, bsh, CONTROL_REG_W, (CTR_AUTO_RELEASE |
        !           462:            CTR_TE_ENABLE | CTR_CR_ENABLE | CTR_LE_ENABLE));
        !           463:
        !           464:        /*
        !           465:         * Reset the MMU and wait for it to be un-busy.
        !           466:         */
        !           467:        SMC_SELECT_BANK(sc, 2);
        !           468:        bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RESET);
        !           469:        while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
        !           470:                /* XXX bound this loop! */ ;
        !           471:
        !           472:        /*
        !           473:         * Disable all interrupts.
        !           474:         */
        !           475:        bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
        !           476:
        !           477:        /*
        !           478:         * Set current media.
        !           479:         */
        !           480:        smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_cur->ifm_media);
        !           481:
        !           482:        /*
        !           483:         * Set the receive filter.  We want receive enable and auto
        !           484:         * strip of CRC from received packet.  If we are in promisc. mode,
        !           485:         * then set that bit as well.
        !           486:         *
        !           487:         * XXX Initialize multicast filter.  For now, we just accept
        !           488:         * XXX all multicast.
        !           489:         */
        !           490:        SMC_SELECT_BANK(sc, 0);
        !           491:
        !           492:        tmp = RCR_ENABLE | RCR_STRIP_CRC | RCR_ALMUL;
        !           493:        if (ifp->if_flags & IFF_PROMISC)
        !           494:                tmp |= RCR_PROMISC;
        !           495:
        !           496:        bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, tmp);
        !           497:
        !           498:        /*
        !           499:         * Set transmitter control to "enabled".
        !           500:         */
        !           501:        tmp = TCR_ENABLE;
        !           502:
        !           503: #ifndef SMC91CXX_SW_PAD
        !           504:        /*
        !           505:         * Enable hardware padding of transmitted packets.
        !           506:         * XXX doesn't work?
        !           507:         */
        !           508:        tmp |= TCR_PAD_ENABLE;
        !           509: #endif
        !           510:
        !           511:        bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, tmp);
        !           512:
        !           513:        /*
        !           514:         * Now, enable interrupts.
        !           515:         */
        !           516:        SMC_SELECT_BANK(sc, 2);
        !           517:
        !           518:        bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
        !           519:            IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | IM_TX_INT);
        !           520:
        !           521:        /* Interface is now running, with no output active. */
        !           522:        ifp->if_flags |= IFF_RUNNING;
        !           523:        ifp->if_flags &= ~IFF_OACTIVE;
        !           524:
        !           525:        if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
        !           526:                /* Start the one second clock. */
        !           527:                timeout_set(&sc->sc_mii_timeout, smc91cxx_tick, sc);
        !           528:                timeout_add(&sc->sc_mii_timeout, hz);
        !           529:        }
        !           530:
        !           531:        /*
        !           532:         * Attempt to start any pending transmission.
        !           533:         */
        !           534:        smc91cxx_start(ifp);
        !           535:
        !           536:        splx(s);
        !           537: }
        !           538:
        !           539: /*
        !           540:  * Start output on an interface.
        !           541:  * Must be called at splnet or interrupt level.
        !           542:  */
        !           543: void
        !           544: smc91cxx_start(ifp)
        !           545:        struct ifnet *ifp;
        !           546: {
        !           547:        struct smc91cxx_softc *sc = ifp->if_softc;
        !           548:        bus_space_tag_t bst = sc->sc_bst;
        !           549:        bus_space_handle_t bsh = sc->sc_bsh;
        !           550:        u_int len;
        !           551:        struct mbuf *m, *top;
        !           552:        u_int16_t length, npages;
        !           553:        u_int8_t packetno;
        !           554:        int timo, pad;
        !           555:
        !           556:        if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
        !           557:                return;
        !           558:
        !           559:  again:
        !           560:        /*
        !           561:         * Peek at the next packet.
        !           562:         */
        !           563:        IFQ_POLL(&ifp->if_snd, m);
        !           564:        if (m == NULL)
        !           565:                return;
        !           566:
        !           567:        /*
        !           568:         * Compute the frame length and set pad to give an overall even
        !           569:         * number of bytes.  Below, we assume that the packet length
        !           570:         * is even.
        !           571:         */
        !           572:        for (len = 0, top = m; m != NULL; m = m->m_next)
        !           573:                len += m->m_len;
        !           574:        pad = (len & 1);
        !           575:
        !           576:        /*
        !           577:         * We drop packets that are too large.  Perhaps we should
        !           578:         * truncate them instead?
        !           579:         */
        !           580:        if ((len + pad) > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
        !           581:                printf("%s: large packet discarded\n", sc->sc_dev.dv_xname);
        !           582:                ifp->if_oerrors++;
        !           583:                IFQ_DEQUEUE(&ifp->if_snd, m);
        !           584:                m_freem(m);
        !           585:                goto readcheck;
        !           586:        }
        !           587:
        !           588: #ifdef SMC91CXX_SW_PAD
        !           589:        /*
        !           590:         * Not using hardware padding; pad to ETHER_MIN_LEN.
        !           591:         */
        !           592:        if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN))
        !           593:                pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
        !           594: #endif
        !           595:
        !           596:        length = pad + len;
        !           597:
        !           598:        /*
        !           599:         * The MMU has a 256 byte page size.  The MMU expects us to
        !           600:         * ask for "npages - 1".  We include space for the status word,
        !           601:         * byte count, and control bytes in the allocation request.
        !           602:         */
        !           603:        npages = (length + 6) >> 8;
        !           604:
        !           605:        /*
        !           606:         * Now allocate the memory.
        !           607:         */
        !           608:        SMC_SELECT_BANK(sc, 2);
        !           609:        bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ALLOC | npages);
        !           610:
        !           611:        timo = MEMORY_WAIT_TIME;
        !           612:        do {
        !           613:                if (bus_space_read_1(bst, bsh, INTR_STAT_REG_B) & IM_ALLOC_INT)
        !           614:                        break;
        !           615:                delay(1);
        !           616:        } while (--timo);
        !           617:
        !           618:        packetno = bus_space_read_1(bst, bsh, ALLOC_RESULT_REG_B);
        !           619:
        !           620:        if (packetno & ARR_FAILED || timo == 0) {
        !           621:                /*
        !           622:                 * No transmit memory is available.  Record the number
        !           623:                 * of requestd pages and enable the allocation completion
        !           624:                 * interrupt.  Set up the watchdog timer in case we miss
        !           625:                 * the interrupt.  Mark the interface as active so that
        !           626:                 * no one else attempts to transmit while we're allocating
        !           627:                 * memory.
        !           628:                 */
        !           629:                bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
        !           630:                    bus_space_read_1(bst, bsh, INTR_MASK_REG_B) | IM_ALLOC_INT);
        !           631:
        !           632:                ifp->if_timer = 5;
        !           633:                ifp->if_flags |= IFF_OACTIVE;
        !           634:
        !           635:                return;
        !           636:        }
        !           637:
        !           638:        /*
        !           639:         * We have a packet number - set the data window.
        !           640:         */
        !           641:        bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
        !           642:
        !           643:        /*
        !           644:         * Point to the beginning of the packet.
        !           645:         */
        !           646:        bus_space_write_2(bst, bsh, POINTER_REG_W, PTR_AUTOINC /* | 0x0000 */);
        !           647:
        !           648:        /*
        !           649:         * Send the packet length (+6 for stats, length, and control bytes)
        !           650:         * and the status word (set to zeros).
        !           651:         */
        !           652:        bus_space_write_2(bst, bsh, DATA_REG_W, 0);
        !           653:        bus_space_write_1(bst, bsh, DATA_REG_B, (length + 6) & 0xff);
        !           654:        bus_space_write_1(bst, bsh, DATA_REG_B, ((length + 6) >> 8) & 0xff);
        !           655:
        !           656:        /*
        !           657:         * Get the packet from the kernel.  This will include the Ethernet
        !           658:         * frame header, MAC address, etc.
        !           659:         */
        !           660:        IFQ_DEQUEUE(&ifp->if_snd, m);
        !           661:
        !           662:        /*
        !           663:         * Push the packet out to the card.
        !           664:         */
        !           665:        for (top = m; m != NULL; m = m->m_next) {
        !           666:                /* Words... */
        !           667:                if (m->m_len > 1)
        !           668:                        bus_space_write_multi_stream_2(bst, bsh, DATA_REG_W,
        !           669:                            mtod(m, u_int16_t *), m->m_len >> 1);
        !           670:
        !           671:                /* ...and the remaining byte, if any. */
        !           672:                if (m->m_len & 1)
        !           673:                        bus_space_write_1(bst, bsh, DATA_REG_B,
        !           674:                          *(u_int8_t *)(mtod(m, u_int8_t *) + (m->m_len - 1)));
        !           675:        }
        !           676:
        !           677: #ifdef SMC91CXX_SW_PAD
        !           678:        /*
        !           679:         * Push out padding.
        !           680:         */
        !           681:        while (pad > 1) {
        !           682:                bus_space_write_2(bst, bsh, DATA_REG_W, 0);
        !           683:                pad -= 2;
        !           684:        }
        !           685:        if (pad)
        !           686:                bus_space_write_1(bst, bsh, DATA_REG_B, 0);
        !           687: #endif
        !           688:
        !           689:        /*
        !           690:         * Push out control byte and unused packet byte.  The control byte
        !           691:         * is 0, meaning the packet is even lengthed and no special
        !           692:         * CRC handling is necessary.
        !           693:         */
        !           694:        bus_space_write_2(bst, bsh, DATA_REG_W, 0);
        !           695:
        !           696:        /*
        !           697:         * Enable transmit interrupts and let the chip go.  Set a watchdog
        !           698:         * in case we miss the interrupt.
        !           699:         */
        !           700:        bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
        !           701:            bus_space_read_1(bst, bsh, INTR_MASK_REG_B) |
        !           702:            IM_TX_INT | IM_TX_EMPTY_INT);
        !           703:
        !           704:        bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ENQUEUE);
        !           705:
        !           706:        ifp->if_timer = 5;
        !           707:
        !           708: #if NBPFILTER > 0
        !           709:        /* Hand off a copy to the bpf. */
        !           710:        if (ifp->if_bpf)
        !           711:                bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_OUT);
        !           712: #endif
        !           713:
        !           714:        ifp->if_opackets++;
        !           715:        m_freem(top);
        !           716:
        !           717:  readcheck:
        !           718:        /*
        !           719:         * Check for incoming pcakets.  We don't want to overflow the small
        !           720:         * RX FIFO.  If nothing has arrived, attempt to queue another
        !           721:         * transmit packet.
        !           722:         */
        !           723:        if (bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) & FIFO_REMPTY)
        !           724:                goto again;
        !           725: }
        !           726:
        !           727: /*
        !           728:  * Interrupt service routine.
        !           729:  */
        !           730: int
        !           731: smc91cxx_intr(arg)
        !           732:        void *arg;
        !           733: {
        !           734:        struct smc91cxx_softc *sc = arg;
        !           735:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           736:        bus_space_tag_t bst = sc->sc_bst;
        !           737:        bus_space_handle_t bsh = sc->sc_bsh;
        !           738:        u_int8_t mask, interrupts, status;
        !           739:        u_int16_t packetno, tx_status, card_stats;
        !           740:
        !           741:        if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 ||
        !           742:            (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
        !           743:                return (0);
        !           744:
        !           745:        SMC_SELECT_BANK(sc, 2);
        !           746:
        !           747:        /*
        !           748:         * Obtain the current interrupt mask.
        !           749:         */
        !           750:        mask = bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
        !           751:
        !           752:        /*
        !           753:         * Get the set of interrupt which occurred and eliminate any
        !           754:         * which are not enabled.
        !           755:         */
        !           756:        interrupts = bus_space_read_1(bst, bsh, INTR_STAT_REG_B);
        !           757:        status = interrupts & mask;
        !           758:
        !           759:        /* Ours? */
        !           760:        if (status == 0)
        !           761:                return (0);
        !           762:
        !           763:        /*
        !           764:         * It's ours; disable all interrupts while we process them.
        !           765:         */
        !           766:        bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
        !           767:
        !           768:        /*
        !           769:         * Receive overrun interrupts.
        !           770:         */
        !           771:        if (status & IM_RX_OVRN_INT) {
        !           772:                bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_RX_OVRN_INT);
        !           773:                ifp->if_ierrors++;
        !           774:        }
        !           775:
        !           776:        /*
        !           777:         * Receive interrupts.
        !           778:         */
        !           779:        if (status & IM_RCV_INT) {
        !           780: #if 1 /* DIAGNOSTIC */
        !           781:                packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
        !           782:                if (packetno & FIFO_REMPTY) {
        !           783:                        printf("%s: receive interrupt on empty fifo\n",
        !           784:                            sc->sc_dev.dv_xname);
        !           785:                        goto out;
        !           786:                } else
        !           787: #endif
        !           788:                smc91cxx_read(sc);
        !           789:        }
        !           790:
        !           791:        /*
        !           792:         * Memory allocation interrupts.
        !           793:         */
        !           794:        if (status & IM_ALLOC_INT) {
        !           795:                /* Disable this interrupt. */
        !           796:                mask &= ~IM_ALLOC_INT;
        !           797:
        !           798:                /*
        !           799:                 * Release the just-allocated memory.  We will reallocate
        !           800:                 * it through the normal start logic.
        !           801:                 */
        !           802:                while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
        !           803:                        /* XXX bound this loop! */ ;
        !           804:                bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
        !           805:
        !           806:                ifp->if_flags &= ~IFF_OACTIVE;
        !           807:                ifp->if_timer = 0;
        !           808:        }
        !           809:
        !           810:        /*
        !           811:         * Transmit complete interrupt.  Handle transmission error messages.
        !           812:         * This will only be called on error condition because of AUTO RELEASE
        !           813:         * mode.
        !           814:         */
        !           815:        if (status & IM_TX_INT) {
        !           816:                bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_INT);
        !           817:
        !           818:                packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) &
        !           819:                    FIFO_TX_MASK;
        !           820:
        !           821:                /*
        !           822:                 * Select this as the packet to read from.
        !           823:                 */
        !           824:                bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
        !           825:
        !           826:                /*
        !           827:                 * Position the pointer to the beginning of the packet.
        !           828:                 */
        !           829:                bus_space_write_2(bst, bsh, POINTER_REG_W,
        !           830:                    PTR_AUTOINC | PTR_READ /* | 0x0000 */);
        !           831:
        !           832:                /*
        !           833:                 * Fetch the TX status word.  This will be a copy of
        !           834:                 * the EPH_STATUS_REG_W at the time of the transmission
        !           835:                 * failure.
        !           836:                 */
        !           837:                tx_status = bus_space_read_2(bst, bsh, DATA_REG_W);
        !           838:
        !           839:                if (tx_status & EPHSR_TX_SUC)
        !           840:                        printf("%s: successful packet caused TX interrupt?!\n",
        !           841:                            sc->sc_dev.dv_xname);
        !           842:                else
        !           843:                        ifp->if_oerrors++;
        !           844:
        !           845:                if (tx_status & EPHSR_LATCOL)
        !           846:                        ifp->if_collisions++;
        !           847:
        !           848:                /*
        !           849:                 * Some of these errors disable the transmitter; reenable it.
        !           850:                 */
        !           851:                SMC_SELECT_BANK(sc, 0);
        !           852: #ifdef SMC91CXX_SW_PAD
        !           853:                bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, TCR_ENABLE);
        !           854: #else
        !           855:                bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W,
        !           856:                    TCR_ENABLE | TCR_PAD_ENABLE);
        !           857: #endif
        !           858:
        !           859:                /*
        !           860:                 * Kill the failed packet and wait for the MMU to unbusy.
        !           861:                 */
        !           862:                SMC_SELECT_BANK(sc, 2);
        !           863:                while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
        !           864:                        /* XXX bound this loop! */ ;
        !           865:                bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
        !           866:
        !           867:                ifp->if_timer = 0;
        !           868:        }
        !           869:
        !           870:        /*
        !           871:         * Transmit underrun interrupts.  We use this opportunity to
        !           872:         * update transmit statistics from the card.
        !           873:         */
        !           874:        if (status & IM_TX_EMPTY_INT) {
        !           875:                bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_EMPTY_INT);
        !           876:
        !           877:                /* Disable this interrupt. */
        !           878:                mask &= ~IM_TX_EMPTY_INT;
        !           879:
        !           880:                SMC_SELECT_BANK(sc, 0);
        !           881:                card_stats = bus_space_read_2(bst, bsh, COUNTER_REG_W);
        !           882:
        !           883:                /* Single collisions. */
        !           884:                ifp->if_collisions += card_stats & ECR_COLN_MASK;
        !           885:
        !           886:                /* Multiple collisions. */
        !           887:                ifp->if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4;
        !           888:
        !           889:                SMC_SELECT_BANK(sc, 2);
        !           890:
        !           891:                ifp->if_timer = 0;
        !           892:        }
        !           893:
        !           894:        /*
        !           895:         * Other errors.  Reset the interface.
        !           896:         */
        !           897:        if (status & IM_EPH_INT) {
        !           898:                smc91cxx_stop(sc);
        !           899:                smc91cxx_init(sc);
        !           900:        }
        !           901:
        !           902:        /*
        !           903:         * Attempt to queue more packets for transmission.
        !           904:         */
        !           905:        smc91cxx_start(ifp);
        !           906:
        !           907: out:
        !           908:        /*
        !           909:         * Reenable the interrupts we wish to receive now that processing
        !           910:         * is complete.
        !           911:         */
        !           912:        mask |= bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
        !           913:        bus_space_write_1(bst, bsh, INTR_MASK_REG_B, mask);
        !           914:
        !           915:        return (1);
        !           916: }
        !           917:
        !           918: /*
        !           919:  * Read a packet from the card and pass it up to the kernel.
        !           920:  * NOTE!  WE EXPECT TO BE IN REGISTER WINDOW 2!
        !           921:  */
        !           922: void
        !           923: smc91cxx_read(sc)
        !           924:        struct smc91cxx_softc *sc;
        !           925: {
        !           926:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           927:        bus_space_tag_t bst = sc->sc_bst;
        !           928:        bus_space_handle_t bsh = sc->sc_bsh;
        !           929:        struct mbuf *m;
        !           930:        u_int16_t status, packetno, packetlen;
        !           931:        u_int8_t *data;
        !           932:
        !           933:  again:
        !           934:        /*
        !           935:         * Set data pointer to the beginning of the packet.  Since
        !           936:         * PTR_RCV is set, the packet number will be found automatically
        !           937:         * in FIFO_PORTS_REG_W, FIFO_RX_MASK.
        !           938:         */
        !           939:        bus_space_write_2(bst, bsh, POINTER_REG_W,
        !           940:            PTR_READ | PTR_RCV | PTR_AUTOINC /* | 0x0000 */);
        !           941:
        !           942:        /*
        !           943:         * First two words are status and packet length.
        !           944:         */
        !           945:        status = bus_space_read_2(bst, bsh, DATA_REG_W);
        !           946:        packetlen = bus_space_read_2(bst, bsh, DATA_REG_W);
        !           947:
        !           948:        /*
        !           949:         * The packet length includes 3 extra words: status, length,
        !           950:         * and an extra word that includes the control byte.
        !           951:         */
        !           952:        packetlen -= 6;
        !           953:
        !           954:        /*
        !           955:         * Account for receive errors and discard.
        !           956:         */
        !           957:        if (status & RS_ERRORS) {
        !           958:                ifp->if_ierrors++;
        !           959:                goto out;
        !           960:        }
        !           961:
        !           962:        /*
        !           963:         * Adjust for odd-length packet.
        !           964:         */
        !           965:        if (status & RS_ODDFRAME)
        !           966:                packetlen++;
        !           967:
        !           968:        /*
        !           969:         * Allocate a header mbuf.
        !           970:         */
        !           971:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           972:        if (m == NULL)
        !           973:                goto out;
        !           974:        m->m_pkthdr.rcvif = ifp;
        !           975:        m->m_pkthdr.len = packetlen;
        !           976:
        !           977:        /*
        !           978:         * Always put the packet in a cluster.
        !           979:         * XXX should chain small mbufs if less than threshold.
        !           980:         */
        !           981:        MCLGET(m, M_DONTWAIT);
        !           982:        if ((m->m_flags & M_EXT) == 0) {
        !           983:                m_freem(m);
        !           984:                ifp->if_ierrors++;
        !           985:                printf("%s: can't allocate cluster for incoming packet\n",
        !           986:                    sc->sc_dev.dv_xname);
        !           987:                goto out;
        !           988:        }
        !           989:
        !           990:        /*
        !           991:         * Pull the packet off the interface.  Make sure the payload
        !           992:         * is aligned.
        !           993:         */
        !           994:        m->m_data = (caddr_t) ALIGN(mtod(m, caddr_t) +
        !           995:            sizeof(struct ether_header)) - sizeof(struct ether_header);
        !           996:
        !           997:        data = mtod(m, u_int8_t *);
        !           998:        if (packetlen > 1)
        !           999:                bus_space_read_multi_stream_2(bst, bsh, DATA_REG_W,
        !          1000:                    (u_int16_t *)data, packetlen >> 1);
        !          1001:        if (packetlen & 1) {
        !          1002:                data += packetlen & ~1;
        !          1003:                *data = bus_space_read_1(bst, bsh, DATA_REG_B);
        !          1004:        }
        !          1005:
        !          1006:        ifp->if_ipackets++;
        !          1007:
        !          1008: #if NBPFILTER > 0
        !          1009:        /*
        !          1010:         * Hand the packet off to bpf listeners.  If there's a bpf listener,
        !          1011:         * we need to check if the packet is ours.
        !          1012:         */
        !          1013:        if (ifp->if_bpf)
        !          1014:                bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
        !          1015: #endif
        !          1016:
        !          1017:        m->m_pkthdr.len = m->m_len = packetlen;
        !          1018:        ether_input_mbuf(ifp, m);
        !          1019:
        !          1020:  out:
        !          1021:        /*
        !          1022:         * Tell the card to free the memory occupied by this packet.
        !          1023:         */
        !          1024:        while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
        !          1025:                /* XXX bound this loop! */ ;
        !          1026:        bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RELEASE);
        !          1027:
        !          1028:        /*
        !          1029:         * Check for another packet.
        !          1030:         */
        !          1031:        packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
        !          1032:        if (packetno & FIFO_REMPTY)
        !          1033:                return;
        !          1034:        goto again;
        !          1035: }
        !          1036:
        !          1037: /*
        !          1038:  * Process an ioctl request.
        !          1039:  */
        !          1040: int
        !          1041: smc91cxx_ioctl(ifp, cmd, data)
        !          1042:        struct ifnet *ifp;
        !          1043:        u_long cmd;
        !          1044:        caddr_t data;
        !          1045: {
        !          1046:        struct smc91cxx_softc *sc = ifp->if_softc;
        !          1047:        struct ifaddr *ifa = (struct ifaddr *)data;
        !          1048:        struct ifreq *ifr = (struct ifreq *)data;
        !          1049:        int s, error = 0;
        !          1050:
        !          1051:        s = splnet();
        !          1052:
        !          1053:        switch (cmd) {
        !          1054:        case SIOCSIFADDR:
        !          1055:                if ((error = smc91cxx_enable(sc)) != 0)
        !          1056:                        break;
        !          1057:                ifp->if_flags |= IFF_UP;
        !          1058:                switch (ifa->ifa_addr->sa_family) {
        !          1059: #ifdef INET
        !          1060:                case AF_INET:
        !          1061:                        smc91cxx_init(sc);
        !          1062:                        arp_ifinit(&sc->sc_arpcom, ifa);
        !          1063:                        break;
        !          1064: #endif
        !          1065:                default:
        !          1066:                        smc91cxx_init(sc);
        !          1067:                        break;
        !          1068:                }
        !          1069:                break;
        !          1070:
        !          1071:        case SIOCSIFFLAGS:
        !          1072:                if ((ifp->if_flags & IFF_UP) == 0 &&
        !          1073:                    (ifp->if_flags & IFF_RUNNING) != 0) {
        !          1074:                        /*
        !          1075:                         * If interface is marked down and it is running,
        !          1076:                         * stop it.
        !          1077:                         */
        !          1078:                        smc91cxx_stop(sc);
        !          1079:                        ifp->if_flags &= ~IFF_RUNNING;
        !          1080:                        smc91cxx_disable(sc);
        !          1081:                } else if ((ifp->if_flags & IFF_UP) != 0 &&
        !          1082:                           (ifp->if_flags & IFF_RUNNING) == 0) {
        !          1083:                        /*
        !          1084:                         * If interface is marked up and it is stopped,
        !          1085:                         * start it.
        !          1086:                         */
        !          1087:                        if ((error = smc91cxx_enable(sc)) != 0)
        !          1088:                                break;
        !          1089:                        smc91cxx_init(sc);
        !          1090:                } else if ((ifp->if_flags & IFF_UP) != 0) {
        !          1091:                        /*
        !          1092:                         * Reset the interface to pick up changes in any
        !          1093:                         * other flags that affect hardware registers.
        !          1094:                         */
        !          1095:                        smc91cxx_reset(sc);
        !          1096:                }
        !          1097:                break;
        !          1098:
        !          1099:        case SIOCADDMULTI:
        !          1100:        case SIOCDELMULTI:
        !          1101:                if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) {
        !          1102:                        error = EIO;
        !          1103:                        break;
        !          1104:                }
        !          1105:
        !          1106:                error = (cmd == SIOCADDMULTI) ?
        !          1107:                    ether_addmulti(ifr, &sc->sc_arpcom) :
        !          1108:                    ether_delmulti(ifr, &sc->sc_arpcom);
        !          1109:                if (error == ENETRESET) {
        !          1110:                        /*
        !          1111:                         * Multicast list has changed; set the hardware
        !          1112:                         * filter accordingly.
        !          1113:                         */
        !          1114:                        if (ifp->if_flags & IFF_RUNNING)
        !          1115:                                smc91cxx_reset(sc);
        !          1116:                        error = 0;
        !          1117:                }
        !          1118:                break;
        !          1119:
        !          1120:        case SIOCGIFMEDIA:
        !          1121:        case SIOCSIFMEDIA:
        !          1122:                error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
        !          1123:                break;
        !          1124:
        !          1125:        default:
        !          1126:                error = EINVAL;
        !          1127:                break;
        !          1128:        }
        !          1129:
        !          1130:        splx(s);
        !          1131:        return (error);
        !          1132: }
        !          1133:
        !          1134: /*
        !          1135:  * Reset the interface.
        !          1136:  */
        !          1137: void
        !          1138: smc91cxx_reset(sc)
        !          1139:        struct smc91cxx_softc *sc;
        !          1140: {
        !          1141:        int s;
        !          1142:
        !          1143:        s = splnet();
        !          1144:        smc91cxx_stop(sc);
        !          1145:        smc91cxx_init(sc);
        !          1146:        splx(s);
        !          1147: }
        !          1148:
        !          1149: /*
        !          1150:  * Watchdog timer.
        !          1151:  */
        !          1152: void
        !          1153: smc91cxx_watchdog(ifp)
        !          1154:        struct ifnet *ifp;
        !          1155: {
        !          1156:        struct smc91cxx_softc *sc = ifp->if_softc;
        !          1157:
        !          1158:        log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
        !          1159:        ++sc->sc_arpcom.ac_if.if_oerrors;
        !          1160:
        !          1161:        smc91cxx_reset(sc);
        !          1162: }
        !          1163:
        !          1164: /*
        !          1165:  * Stop output on the interface.
        !          1166:  */
        !          1167: void
        !          1168: smc91cxx_stop(sc)
        !          1169:        struct smc91cxx_softc *sc;
        !          1170: {
        !          1171:        bus_space_tag_t bst = sc->sc_bst;
        !          1172:        bus_space_handle_t bsh = sc->sc_bsh;
        !          1173:
        !          1174:        /*
        !          1175:         * Clear interrupt mask; disable all interrupts.
        !          1176:         */
        !          1177:        SMC_SELECT_BANK(sc, 2);
        !          1178:        bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
        !          1179:
        !          1180:        /*
        !          1181:         * Disable transmitter and receiver.
        !          1182:         */
        !          1183:        SMC_SELECT_BANK(sc, 0);
        !          1184:        bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
        !          1185:        bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
        !          1186:
        !          1187:        /*
        !          1188:         * Cancel watchdog timer.
        !          1189:         */
        !          1190:        sc->sc_arpcom.ac_if.if_timer = 0;
        !          1191: }
        !          1192:
        !          1193: /*
        !          1194:  * Enable power on the interface.
        !          1195:  */
        !          1196: int
        !          1197: smc91cxx_enable(sc)
        !          1198:        struct smc91cxx_softc *sc;
        !          1199: {
        !          1200:        if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 && sc->sc_enable != NULL) {
        !          1201:                if ((*sc->sc_enable)(sc) != 0) {
        !          1202:                        printf("%s: device enable failed\n",
        !          1203:                            sc->sc_dev.dv_xname);
        !          1204:                        return (EIO);
        !          1205:                }
        !          1206:        }
        !          1207:
        !          1208:        sc->sc_flags |= SMC_FLAGS_ENABLED;
        !          1209:        return (0);
        !          1210: }
        !          1211:
        !          1212: /*
        !          1213:  * Disable power on the interface.
        !          1214:  */
        !          1215: void
        !          1216: smc91cxx_disable(sc)
        !          1217:        struct smc91cxx_softc *sc;
        !          1218: {
        !          1219:        if ((sc->sc_flags & SMC_FLAGS_ENABLED) != 0 && sc->sc_disable != NULL) {
        !          1220:                (*sc->sc_disable)(sc);
        !          1221:                sc->sc_flags &= ~SMC_FLAGS_ENABLED;
        !          1222:        }
        !          1223: }
        !          1224:
        !          1225: int
        !          1226: smc91cxx_activate(self, act)
        !          1227:        struct device *self;
        !          1228:        enum devact act;
        !          1229: {
        !          1230: #if 0
        !          1231:        struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
        !          1232: #endif
        !          1233:        int rv = 0, s;
        !          1234:
        !          1235:        s = splnet();
        !          1236:        switch (act) {
        !          1237:        case DVACT_ACTIVATE:
        !          1238:                break;
        !          1239:
        !          1240:        case DVACT_DEACTIVATE:
        !          1241: #if 0
        !          1242:                if_deactivate(&sc->sc_ic.ic_if);
        !          1243: #endif
        !          1244:                break;
        !          1245:        }
        !          1246:        splx(s);
        !          1247:        return(rv);
        !          1248: }
        !          1249:
        !          1250: int
        !          1251: smc91cxx_detach(self, flags)
        !          1252:        struct device *self;
        !          1253:        int flags;
        !          1254: {
        !          1255:        struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
        !          1256:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !          1257:
        !          1258:        /* Succeed now if there's no work to do. */
        !          1259:        if ((sc->sc_flags & SMC_FLAGS_ATTACHED) == 0)
        !          1260:                return(0);
        !          1261:
        !          1262:        /* smc91cxx_disable() checks SMC_FLAGS_ENABLED */
        !          1263:        smc91cxx_disable(sc);
        !          1264:
        !          1265:        /* smc91cxx_attach() never fails */
        !          1266:
        !          1267:        /* Delete all media. */
        !          1268:        ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
        !          1269:
        !          1270: #if NBPFILTER > 0
        !          1271:        bpfdetach(ifp);
        !          1272: #endif
        !          1273:        ether_ifdetach(ifp);
        !          1274:        if_detach(ifp);
        !          1275:
        !          1276:        return (0);
        !          1277: }
        !          1278:
        !          1279: u_int32_t
        !          1280: smc91cxx_mii_bitbang_read(self)
        !          1281:        struct device *self;
        !          1282: {
        !          1283:        struct smc91cxx_softc *sc = (void *) self;
        !          1284:
        !          1285:        /* We're already in bank 3. */
        !          1286:        return (bus_space_read_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W));
        !          1287: }
        !          1288:
        !          1289: void
        !          1290: smc91cxx_mii_bitbang_write(self, val)
        !          1291:        struct device *self;
        !          1292:        u_int32_t val;
        !          1293: {
        !          1294:        struct smc91cxx_softc *sc = (void *) self;
        !          1295:
        !          1296:        /* We're already in bank 3. */
        !          1297:        bus_space_write_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W, val);
        !          1298: }
        !          1299:
        !          1300: int
        !          1301: smc91cxx_mii_readreg(self, phy, reg)
        !          1302:        struct device *self;
        !          1303:        int phy, reg;
        !          1304: {
        !          1305:        struct smc91cxx_softc *sc = (void *) self;
        !          1306:        int val;
        !          1307:
        !          1308:        SMC_SELECT_BANK(sc, 3);
        !          1309:
        !          1310:        val = mii_bitbang_readreg(self, &smc91cxx_mii_bitbang_ops, phy, reg);
        !          1311:
        !          1312:        SMC_SELECT_BANK(sc, 2);
        !          1313:
        !          1314:        return (val);
        !          1315: }
        !          1316:
        !          1317: void
        !          1318: smc91cxx_mii_writereg(self, phy, reg, val)
        !          1319:        struct device *self;
        !          1320:        int phy, reg, val;
        !          1321: {
        !          1322:        struct smc91cxx_softc *sc = (void *) self;
        !          1323:
        !          1324:        SMC_SELECT_BANK(sc, 3);
        !          1325:
        !          1326:        mii_bitbang_writereg(self, &smc91cxx_mii_bitbang_ops, phy, reg, val);
        !          1327:
        !          1328:        SMC_SELECT_BANK(sc, 2);
        !          1329: }
        !          1330:
        !          1331: void
        !          1332: smc91cxx_statchg(self)
        !          1333:        struct device *self;
        !          1334: {
        !          1335:        struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
        !          1336:        bus_space_tag_t bst = sc->sc_bst;
        !          1337:        bus_space_handle_t bsh = sc->sc_bsh;
        !          1338:        int mctl;
        !          1339:
        !          1340:        SMC_SELECT_BANK(sc, 0);
        !          1341:        mctl = bus_space_read_2(bst, bsh, TXMIT_CONTROL_REG_W);
        !          1342:        if (sc->sc_mii.mii_media_active & IFM_FDX)
        !          1343:                mctl |= TCR_SWFDUP;
        !          1344:        else
        !          1345:                mctl &= ~TCR_SWFDUP;
        !          1346:        bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, mctl);
        !          1347:        SMC_SELECT_BANK(sc, 2); /* back to operating window */
        !          1348: }
        !          1349:
        !          1350: /*
        !          1351:  * One second timer, used to tick the MII.
        !          1352:  */
        !          1353: void
        !          1354: smc91cxx_tick(arg)
        !          1355:        void *arg;
        !          1356: {
        !          1357:        struct smc91cxx_softc *sc = arg;
        !          1358:        int s;
        !          1359:
        !          1360: #ifdef DIAGNOSTIC
        !          1361:        if ((sc->sc_flags & SMC_FLAGS_HAS_MII) == 0)
        !          1362:                panic("smc91cxx_tick");
        !          1363: #endif
        !          1364:
        !          1365:        if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
        !          1366:                return;
        !          1367:
        !          1368:        s = splnet();
        !          1369:        mii_tick(&sc->sc_mii);
        !          1370:        splx(s);
        !          1371:
        !          1372:        timeout_add(&sc->sc_mii_timeout, hz);
        !          1373: }

CVSweb