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

Annotation of sys/dev/sbus/be.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: be.c,v 1.19 2006/06/02 20:00:56 miod Exp $    */
        !             2: /*     $NetBSD: be.c,v 1.26 2001/03/20 15:39:20 pk Exp $       */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1999 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Paul Kranenburg.
        !            10:  *
        !            11:  * Redistribution and use in source and binary forms, with or without
        !            12:  * modification, are permitted provided that the following conditions
        !            13:  * are met:
        !            14:  * 1. Redistributions of source code must retain the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer.
        !            16:  * 2. Redistributions in binary form must reproduce the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer in the
        !            18:  *    documentation and/or other materials provided with the distribution.
        !            19:  * 3. All advertising materials mentioning features or use of this software
        !            20:  *    must display the following acknowledgement:
        !            21:  *        This product includes software developed by the NetBSD
        !            22:  *        Foundation, Inc. and its contributors.
        !            23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            24:  *    contributors may be used to endorse or promote products derived
        !            25:  *    from this software without specific prior written permission.
        !            26:  *
        !            27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            37:  * POSSIBILITY OF SUCH DAMAGE.
        !            38:  */
        !            39:
        !            40: /*
        !            41:  * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
        !            42:  * All rights reserved.
        !            43:  *
        !            44:  * Redistribution and use in source and binary forms, with or without
        !            45:  * modification, are permitted provided that the following conditions
        !            46:  * are met:
        !            47:  * 1. Redistributions of source code must retain the above copyright
        !            48:  *    notice, this list of conditions and the following disclaimer.
        !            49:  * 2. Redistributions in binary form must reproduce the above copyright
        !            50:  *    notice, this list of conditions and the following disclaimer in the
        !            51:  *    documentation and/or other materials provided with the distribution.
        !            52:  *
        !            53:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
        !            54:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            55:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            56:  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            57:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            58:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            59:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            60:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            61:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            62:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            63:  */
        !            64:
        !            65: #include "bpfilter.h"
        !            66:
        !            67: #include <sys/param.h>
        !            68: #include <sys/systm.h>
        !            69: #include <sys/timeout.h>
        !            70: #include <sys/kernel.h>
        !            71: #include <sys/errno.h>
        !            72: #include <sys/ioctl.h>
        !            73: #include <sys/mbuf.h>
        !            74: #include <sys/socket.h>
        !            75: #include <sys/syslog.h>
        !            76: #include <sys/device.h>
        !            77: #include <sys/malloc.h>
        !            78:
        !            79: #include <net/if.h>
        !            80: #include <net/if_dl.h>
        !            81: #include <net/if_types.h>
        !            82: #include <net/netisr.h>
        !            83: #include <net/if_media.h>
        !            84:
        !            85: #ifdef INET
        !            86: #include <netinet/in.h>
        !            87: #include <netinet/in_systm.h>
        !            88: #include <netinet/in_var.h>
        !            89: #include <netinet/ip.h>
        !            90: #include <netinet/if_ether.h>
        !            91: #endif
        !            92:
        !            93: #if NBPFILTER > 0
        !            94: #include <net/bpf.h>
        !            95: #endif
        !            96:
        !            97: #include <machine/bus.h>
        !            98: #include <machine/intr.h>
        !            99: #include <machine/autoconf.h>
        !           100:
        !           101: #include <dev/sbus/sbusvar.h>
        !           102:
        !           103: #include <dev/mii/mii.h>
        !           104: #include <dev/mii/miivar.h>
        !           105:
        !           106: #include <dev/sbus/qecreg.h>
        !           107: #include <dev/sbus/qecvar.h>
        !           108: #include <dev/sbus/bereg.h>
        !           109:
        !           110: struct be_softc {
        !           111:        struct  device  sc_dev;
        !           112:        bus_space_tag_t sc_bustag;      /* bus & dma tags */
        !           113:        bus_dma_tag_t   sc_dmatag;
        !           114:        bus_dmamap_t    sc_dmamap;
        !           115:        struct  arpcom sc_arpcom;
        !           116:        /*struct        ifmedia sc_ifmedia;     -* interface media */
        !           117:        struct mii_data sc_mii;         /* MII media control */
        !           118: #define sc_media       sc_mii.mii_media/* shorthand */
        !           119:        int             sc_phys[2];     /* MII instance -> phy */
        !           120:
        !           121:        struct timeout sc_tick_ch;
        !           122:
        !           123:        /*
        !           124:         * Some `mii_softc' items we need to emulate MII operation
        !           125:         * for our internal transceiver.
        !           126:         */
        !           127:        int             sc_mii_inst;    /* instance of internal phy */
        !           128:        int             sc_mii_active;  /* currently active medium */
        !           129:        int             sc_mii_ticks;   /* tick counter */
        !           130:        int             sc_mii_flags;   /* phy status flags */
        !           131: #define MIIF_HAVELINK  0x04000000
        !           132:        int             sc_intphy_curspeed;     /* Established link speed */
        !           133:
        !           134:        struct  qec_softc *sc_qec;      /* QEC parent */
        !           135:
        !           136:        bus_space_handle_t      sc_qr;  /* QEC registers */
        !           137:        bus_space_handle_t      sc_br;  /* BE registers */
        !           138:        bus_space_handle_t      sc_cr;  /* channel registers */
        !           139:        bus_space_handle_t      sc_tr;  /* transceiver registers */
        !           140:
        !           141:        u_int   sc_rev;
        !           142:
        !           143:        int     sc_channel;             /* channel number */
        !           144:        int     sc_burst;
        !           145:
        !           146:        struct  qec_ring        sc_rb;  /* Packet Ring Buffer */
        !           147: };
        !           148:
        !           149: int    bematch(struct device *, void *, void *);
        !           150: void   beattach(struct device *, struct device *, void *);
        !           151:
        !           152: void   beinit(struct be_softc *);
        !           153: void   bestart(struct ifnet *);
        !           154: void   bestop(struct be_softc *);
        !           155: void   bewatchdog(struct ifnet *);
        !           156: int    beioctl(struct ifnet *, u_long, caddr_t);
        !           157: void   bereset(struct be_softc *);
        !           158:
        !           159: int    beintr(void *);
        !           160: int    berint(struct be_softc *);
        !           161: int    betint(struct be_softc *);
        !           162: int    beqint(struct be_softc *, u_int32_t);
        !           163: int    beeint(struct be_softc *, u_int32_t);
        !           164:
        !           165: static void    be_read(struct be_softc *, int, int);
        !           166: static int     be_put(struct be_softc *, int, struct mbuf *);
        !           167: static struct mbuf *be_get(struct be_softc *, int, int);
        !           168:
        !           169: void   be_pal_gate(struct be_softc *, int);
        !           170:
        !           171: /* ifmedia callbacks */
        !           172: void   be_ifmedia_sts(struct ifnet *, struct ifmediareq *);
        !           173: int    be_ifmedia_upd(struct ifnet *);
        !           174:
        !           175: void   be_mcreset(struct be_softc *);
        !           176:
        !           177: /* MII methods & callbacks */
        !           178: static int     be_mii_readreg(struct device *, int, int);
        !           179: static void    be_mii_writereg(struct device *, int, int, int);
        !           180: static void    be_mii_statchg(struct device *);
        !           181:
        !           182: /* MII helpers */
        !           183: static void    be_mii_sync(struct be_softc *);
        !           184: static void    be_mii_sendbits(struct be_softc *, int, u_int32_t, int);
        !           185: static int     be_mii_reset(struct be_softc *, int);
        !           186: static int     be_tcvr_read_bit(struct be_softc *, int);
        !           187: static void    be_tcvr_write_bit(struct be_softc *, int, int);
        !           188:
        !           189: void   be_tick(void *);
        !           190: void   be_intphy_auto(struct be_softc *);
        !           191: void   be_intphy_status(struct be_softc *);
        !           192: int    be_intphy_service(struct be_softc *, struct mii_data *, int);
        !           193:
        !           194:
        !           195: struct cfattach be_ca = {
        !           196:        sizeof(struct be_softc), bematch, beattach
        !           197: };
        !           198:
        !           199: struct cfdriver be_cd = {
        !           200:        NULL, "be", DV_IFNET
        !           201: };
        !           202:
        !           203: int
        !           204: bematch(struct device *parent, void *vcf, void *aux)
        !           205: {
        !           206:        struct cfdata *cf = vcf;
        !           207:        struct sbus_attach_args *sa = aux;
        !           208:
        !           209:        return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
        !           210: }
        !           211:
        !           212: void
        !           213: beattach(struct device *parent, struct device *self, void *aux)
        !           214: {
        !           215:        struct sbus_attach_args *sa = aux;
        !           216:        struct qec_softc *qec = (struct qec_softc *)parent;
        !           217:        struct be_softc *sc = (struct be_softc *)self;
        !           218:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           219:        struct mii_data *mii = &sc->sc_mii;
        !           220:        struct mii_softc *child;
        !           221:        int node = sa->sa_node;
        !           222:        bus_dma_tag_t dmatag = sa->sa_dmatag;
        !           223:        bus_dma_segment_t seg;
        !           224:        bus_size_t size;
        !           225:        int instance;
        !           226:        int rseg, error;
        !           227:        u_int32_t v;
        !           228:        extern void myetheraddr(u_char *);
        !           229:
        !           230:        /* Pass on the bus tags */
        !           231:        sc->sc_bustag = sa->sa_bustag;
        !           232:        sc->sc_dmatag = sa->sa_dmatag;
        !           233:
        !           234:        if (sa->sa_nreg < 3) {
        !           235:                printf("%s: only %d register sets\n",
        !           236:                    self->dv_xname, sa->sa_nreg);
        !           237:                return;
        !           238:        }
        !           239:
        !           240:        if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
        !           241:            (bus_addr_t)sa->sa_reg[0].sbr_offset,
        !           242:            (bus_size_t)sa->sa_reg[0].sbr_size, 0, 0, &sc->sc_cr) != 0) {
        !           243:                printf("beattach: cannot map registers\n");
        !           244:                return;
        !           245:        }
        !           246:
        !           247:        if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[1].sbr_slot,
        !           248:            (bus_addr_t)sa->sa_reg[1].sbr_offset,
        !           249:            (bus_size_t)sa->sa_reg[1].sbr_size, 0, 0, &sc->sc_br) != 0) {
        !           250:                printf("beattach: cannot map registers\n");
        !           251:                return;
        !           252:        }
        !           253:
        !           254:        if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[2].sbr_slot,
        !           255:            (bus_addr_t)sa->sa_reg[2].sbr_offset,
        !           256:            (bus_size_t)sa->sa_reg[2].sbr_size, 0, 0, &sc->sc_tr) != 0) {
        !           257:                printf("beattach: cannot map registers\n");
        !           258:                return;
        !           259:        }
        !           260:
        !           261:        sc->sc_qec = qec;
        !           262:        sc->sc_qr = qec->sc_regs;
        !           263:
        !           264:        sc->sc_rev = getpropint(node, "board-version", -1);
        !           265:        printf(" rev %x", sc->sc_rev);
        !           266:
        !           267:        bestop(sc);
        !           268:
        !           269:        sc->sc_channel = getpropint(node, "channel#", -1);
        !           270:        if (sc->sc_channel == -1)
        !           271:                sc->sc_channel = 0;
        !           272:
        !           273:        sc->sc_burst = getpropint(node, "burst-sizes", -1);
        !           274:        if (sc->sc_burst == -1)
        !           275:                sc->sc_burst = qec->sc_burst;
        !           276:
        !           277:        /* Clamp at parent's burst sizes */
        !           278:        sc->sc_burst &= qec->sc_burst;
        !           279:
        !           280:        /* Establish interrupt handler */
        !           281:        if (sa->sa_nintr == 0 || bus_intr_establish(sa->sa_bustag, sa->sa_pri,
        !           282:            IPL_NET, 0, beintr, sc, self->dv_xname) == NULL) {
        !           283:                printf(": no interrupt established\n");
        !           284:                return;
        !           285:        }
        !           286:
        !           287:        myetheraddr(sc->sc_arpcom.ac_enaddr);
        !           288:        printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
        !           289:
        !           290:        /*
        !           291:         * Allocate descriptor ring and buffers.
        !           292:         */
        !           293:
        !           294:        /* for now, allocate as many bufs as there are ring descriptors */
        !           295:        sc->sc_rb.rb_ntbuf = QEC_XD_RING_MAXSIZE;
        !           296:        sc->sc_rb.rb_nrbuf = QEC_XD_RING_MAXSIZE;
        !           297:
        !           298:        size =  QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
        !           299:                QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
        !           300:                sc->sc_rb.rb_ntbuf * BE_PKT_BUF_SZ +
        !           301:                sc->sc_rb.rb_nrbuf * BE_PKT_BUF_SZ;
        !           302:
        !           303:        /* Get a DMA handle */
        !           304:        if ((error = bus_dmamap_create(dmatag, size, 1, size, 0,
        !           305:            BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
        !           306:                printf("%s: DMA map create error %d\n", self->dv_xname, error);
        !           307:                return;
        !           308:        }
        !           309:
        !           310:        /* Allocate DMA buffer */
        !           311:        if ((error = bus_dmamem_alloc(sa->sa_dmatag, size, 0, 0,
        !           312:            &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
        !           313:                printf("%s: DMA buffer alloc error %d\n",
        !           314:                        self->dv_xname, error);
        !           315:                return;
        !           316:        }
        !           317:
        !           318:        /* Map DMA memory in CPU addressable space */
        !           319:        if ((error = bus_dmamem_map(sa->sa_dmatag, &seg, rseg, size,
        !           320:            &sc->sc_rb.rb_membase, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
        !           321:                printf("%s: DMA buffer map error %d\n",
        !           322:                        self->dv_xname, error);
        !           323:                bus_dmamem_free(sa->sa_dmatag, &seg, rseg);
        !           324:                return;
        !           325:        }
        !           326:
        !           327:        /* Load the buffer */
        !           328:        if ((error = bus_dmamap_load(dmatag, sc->sc_dmamap,
        !           329:            sc->sc_rb.rb_membase, size, NULL, BUS_DMA_NOWAIT)) != 0) {
        !           330:                printf("%s: DMA buffer map load error %d\n",
        !           331:                    self->dv_xname, error);
        !           332:                bus_dmamem_unmap(dmatag, sc->sc_rb.rb_membase, size);
        !           333:                bus_dmamem_free(dmatag, &seg, rseg);
        !           334:                return;
        !           335:        }
        !           336:        sc->sc_rb.rb_dmabase = sc->sc_dmamap->dm_segs[0].ds_addr;
        !           337:
        !           338:        /*
        !           339:         * Initialize our media structures and MII info.
        !           340:         */
        !           341:        mii->mii_ifp = ifp;
        !           342:        mii->mii_readreg = be_mii_readreg;
        !           343:        mii->mii_writereg = be_mii_writereg;
        !           344:        mii->mii_statchg = be_mii_statchg;
        !           345:
        !           346:        ifmedia_init(&mii->mii_media, 0, be_ifmedia_upd, be_ifmedia_sts);
        !           347:
        !           348:        timeout_set(&sc->sc_tick_ch, be_tick, sc);
        !           349:
        !           350:        /*
        !           351:         * Initialize transceiver and determine which PHY connection to use.
        !           352:         */
        !           353:        be_mii_sync(sc);
        !           354:        v = bus_space_read_4(sc->sc_bustag, sc->sc_tr, BE_TRI_MGMTPAL);
        !           355:
        !           356:        instance = 0;
        !           357:
        !           358:        if ((v & MGMT_PAL_EXT_MDIO) != 0) {
        !           359:
        !           360:                mii_attach(&sc->sc_dev, mii, 0xffffffff, BE_PHY_EXTERNAL,
        !           361:                    MII_OFFSET_ANY, 0);
        !           362:
        !           363:                child = LIST_FIRST(&mii->mii_phys);
        !           364:                if (child == NULL) {
        !           365:                        /* No PHY attached */
        !           366:                        ifmedia_add(&sc->sc_media,
        !           367:                            IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance),
        !           368:                            0, NULL);
        !           369:                        ifmedia_set(&sc->sc_media,
        !           370:                            IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance));
        !           371:                } else {
        !           372:                        /*
        !           373:                         * Note: we support just one PHY on the external
        !           374:                         * MII connector.
        !           375:                         */
        !           376: #ifdef DIAGNOSTIC
        !           377:                        if (LIST_NEXT(child, mii_list) != NULL) {
        !           378:                                printf("%s: spurious MII device %s attached\n",
        !           379:                                    sc->sc_dev.dv_xname,
        !           380:                                    child->mii_dev.dv_xname);
        !           381:                        }
        !           382: #endif
        !           383:                        if (child->mii_phy != BE_PHY_EXTERNAL ||
        !           384:                            child->mii_inst > 0) {
        !           385:                                printf("%s: cannot accommodate MII device %s"
        !           386:                                    " at phy %d, instance %d\n",
        !           387:                                    sc->sc_dev.dv_xname,
        !           388:                                    child->mii_dev.dv_xname,
        !           389:                                    child->mii_phy, child->mii_inst);
        !           390:                        } else {
        !           391:                                sc->sc_phys[instance] = child->mii_phy;
        !           392:                        }
        !           393:
        !           394:                        /*
        !           395:                         * XXX - we can really do the following ONLY if the
        !           396:                         * phy indeed has the auto negotiation capability!!
        !           397:                         */
        !           398:                        ifmedia_set(&sc->sc_media,
        !           399:                            IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
        !           400:
        !           401:                        /* Mark our current media setting */
        !           402:                        be_pal_gate(sc, BE_PHY_EXTERNAL);
        !           403:                        instance++;
        !           404:                }
        !           405:
        !           406:        }
        !           407:
        !           408:        if ((v & MGMT_PAL_INT_MDIO) != 0) {
        !           409:                /*
        !           410:                 * The be internal phy looks vaguely like MII hardware,
        !           411:                 * but not enough to be able to use the MII device
        !           412:                 * layer. Hence, we have to take care of media selection
        !           413:                 * ourselves.
        !           414:                 */
        !           415:
        !           416:                sc->sc_mii_inst = instance;
        !           417:                sc->sc_phys[instance] = BE_PHY_INTERNAL;
        !           418:
        !           419:                /* Use `ifm_data' to store BMCR bits */
        !           420:                ifmedia_add(&sc->sc_media,
        !           421:                    IFM_MAKEWORD(IFM_ETHER,IFM_10_T,0,instance), 0, NULL);
        !           422:                ifmedia_add(&sc->sc_media,
        !           423:                    IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,0,instance),
        !           424:                    BMCR_S100, NULL);
        !           425:                ifmedia_add(&sc->sc_media,
        !           426:                    IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance), 0, NULL);
        !           427:
        !           428:                printf("on-board transceiver at %s: 10baseT, 100baseTX, auto\n",
        !           429:                    self->dv_xname);
        !           430:
        !           431:                be_mii_reset(sc, BE_PHY_INTERNAL);
        !           432:                /* Only set default medium here if there's no external PHY */
        !           433:                if (instance == 0) {
        !           434:                        be_pal_gate(sc, BE_PHY_INTERNAL);
        !           435:                        ifmedia_set(&sc->sc_media,
        !           436:                            IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
        !           437:                } else
        !           438:                        be_mii_writereg((void *)sc,
        !           439:                            BE_PHY_INTERNAL, MII_BMCR, BMCR_ISO);
        !           440:        }
        !           441:
        !           442:        bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
        !           443:        ifp->if_softc = sc;
        !           444:        ifp->if_start = bestart;
        !           445:        ifp->if_ioctl = beioctl;
        !           446:        ifp->if_watchdog = bewatchdog;
        !           447:        ifp->if_flags =
        !           448:            IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
        !           449:        IFQ_SET_READY(&ifp->if_snd);
        !           450:
        !           451:        /* Attach the interface. */
        !           452:        if_attach(ifp);
        !           453:        ether_ifattach(ifp);
        !           454: }
        !           455:
        !           456:
        !           457: /*
        !           458:  * Routine to copy from mbuf chain to transmit buffer in
        !           459:  * network buffer memory.
        !           460:  */
        !           461: static __inline__ int
        !           462: be_put(struct be_softc *sc, int idx, struct mbuf *m)
        !           463: {
        !           464:        struct mbuf *n;
        !           465:        int len, tlen = 0, boff = 0;
        !           466:        caddr_t bp;
        !           467:
        !           468:        bp = sc->sc_rb.rb_txbuf + (idx % sc->sc_rb.rb_ntbuf) * BE_PKT_BUF_SZ;
        !           469:
        !           470:        for (; m; m = n) {
        !           471:                len = m->m_len;
        !           472:                if (len == 0) {
        !           473:                        MFREE(m, n);
        !           474:                        continue;
        !           475:                }
        !           476:                bcopy(mtod(m, caddr_t), bp+boff, len);
        !           477:                boff += len;
        !           478:                tlen += len;
        !           479:                MFREE(m, n);
        !           480:        }
        !           481:        return (tlen);
        !           482: }
        !           483:
        !           484: /*
        !           485:  * Pull data off an interface.
        !           486:  * Len is the length of data, with local net header stripped.
        !           487:  * We copy the data into mbufs.  When full cluster sized units are present,
        !           488:  * we copy into clusters.
        !           489:  */
        !           490: static __inline__ struct mbuf *
        !           491: be_get(struct be_softc *sc, int idx, int totlen)
        !           492: {
        !           493:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           494:        struct mbuf *m;
        !           495:        struct mbuf *top, **mp;
        !           496:        int len, pad, boff = 0;
        !           497:        caddr_t bp;
        !           498:
        !           499:        bp = sc->sc_rb.rb_rxbuf + (idx % sc->sc_rb.rb_nrbuf) * BE_PKT_BUF_SZ;
        !           500:
        !           501:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           502:        if (m == NULL)
        !           503:                return (NULL);
        !           504:        m->m_pkthdr.rcvif = ifp;
        !           505:        m->m_pkthdr.len = totlen;
        !           506:
        !           507:        pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
        !           508:        m->m_data += pad;
        !           509:        len = MHLEN - pad;
        !           510:        top = NULL;
        !           511:        mp = &top;
        !           512:
        !           513:        while (totlen > 0) {
        !           514:                if (top) {
        !           515:                        MGET(m, M_DONTWAIT, MT_DATA);
        !           516:                        if (m == NULL) {
        !           517:                                m_freem(top);
        !           518:                                return (NULL);
        !           519:                        }
        !           520:                        len = MLEN;
        !           521:                }
        !           522:                if (top && totlen >= MINCLSIZE) {
        !           523:                        MCLGET(m, M_DONTWAIT);
        !           524:                        if (m->m_flags & M_EXT)
        !           525:                                len = MCLBYTES;
        !           526:                }
        !           527:                m->m_len = len = min(totlen, len);
        !           528:                bcopy(bp + boff, mtod(m, caddr_t), len);
        !           529:                boff += len;
        !           530:                totlen -= len;
        !           531:                *mp = m;
        !           532:                mp = &m->m_next;
        !           533:        }
        !           534:
        !           535:        return (top);
        !           536: }
        !           537:
        !           538: /*
        !           539:  * Pass a packet to the higher levels.
        !           540:  */
        !           541: static __inline__ void
        !           542: be_read(struct be_softc *sc, int idx, int len)
        !           543: {
        !           544:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           545:        struct mbuf *m;
        !           546:
        !           547:        if (len <= sizeof(struct ether_header) ||
        !           548:            len > ETHERMTU + sizeof(struct ether_header)) {
        !           549:
        !           550:                printf("%s: invalid packet size %d; dropping\n",
        !           551:                    ifp->if_xname, len);
        !           552:
        !           553:                ifp->if_ierrors++;
        !           554:                return;
        !           555:        }
        !           556:
        !           557:        /*
        !           558:         * Pull packet off interface.
        !           559:         */
        !           560:        m = be_get(sc, idx, len);
        !           561:        if (m == NULL) {
        !           562:                ifp->if_ierrors++;
        !           563:                return;
        !           564:        }
        !           565:        ifp->if_ipackets++;
        !           566:
        !           567: #if NBPFILTER > 0
        !           568:        /*
        !           569:         * Check if there's a BPF listener on this interface.
        !           570:         * If so, hand off the raw packet to BPF.
        !           571:         */
        !           572:        if (ifp->if_bpf)
        !           573:                bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
        !           574: #endif
        !           575:        /* Pass the packet up. */
        !           576:        ether_input_mbuf(ifp, m);
        !           577: }
        !           578:
        !           579: /*
        !           580:  * Start output on interface.
        !           581:  * We make two assumptions here:
        !           582:  *  1) that the current priority is set to splnet _before_ this code
        !           583:  *     is called *and* is returned to the appropriate priority after
        !           584:  *     return
        !           585:  *  2) that the IFF_OACTIVE flag is checked before this code is called
        !           586:  *     (i.e. that the output part of the interface is idle)
        !           587:  */
        !           588: void
        !           589: bestart(struct ifnet *ifp)
        !           590: {
        !           591:        struct be_softc *sc = (struct be_softc *)ifp->if_softc;
        !           592:        struct qec_xd *txd = sc->sc_rb.rb_txd;
        !           593:        struct mbuf *m;
        !           594:        unsigned int bix, len;
        !           595:        unsigned int ntbuf = sc->sc_rb.rb_ntbuf;
        !           596:
        !           597:        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
        !           598:                return;
        !           599:
        !           600:        bix = sc->sc_rb.rb_tdhead;
        !           601:
        !           602:        for (;;) {
        !           603:                IFQ_DEQUEUE(&ifp->if_snd, m);
        !           604:                if (m == 0)
        !           605:                        break;
        !           606:
        !           607: #if NBPFILTER > 0
        !           608:                /*
        !           609:                 * If BPF is listening on this interface, let it see the
        !           610:                 * packet before we commit it to the wire.
        !           611:                 */
        !           612:                if (ifp->if_bpf)
        !           613:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
        !           614: #endif
        !           615:
        !           616:                /*
        !           617:                 * Copy the mbuf chain into the transmit buffer.
        !           618:                 */
        !           619:                len = be_put(sc, bix, m);
        !           620:
        !           621:                /*
        !           622:                 * Initialize transmit registers and start transmission
        !           623:                 */
        !           624:                txd[bix].xd_flags = QEC_XD_OWN | QEC_XD_SOP | QEC_XD_EOP |
        !           625:                                    (len & QEC_XD_LENGTH);
        !           626:                bus_space_write_4(sc->sc_bustag, sc->sc_cr, BE_CRI_CTRL,
        !           627:                                  BE_CR_CTRL_TWAKEUP);
        !           628:
        !           629:                if (++bix == QEC_XD_RING_MAXSIZE)
        !           630:                        bix = 0;
        !           631:
        !           632:                if (++sc->sc_rb.rb_td_nbusy == ntbuf) {
        !           633:                        ifp->if_flags |= IFF_OACTIVE;
        !           634:                        break;
        !           635:                }
        !           636:        }
        !           637:
        !           638:        sc->sc_rb.rb_tdhead = bix;
        !           639: }
        !           640:
        !           641: void
        !           642: bestop(struct be_softc *sc)
        !           643: {
        !           644:        int n;
        !           645:        bus_space_tag_t t = sc->sc_bustag;
        !           646:        bus_space_handle_t br = sc->sc_br;
        !           647:
        !           648:        timeout_del(&sc->sc_tick_ch);
        !           649:
        !           650:        /* Down the MII. */
        !           651:        mii_down(&sc->sc_mii);
        !           652:        (void)be_intphy_service(sc, &sc->sc_mii, MII_DOWN);
        !           653:
        !           654:        /* Stop the transmitter */
        !           655:        bus_space_write_4(t, br, BE_BRI_TXCFG, 0);
        !           656:        for (n = 32; n > 0; n--) {
        !           657:                if (bus_space_read_4(t, br, BE_BRI_TXCFG) == 0)
        !           658:                        break;
        !           659:                DELAY(20);
        !           660:        }
        !           661:
        !           662:        /* Stop the receiver */
        !           663:        bus_space_write_4(t, br, BE_BRI_RXCFG, 0);
        !           664:        for (n = 32; n > 0; n--) {
        !           665:                if (bus_space_read_4(t, br, BE_BRI_RXCFG) == 0)
        !           666:                        break;
        !           667:                DELAY(20);
        !           668:        }
        !           669: }
        !           670:
        !           671: /*
        !           672:  * Reset interface.
        !           673:  */
        !           674: void
        !           675: bereset(struct be_softc *sc)
        !           676: {
        !           677:        int s;
        !           678:
        !           679:        s = splnet();
        !           680:        bestop(sc);
        !           681:        if ((sc->sc_arpcom.ac_if.if_flags & IFF_UP) != 0)
        !           682:                beinit(sc);
        !           683:        splx(s);
        !           684: }
        !           685:
        !           686: void
        !           687: bewatchdog(struct ifnet *ifp)
        !           688: {
        !           689:        struct be_softc *sc = ifp->if_softc;
        !           690:
        !           691:        log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
        !           692:        ++sc->sc_arpcom.ac_if.if_oerrors;
        !           693:        bereset(sc);
        !           694: }
        !           695:
        !           696: int
        !           697: beintr(void *v)
        !           698: {
        !           699:        struct be_softc *sc = (struct be_softc *)v;
        !           700:        bus_space_tag_t t = sc->sc_bustag;
        !           701:        u_int32_t whyq, whyb, whyc;
        !           702:        int r = 0;
        !           703:
        !           704:        /* Read QEC status, channel status and BE status */
        !           705:        whyq = bus_space_read_4(t, sc->sc_qr, QEC_QRI_STAT);
        !           706:        whyc = bus_space_read_4(t, sc->sc_cr, BE_CRI_STAT);
        !           707:        whyb = bus_space_read_4(t, sc->sc_br, BE_BRI_STAT);
        !           708:
        !           709:        if (whyq & QEC_STAT_BM)
        !           710:                r |= beeint(sc, whyb);
        !           711:
        !           712:        if (whyq & QEC_STAT_ER)
        !           713:                r |= beqint(sc, whyc);
        !           714:
        !           715:        if (whyq & QEC_STAT_TX && whyc & BE_CR_STAT_TXIRQ)
        !           716:                r |= betint(sc);
        !           717:
        !           718:        if (whyq & QEC_STAT_RX && whyc & BE_CR_STAT_RXIRQ)
        !           719:                r |= berint(sc);
        !           720:
        !           721:        return (r);
        !           722: }
        !           723:
        !           724: /*
        !           725:  * QEC Interrupt.
        !           726:  */
        !           727: int
        !           728: beqint(struct be_softc *sc, u_int32_t why)
        !           729: {
        !           730:        int r = 0, rst = 0;
        !           731:
        !           732:        if (why & BE_CR_STAT_TXIRQ)
        !           733:                r |= 1;
        !           734:        if (why & BE_CR_STAT_RXIRQ)
        !           735:                r |= 1;
        !           736:
        !           737:        if (why & BE_CR_STAT_BERROR) {
        !           738:                r |= 1;
        !           739:                rst = 1;
        !           740:                printf("%s: bigmac error\n", sc->sc_dev.dv_xname);
        !           741:        }
        !           742:
        !           743:        if (why & BE_CR_STAT_TXDERR) {
        !           744:                r |= 1;
        !           745:                rst = 1;
        !           746:                printf("%s: bogus tx descriptor\n", sc->sc_dev.dv_xname);
        !           747:        }
        !           748:
        !           749:        if (why & (BE_CR_STAT_TXLERR | BE_CR_STAT_TXPERR | BE_CR_STAT_TXSERR)) {
        !           750:                r |= 1;
        !           751:                rst = 1;
        !           752:                printf("%s: tx dma error ( ", sc->sc_dev.dv_xname);
        !           753:                if (why & BE_CR_STAT_TXLERR)
        !           754:                        printf("Late ");
        !           755:                if (why & BE_CR_STAT_TXPERR)
        !           756:                        printf("Parity ");
        !           757:                if (why & BE_CR_STAT_TXSERR)
        !           758:                        printf("Generic ");
        !           759:                printf(")\n");
        !           760:        }
        !           761:
        !           762:        if (why & BE_CR_STAT_RXDROP) {
        !           763:                r |= 1;
        !           764:                rst = 1;
        !           765:                printf("%s: out of rx descriptors\n", sc->sc_dev.dv_xname);
        !           766:        }
        !           767:
        !           768:        if (why & BE_CR_STAT_RXSMALL) {
        !           769:                r |= 1;
        !           770:                rst = 1;
        !           771:                printf("%s: rx descriptor too small\n", sc->sc_dev.dv_xname);
        !           772:        }
        !           773:
        !           774:        if (why & (BE_CR_STAT_RXLERR | BE_CR_STAT_RXPERR | BE_CR_STAT_RXSERR)) {
        !           775:                r |= 1;
        !           776:                rst = 1;
        !           777:                printf("%s: rx dma error ( ", sc->sc_dev.dv_xname);
        !           778:                if (why & BE_CR_STAT_RXLERR)
        !           779:                        printf("Late ");
        !           780:                if (why & BE_CR_STAT_RXPERR)
        !           781:                        printf("Parity ");
        !           782:                if (why & BE_CR_STAT_RXSERR)
        !           783:                        printf("Generic ");
        !           784:                printf(")\n");
        !           785:        }
        !           786:
        !           787:        if (!r) {
        !           788:                rst = 1;
        !           789:                printf("%s: unexpected error interrupt %08x\n",
        !           790:                        sc->sc_dev.dv_xname, why);
        !           791:        }
        !           792:
        !           793:        if (rst) {
        !           794:                printf("%s: resetting\n", sc->sc_dev.dv_xname);
        !           795:                bereset(sc);
        !           796:        }
        !           797:
        !           798:        return (r);
        !           799: }
        !           800:
        !           801: /*
        !           802:  * Error interrupt.
        !           803:  */
        !           804: int
        !           805: beeint(struct be_softc *sc, u_int32_t why)
        !           806: {
        !           807:        int r = 0, rst = 0;
        !           808:
        !           809:        if (why & BE_BR_STAT_RFIFOVF) {
        !           810:                r |= 1;
        !           811:                rst = 1;
        !           812:                printf("%s: receive fifo overrun\n", sc->sc_dev.dv_xname);
        !           813:        }
        !           814:        if (why & BE_BR_STAT_TFIFO_UND) {
        !           815:                r |= 1;
        !           816:                rst = 1;
        !           817:                printf("%s: transmit fifo underrun\n", sc->sc_dev.dv_xname);
        !           818:        }
        !           819:        if (why & BE_BR_STAT_MAXPKTERR) {
        !           820:                r |= 1;
        !           821:                rst = 1;
        !           822:                printf("%s: max packet size error\n", sc->sc_dev.dv_xname);
        !           823:        }
        !           824:
        !           825:        if (!r) {
        !           826:                rst = 1;
        !           827:                printf("%s: unexpected error interrupt %08x\n",
        !           828:                        sc->sc_dev.dv_xname, why);
        !           829:        }
        !           830:
        !           831:        if (rst) {
        !           832:                printf("%s: resetting\n", sc->sc_dev.dv_xname);
        !           833:                bereset(sc);
        !           834:        }
        !           835:
        !           836:        return (r);
        !           837: }
        !           838:
        !           839: /*
        !           840:  * Transmit interrupt.
        !           841:  */
        !           842: int
        !           843: betint(struct be_softc *sc)
        !           844: {
        !           845:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           846:        bus_space_tag_t t = sc->sc_bustag;
        !           847:        bus_space_handle_t br = sc->sc_br;
        !           848:        unsigned int bix, txflags;
        !           849:
        !           850:        /*
        !           851:         * Unload collision counters
        !           852:         */
        !           853:        ifp->if_collisions +=
        !           854:                bus_space_read_4(t, br, BE_BRI_NCCNT) +
        !           855:                bus_space_read_4(t, br, BE_BRI_FCCNT) +
        !           856:                bus_space_read_4(t, br, BE_BRI_EXCNT) +
        !           857:                bus_space_read_4(t, br, BE_BRI_LTCNT);
        !           858:
        !           859:        /*
        !           860:         * the clear the hardware counters
        !           861:         */
        !           862:        bus_space_write_4(t, br, BE_BRI_NCCNT, 0);
        !           863:        bus_space_write_4(t, br, BE_BRI_FCCNT, 0);
        !           864:        bus_space_write_4(t, br, BE_BRI_EXCNT, 0);
        !           865:        bus_space_write_4(t, br, BE_BRI_LTCNT, 0);
        !           866:
        !           867:        bix = sc->sc_rb.rb_tdtail;
        !           868:
        !           869:        for (;;) {
        !           870:                if (sc->sc_rb.rb_td_nbusy <= 0)
        !           871:                        break;
        !           872:
        !           873:                txflags = sc->sc_rb.rb_txd[bix].xd_flags;
        !           874:
        !           875:                if (txflags & QEC_XD_OWN)
        !           876:                        break;
        !           877:
        !           878:                ifp->if_flags &= ~IFF_OACTIVE;
        !           879:                ifp->if_opackets++;
        !           880:
        !           881:                if (++bix == QEC_XD_RING_MAXSIZE)
        !           882:                        bix = 0;
        !           883:
        !           884:                --sc->sc_rb.rb_td_nbusy;
        !           885:        }
        !           886:
        !           887:        sc->sc_rb.rb_tdtail = bix;
        !           888:
        !           889:        bestart(ifp);
        !           890:
        !           891:        if (sc->sc_rb.rb_td_nbusy == 0)
        !           892:                ifp->if_timer = 0;
        !           893:
        !           894:        return (1);
        !           895: }
        !           896:
        !           897: /*
        !           898:  * Receive interrupt.
        !           899:  */
        !           900: int
        !           901: berint(struct be_softc *sc)
        !           902: {
        !           903:        struct qec_xd *xd = sc->sc_rb.rb_rxd;
        !           904:        unsigned int bix, len;
        !           905:        unsigned int nrbuf = sc->sc_rb.rb_nrbuf;
        !           906:
        !           907:        bix = sc->sc_rb.rb_rdtail;
        !           908:
        !           909:        /*
        !           910:         * Process all buffers with valid data.
        !           911:         */
        !           912:        for (;;) {
        !           913:                len = xd[bix].xd_flags;
        !           914:                if (len & QEC_XD_OWN)
        !           915:                        break;
        !           916:
        !           917:                len &= QEC_XD_LENGTH;
        !           918:                be_read(sc, bix, len);
        !           919:
        !           920:                /* ... */
        !           921:                xd[(bix+nrbuf) % QEC_XD_RING_MAXSIZE].xd_flags =
        !           922:                        QEC_XD_OWN | (BE_PKT_BUF_SZ & QEC_XD_LENGTH);
        !           923:
        !           924:                if (++bix == QEC_XD_RING_MAXSIZE)
        !           925:                        bix = 0;
        !           926:        }
        !           927:
        !           928:        sc->sc_rb.rb_rdtail = bix;
        !           929:
        !           930:        return (1);
        !           931: }
        !           932:
        !           933: int
        !           934: beioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        !           935: {
        !           936:        struct be_softc *sc = ifp->if_softc;
        !           937:        struct ifaddr *ifa = (struct ifaddr *)data;
        !           938:        struct ifreq *ifr = (struct ifreq *)data;
        !           939:        int s, error = 0;
        !           940:
        !           941:        s = splnet();
        !           942:
        !           943:        if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
        !           944:                splx(s);
        !           945:                return (error);
        !           946:        }
        !           947:
        !           948:        switch (cmd) {
        !           949:        case SIOCSIFADDR:
        !           950:                ifp->if_flags |= IFF_UP;
        !           951:                switch (ifa->ifa_addr->sa_family) {
        !           952: #ifdef INET
        !           953:                case AF_INET:
        !           954:                        beinit(sc);
        !           955:                        arp_ifinit(&sc->sc_arpcom, ifa);
        !           956:                        break;
        !           957: #endif /* INET */
        !           958:                default:
        !           959:                        beinit(sc);
        !           960:                        break;
        !           961:                }
        !           962:                break;
        !           963:
        !           964:        case SIOCSIFFLAGS:
        !           965:                if ((ifp->if_flags & IFF_UP) == 0 &&
        !           966:                    (ifp->if_flags & IFF_RUNNING) != 0) {
        !           967:                        /*
        !           968:                         * If interface is marked down and it is running, then
        !           969:                         * stop it.
        !           970:                         */
        !           971:                        bestop(sc);
        !           972:                        ifp->if_flags &= ~IFF_RUNNING;
        !           973:                } else if ((ifp->if_flags & IFF_UP) != 0 &&
        !           974:                    (ifp->if_flags & IFF_RUNNING) == 0) {
        !           975:                        /*
        !           976:                         * If interface is marked up and it is stopped, then
        !           977:                         * start it.
        !           978:                         */
        !           979:                        beinit(sc);
        !           980:                } else {
        !           981:                        /*
        !           982:                         * Reset the interface to pick up changes in any other
        !           983:                         * flags that affect hardware registers.
        !           984:                         */
        !           985:                        bestop(sc);
        !           986:                        beinit(sc);
        !           987:                }
        !           988: #ifdef BEDEBUG
        !           989:                if (ifp->if_flags & IFF_DEBUG)
        !           990:                        sc->sc_debug = 1;
        !           991:                else
        !           992:                        sc->sc_debug = 0;
        !           993: #endif
        !           994:                break;
        !           995:
        !           996:        case SIOCADDMULTI:
        !           997:        case SIOCDELMULTI:
        !           998:                error = (cmd == SIOCADDMULTI) ?
        !           999:                    ether_addmulti(ifr, &sc->sc_arpcom):
        !          1000:                    ether_delmulti(ifr, &sc->sc_arpcom);
        !          1001:
        !          1002:                if (error == ENETRESET) {
        !          1003:                        /*
        !          1004:                         * Multicast list has changed; set the hardware filter
        !          1005:                         * accordingly.
        !          1006:                         */
        !          1007:                        if (ifp->if_flags & IFF_RUNNING)
        !          1008:                                be_mcreset(sc);
        !          1009:                        error = 0;
        !          1010:                }
        !          1011:                break;
        !          1012:        case SIOCGIFMEDIA:
        !          1013:        case SIOCSIFMEDIA:
        !          1014:                error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
        !          1015:                break;
        !          1016:        default:
        !          1017:                error = EINVAL;
        !          1018:                break;
        !          1019:        }
        !          1020:        splx(s);
        !          1021:        return (error);
        !          1022: }
        !          1023:
        !          1024:
        !          1025: void
        !          1026: beinit(struct be_softc *sc)
        !          1027: {
        !          1028:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !          1029:        bus_space_tag_t t = sc->sc_bustag;
        !          1030:        bus_space_handle_t br = sc->sc_br;
        !          1031:        bus_space_handle_t cr = sc->sc_cr;
        !          1032:        struct qec_softc *qec = sc->sc_qec;
        !          1033:        u_int32_t v;
        !          1034:        u_int32_t qecaddr;
        !          1035:        u_int8_t *ea;
        !          1036:        int s;
        !          1037:
        !          1038:        s = splnet();
        !          1039:
        !          1040:        qec_meminit(&sc->sc_rb, BE_PKT_BUF_SZ);
        !          1041:
        !          1042:        bestop(sc);
        !          1043:
        !          1044:        ea = sc->sc_arpcom.ac_enaddr;
        !          1045:        bus_space_write_4(t, br, BE_BRI_MACADDR0, (ea[0] << 8) | ea[1]);
        !          1046:        bus_space_write_4(t, br, BE_BRI_MACADDR1, (ea[2] << 8) | ea[3]);
        !          1047:        bus_space_write_4(t, br, BE_BRI_MACADDR2, (ea[4] << 8) | ea[5]);
        !          1048:
        !          1049:        /* Clear hash table */
        !          1050:        bus_space_write_4(t, br, BE_BRI_HASHTAB0, 0);
        !          1051:        bus_space_write_4(t, br, BE_BRI_HASHTAB1, 0);
        !          1052:        bus_space_write_4(t, br, BE_BRI_HASHTAB2, 0);
        !          1053:        bus_space_write_4(t, br, BE_BRI_HASHTAB3, 0);
        !          1054:
        !          1055:        /* Re-initialize RX configuration */
        !          1056:        v = BE_BR_RXCFG_FIFO;
        !          1057:        bus_space_write_4(t, br, BE_BRI_RXCFG, v);
        !          1058:
        !          1059:        be_mcreset(sc);
        !          1060:
        !          1061:        bus_space_write_4(t, br, BE_BRI_RANDSEED, 0xbd);
        !          1062:
        !          1063:        bus_space_write_4(t, br, BE_BRI_XIFCFG,
        !          1064:                          BE_BR_XCFG_ODENABLE | BE_BR_XCFG_RESV);
        !          1065:
        !          1066:        bus_space_write_4(t, br, BE_BRI_JSIZE, 4);
        !          1067:
        !          1068:        /*
        !          1069:         * Turn off counter expiration interrupts as well as
        !          1070:         * 'gotframe' and 'sentframe'
        !          1071:         */
        !          1072:        bus_space_write_4(t, br, BE_BRI_IMASK,
        !          1073:                          BE_BR_IMASK_GOTFRAME  |
        !          1074:                          BE_BR_IMASK_RCNTEXP   |
        !          1075:                          BE_BR_IMASK_ACNTEXP   |
        !          1076:                          BE_BR_IMASK_CCNTEXP   |
        !          1077:                          BE_BR_IMASK_LCNTEXP   |
        !          1078:                          BE_BR_IMASK_CVCNTEXP  |
        !          1079:                          BE_BR_IMASK_SENTFRAME |
        !          1080:                          BE_BR_IMASK_NCNTEXP   |
        !          1081:                          BE_BR_IMASK_ECNTEXP   |
        !          1082:                          BE_BR_IMASK_LCCNTEXP  |
        !          1083:                          BE_BR_IMASK_FCNTEXP   |
        !          1084:                          BE_BR_IMASK_DTIMEXP);
        !          1085:
        !          1086:        /* Channel registers: */
        !          1087:        bus_space_write_4(t, cr, BE_CRI_RXDS, (u_int32_t)sc->sc_rb.rb_rxddma);
        !          1088:        bus_space_write_4(t, cr, BE_CRI_TXDS, (u_int32_t)sc->sc_rb.rb_txddma);
        !          1089:
        !          1090:        qecaddr = sc->sc_channel * qec->sc_msize;
        !          1091:        bus_space_write_4(t, cr, BE_CRI_RXWBUF, qecaddr);
        !          1092:        bus_space_write_4(t, cr, BE_CRI_RXRBUF, qecaddr);
        !          1093:        bus_space_write_4(t, cr, BE_CRI_TXWBUF, qecaddr + qec->sc_rsize);
        !          1094:        bus_space_write_4(t, cr, BE_CRI_TXRBUF, qecaddr + qec->sc_rsize);
        !          1095:
        !          1096:        bus_space_write_4(t, cr, BE_CRI_RIMASK, 0);
        !          1097:        bus_space_write_4(t, cr, BE_CRI_TIMASK, 0);
        !          1098:        bus_space_write_4(t, cr, BE_CRI_QMASK, 0);
        !          1099:        bus_space_write_4(t, cr, BE_CRI_BMASK, 0);
        !          1100:        bus_space_write_4(t, cr, BE_CRI_CCNT, 0);
        !          1101:
        !          1102:        /* Enable transmitter */
        !          1103:        bus_space_write_4(t, br, BE_BRI_TXCFG,
        !          1104:                          BE_BR_TXCFG_FIFO | BE_BR_TXCFG_ENABLE);
        !          1105:
        !          1106:        /* Enable receiver */
        !          1107:        v = bus_space_read_4(t, br, BE_BRI_RXCFG);
        !          1108:        v |= BE_BR_RXCFG_FIFO | BE_BR_RXCFG_ENABLE;
        !          1109:        bus_space_write_4(t, br, BE_BRI_RXCFG, v);
        !          1110:
        !          1111:        ifp->if_flags |= IFF_RUNNING;
        !          1112:        ifp->if_flags &= ~IFF_OACTIVE;
        !          1113:
        !          1114:        be_ifmedia_upd(ifp);
        !          1115:        timeout_add(&sc->sc_tick_ch, hz);
        !          1116:        splx(s);
        !          1117: }
        !          1118:
        !          1119: void
        !          1120: be_mcreset(struct be_softc *sc)
        !          1121: {
        !          1122:        struct arpcom *ac = &sc->sc_arpcom;
        !          1123:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !          1124:        bus_space_tag_t t = sc->sc_bustag;
        !          1125:        bus_space_handle_t br = sc->sc_br;
        !          1126:        u_int32_t crc;
        !          1127:        u_int16_t hash[4];
        !          1128:        u_int8_t octet;
        !          1129:        u_int32_t v;
        !          1130:        int i, j;
        !          1131:        struct ether_multi *enm;
        !          1132:        struct ether_multistep step;
        !          1133:
        !          1134:        if (ifp->if_flags & IFF_PROMISC) {
        !          1135:                v = bus_space_read_4(t, br, BE_BRI_RXCFG);
        !          1136:                v |= BE_BR_RXCFG_PMISC;
        !          1137:                bus_space_write_4(t, br, BE_BRI_RXCFG, v);
        !          1138:                return;
        !          1139:        }
        !          1140:
        !          1141:        if (ifp->if_flags & IFF_ALLMULTI) {
        !          1142:                hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
        !          1143:                goto chipit;
        !          1144:        }
        !          1145:
        !          1146:        hash[3] = hash[2] = hash[1] = hash[0] = 0;
        !          1147:
        !          1148:        ETHER_FIRST_MULTI(step, ac, enm);
        !          1149:        while (enm != NULL) {
        !          1150:                if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
        !          1151:                        /*
        !          1152:                         * We must listen to a range of multicast
        !          1153:                         * addresses.  For now, just accept all
        !          1154:                         * multicasts, rather than trying to set only
        !          1155:                         * those filter bits needed to match the range.
        !          1156:                         * (At this time, the only use of address
        !          1157:                         * ranges is for IP multicast routing, for
        !          1158:                         * which the range is big enough to require
        !          1159:                         * all bits set.)
        !          1160:                         */
        !          1161:                        hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
        !          1162:                        ifp->if_flags |= IFF_ALLMULTI;
        !          1163:                        goto chipit;
        !          1164:                }
        !          1165:
        !          1166:                crc = 0xffffffff;
        !          1167:
        !          1168:                for (i = 0; i < ETHER_ADDR_LEN; i++) {
        !          1169:                        octet = enm->enm_addrlo[i];
        !          1170:
        !          1171:                        for (j = 0; j < 8; j++) {
        !          1172:                                if ((crc & 1) ^ (octet & 1)) {
        !          1173:                                        crc >>= 1;
        !          1174:                                        crc ^= MC_POLY_LE;
        !          1175:                                }
        !          1176:                                else
        !          1177:                                        crc >>= 1;
        !          1178:                                octet >>= 1;
        !          1179:                        }
        !          1180:                }
        !          1181:
        !          1182:                crc >>= 26;
        !          1183:                hash[crc >> 4] |= 1 << (crc & 0xf);
        !          1184:                ETHER_NEXT_MULTI(step, enm);
        !          1185:        }
        !          1186:
        !          1187:        ifp->if_flags &= ~IFF_ALLMULTI;
        !          1188:
        !          1189: chipit:
        !          1190:        /* Enable the hash filter */
        !          1191:        bus_space_write_4(t, br, BE_BRI_HASHTAB0, hash[0]);
        !          1192:        bus_space_write_4(t, br, BE_BRI_HASHTAB1, hash[1]);
        !          1193:        bus_space_write_4(t, br, BE_BRI_HASHTAB2, hash[2]);
        !          1194:        bus_space_write_4(t, br, BE_BRI_HASHTAB3, hash[3]);
        !          1195:
        !          1196:        v = bus_space_read_4(t, br, BE_BRI_RXCFG);
        !          1197:        v &= ~BE_BR_RXCFG_PMISC;
        !          1198:        v |= BE_BR_RXCFG_HENABLE;
        !          1199:        bus_space_write_4(t, br, BE_BRI_RXCFG, v);
        !          1200: }
        !          1201:
        !          1202: /*
        !          1203:  * Set the tcvr to an idle state
        !          1204:  */
        !          1205: void
        !          1206: be_mii_sync(struct be_softc *sc)
        !          1207: {
        !          1208:        bus_space_tag_t t = sc->sc_bustag;
        !          1209:        bus_space_handle_t tr = sc->sc_tr;
        !          1210:        int n = 32;
        !          1211:
        !          1212:        while (n--) {
        !          1213:                bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
        !          1214:                    MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO | MGMT_PAL_OENAB);
        !          1215:                (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1216:                bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
        !          1217:                    MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO |
        !          1218:                    MGMT_PAL_OENAB | MGMT_PAL_DCLOCK);
        !          1219:                (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1220:        }
        !          1221: }
        !          1222:
        !          1223: void
        !          1224: be_pal_gate(struct be_softc *sc, int phy)
        !          1225: {
        !          1226:        bus_space_tag_t t = sc->sc_bustag;
        !          1227:        bus_space_handle_t tr = sc->sc_tr;
        !          1228:        u_int32_t v;
        !          1229:
        !          1230:        be_mii_sync(sc);
        !          1231:
        !          1232:        v = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE);
        !          1233:        if (phy == BE_PHY_INTERNAL)
        !          1234:                v &= ~TCVR_PAL_SERIAL;
        !          1235:
        !          1236:        bus_space_write_4(t, tr, BE_TRI_TCVRPAL, v);
        !          1237:        (void)bus_space_read_4(t, tr, BE_TRI_TCVRPAL);
        !          1238: }
        !          1239:
        !          1240: static int
        !          1241: be_tcvr_read_bit(struct be_softc *sc, int phy)
        !          1242: {
        !          1243:        bus_space_tag_t t = sc->sc_bustag;
        !          1244:        bus_space_handle_t tr = sc->sc_tr;
        !          1245:        int ret;
        !          1246:
        !          1247:        if (phy == BE_PHY_INTERNAL) {
        !          1248:                bus_space_write_4(t, tr, BE_TRI_MGMTPAL, MGMT_PAL_EXT_MDIO);
        !          1249:                (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1250:                bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
        !          1251:                    MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK);
        !          1252:                (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1253:                ret = (bus_space_read_4(t, tr, BE_TRI_MGMTPAL) &
        !          1254:                        MGMT_PAL_INT_MDIO) >> MGMT_PAL_INT_MDIO_SHIFT;
        !          1255:        } else {
        !          1256:                bus_space_write_4(t, tr, BE_TRI_MGMTPAL, MGMT_PAL_INT_MDIO);
        !          1257:                (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1258:                ret = (bus_space_read_4(t, tr, BE_TRI_MGMTPAL) &
        !          1259:                    MGMT_PAL_EXT_MDIO) >> MGMT_PAL_EXT_MDIO_SHIFT;
        !          1260:                bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
        !          1261:                    MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK);
        !          1262:                (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1263:        }
        !          1264:
        !          1265:        return (ret);
        !          1266: }
        !          1267:
        !          1268: static void
        !          1269: be_tcvr_write_bit(struct be_softc *sc, int phy, int bit)
        !          1270: {
        !          1271:        bus_space_tag_t t = sc->sc_bustag;
        !          1272:        bus_space_handle_t tr = sc->sc_tr;
        !          1273:        u_int32_t v;
        !          1274:
        !          1275:        if (phy == BE_PHY_INTERNAL) {
        !          1276:                v = ((bit & 1) << MGMT_PAL_INT_MDIO_SHIFT) |
        !          1277:                    MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO;
        !          1278:        } else {
        !          1279:                v = ((bit & 1) << MGMT_PAL_EXT_MDIO_SHIFT)
        !          1280:                    | MGMT_PAL_OENAB | MGMT_PAL_INT_MDIO;
        !          1281:        }
        !          1282:        bus_space_write_4(t, tr, BE_TRI_MGMTPAL, v);
        !          1283:        (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1284:        bus_space_write_4(t, tr, BE_TRI_MGMTPAL, v | MGMT_PAL_DCLOCK);
        !          1285:        (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
        !          1286: }
        !          1287:
        !          1288: static void
        !          1289: be_mii_sendbits(struct be_softc *sc, int phy, u_int32_t data, int nbits)
        !          1290: {
        !          1291:        int i;
        !          1292:
        !          1293:        for (i = 1 << (nbits - 1); i != 0; i >>= 1)
        !          1294:                be_tcvr_write_bit(sc, phy, (data & i) != 0);
        !          1295: }
        !          1296:
        !          1297: static int
        !          1298: be_mii_readreg(struct device *self, int phy, int reg)
        !          1299: {
        !          1300:        struct be_softc *sc = (struct be_softc *)self;
        !          1301:        int val = 0, i;
        !          1302:
        !          1303:        /*
        !          1304:         * Read the PHY register by manually driving the MII control lines.
        !          1305:         */
        !          1306:        be_mii_sync(sc);
        !          1307:        be_mii_sendbits(sc, phy, MII_COMMAND_START, 2);
        !          1308:        be_mii_sendbits(sc, phy, MII_COMMAND_READ, 2);
        !          1309:        be_mii_sendbits(sc, phy, phy, 5);
        !          1310:        be_mii_sendbits(sc, phy, reg, 5);
        !          1311:
        !          1312:        (void) be_tcvr_read_bit(sc, phy);
        !          1313:        (void) be_tcvr_read_bit(sc, phy);
        !          1314:
        !          1315:        for (i = 15; i >= 0; i--)
        !          1316:                val |= (be_tcvr_read_bit(sc, phy) << i);
        !          1317:
        !          1318:        (void) be_tcvr_read_bit(sc, phy);
        !          1319:        (void) be_tcvr_read_bit(sc, phy);
        !          1320:        (void) be_tcvr_read_bit(sc, phy);
        !          1321:
        !          1322:        return (val);
        !          1323: }
        !          1324:
        !          1325: void
        !          1326: be_mii_writereg(struct device *self, int phy, int reg, int val)
        !          1327: {
        !          1328:        struct be_softc *sc = (struct be_softc *)self;
        !          1329:        int i;
        !          1330:
        !          1331:        /*
        !          1332:         * Write the PHY register by manually driving the MII control lines.
        !          1333:         */
        !          1334:        be_mii_sync(sc);
        !          1335:        be_mii_sendbits(sc, phy, MII_COMMAND_START, 2);
        !          1336:        be_mii_sendbits(sc, phy, MII_COMMAND_WRITE, 2);
        !          1337:        be_mii_sendbits(sc, phy, phy, 5);
        !          1338:        be_mii_sendbits(sc, phy, reg, 5);
        !          1339:
        !          1340:        be_tcvr_write_bit(sc, phy, 1);
        !          1341:        be_tcvr_write_bit(sc, phy, 0);
        !          1342:
        !          1343:        for (i = 15; i >= 0; i--)
        !          1344:                be_tcvr_write_bit(sc, phy, (val >> i) & 1);
        !          1345: }
        !          1346:
        !          1347: int
        !          1348: be_mii_reset(struct be_softc *sc, int phy)
        !          1349: {
        !          1350:        int n;
        !          1351:
        !          1352:        be_mii_writereg((struct device *)sc, phy, MII_BMCR,
        !          1353:            BMCR_LOOP | BMCR_PDOWN | BMCR_ISO);
        !          1354:        be_mii_writereg((struct device *)sc, phy, MII_BMCR, BMCR_RESET);
        !          1355:
        !          1356:        for (n = 16; n >= 0; n--) {
        !          1357:                int bmcr = be_mii_readreg((struct device *)sc, phy, MII_BMCR);
        !          1358:                if ((bmcr & BMCR_RESET) == 0)
        !          1359:                        break;
        !          1360:                DELAY(20);
        !          1361:        }
        !          1362:        if (n == 0) {
        !          1363:                printf("%s: bmcr reset failed\n", sc->sc_dev.dv_xname);
        !          1364:                return (EIO);
        !          1365:        }
        !          1366:
        !          1367:        return (0);
        !          1368: }
        !          1369:
        !          1370: void
        !          1371: be_tick(void *arg)
        !          1372: {
        !          1373:        struct be_softc *sc = arg;
        !          1374:        int s = splnet();
        !          1375:
        !          1376:        mii_tick(&sc->sc_mii);
        !          1377:        (void)be_intphy_service(sc, &sc->sc_mii, MII_TICK);
        !          1378:
        !          1379:        timeout_add(&sc->sc_tick_ch, hz);
        !          1380:        splx(s);
        !          1381: }
        !          1382:
        !          1383: void
        !          1384: be_mii_statchg(struct device *self)
        !          1385: {
        !          1386:        struct be_softc *sc = (struct be_softc *)self;
        !          1387:        bus_space_tag_t t = sc->sc_bustag;
        !          1388:        bus_space_handle_t br = sc->sc_br;
        !          1389:        u_int instance;
        !          1390:        u_int32_t v;
        !          1391:
        !          1392:        instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
        !          1393: #ifdef DIAGNOSTIC
        !          1394:        if (instance > 1)
        !          1395:                panic("be_mii_statchg: instance %d out of range", instance);
        !          1396: #endif
        !          1397:
        !          1398:        /* Update duplex mode in TX configuration */
        !          1399:        v = bus_space_read_4(t, br, BE_BRI_TXCFG);
        !          1400:        if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
        !          1401:                v |= BE_BR_TXCFG_FULLDPLX;
        !          1402:        else
        !          1403:                v &= ~BE_BR_TXCFG_FULLDPLX;
        !          1404:        bus_space_write_4(t, br, BE_BRI_TXCFG, v);
        !          1405:
        !          1406:        /* Change to appropriate gate in transceiver PAL */
        !          1407:        be_pal_gate(sc, sc->sc_phys[instance]);
        !          1408: }
        !          1409:
        !          1410: /*
        !          1411:  * Get current media settings.
        !          1412:  */
        !          1413: void
        !          1414: be_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
        !          1415: {
        !          1416:        struct be_softc *sc = ifp->if_softc;
        !          1417:
        !          1418:        mii_pollstat(&sc->sc_mii);
        !          1419:        (void)be_intphy_service(sc, &sc->sc_mii, MII_POLLSTAT);
        !          1420:
        !          1421:        ifmr->ifm_status = sc->sc_mii.mii_media_status;
        !          1422:        ifmr->ifm_active = sc->sc_mii.mii_media_active;
        !          1423:        return;
        !          1424: }
        !          1425:
        !          1426: /*
        !          1427:  * Set media options.
        !          1428:  */
        !          1429: int
        !          1430: be_ifmedia_upd(struct ifnet *ifp)
        !          1431: {
        !          1432:        struct be_softc *sc = ifp->if_softc;
        !          1433:        int error;
        !          1434:
        !          1435:        if ((error = mii_mediachg(&sc->sc_mii)) != 0)
        !          1436:                return (error);
        !          1437:
        !          1438:        return (be_intphy_service(sc, &sc->sc_mii, MII_MEDIACHG));
        !          1439: }
        !          1440:
        !          1441: /*
        !          1442:  * Service routine for our pseudo-MII internal transceiver.
        !          1443:  */
        !          1444: int
        !          1445: be_intphy_service(struct be_softc *sc, struct mii_data *mii, int cmd)
        !          1446: {
        !          1447:        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
        !          1448:        int bmcr, bmsr;
        !          1449:        int error;
        !          1450:
        !          1451:        switch (cmd) {
        !          1452:        case MII_POLLSTAT:
        !          1453:                /*
        !          1454:                 * If we're not polling our PHY instance, just return.
        !          1455:                 */
        !          1456:                if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst)
        !          1457:                        return (0);
        !          1458:
        !          1459:                break;
        !          1460:
        !          1461:        case MII_MEDIACHG:
        !          1462:
        !          1463:                /*
        !          1464:                 * If the media indicates a different PHY instance,
        !          1465:                 * isolate ourselves.
        !          1466:                 */
        !          1467:                if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst) {
        !          1468:                        bmcr = be_mii_readreg((void *)sc,
        !          1469:                            BE_PHY_INTERNAL, MII_BMCR);
        !          1470:                        be_mii_writereg((void *)sc,
        !          1471:                            BE_PHY_INTERNAL, MII_BMCR, bmcr | BMCR_ISO);
        !          1472:                        sc->sc_mii_flags &= ~MIIF_HAVELINK;
        !          1473:                        sc->sc_intphy_curspeed = 0;
        !          1474:                        return (0);
        !          1475:                }
        !          1476:
        !          1477:
        !          1478:                if ((error = be_mii_reset(sc, BE_PHY_INTERNAL)) != 0)
        !          1479:                        return (error);
        !          1480:
        !          1481:                bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
        !          1482:
        !          1483:                /*
        !          1484:                 * Select the new mode and take out of isolation
        !          1485:                 */
        !          1486:                if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX)
        !          1487:                        bmcr |= BMCR_S100;
        !          1488:                else if (IFM_SUBTYPE(ife->ifm_media) == IFM_10_T)
        !          1489:                        bmcr &= ~BMCR_S100;
        !          1490:                else if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
        !          1491:                        if ((sc->sc_mii_flags & MIIF_HAVELINK) != 0) {
        !          1492:                                bmcr &= ~BMCR_S100;
        !          1493:                                bmcr |= sc->sc_intphy_curspeed;
        !          1494:                        } else {
        !          1495:                                /* Keep isolated until link is up */
        !          1496:                                bmcr |= BMCR_ISO;
        !          1497:                                sc->sc_mii_flags |= MIIF_DOINGAUTO;
        !          1498:                        }
        !          1499:                }
        !          1500:
        !          1501:                if ((IFM_OPTIONS(ife->ifm_media) & IFM_FDX) != 0)
        !          1502:                        bmcr |= BMCR_FDX;
        !          1503:                else
        !          1504:                        bmcr &= ~BMCR_FDX;
        !          1505:
        !          1506:                be_mii_writereg((void *)sc, BE_PHY_INTERNAL, MII_BMCR, bmcr);
        !          1507:                break;
        !          1508:
        !          1509:        case MII_TICK:
        !          1510:                /*
        !          1511:                 * If we're not currently selected, just return.
        !          1512:                 */
        !          1513:                if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst)
        !          1514:                        return (0);
        !          1515:
        !          1516:                /* Only used for automatic media selection */
        !          1517:                if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
        !          1518:                        return (0);
        !          1519:
        !          1520:                /* Is the interface even up? */
        !          1521:                if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
        !          1522:                        return (0);
        !          1523:
        !          1524:                /*
        !          1525:                 * Check link status; if we don't have a link, try another
        !          1526:                 * speed. We can't detect duplex mode, so half-duplex is
        !          1527:                 * what we have to settle for.
        !          1528:                 */
        !          1529:
        !          1530:                /* Read twice in case the register is latched */
        !          1531:                bmsr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMSR) |
        !          1532:                    be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMSR);
        !          1533:
        !          1534:                if ((bmsr & BMSR_LINK) != 0) {
        !          1535:                        /* We have a carrier */
        !          1536:                        bmcr = be_mii_readreg((void *)sc,
        !          1537:                            BE_PHY_INTERNAL, MII_BMCR);
        !          1538:
        !          1539:                        if ((sc->sc_mii_flags & MIIF_DOINGAUTO) != 0) {
        !          1540:                                bmcr = be_mii_readreg((void *)sc,
        !          1541:                                    BE_PHY_INTERNAL, MII_BMCR);
        !          1542:
        !          1543:                                sc->sc_mii_flags |= MIIF_HAVELINK;
        !          1544:                                sc->sc_intphy_curspeed = (bmcr & BMCR_S100);
        !          1545:                                sc->sc_mii_flags &= ~MIIF_DOINGAUTO;
        !          1546:
        !          1547:                                bmcr &= ~BMCR_ISO;
        !          1548:                                be_mii_writereg((void *)sc,
        !          1549:                                    BE_PHY_INTERNAL, MII_BMCR, bmcr);
        !          1550:
        !          1551:                                printf("%s: link up at %s Mbps\n",
        !          1552:                                    sc->sc_dev.dv_xname,
        !          1553:                                    (bmcr & BMCR_S100) ? "100" : "10");
        !          1554:                        }
        !          1555:                        return (0);
        !          1556:                }
        !          1557:
        !          1558:                if ((sc->sc_mii_flags & MIIF_DOINGAUTO) == 0) {
        !          1559:                        sc->sc_mii_flags |= MIIF_DOINGAUTO;
        !          1560:                        sc->sc_mii_flags &= ~MIIF_HAVELINK;
        !          1561:                        sc->sc_intphy_curspeed = 0;
        !          1562:                        printf("%s: link down\n", sc->sc_dev.dv_xname);
        !          1563:                }
        !          1564:
        !          1565:                /* Only retry autonegotiation every 5 seconds. */
        !          1566:                if (++sc->sc_mii_ticks < 5)
        !          1567:                        return(0);
        !          1568:
        !          1569:                sc->sc_mii_ticks = 0;
        !          1570:                bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
        !          1571:                /* Just flip the fast speed bit */
        !          1572:                bmcr ^= BMCR_S100;
        !          1573:                be_mii_writereg((void *)sc, BE_PHY_INTERNAL, MII_BMCR, bmcr);
        !          1574:
        !          1575:                break;
        !          1576:
        !          1577:        case MII_DOWN:
        !          1578:                /* Isolate this phy */
        !          1579:                bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
        !          1580:                be_mii_writereg((void *)sc,
        !          1581:                    BE_PHY_INTERNAL, MII_BMCR, bmcr | BMCR_ISO);
        !          1582:                return (0);
        !          1583:        }
        !          1584:
        !          1585:        /* Update the media status. */
        !          1586:        be_intphy_status(sc);
        !          1587:
        !          1588:        /* Callback if something changed. */
        !          1589:        if (sc->sc_mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
        !          1590:                (*mii->mii_statchg)((struct device *)sc);
        !          1591:                sc->sc_mii_active = mii->mii_media_active;
        !          1592:        }
        !          1593:        return (0);
        !          1594: }
        !          1595:
        !          1596: /*
        !          1597:  * Determine status of internal transceiver
        !          1598:  */
        !          1599: void
        !          1600: be_intphy_status(struct be_softc *sc)
        !          1601: {
        !          1602:        struct mii_data *mii = &sc->sc_mii;
        !          1603:        int media_active, media_status;
        !          1604:        int bmcr, bmsr;
        !          1605:
        !          1606:        media_status = IFM_AVALID;
        !          1607:        media_active = 0;
        !          1608:
        !          1609:        /*
        !          1610:         * Internal transceiver; do the work here.
        !          1611:         */
        !          1612:        bmcr = be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMCR);
        !          1613:
        !          1614:        switch (bmcr & (BMCR_S100 | BMCR_FDX)) {
        !          1615:        case (BMCR_S100 | BMCR_FDX):
        !          1616:                media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
        !          1617:                break;
        !          1618:        case BMCR_S100:
        !          1619:                media_active = IFM_ETHER | IFM_100_TX | IFM_HDX;
        !          1620:                break;
        !          1621:        case BMCR_FDX:
        !          1622:                media_active = IFM_ETHER | IFM_10_T | IFM_FDX;
        !          1623:                break;
        !          1624:        case 0:
        !          1625:                media_active = IFM_ETHER | IFM_10_T | IFM_HDX;
        !          1626:                break;
        !          1627:        }
        !          1628:
        !          1629:        /* Read twice in case the register is latched */
        !          1630:        bmsr = be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR)|
        !          1631:               be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR);
        !          1632:        if (bmsr & BMSR_LINK)
        !          1633:                media_status |=  IFM_ACTIVE;
        !          1634:
        !          1635:        mii->mii_media_status = media_status;
        !          1636:        mii->mii_media_active = media_active;
        !          1637: }

CVSweb