[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

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