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

Annotation of sys/arch/sparc/dev/hme.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: hme.c,v 1.55 2006/06/25 21:53:44 brad Exp $   */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1998 Jason L. Wright (jason@thought.net)
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            18:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            19:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            20:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            22:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            24:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            25:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            26:  * POSSIBILITY OF SUCH DAMAGE.
        !            27:  */
        !            28:
        !            29: /*
        !            30:  * Driver for the Happy Meal (hme) ethernet boards
        !            31:  * Based on information gleaned from reading the
        !            32:  *     S/Linux driver by David Miller
        !            33:  *
        !            34:  * Thanks go to the University of North Carolina at Greensboro, Systems
        !            35:  * and Networks Department for some of the resources used to develop
        !            36:  * this driver.
        !            37:  */
        !            38:
        !            39: #include "bpfilter.h"
        !            40: #include "vlan.h"
        !            41:
        !            42: #include <sys/param.h>
        !            43: #include <sys/systm.h>
        !            44: #include <sys/kernel.h>
        !            45: #include <sys/errno.h>
        !            46: #include <sys/ioctl.h>
        !            47: #include <sys/mbuf.h>
        !            48: #include <sys/socket.h>
        !            49: #include <sys/syslog.h>
        !            50: #include <sys/device.h>
        !            51: #include <sys/malloc.h>
        !            52:
        !            53: #include <net/if.h>
        !            54: #include <net/if_dl.h>
        !            55: #include <net/if_types.h>
        !            56: #include <net/netisr.h>
        !            57: #include <net/if_media.h>
        !            58:
        !            59: #ifdef INET
        !            60: #include <netinet/in.h>
        !            61: #include <netinet/in_systm.h>
        !            62: #include <netinet/in_var.h>
        !            63: #include <netinet/ip.h>
        !            64: #include <netinet/if_ether.h>
        !            65: #include <netinet/tcp.h>
        !            66: #include <netinet/udp.h>
        !            67: #endif
        !            68:
        !            69: #if NBPFILTER > 0
        !            70: #include <net/bpf.h>
        !            71: #include <net/bpfdesc.h>
        !            72: #endif
        !            73:
        !            74: #include <machine/autoconf.h>
        !            75: #include <sparc/cpu.h>
        !            76: #include <sparc/sparc/cpuvar.h>
        !            77: #include <sparc/dev/sbusvar.h>
        !            78: #include <sparc/dev/dmareg.h>  /* for SBUS_BURST_* */
        !            79: #include <dev/mii/mii.h>
        !            80: #include <dev/mii/miivar.h>
        !            81: #include <sparc/dev/hmereg.h>
        !            82: #include <sparc/dev/hmevar.h>
        !            83:
        !            84: int    hmematch(struct device *, void *, void *);
        !            85: void   hmeattach(struct device *, struct device *, void *);
        !            86: void   hmewatchdog(struct ifnet *);
        !            87: int    hmeintr(void *);
        !            88: int    hmeioctl(struct ifnet *, u_long, caddr_t);
        !            89: void   hmereset(struct hme_softc *);
        !            90: void   hmestart(struct ifnet *);
        !            91: void   hmestop(struct hme_softc *);
        !            92: void   hmeinit(struct hme_softc *);
        !            93: void   hme_meminit(struct hme_softc *);
        !            94:
        !            95: void   hme_tcvr_bb_writeb(struct hme_softc *, int);
        !            96: int    hme_tcvr_bb_readb(struct hme_softc *, int);
        !            97:
        !            98: void   hme_poll_stop(struct hme_softc *sc);
        !            99:
        !           100: int    hme_rint(struct hme_softc *);
        !           101: int    hme_tint(struct hme_softc *);
        !           102: int    hme_mint(struct hme_softc *, u_int32_t);
        !           103: int    hme_eint(struct hme_softc *, u_int32_t);
        !           104:
        !           105: /* TCP/UDP checksum offload support */
        !           106: void   hme_rxcksum(struct mbuf *, u_int32_t);
        !           107:
        !           108: void   hme_reset_rx(struct hme_softc *);
        !           109: void   hme_reset_tx(struct hme_softc *);
        !           110:
        !           111: void   hme_read(struct hme_softc *, int, int, u_int32_t);
        !           112: int    hme_put(struct hme_softc *, int, struct mbuf *);
        !           113:
        !           114: /*
        !           115:  * ifmedia glue
        !           116:  */
        !           117: int    hme_mediachange(struct ifnet *);
        !           118: void   hme_mediastatus(struct ifnet *, struct ifmediareq *);
        !           119:
        !           120: /*
        !           121:  * mii glue
        !           122:  */
        !           123: int    hme_mii_read(struct device *, int, int);
        !           124: void   hme_mii_write(struct device *, int, int, int);
        !           125: void   hme_mii_statchg(struct device *);
        !           126:
        !           127: void   hme_mcreset(struct hme_softc *);
        !           128:
        !           129: struct cfattach hme_ca = {
        !           130:        sizeof (struct hme_softc), hmematch, hmeattach
        !           131: };
        !           132:
        !           133: struct cfdriver hme_cd = {
        !           134:        NULL, "hme", DV_IFNET
        !           135: };
        !           136:
        !           137: int
        !           138: hmematch(parent, vcf, aux)
        !           139:        struct device *parent;
        !           140:        void *vcf, *aux;
        !           141: {
        !           142:        struct cfdata *cf = vcf;
        !           143:        struct confargs *ca = aux;
        !           144:        register struct romaux *ra = &ca->ca_ra;
        !           145:
        !           146:        if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
        !           147:            strcmp("SUNW,hme", ra->ra_name) &&
        !           148:            strcmp("SUNW,qfe", ra->ra_name)) {
        !           149:                return (0);
        !           150:        }
        !           151:        if (!sbus_testdma((struct sbus_softc *)parent, ca))
        !           152:                return(0);
        !           153:        return (1);
        !           154: }
        !           155:
        !           156: void
        !           157: hmeattach(parent, self, aux)
        !           158:        struct device *parent, *self;
        !           159:        void *aux;
        !           160: {
        !           161:        struct confargs *ca = aux;
        !           162:        struct hme_softc *sc = (struct hme_softc *)self;
        !           163:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           164:        int pri;
        !           165:        struct bootpath *bp;
        !           166:        /* XXX the following declaration should be elsewhere */
        !           167:        extern void myetheraddr(u_char *);
        !           168:
        !           169:        if (ca->ca_ra.ra_nintr != 1) {
        !           170:                printf(": expected 1 interrupt, got %d\n",
        !           171:                        ca->ca_ra.ra_nintr);
        !           172:                return;
        !           173:        }
        !           174:        pri = ca->ca_ra.ra_intr[0].int_pri;
        !           175:
        !           176:        /* map registers */
        !           177:        if (ca->ca_ra.ra_nreg != 5) {
        !           178:                printf(": expected 5 registers, got %d\n", ca->ca_ra.ra_nreg);
        !           179:                return;
        !           180:        }
        !           181:        sc->sc_gr = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
        !           182:                        ca->ca_ra.ra_reg[0].rr_len);
        !           183:        sc->sc_txr = mapiodev(&(ca->ca_ra.ra_reg[1]), 0,
        !           184:                        ca->ca_ra.ra_reg[1].rr_len);
        !           185:        sc->sc_rxr = mapiodev(&(ca->ca_ra.ra_reg[2]), 0,
        !           186:                        ca->ca_ra.ra_reg[2].rr_len);
        !           187:        sc->sc_cr = mapiodev(&(ca->ca_ra.ra_reg[3]), 0,
        !           188:                        ca->ca_ra.ra_reg[3].rr_len);
        !           189:        sc->sc_tcvr = mapiodev(&(ca->ca_ra.ra_reg[4]), 0,
        !           190:                        ca->ca_ra.ra_reg[4].rr_len);
        !           191:
        !           192:        sc->sc_node = ca->ca_ra.ra_node;
        !           193:
        !           194:        sc->sc_rev = getpropint(ca->ca_ra.ra_node, "hm-rev", -1);
        !           195:        if (sc->sc_rev == 0xff)
        !           196:                sc->sc_rev = 0xa0;
        !           197:        if (sc->sc_rev == 0x20 || sc->sc_rev == 0x21)
        !           198:                sc->sc_flags = HME_FLAG_20_21;
        !           199:        else if (sc->sc_rev != 0xa0)
        !           200:                sc->sc_flags = HME_FLAG_NOT_A0;
        !           201:
        !           202:        sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);
        !           203:        if (sc->sc_burst == -1)
        !           204:                sc->sc_burst = ((struct sbus_softc *)parent)->sc_burst;
        !           205:
        !           206:        /* Clamp at parent's burst sizes */
        !           207:        sc->sc_burst &= ((struct sbus_softc *)parent)->sc_burst;
        !           208:
        !           209:        hme_meminit(sc);
        !           210:
        !           211:        sc->sc_ih.ih_fun = hmeintr;
        !           212:        sc->sc_ih.ih_arg = sc;
        !           213:        intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_NET,
        !           214:            self->dv_xname);
        !           215:
        !           216:        /*
        !           217:         * Get MAC address from card if 'local-mac-address' property exists.
        !           218:         * Otherwise, use the machine's builtin MAC.
        !           219:         */
        !           220:        if (getprop(ca->ca_ra.ra_node, "local-mac-address",
        !           221:            sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN) <= 0) {
        !           222:                myetheraddr(sc->sc_arpcom.ac_enaddr);
        !           223:        }
        !           224:
        !           225:        printf(" pri %d: address %s rev %d\n", pri,
        !           226:            ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_rev);
        !           227:
        !           228:        sc->sc_mii.mii_ifp = ifp;
        !           229:        sc->sc_mii.mii_readreg = hme_mii_read;
        !           230:        sc->sc_mii.mii_writereg = hme_mii_write;
        !           231:        sc->sc_mii.mii_statchg = hme_mii_statchg;
        !           232:        ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, hme_mediachange,
        !           233:            hme_mediastatus);
        !           234:        mii_phy_probe(self, &sc->sc_mii, 0xffffffff);
        !           235:
        !           236:        if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
        !           237:                ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE,
        !           238:                    0, NULL);
        !           239:                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
        !           240:        }
        !           241:        else
        !           242:                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
        !           243:
        !           244:        bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
        !           245:        ifp->if_softc = sc;
        !           246:        ifp->if_start = hmestart;
        !           247:        ifp->if_ioctl = hmeioctl;
        !           248:        ifp->if_watchdog = hmewatchdog;
        !           249:        ifp->if_flags =
        !           250:                IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
        !           251:        sc->sc_if_flags = ifp->if_flags;
        !           252:        ifp->if_capabilities = IFCAP_VLAN_MTU;
        !           253:        IFQ_SET_MAXLEN(&ifp->if_snd, HME_TX_RING_SIZE);
        !           254:        IFQ_SET_READY(&ifp->if_snd);
        !           255:
        !           256:        /* Attach the interface. */
        !           257:        if_attach(ifp);
        !           258:        ether_ifattach(ifp);
        !           259:
        !           260:        bp = ca->ca_ra.ra_bp;
        !           261:        if (bp != NULL && sc->sc_dev.dv_unit == bp->val[1] &&
        !           262:            ((strcmp(bp->name, hme_cd.cd_name) == 0) ||
        !           263:             (strcmp(bp->name, "qfe") == 0) ||
        !           264:             (strcmp(bp->name, "SUNW,hme") == 0)))
        !           265:                bp->dev = &sc->sc_dev;
        !           266: }
        !           267:
        !           268: /*
        !           269:  * Start output on interface.
        !           270:  * We make two assumptions here:
        !           271:  *  1) that the current priority is set to splnet _before_ this code
        !           272:  *     is called *and* is returned to the appropriate priority after
        !           273:  *     return
        !           274:  *  2) that the IFF_OACTIVE flag is checked before this code is called
        !           275:  *     (i.e. that the output part of the interface is idle)
        !           276:  */
        !           277: void
        !           278: hmestart(ifp)
        !           279:        struct ifnet *ifp;
        !           280: {
        !           281:        struct hme_softc *sc = ifp->if_softc;
        !           282:        struct mbuf *m;
        !           283:        int bix, len;
        !           284:
        !           285:        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
        !           286:                return;
        !           287:
        !           288:        bix = sc->sc_last_td;
        !           289:
        !           290:        for (;;) {
        !           291:                IFQ_DEQUEUE(&ifp->if_snd, m);
        !           292:                if (m == NULL)
        !           293:                        break;
        !           294: #if NBPFILTER > 0
        !           295:                /*
        !           296:                 * If BPF is listening on this interface, let it see the
        !           297:                 * packet before we commit it to the wire.
        !           298:                 */
        !           299:                if (ifp->if_bpf)
        !           300:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
        !           301: #endif
        !           302:
        !           303:                /*
        !           304:                 * Copy the mbuf chain into the transmit buffer.
        !           305:                 */
        !           306:                len = hme_put(sc, bix, m);
        !           307:
        !           308:                /*
        !           309:                 * Initialize transmit registers and start transmission.
        !           310:                 */
        !           311:                sc->sc_desc->hme_txd[bix].tx_flags =
        !           312:                    HME_TXD_OWN | HME_TXD_SOP | HME_TXD_EOP |
        !           313:                    (len & HME_TXD_SIZE);
        !           314:                sc->sc_txr->tx_pnding = TXR_TP_DMAWAKEUP;
        !           315:
        !           316:                if (++bix == HME_TX_RING_SIZE)
        !           317:                        bix = 0;
        !           318:
        !           319:                if (++sc->sc_no_td == HME_TX_RING_SIZE) {
        !           320:                        ifp->if_flags |= IFF_OACTIVE;
        !           321:                        break;
        !           322:                }
        !           323:        }
        !           324:
        !           325:        sc->sc_last_td = bix;
        !           326: }
        !           327:
        !           328: #define MAX_STOP_TRIES 16
        !           329:
        !           330: void
        !           331: hmestop(sc)
        !           332:        struct hme_softc *sc;
        !           333: {
        !           334:        int tries = 0;
        !           335:
        !           336:        sc->sc_gr->reset = GR_RESET_ALL;
        !           337:        while (sc->sc_gr->reset && (++tries != MAX_STOP_TRIES))
        !           338:                DELAY(20);
        !           339:        if (tries == MAX_STOP_TRIES)
        !           340:                printf("%s: stop failed\n", sc->sc_dev.dv_xname);
        !           341:        sc->sc_mii.mii_media_status &= ~IFM_ACTIVE;
        !           342: }
        !           343:
        !           344: /*
        !           345:  * Reset interface.
        !           346:  */
        !           347: void
        !           348: hmereset(sc)
        !           349:        struct hme_softc *sc;
        !           350: {
        !           351:        int s;
        !           352:
        !           353:        s = splnet();
        !           354:        hmestop(sc);
        !           355:        hmeinit(sc);
        !           356:        splx(s);
        !           357: }
        !           358:
        !           359: /*
        !           360:  * Device timeout/watchdog routine. Entered if the device neglects to generate
        !           361:  * an interrupt after a transmit has been started on it.
        !           362:  */
        !           363: void
        !           364: hmewatchdog(ifp)
        !           365:        struct ifnet *ifp;
        !           366: {
        !           367:        struct hme_softc *sc = ifp->if_softc;
        !           368:
        !           369:        log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
        !           370:        ++sc->sc_arpcom.ac_if.if_oerrors;
        !           371:
        !           372:        hmereset(sc);
        !           373: }
        !           374:
        !           375: int
        !           376: hmeioctl(ifp, cmd, data)
        !           377:        struct ifnet *ifp;
        !           378:        u_long cmd;
        !           379:        caddr_t data;
        !           380: {
        !           381:        struct hme_softc *sc = ifp->if_softc;
        !           382:        struct ifaddr *ifa = (struct ifaddr *)data;
        !           383:        struct ifreq *ifr = (struct ifreq *)data;
        !           384:        int s, error = 0;
        !           385:
        !           386:        s = splnet();
        !           387:
        !           388:        if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
        !           389:                splx(s);
        !           390:                return (error);
        !           391:        }
        !           392:
        !           393:        switch (cmd) {
        !           394:        case SIOCSIFADDR:
        !           395:                switch (ifa->ifa_addr->sa_family) {
        !           396: #ifdef INET
        !           397:                case AF_INET:
        !           398:                        if (ifp->if_flags & IFF_UP)
        !           399:                                hme_mcreset(sc);
        !           400:                        else {
        !           401:                                ifp->if_flags |= IFF_UP;
        !           402:                                hmeinit(sc);
        !           403:                        }
        !           404:                        arp_ifinit(&sc->sc_arpcom, ifa);
        !           405:                        break;
        !           406: #endif /* INET */
        !           407:                default:
        !           408:                        ifp->if_flags |= IFF_UP;
        !           409:                        hmeinit(sc);
        !           410:                        break;
        !           411:                }
        !           412:                break;
        !           413:
        !           414:        case SIOCSIFFLAGS:
        !           415:                if ((ifp->if_flags & IFF_UP) == 0 &&
        !           416:                    (ifp->if_flags & IFF_RUNNING) != 0) {
        !           417:                        /*
        !           418:                         * If interface is marked down and it is running, then
        !           419:                         * stop it.
        !           420:                         */
        !           421:                        hmestop(sc);
        !           422:                        ifp->if_flags &= ~IFF_RUNNING;
        !           423:                } else if ((ifp->if_flags & IFF_UP) != 0 &&
        !           424:                           (ifp->if_flags & IFF_RUNNING) == 0) {
        !           425:                        /*
        !           426:                         * If interface is marked up and it is stopped, then
        !           427:                         * start it.
        !           428:                         */
        !           429:                        hmeinit(sc);
        !           430:                } else {
        !           431:                        /*
        !           432:                         * If setting debug or promiscuous mode, do not reset
        !           433:                         * the chip; for everything else, call hmeinit()
        !           434:                         * which will trigger a reset.
        !           435:                         */
        !           436: #define RESETIGN (IFF_CANTCHANGE | IFF_DEBUG)
        !           437:                        if (ifp->if_flags == sc->sc_if_flags)
        !           438:                                break;
        !           439:                        if ((ifp->if_flags & (~RESETIGN))
        !           440:                            == (sc->sc_if_flags & (~RESETIGN)))
        !           441:                                hme_mcreset(sc);
        !           442:                        else
        !           443:                                hmeinit(sc);
        !           444: #undef RESETIGN
        !           445:                }
        !           446:                break;
        !           447:
        !           448:        case SIOCADDMULTI:
        !           449:        case SIOCDELMULTI:
        !           450:                error = (cmd == SIOCADDMULTI) ?
        !           451:                        ether_addmulti(ifr, &sc->sc_arpcom):
        !           452:                        ether_delmulti(ifr, &sc->sc_arpcom);
        !           453:
        !           454:                if (error == ENETRESET) {
        !           455:                        /*
        !           456:                         * Multicast list has changed; set the hardware filter
        !           457:                         * accordingly.
        !           458:                         */
        !           459:                        if (ifp->if_flags & IFF_RUNNING)
        !           460:                                hme_mcreset(sc);
        !           461:                        error = 0;
        !           462:                }
        !           463:                break;
        !           464:        case SIOCGIFMEDIA:
        !           465:        case SIOCSIFMEDIA:
        !           466:                error = ifmedia_ioctl(ifp, ifr,  &sc->sc_mii.mii_media, cmd);
        !           467:                break;
        !           468:        default:
        !           469:                error = ENOTTY;
        !           470:        }
        !           471:
        !           472:        sc->sc_if_flags = ifp->if_flags;
        !           473:        splx(s);
        !           474:        return (error);
        !           475: }
        !           476:
        !           477: void
        !           478: hme_meminit(sc)
        !           479:        struct hme_softc *sc;
        !           480: {
        !           481:        struct hme_desc *desc;
        !           482:        int i;
        !           483:
        !           484:        if (sc->sc_desc_dva == NULL)
        !           485:                sc->sc_desc_dva = (struct hme_desc *) dvma_malloc(
        !           486:                    sizeof(struct hme_desc), &sc->sc_desc, M_NOWAIT);
        !           487:        if (sc->sc_bufs_dva == NULL)
        !           488:                sc->sc_bufs_dva = (struct hme_bufs *) dvma_malloc(
        !           489:                    sizeof(struct hme_bufs), &sc->sc_bufs, M_NOWAIT);
        !           490:
        !           491:        desc = sc->sc_desc;
        !           492:
        !           493:        /*
        !           494:         * Setup TX descriptors
        !           495:         */
        !           496:        sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
        !           497:        for (i = 0; i < HME_TX_RING_SIZE; i++) {
        !           498:                desc->hme_txd[i].tx_addr =
        !           499:                    (u_int32_t)sc->sc_bufs_dva->tx_buf[i];
        !           500:                desc->hme_txd[i].tx_flags = 0;
        !           501:        }
        !           502:
        !           503:        /*
        !           504:         * Setup RX descriptors
        !           505:         */
        !           506:        sc->sc_last_rd = 0;
        !           507:        for (i = 0; i < HME_RX_RING_SIZE; i++) {
        !           508:                desc->hme_rxd[i].rx_addr =
        !           509:                    (u_int32_t)sc->sc_bufs_dva->rx_buf[i];
        !           510:                desc->hme_rxd[i].rx_flags = HME_RXD_OWN |
        !           511:                    ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);
        !           512:        }
        !           513: }
        !           514:
        !           515: void
        !           516: hmeinit(sc)
        !           517:        struct hme_softc *sc;
        !           518: {
        !           519:        u_int32_t c, n;
        !           520:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           521:        struct hme_tcvr *tcvr = sc->sc_tcvr;
        !           522:        struct hme_cr *cr = sc->sc_cr;
        !           523:        struct hme_gr *gr = sc->sc_gr;
        !           524:        struct hme_txr *txr = sc->sc_txr;
        !           525:        struct hme_rxr *rxr = sc->sc_rxr;
        !           526:
        !           527:        hme_poll_stop(sc);
        !           528:        hmestop(sc);
        !           529:
        !           530:        hme_meminit(sc);
        !           531:
        !           532:        tcvr->int_mask = 0xffff;
        !           533:
        !           534:        c = tcvr->cfg;
        !           535:        if (sc->sc_flags & HME_FLAG_FENABLE)
        !           536:                tcvr->cfg = c & ~(TCVR_CFG_BENABLE);
        !           537:        else
        !           538:                tcvr->cfg = c | TCVR_CFG_BENABLE;
        !           539:
        !           540:        hme_reset_tx(sc);
        !           541:        hme_reset_rx(sc);
        !           542:
        !           543:        cr->rand_seed = sc->sc_arpcom.ac_enaddr[5] |
        !           544:            ((sc->sc_arpcom.ac_enaddr[4] << 8) & 0x3f00);
        !           545:        cr->mac_addr0 = (sc->sc_arpcom.ac_enaddr[0] << 8) |
        !           546:                           sc->sc_arpcom.ac_enaddr[1];
        !           547:        cr->mac_addr1 = (sc->sc_arpcom.ac_enaddr[2] << 8) |
        !           548:                           sc->sc_arpcom.ac_enaddr[3];
        !           549:        cr->mac_addr2 = (sc->sc_arpcom.ac_enaddr[4] << 8) |
        !           550:                           sc->sc_arpcom.ac_enaddr[5];
        !           551:        cr->tx_pkt_max = cr->rx_pkt_max = ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN;
        !           552:
        !           553:        cr->jsize = HME_DEFAULT_JSIZE;
        !           554:        cr->ipkt_gap1 = HME_DEFAULT_IPKT_GAP1;
        !           555:        cr->ipkt_gap2 = HME_DEFAULT_IPKT_GAP2;
        !           556:
        !           557:        rxr->rx_ring = (u_int32_t)sc->sc_desc_dva->hme_rxd;
        !           558:        txr->tx_ring = (u_int32_t)sc->sc_desc_dva->hme_txd;
        !           559:
        !           560:        if (sc->sc_burst & SBUS_BURST_64)
        !           561:                gr->cfg = GR_CFG_BURST64;
        !           562:        else if (sc->sc_burst & SBUS_BURST_32)
        !           563:                gr->cfg = GR_CFG_BURST32;
        !           564:        else if (sc->sc_burst & SBUS_BURST_16)
        !           565:                gr->cfg = GR_CFG_BURST16;
        !           566:        else {
        !           567:                printf("%s: burst size unknown\n", sc->sc_dev.dv_xname);
        !           568:                gr->cfg = 0;
        !           569:        }
        !           570:
        !           571:        gr->imask = GR_IMASK_SENTFRAME | GR_IMASK_TXPERR |
        !           572:                      GR_IMASK_GOTFRAME | GR_IMASK_RCNTEXP;
        !           573:
        !           574:        txr->tx_rsize = (HME_TX_RING_SIZE >> TXR_RSIZE_SHIFT) - 1;
        !           575:        txr->cfg |= TXR_CFG_DMAENABLE;
        !           576:
        !           577:        c = RXR_CFG_DMAENABLE | (HME_RX_OFFSET << 3);
        !           578:        /* RX TCP/UDP cksum offset */
        !           579:        n = (ETHER_HDR_LEN + sizeof(struct ip)) / 2;
        !           580:        n = (n << RXR_CFG_CSUM_SHIFT) & RXR_CFG_CSUMSTART;
        !           581:        c |= n;
        !           582: #if HME_RX_RING_SIZE == 32
        !           583:        c |= RXR_CFG_RINGSIZE32;
        !           584: #elif HME_RX_RING_SIZE == 64
        !           585:        c |= RXR_CFG_RINGSIZE64;
        !           586: #elif HME_RX_RING_SIZE == 128
        !           587:        c |= RXR_CFG_RINGSIZE128;
        !           588: #elif HME_RX_RING_SIZE == 256
        !           589:        c |= RXR_CFG_RINGSIZE256;
        !           590: #else
        !           591: #error "HME_RX_RING_SIZE must be 32, 64, 128, or 256."
        !           592: #endif
        !           593:        rxr->cfg = c;
        !           594:        DELAY(20);
        !           595:        if (c != rxr->cfg)      /* the receiver sometimes misses bits */
        !           596:                printf("%s: setting rxreg->cfg failed.\n", sc->sc_dev.dv_xname);
        !           597:
        !           598:        cr->rx_cfg = 0;
        !           599:        hme_mcreset(sc);
        !           600:        DELAY(10);
        !           601:
        !           602:        cr->tx_cfg |= CR_TXCFG_DGIVEUP;
        !           603:
        !           604:        c = CR_XCFG_ODENABLE;
        !           605:        if (sc->sc_flags & HME_FLAG_LANCE)
        !           606:                c |= (HME_DEFAULT_IPKT_GAP0 << 5) | CR_XCFG_LANCE;
        !           607:        cr->xif_cfg = c;
        !           608:
        !           609:        cr->tx_cfg |= CR_TXCFG_ENABLE;  /* enable tx */
        !           610:        cr->rx_cfg |= CR_RXCFG_ENABLE;  /* enable rx */
        !           611:
        !           612:        mii_mediachg(&sc->sc_mii);
        !           613:
        !           614:        ifp->if_flags |= IFF_RUNNING;
        !           615:        ifp->if_flags &= ~IFF_OACTIVE;
        !           616:        sc->sc_if_flags = ifp->if_flags;
        !           617:        ifp->if_timer = 0;
        !           618: }
        !           619:
        !           620: void
        !           621: hme_poll_stop(sc)
        !           622:        struct hme_softc *sc;
        !           623: {
        !           624:        struct hme_tcvr *tcvr = sc->sc_tcvr;
        !           625:
        !           626:        /* if not polling, or polling not enabled, we're done. */
        !           627:        if ((sc->sc_flags & (HME_FLAG_POLLENABLE | HME_FLAG_POLL)) !=
        !           628:            (HME_FLAG_POLLENABLE | HME_FLAG_POLL))
        !           629:                return;
        !           630:
        !           631:        /* Turn off MIF interrupts, and disable polling */
        !           632:        tcvr->int_mask = 0xffff;
        !           633:        tcvr->cfg &= ~(TCVR_CFG_PENABLE);
        !           634:        sc->sc_flags &= ~(HME_FLAG_POLL);
        !           635:        DELAY(200);
        !           636: }
        !           637:
        !           638: #define RESET_TRIES    32
        !           639:
        !           640: void
        !           641: hme_reset_tx(sc)
        !           642:        struct hme_softc *sc;
        !           643: {
        !           644:        int tries = RESET_TRIES;
        !           645:        struct hme_cr *cr = sc->sc_cr;
        !           646:
        !           647:        cr->tx_swreset = 0;
        !           648:        while (--tries && (cr->tx_swreset & 1))
        !           649:                DELAY(20);
        !           650:
        !           651:        if (!tries)
        !           652:                printf("%s: reset tx failed\n", sc->sc_dev.dv_xname);
        !           653: }
        !           654:
        !           655: void
        !           656: hme_reset_rx(sc)
        !           657:        struct hme_softc *sc;
        !           658: {
        !           659:        int tries = RESET_TRIES;
        !           660:        struct hme_cr *cr = sc->sc_cr;
        !           661:
        !           662:        cr->rx_swreset = 0;
        !           663:        while (--tries && (cr->rx_swreset & 1))
        !           664:                DELAY(20);
        !           665:
        !           666:        if (!tries)
        !           667:                printf("%s: reset rx failed\n", sc->sc_dev.dv_xname);
        !           668: }
        !           669:
        !           670: /*
        !           671:  * mif interrupt
        !           672:  */
        !           673: int
        !           674: hme_mint(sc, why)
        !           675:        struct hme_softc *sc;
        !           676:        u_int32_t why;
        !           677: {
        !           678:        printf("%s: link status changed\n", sc->sc_dev.dv_xname);
        !           679:        hme_poll_stop(sc);
        !           680:        return (1);
        !           681: }
        !           682:
        !           683: /*
        !           684:  * transmit interrupt
        !           685:  */
        !           686: int
        !           687: hme_tint(sc)
        !           688:        struct hme_softc *sc;
        !           689: {
        !           690:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           691:        struct hme_cr *cr = sc->sc_cr;
        !           692:        int bix;
        !           693:        struct hme_txd txd;
        !           694:
        !           695:        /*
        !           696:         * Get collision counters
        !           697:         */
        !           698:        ifp->if_collisions += cr->ex_ctr + cr->lt_ctr + cr->fc_ctr + cr->nc_ctr;
        !           699:        cr->ex_ctr = 0;
        !           700:        cr->lt_ctr = 0;
        !           701:        cr->fc_ctr = 0;
        !           702:        cr->nc_ctr = 0;
        !           703:
        !           704:        bix = sc->sc_first_td;
        !           705:
        !           706:        for (;;) {
        !           707:                if (sc->sc_no_td <= 0)
        !           708:                        break;
        !           709:
        !           710:                bcopy(&sc->sc_desc->hme_txd[bix], &txd, sizeof(txd));
        !           711:
        !           712:                if (txd.tx_flags & HME_TXD_OWN)
        !           713:                        break;
        !           714:
        !           715:                ifp->if_flags &= ~IFF_OACTIVE;
        !           716:                ifp->if_opackets++;
        !           717:
        !           718:                if (++bix == HME_TX_RING_SIZE)
        !           719:                        bix = 0;
        !           720:
        !           721:                --sc->sc_no_td;
        !           722:        }
        !           723:
        !           724:        sc->sc_first_td = bix;
        !           725:
        !           726:        hmestart(ifp);
        !           727:
        !           728:        if (sc->sc_no_td == 0)
        !           729:                ifp->if_timer = 0;
        !           730:
        !           731:        return (1);
        !           732: }
        !           733:
        !           734: /*
        !           735:  * XXX layering violation
        !           736:  *
        !           737:  * If we can have additional csum data member in 'struct pkthdr' for
        !           738:  * these incomplete checksum offload capable hardware, things would be
        !           739:  * much simpler. That member variable will carry partial checksum
        !           740:  * data and it may be evaluated in TCP/UDP input handler after
        !           741:  * computing pseudo header checksumming.
        !           742:  */
        !           743: void
        !           744: hme_rxcksum(struct mbuf *m, u_int32_t flags)
        !           745: {
        !           746:        struct ether_header *eh;
        !           747:        struct ip *ip;
        !           748:        struct udphdr *uh;
        !           749:        int32_t hlen, len, pktlen;
        !           750:        u_int16_t cksum, *opts;
        !           751:        u_int32_t temp32;
        !           752:        union pseudoh {
        !           753:                struct hdr {
        !           754:                        u_int16_t len;
        !           755:                        u_int8_t ttl;
        !           756:                        u_int8_t proto;
        !           757:                        u_int32_t src;
        !           758:                        u_int32_t dst;
        !           759:                } h;
        !           760:                u_int16_t w[6];
        !           761:        } ph;
        !           762:
        !           763:        pktlen = m->m_pkthdr.len;
        !           764:        if (pktlen < sizeof(struct ether_header))
        !           765:                return;
        !           766:        eh = mtod(m, struct ether_header *);
        !           767:        if (eh->ether_type != htons(ETHERTYPE_IP))
        !           768:                return;
        !           769:        ip = (struct ip *)(eh + 1);
        !           770:        if (ip->ip_v != IPVERSION)
        !           771:                return;
        !           772:
        !           773:        hlen = ip->ip_hl << 2;
        !           774:        pktlen -= sizeof(struct ether_header);
        !           775:        if (hlen < sizeof(struct ip))
        !           776:                return;
        !           777:        if (ntohs(ip->ip_len) < hlen)
        !           778:                return;
        !           779:        if (ntohs(ip->ip_len) != pktlen)
        !           780:                return;
        !           781:        if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
        !           782:                return; /* can't handle fragmented packet */
        !           783:
        !           784:        switch (ip->ip_p) {
        !           785:        case IPPROTO_TCP:
        !           786:                if (pktlen < (hlen + sizeof(struct tcphdr)))
        !           787:                        return;
        !           788:                break;
        !           789:        case IPPROTO_UDP:
        !           790:                if (pktlen < (hlen + sizeof(struct udphdr)))
        !           791:                        return;
        !           792:                uh = (struct udphdr *)((caddr_t)ip + hlen);
        !           793:                if (uh->uh_sum == 0)
        !           794:                        return; /* no checksum */
        !           795:                break;
        !           796:        default:
        !           797:                return;
        !           798:        }
        !           799:
        !           800:        cksum = htons(~(flags & HME_RXD_CSUM));
        !           801:        /* cksum fixup for IP options */
        !           802:        len = hlen - sizeof(struct ip);
        !           803:        if (len > 0) {
        !           804:                opts = (u_int16_t *)(ip + 1);
        !           805:                for (; len > 0; len -= sizeof(u_int16_t), opts++) {
        !           806:                        temp32 = cksum - *opts;
        !           807:                        temp32 = (temp32 >> 16) + (temp32 & 65535);
        !           808:                        cksum = temp32 & 65535;
        !           809:                }
        !           810:        }
        !           811:        /* cksum fixup for pseudo-header, replace with in_cksum_phdr()? */
        !           812:        ph.h.len = htons(ntohs(ip->ip_len) - hlen);
        !           813:        ph.h.ttl = 0;
        !           814:        ph.h.proto = ip->ip_p;
        !           815:        ph.h.src = ip->ip_src.s_addr;
        !           816:        ph.h.dst = ip->ip_dst.s_addr;
        !           817:        temp32 = cksum;
        !           818:        opts = &ph.w[0];
        !           819:        temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
        !           820:        temp32 = (temp32 >> 16) + (temp32 & 65535);
        !           821:        temp32 += (temp32 >> 16);
        !           822:        cksum = ~temp32;
        !           823:        if (cksum == 0) {
        !           824:                m->m_pkthdr.csum_flags |=
        !           825:                        M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
        !           826:        }
        !           827: }
        !           828:
        !           829: int
        !           830: hme_rint(sc)
        !           831:        struct hme_softc *sc;
        !           832: {
        !           833:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           834:        int bix, len;
        !           835:        struct hme_rxd rxd;
        !           836:
        !           837:        bix = sc->sc_last_rd;
        !           838:
        !           839:        for (;;) {
        !           840:                bcopy(&sc->sc_desc->hme_rxd[bix], &rxd, sizeof(rxd));
        !           841:                len = rxd.rx_flags >> 16;
        !           842:
        !           843:                if (rxd.rx_flags & HME_RXD_OWN)
        !           844:                        break;
        !           845:
        !           846:                if (rxd.rx_flags & HME_RXD_OVERFLOW)
        !           847:                        ifp->if_ierrors++;
        !           848:                else
        !           849:                        hme_read(sc, bix, len, rxd.rx_flags);
        !           850:
        !           851:                rxd.rx_flags = HME_RXD_OWN |
        !           852:                    ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);
        !           853:                bcopy(&rxd, &sc->sc_desc->hme_rxd[bix], sizeof(rxd));
        !           854:
        !           855:                if (++bix == HME_RX_RING_SIZE)
        !           856:                        bix = 0;
        !           857:        }
        !           858:
        !           859:        sc->sc_last_rd = bix;
        !           860:
        !           861:        return (1);
        !           862: }
        !           863:
        !           864: /*
        !           865:  * error interrupt
        !           866:  */
        !           867: int
        !           868: hme_eint(sc, why)
        !           869:        struct hme_softc *sc;
        !           870:        u_int32_t why;
        !           871: {
        !           872:        if (why & GR_STAT_NORXD) {
        !           873:                sc->sc_arpcom.ac_if.if_ierrors++;
        !           874:                why &= ~GR_STAT_NORXD;
        !           875:        }
        !           876:        if (why & GR_STAT_DTIMEXP) {
        !           877:                sc->sc_arpcom.ac_if.if_oerrors++;
        !           878:                why &= ~GR_STAT_DTIMEXP;
        !           879:        }
        !           880:
        !           881:        if (why & GR_STAT_ALL_ERRORS) {
        !           882:                printf("%s: stat=%b, resetting.\n", sc->sc_dev.dv_xname,
        !           883:                    why, GR_STAT_BITS);
        !           884:                hmereset(sc);
        !           885:        }
        !           886:
        !           887:        return (1);
        !           888: }
        !           889:
        !           890: /*
        !           891:  * Interrupt handler
        !           892:  */
        !           893: int
        !           894: hmeintr(v)
        !           895:        void *v;
        !           896: {
        !           897:        struct hme_softc *sc = (struct hme_softc *)v;
        !           898:        struct hme_gr *gr = sc->sc_gr;
        !           899:        u_int32_t why;
        !           900:        int r = 0;
        !           901:
        !           902:        why = gr->stat;
        !           903:
        !           904:        if (why & GR_STAT_ALL_ERRORS)
        !           905:                r |= hme_eint(sc, why);
        !           906:
        !           907:        if (why & GR_STAT_MIFIRQ)
        !           908:                r |= hme_mint(sc, why);
        !           909:
        !           910:        if (why & (GR_STAT_TXALL | GR_STAT_HOSTTOTX))
        !           911:                r |= hme_tint(sc);
        !           912:
        !           913:        if (why & GR_STAT_RXTOHOST)
        !           914:                r |= hme_rint(sc);
        !           915:
        !           916:        return (r);
        !           917: }
        !           918:
        !           919: int
        !           920: hme_put(sc, idx, m)
        !           921:        struct hme_softc *sc;
        !           922:        int idx;
        !           923:        struct mbuf *m;
        !           924: {
        !           925:        struct mbuf *n;
        !           926:        u_int8_t *buf = sc->sc_bufs->tx_buf[idx];
        !           927:        int len, tlen = 0;
        !           928:
        !           929:        for (; m; m = n) {
        !           930:                len = m->m_len;
        !           931:                if (len == 0) {
        !           932:                        MFREE(m, n);
        !           933:                        continue;
        !           934:                }
        !           935:                bcopy(mtod(m, caddr_t), buf, len);
        !           936:                buf += len;
        !           937:                tlen += len;
        !           938:                MFREE(m, n);
        !           939:        }
        !           940:        return (tlen);
        !           941: }
        !           942:
        !           943: void
        !           944: hme_read(sc, idx, len, flags)
        !           945:        struct hme_softc *sc;
        !           946:        int idx, len;
        !           947:        u_int32_t flags;
        !           948: {
        !           949:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           950:        struct mbuf *m;
        !           951:
        !           952:        if (len <= sizeof(struct ether_header) ||
        !           953:            len > ETHERMTU + sizeof(struct ether_header)) {
        !           954:                printf("%s: invalid packet size %d; dropping\n",
        !           955:                    ifp->if_xname, len);
        !           956:                ifp->if_ierrors++;
        !           957:                return;
        !           958:        }
        !           959:
        !           960:        /* Pull packet off interface. */
        !           961:        m = m_devget(sc->sc_bufs->rx_buf[idx], len + HME_RX_OFFSET, 0,
        !           962:            &sc->sc_arpcom.ac_if, NULL);
        !           963:        if (m == NULL) {
        !           964:                ifp->if_ierrors++;
        !           965:                return;
        !           966:        }
        !           967:        m_adj(m, HME_RX_OFFSET);
        !           968:
        !           969:        ifp->if_ipackets++;
        !           970:        hme_rxcksum(m, flags);
        !           971:
        !           972: #if NBPFILTER > 0
        !           973:        /*
        !           974:         * Check if there's a BPF listener on this interface.
        !           975:         * If so, hand off the raw packet to BPF.
        !           976:         */
        !           977:        if (ifp->if_bpf)
        !           978:                bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
        !           979: #endif
        !           980:        /* Pass the packet up. */
        !           981:        ether_input_mbuf(ifp, m);
        !           982: }
        !           983:
        !           984: /*
        !           985:  * Program the multicast receive filter.
        !           986:  */
        !           987: void
        !           988: hme_mcreset(sc)
        !           989:        struct hme_softc *sc;
        !           990: {
        !           991:        struct arpcom *ac = &sc->sc_arpcom;
        !           992:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           993:        struct hme_cr *cr = sc->sc_cr;
        !           994:        u_int32_t crc;
        !           995:        u_int16_t hash[4];
        !           996:        u_int8_t octet;
        !           997:        int i, j;
        !           998:        struct ether_multi *enm;
        !           999:        struct ether_multistep step;
        !          1000:
        !          1001:        if (ifp->if_flags & IFF_PROMISC) {
        !          1002:                cr->rx_cfg |= CR_RXCFG_PMISC;
        !          1003:                return;
        !          1004:        }
        !          1005:        else
        !          1006:                cr->rx_cfg &= ~CR_RXCFG_PMISC;
        !          1007:
        !          1008:        if (ifp->if_flags & IFF_ALLMULTI) {
        !          1009:                cr->htable3 = 0xffff;
        !          1010:                cr->htable2 = 0xffff;
        !          1011:                cr->htable1 = 0xffff;
        !          1012:                cr->htable0 = 0xffff;
        !          1013:                cr->rx_cfg |= CR_RXCFG_HENABLE;
        !          1014:                return;
        !          1015:        }
        !          1016:
        !          1017:        hash[3] = hash[2] = hash[1] = hash[0] = 0;
        !          1018:
        !          1019:        ETHER_FIRST_MULTI(step, ac, enm);
        !          1020:        while (enm != NULL) {
        !          1021:                if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
        !          1022:                        /*
        !          1023:                         * We must listen to a range of multicast
        !          1024:                         * addresses.  For now, just accept all
        !          1025:                         * multicasts, rather than trying to set only
        !          1026:                         * those filter bits needed to match the range.
        !          1027:                         * (At this time, the only use of address
        !          1028:                         * ranges is for IP multicast routing, for
        !          1029:                         * which the range is big enough to require
        !          1030:                         * all bits set.)
        !          1031:                         */
        !          1032:                        cr->htable3 = 0xffff;
        !          1033:                        cr->htable2 = 0xffff;
        !          1034:                        cr->htable1 = 0xffff;
        !          1035:                        cr->htable0 = 0xffff;
        !          1036:                        cr->rx_cfg |= CR_RXCFG_HENABLE;
        !          1037:                        ifp->if_flags |= IFF_ALLMULTI;
        !          1038:                        return;
        !          1039:                }
        !          1040:
        !          1041:                crc = 0xffffffff;
        !          1042:
        !          1043:                for (i = 0; i < ETHER_ADDR_LEN; i++) {
        !          1044:                        octet = enm->enm_addrlo[i];
        !          1045:
        !          1046:                        for (j = 0; j < 8; j++) {
        !          1047:                                if ((crc & 1) ^ (octet & 1)) {
        !          1048:                                        crc >>= 1;
        !          1049:                                        crc ^= ETHER_CRC_POLY_LE;
        !          1050:                                }
        !          1051:                                else
        !          1052:                                        crc >>= 1;
        !          1053:                                octet >>= 1;
        !          1054:                        }
        !          1055:                }
        !          1056:
        !          1057:                crc >>=26;
        !          1058:                hash[crc >> 4] |= 1 << (crc & 0xf);
        !          1059:                ETHER_NEXT_MULTI(step, enm);
        !          1060:        }
        !          1061:        cr->htable3 = hash[3];
        !          1062:        cr->htable2 = hash[2];
        !          1063:        cr->htable1 = hash[1];
        !          1064:        cr->htable0 = hash[0];
        !          1065:        cr->rx_cfg |= CR_RXCFG_HENABLE;
        !          1066:        ifp->if_flags &= ~IFF_ALLMULTI;
        !          1067: }
        !          1068:
        !          1069: /*
        !          1070:  * Writing to the serial BitBang, is a matter of putting the bit
        !          1071:  * into the data register, then strobing the clock.
        !          1072:  */
        !          1073: void
        !          1074: hme_tcvr_bb_writeb(sc, b)
        !          1075:        struct hme_softc *sc;
        !          1076:        int b;
        !          1077: {
        !          1078:        sc->sc_tcvr->bb_data = b & 0x1;
        !          1079:        sc->sc_tcvr->bb_clock = 0;
        !          1080:        sc->sc_tcvr->bb_clock = 1;
        !          1081: }
        !          1082:
        !          1083: /*
        !          1084:  * Read a bit from a PHY, if the PHY is not our internal or external
        !          1085:  * phy addr, just return all zero's.
        !          1086:  */
        !          1087: int
        !          1088: hme_tcvr_bb_readb(sc, phy)
        !          1089:        struct hme_softc *sc;
        !          1090:        int phy;
        !          1091: {
        !          1092:        int ret;
        !          1093:
        !          1094:        sc->sc_tcvr->bb_clock = 0;
        !          1095:        DELAY(10);
        !          1096:
        !          1097:        if (phy == TCVR_PHYADDR_ITX)
        !          1098:                ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO0;
        !          1099:        else if (phy == TCVR_PHYADDR_ETX)
        !          1100:                ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO1;
        !          1101:        else
        !          1102:                ret = 0;
        !          1103:
        !          1104:        sc->sc_tcvr->bb_clock = 1;
        !          1105:
        !          1106:        return ((ret) ? 1 : 0);
        !          1107: }
        !          1108:
        !          1109: void
        !          1110: hme_mii_write(self, phy, reg, val)
        !          1111:        struct device *self;
        !          1112:        int phy, reg, val;
        !          1113: {
        !          1114:        struct hme_softc *sc = (struct hme_softc *)self;
        !          1115:        struct hme_tcvr *tcvr = sc->sc_tcvr;
        !          1116:        int tries = 16, i;
        !          1117:
        !          1118:        if (sc->sc_flags & HME_FLAG_FENABLE) {
        !          1119:                tcvr->frame = (FRAME_WRITE | phy << 23) |
        !          1120:                    ((reg & 0xff) << 18) | (val & 0xffff);
        !          1121:                while (!(tcvr->frame & 0x10000) && (tries != 0)) {
        !          1122:                        tries--;
        !          1123:                        DELAY(200);
        !          1124:                }
        !          1125:                if (!tries)
        !          1126:                        printf("%s: mii_write failed\n", sc->sc_dev.dv_xname);
        !          1127:                return;
        !          1128:        }
        !          1129:
        !          1130:        tcvr->bb_oenab = 1;
        !          1131:
        !          1132:        for (i = 0; i < 32; i++)
        !          1133:                hme_tcvr_bb_writeb(sc, 1);
        !          1134:
        !          1135:        hme_tcvr_bb_writeb(sc, (MII_COMMAND_START >> 1) & 1);
        !          1136:        hme_tcvr_bb_writeb(sc, MII_COMMAND_START & 1);
        !          1137:        hme_tcvr_bb_writeb(sc, (MII_COMMAND_WRITE >> 1) & 1);
        !          1138:        hme_tcvr_bb_writeb(sc, MII_COMMAND_WRITE & 1);
        !          1139:
        !          1140:        for (i = 4; i >= 0; i--)
        !          1141:                hme_tcvr_bb_writeb(sc, (phy >> i) & 1);
        !          1142:
        !          1143:        for (i = 4; i >= 0; i--)
        !          1144:                hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
        !          1145:
        !          1146:        for (i = 15; i >= 0; i--)
        !          1147:                hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
        !          1148:
        !          1149:        tcvr->bb_oenab = 0;
        !          1150: }
        !          1151:
        !          1152: int
        !          1153: hme_mii_read(self, phy, reg)
        !          1154:        struct device *self;
        !          1155:        int phy, reg;
        !          1156: {
        !          1157:        struct hme_softc *sc = (struct hme_softc *)self;
        !          1158:        struct hme_tcvr *tcvr = sc->sc_tcvr;
        !          1159:        int tries = 16, i, ret = 0;
        !          1160:
        !          1161:        /* Use the frame if possible */
        !          1162:        if (sc->sc_flags & HME_FLAG_FENABLE) {
        !          1163:                tcvr->frame = (FRAME_READ | phy << 23) |
        !          1164:                    ((reg & 0xff) << 18);
        !          1165:                while (!(tcvr->frame & 0x10000) && (tries != 0)) {
        !          1166:                        tries--;
        !          1167:                        DELAY(20);
        !          1168:                }
        !          1169:                if (!tries) {
        !          1170:                        printf("%s: mii_read failed\n", sc->sc_dev.dv_xname);
        !          1171:                        return (0);
        !          1172:                }
        !          1173:                return (tcvr->frame & 0xffff);
        !          1174:        }
        !          1175:
        !          1176:        tcvr->bb_oenab = 1;
        !          1177:
        !          1178:        for (i = 0; i < 32; i++)                /* make bitbang idle */
        !          1179:                hme_tcvr_bb_writeb(sc, 1);
        !          1180:
        !          1181:        hme_tcvr_bb_writeb(sc, (MII_COMMAND_START >> 1) & 1);
        !          1182:        hme_tcvr_bb_writeb(sc, MII_COMMAND_START & 1);
        !          1183:        hme_tcvr_bb_writeb(sc, (MII_COMMAND_READ >> 1) & 1);
        !          1184:        hme_tcvr_bb_writeb(sc, MII_COMMAND_READ & 1);
        !          1185:
        !          1186:        for (i = 4; i >= 0; i--)
        !          1187:                hme_tcvr_bb_writeb(sc, (phy >> i) & 1);
        !          1188:
        !          1189:        for (i = 4; i >= 0; i--)
        !          1190:                hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
        !          1191:
        !          1192:        tcvr->bb_oenab = 0;                     /* turn off bitbang intrs */
        !          1193:
        !          1194:        hme_tcvr_bb_readb(sc, phy);             /* ignore... */
        !          1195:
        !          1196:        for (i = 15; i >= 15; i--)              /* read value */
        !          1197:                ret |= hme_tcvr_bb_readb(sc, phy) << i;
        !          1198:
        !          1199:        hme_tcvr_bb_readb(sc, phy);                     /* ignore... */
        !          1200:        hme_tcvr_bb_readb(sc, phy);                     /* ignore... */
        !          1201:        hme_tcvr_bb_readb(sc, phy);                     /* ignore... */
        !          1202:
        !          1203:        return (ret);
        !          1204: }
        !          1205:
        !          1206: int
        !          1207: hme_mediachange(ifp)
        !          1208:        struct ifnet *ifp;
        !          1209: {
        !          1210:        if (ifp->if_flags & IFF_UP)
        !          1211:                hmeinit(ifp->if_softc);
        !          1212:        return (0);
        !          1213: }
        !          1214:
        !          1215: void
        !          1216: hme_mediastatus(ifp, ifmr)
        !          1217:        struct ifnet *ifp;
        !          1218:        struct ifmediareq *ifmr;
        !          1219: {
        !          1220:        struct hme_softc *sc = (struct hme_softc *)ifp->if_softc;
        !          1221:
        !          1222:        mii_pollstat(&sc->sc_mii);
        !          1223:        ifmr->ifm_active = sc->sc_mii.mii_media_active;
        !          1224:        ifmr->ifm_status = sc->sc_mii.mii_media_status;
        !          1225: }
        !          1226:
        !          1227: void
        !          1228: hme_mii_statchg(self)
        !          1229:        struct device *self;
        !          1230: {
        !          1231:        struct hme_softc *sc = (struct hme_softc *)self;
        !          1232:        struct hme_cr *cr = sc->sc_cr;
        !          1233:
        !          1234:        /* Apparently the hme chip is SIMPLEX if working in full duplex mode,
        !          1235:           but not otherwise. */
        !          1236:        if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) {
        !          1237:                cr->tx_cfg |= CR_TXCFG_FULLDPLX;
        !          1238:                sc->sc_arpcom.ac_if.if_flags |= IFF_SIMPLEX;
        !          1239:        } else {
        !          1240:                cr->tx_cfg &= ~CR_TXCFG_FULLDPLX;
        !          1241:                sc->sc_arpcom.ac_if.if_flags &= ~IFF_SIMPLEX;
        !          1242:        }
        !          1243:        sc->sc_if_flags = sc->sc_arpcom.ac_if.if_flags;
        !          1244: }

CVSweb