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

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

1.1     ! nbrk        1: /*     $OpenBSD: mtd8xx.c,v 1.12 2006/03/25 22:41:43 djm Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2003 Oleg Safiullin <form@pdp11.org.ru>
        !             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 unmodified, this list of conditions, and the following
        !            12:  *    disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  *
        !            29:  */
        !            30:
        !            31: #include "bpfilter.h"
        !            32:
        !            33: #include <sys/param.h>
        !            34: #include <sys/mbuf.h>
        !            35: #include <sys/systm.h>
        !            36: #include <sys/device.h>
        !            37: #include <sys/socket.h>
        !            38: #include <sys/ioctl.h>
        !            39:
        !            40: #include <net/if.h>
        !            41: #include <net/if_media.h>
        !            42:
        !            43: #if NBPFILTER > 0
        !            44: #include <net/bpf.h>
        !            45: #endif
        !            46:
        !            47: #ifdef INET
        !            48: #include <netinet/in.h>
        !            49: #include <netinet/if_ether.h>
        !            50: #endif
        !            51:
        !            52: #include <machine/bus.h>
        !            53:
        !            54: #include <dev/mii/mii.h>
        !            55: #include <dev/mii/miivar.h>
        !            56:
        !            57: #include <dev/pci/pcidevs.h>
        !            58: #include <dev/pci/pcivar.h>
        !            59:
        !            60: #include <dev/ic/mtd8xxreg.h>
        !            61: #include <dev/ic/mtd8xxvar.h>
        !            62:
        !            63:
        !            64: static int mtd_ifmedia_upd(struct ifnet *);
        !            65: static void mtd_ifmedia_sts(struct ifnet *, struct ifmediareq *);
        !            66:
        !            67: static u_int32_t mtd_mii_command(struct mtd_softc *, int, int, int);
        !            68: static int mtd_miibus_readreg(struct device *, int, int);
        !            69: static void mtd_miibus_writereg(struct device *, int, int, int);
        !            70: static void mtd_miibus_statchg(struct device *);
        !            71: static void mtd_setmulti(struct mtd_softc *);
        !            72:
        !            73: static int mtd_encap(struct mtd_softc *, struct mbuf *, u_int32_t *);
        !            74: static int mtd_list_rx_init(struct mtd_softc *);
        !            75: static void mtd_list_tx_init(struct mtd_softc *);
        !            76: static int mtd_newbuf(struct mtd_softc *, int, struct mbuf *);
        !            77:
        !            78: static void mtd_reset(struct mtd_softc *sc);
        !            79: static int mtd_ioctl(struct ifnet *, u_long, caddr_t);
        !            80: static void mtd_init(struct ifnet *);
        !            81: static void mtd_start(struct ifnet *);
        !            82: static void mtd_stop(struct ifnet *);
        !            83: static void mtd_watchdog(struct ifnet *);
        !            84:
        !            85: static void mtd_rxeof(struct mtd_softc *);
        !            86: static int mtd_rx_resync(struct mtd_softc *);
        !            87: static void mtd_txeof(struct mtd_softc *);
        !            88:
        !            89:
        !            90: void
        !            91: mtd_attach(struct mtd_softc *sc)
        !            92: {
        !            93:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !            94:        u_int32_t enaddr[2];
        !            95:        int i;
        !            96:
        !            97:        /* Reset the adapter. */
        !            98:        mtd_reset(sc);
        !            99:
        !           100:        if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct mtd_list_data),
        !           101:            PAGE_SIZE, 0, sc->sc_listseg, 1, &sc->sc_listnseg,
        !           102:            BUS_DMA_NOWAIT) != 0) {
        !           103:                printf(": can't alloc list mem\n");
        !           104:                return;
        !           105:        }
        !           106:        if (bus_dmamem_map(sc->sc_dmat, sc->sc_listseg, sc->sc_listnseg,
        !           107:            sizeof(struct mtd_list_data), &sc->sc_listkva,
        !           108:            BUS_DMA_NOWAIT) != 0) {
        !           109:                printf(": can't map list mem\n");
        !           110:                return;
        !           111:        }
        !           112:        if (bus_dmamap_create(sc->sc_dmat, sizeof(struct mtd_list_data), 1,
        !           113:            sizeof(struct mtd_list_data), 0, BUS_DMA_NOWAIT,
        !           114:            &sc->sc_listmap) != 0) {
        !           115:                printf(": can't alloc list map\n");
        !           116:                return;
        !           117:        }
        !           118:        if (bus_dmamap_load(sc->sc_dmat, sc->sc_listmap, sc->sc_listkva,
        !           119:            sizeof(struct mtd_list_data), NULL, BUS_DMA_NOWAIT) != 0) {
        !           120:                printf(": can't load list map\n");
        !           121:                return;
        !           122:        }
        !           123:        sc->mtd_ldata = (struct mtd_list_data *)sc->sc_listkva;
        !           124:        bzero(sc->mtd_ldata, sizeof(struct mtd_list_data));
        !           125:
        !           126:        for (i = 0; i < MTD_RX_LIST_CNT; i++) {
        !           127:                if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
        !           128:                    0, BUS_DMA_NOWAIT,
        !           129:                    &sc->mtd_cdata.mtd_rx_chain[i].sd_map) != 0) {
        !           130:                        printf(": can't create rx map\n");
        !           131:                        return;
        !           132:                }
        !           133:        }
        !           134:        if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
        !           135:            BUS_DMA_NOWAIT, &sc->sc_rx_sparemap) != 0) {
        !           136:                printf(": can't create rx spare map\n");
        !           137:                return;
        !           138:        }
        !           139:
        !           140:        for (i = 0; i < MTD_TX_LIST_CNT; i++) {
        !           141:                if (bus_dmamap_create(sc->sc_dmat, MCLBYTES,
        !           142:                    MTD_TX_LIST_CNT - 5, MCLBYTES, 0, BUS_DMA_NOWAIT,
        !           143:                    &sc->mtd_cdata.mtd_tx_chain[i].sd_map) != 0) {
        !           144:                        printf(": can't create tx map\n");
        !           145:                        return;
        !           146:                }
        !           147:        }
        !           148:        if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, MTD_TX_LIST_CNT - 5,
        !           149:            MCLBYTES, 0, BUS_DMA_NOWAIT, &sc->sc_tx_sparemap) != 0) {
        !           150:                printf(": can't create tx spare map\n");
        !           151:                return;
        !           152:        }
        !           153:
        !           154:
        !           155:        /* Get station address. */
        !           156:        enaddr[0] = letoh32(CSR_READ_4(MTD_PAR0));
        !           157:        enaddr[1] = letoh32(CSR_READ_4(MTD_PAR4));
        !           158:        bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
        !           159:        printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
        !           160:
        !           161:        /* Initialize interface */
        !           162:        ifp->if_softc = sc;
        !           163:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
        !           164:        ifp->if_ioctl = mtd_ioctl;
        !           165:        ifp->if_start = mtd_start;
        !           166:        ifp->if_watchdog = mtd_watchdog;
        !           167:        ifp->if_baudrate = 10000000;
        !           168:        IFQ_SET_READY(&ifp->if_snd);
        !           169:        bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
        !           170:
        !           171:        ifp->if_capabilities = IFCAP_VLAN_MTU;
        !           172:
        !           173:        /*
        !           174:         * Initialize our media structures and probe the MII.
        !           175:         */
        !           176:        sc->sc_mii.mii_ifp = ifp;
        !           177:        sc->sc_mii.mii_readreg = mtd_miibus_readreg;
        !           178:        sc->sc_mii.mii_writereg = mtd_miibus_writereg;
        !           179:        sc->sc_mii.mii_statchg = mtd_miibus_statchg;
        !           180:        ifmedia_init(&sc->sc_mii.mii_media, 0, mtd_ifmedia_upd,
        !           181:            mtd_ifmedia_sts);
        !           182:        mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
        !           183:            MII_OFFSET_ANY, 0);
        !           184:        if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
        !           185:                ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE, 0,
        !           186:                    NULL);
        !           187:                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
        !           188:        } else
        !           189:                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
        !           190:
        !           191:        /*
        !           192:         * Attach us everywhere
        !           193:         */
        !           194:        if_attach(ifp);
        !           195:        ether_ifattach(ifp);
        !           196: }
        !           197:
        !           198:
        !           199: static int
        !           200: mtd_ifmedia_upd(struct ifnet *ifp)
        !           201: {
        !           202:        struct mtd_softc *sc = ifp->if_softc;
        !           203:
        !           204:        return (mii_mediachg(&sc->sc_mii));
        !           205: }
        !           206:
        !           207:
        !           208: static void
        !           209: mtd_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
        !           210: {
        !           211:        struct mtd_softc *sc = ifp->if_softc;
        !           212:
        !           213:        mii_pollstat(&sc->sc_mii);
        !           214:        ifmr->ifm_active = sc->sc_mii.mii_media_active;
        !           215:        ifmr->ifm_status = sc->sc_mii.mii_media_status;
        !           216: }
        !           217:
        !           218:
        !           219: static u_int32_t
        !           220: mtd_mii_command(struct mtd_softc *sc, int opcode, int phy, int reg)
        !           221: {
        !           222:        u_int32_t miir, mask, data;
        !           223:        int i;
        !           224:
        !           225:        miir = (CSR_READ_4(MTD_MIIMGT) & ~MIIMGT_MASK) | MIIMGT_WRITE |
        !           226:            MIIMGT_MDO;
        !           227:
        !           228:        for (i = 0; i < 32; i++) {
        !           229:                miir &= ~MIIMGT_MDC;
        !           230:                CSR_WRITE_4(MTD_MIIMGT, miir);
        !           231:                miir |= MIIMGT_MDC;
        !           232:                CSR_WRITE_4(MTD_MIIMGT, miir);
        !           233:        }
        !           234:
        !           235:        data = opcode | (phy << 7) | (reg << 2);
        !           236:
        !           237:        for (mask = 0; mask; mask >>= 1) {
        !           238:                miir &= ~(MIIMGT_MDC | MIIMGT_MDO);
        !           239:                if (mask & data)
        !           240:                        miir |= MIIMGT_MDO;
        !           241:                CSR_WRITE_4(MTD_MIIMGT, miir);
        !           242:                miir |= MIIMGT_MDC;
        !           243:                CSR_WRITE_4(MTD_MIIMGT, miir);
        !           244:                DELAY(30);
        !           245:
        !           246:                if (mask == 0x4 && opcode == MII_OPCODE_RD)
        !           247:                        miir &= ~MIIMGT_WRITE;
        !           248:        }
        !           249:        return (miir);
        !           250: }
        !           251:
        !           252:
        !           253:
        !           254: static int
        !           255: mtd_miibus_readreg(struct device *self, int phy, int reg)
        !           256: {
        !           257:        struct mtd_softc *sc = (void *)self;
        !           258:
        !           259:        if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD803)
        !           260:                return (phy ? 0 : (int)CSR_READ_2(MTD_PHYCSR + (reg << 1)));
        !           261:        else {
        !           262:                u_int32_t miir, mask, data;
        !           263:
        !           264:                miir = mtd_mii_command(sc, MII_OPCODE_RD, phy, reg);
        !           265:                for (mask = 0x8000, data = 0; mask; mask >>= 1) {
        !           266:                        miir &= ~MIIMGT_MDC;
        !           267:                        CSR_WRITE_4(MTD_MIIMGT, miir);
        !           268:                        miir = CSR_READ_4(MTD_MIIMGT);
        !           269:                        if (miir & MIIMGT_MDI)
        !           270:                                data |= mask;
        !           271:                        miir |= MIIMGT_MDC;
        !           272:                        CSR_WRITE_4(MTD_MIIMGT, miir);
        !           273:                        DELAY(30);
        !           274:                }
        !           275:                miir &= ~MIIMGT_MDC;
        !           276:                CSR_WRITE_4(MTD_MIIMGT, miir);
        !           277:
        !           278:                return ((int)data);
        !           279:        }
        !           280: }
        !           281:
        !           282:
        !           283: static void
        !           284: mtd_miibus_writereg(struct device *self, int phy, int reg, int val)
        !           285: {
        !           286:        struct mtd_softc *sc = (void *)self;
        !           287:
        !           288:        if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD803) {
        !           289:                if (!phy)
        !           290:                        CSR_WRITE_2(MTD_PHYCSR + (reg << 1), val);
        !           291:        } else {
        !           292:                u_int32_t miir, mask;
        !           293:
        !           294:                miir = mtd_mii_command(sc, MII_OPCODE_WR, phy, reg);
        !           295:                for (mask = 0x8000; mask; mask >>= 1) {
        !           296:                        miir &= ~(MIIMGT_MDC | MIIMGT_MDO);
        !           297:                        if (mask & (u_int32_t)val)
        !           298:                                miir |= MIIMGT_MDO;
        !           299:                        CSR_WRITE_4(MTD_MIIMGT, miir);
        !           300:                        miir |= MIIMGT_MDC;
        !           301:                        CSR_WRITE_4(MTD_MIIMGT, miir);
        !           302:                        DELAY(1);
        !           303:                }
        !           304:                miir &= ~MIIMGT_MDC;
        !           305:                CSR_WRITE_4(MTD_MIIMGT, miir);
        !           306:        }
        !           307: }
        !           308:
        !           309:
        !           310: static void
        !           311: mtd_miibus_statchg(struct device *self)
        !           312: {
        !           313:        /* NOTHING */
        !           314: }
        !           315:
        !           316:
        !           317: void
        !           318: mtd_setmulti(struct mtd_softc *sc)
        !           319: {
        !           320:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           321:        u_int32_t rxfilt, crc, hash[2] = { 0, 0 };
        !           322:        struct ether_multistep step;
        !           323:        struct ether_multi *enm;
        !           324:        int mcnt = 0;
        !           325:
        !           326: allmulti:
        !           327:        rxfilt = CSR_READ_4(MTD_TCRRCR) & ~RCR_AM;
        !           328:        if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
        !           329:                rxfilt |= RCR_AM;
        !           330:                CSR_WRITE_4(MTD_TCRRCR, rxfilt);
        !           331:                CSR_WRITE_4(MTD_MAR0, 0xffffffff);
        !           332:                CSR_WRITE_4(MTD_MAR4, 0xffffffff);
        !           333:                return;
        !           334:        }
        !           335:
        !           336:        /* First, zot all the existing hash bits. */
        !           337:        CSR_WRITE_4(MTD_MAR0, 0);
        !           338:        CSR_WRITE_4(MTD_MAR4, 0);
        !           339:
        !           340:        /* Now program new ones. */
        !           341:        ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
        !           342:        while (enm != NULL) {
        !           343:                if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
        !           344:                        ifp->if_flags |= IFF_ALLMULTI;
        !           345:                        goto allmulti;
        !           346:                }
        !           347:                crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
        !           348:                hash[crc >> 5] |= 1 << (crc & 0xf);
        !           349:                ++mcnt;
        !           350:                ETHER_NEXT_MULTI(step, enm);
        !           351:        }
        !           352:
        !           353:        if (mcnt)
        !           354:                rxfilt |= RCR_AM;
        !           355:        CSR_WRITE_4(MTD_MAR0, hash[0]);
        !           356:        CSR_WRITE_4(MTD_MAR4, hash[1]);
        !           357:        CSR_WRITE_4(MTD_TCRRCR, rxfilt);
        !           358: }
        !           359:
        !           360:
        !           361: /*
        !           362:  * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
        !           363:  * pointers to the fragment pointers.
        !           364:  */
        !           365: int
        !           366: mtd_encap(struct mtd_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
        !           367: {
        !           368:        struct mtd_tx_desc *f = NULL;
        !           369:        int frag, cur, cnt = 0, i, total_len = 0;
        !           370:        bus_dmamap_t map;
        !           371:
        !           372:        /*
        !           373:         * Start packing the mbufs in this chain into
        !           374:         * the fragment pointers. Stop when we run out
        !           375:         * of fragments or hit the end of the mbuf chain.
        !           376:         */
        !           377:        map = sc->sc_tx_sparemap;
        !           378:
        !           379:        if (bus_dmamap_load_mbuf(sc->sc_dmat, map,
        !           380:            m_head, BUS_DMA_NOWAIT) != 0)
        !           381:                return (1);
        !           382:
        !           383:        cur = frag = *txidx;
        !           384:
        !           385:        for (i = 0; i < map->dm_nsegs; i++) {
        !           386:                if ((MTD_TX_LIST_CNT -
        !           387:                    (sc->mtd_cdata.mtd_tx_cnt + cnt)) < 5) {
        !           388:                        bus_dmamap_unload(sc->sc_dmat, map);
        !           389:                        return (1);
        !           390:                }
        !           391:
        !           392:                f = &sc->mtd_ldata->mtd_tx_list[frag];
        !           393:                f->td_tcw = htole32(map->dm_segs[i].ds_len);
        !           394:                total_len += map->dm_segs[i].ds_len;
        !           395:                if (cnt == 0) {
        !           396:                        f->td_tsw = 0;
        !           397:                        f->td_tcw |= htole32(TCW_FD | TCW_CRC | TCW_PAD);
        !           398:                } else
        !           399:                        f->td_tsw = htole32(TSW_OWN);
        !           400:                f->td_buf = htole32(map->dm_segs[i].ds_addr);
        !           401:                cur = frag;
        !           402:                frag = (frag + 1) % MTD_TX_LIST_CNT;
        !           403:                cnt++;
        !           404:        }
        !           405:
        !           406:        sc->mtd_cdata.mtd_tx_cnt += cnt;
        !           407:        sc->mtd_cdata.mtd_tx_chain[cur].sd_mbuf = m_head;
        !           408:        sc->sc_tx_sparemap = sc->mtd_cdata.mtd_tx_chain[cur].sd_map;
        !           409:        sc->mtd_cdata.mtd_tx_chain[cur].sd_map = map;
        !           410:        sc->mtd_ldata->mtd_tx_list[cur].td_tcw |= htole32(TCW_LD | TCW_IC);
        !           411:        if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD891)
        !           412:                sc->mtd_ldata->mtd_tx_list[cur].td_tcw |=
        !           413:                    htole32(TCW_EIC | TCW_RTLC);
        !           414:
        !           415:        bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
        !           416:            BUS_DMASYNC_PREWRITE);
        !           417:
        !           418:        sc->mtd_ldata->mtd_tx_list[*txidx].td_tsw = htole32(TSW_OWN);
        !           419:        sc->mtd_ldata->mtd_tx_list[*txidx].td_tcw |=
        !           420:            htole32(total_len << TCW_PKTS_SHIFT);
        !           421:
        !           422:        bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
        !           423:            offsetof(struct mtd_list_data, mtd_tx_list[0]),
        !           424:            sizeof(struct mtd_tx_desc) * MTD_TX_LIST_CNT,
        !           425:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           426:
        !           427:        *txidx = frag;
        !           428:
        !           429:        return (0);
        !           430: }
        !           431:
        !           432:
        !           433: /*
        !           434:  * Initialize the transmit descriptors.
        !           435:  */
        !           436: static void
        !           437: mtd_list_tx_init(struct mtd_softc *sc)
        !           438: {
        !           439:        struct mtd_chain_data *cd;
        !           440:        struct mtd_list_data *ld;
        !           441:        int i;
        !           442:
        !           443:        cd = &sc->mtd_cdata;
        !           444:        ld = sc->mtd_ldata;
        !           445:        for (i = 0; i < MTD_TX_LIST_CNT; i++) {
        !           446:                cd->mtd_tx_chain[i].sd_mbuf = NULL;
        !           447:                ld->mtd_tx_list[i].td_tsw = 0;
        !           448:                ld->mtd_tx_list[i].td_tcw = 0;
        !           449:                ld->mtd_tx_list[i].td_buf = 0;
        !           450:                ld->mtd_tx_list[i].td_next = htole32(
        !           451:                    sc->sc_listmap->dm_segs[0].ds_addr +
        !           452:                    offsetof(struct mtd_list_data,
        !           453:                    mtd_tx_list[(i + 1) % MTD_TX_LIST_CNT]));
        !           454:        }
        !           455:
        !           456:        cd->mtd_tx_prod = cd->mtd_tx_cons = cd->mtd_tx_cnt = 0;
        !           457: }
        !           458:
        !           459:
        !           460: /*
        !           461:  * Initialize the RX descriptors and allocate mbufs for them. Note that
        !           462:  * we arrange the descriptors in a closed ring, so that the last descriptor
        !           463:  * points back to the first.
        !           464:  */
        !           465: static int
        !           466: mtd_list_rx_init(struct mtd_softc *sc)
        !           467: {
        !           468:        struct mtd_list_data *ld;
        !           469:        int i;
        !           470:
        !           471:        ld = sc->mtd_ldata;
        !           472:
        !           473:        for (i = 0; i < MTD_RX_LIST_CNT; i++) {
        !           474:                if (mtd_newbuf(sc, i, NULL))
        !           475:                        return (1);
        !           476:                ld->mtd_rx_list[i].rd_next = htole32(
        !           477:                    sc->sc_listmap->dm_segs[0].ds_addr +
        !           478:                    offsetof(struct mtd_list_data,
        !           479:                    mtd_rx_list[(i + 1) % MTD_RX_LIST_CNT])
        !           480:                );
        !           481:        }
        !           482:
        !           483:        sc->mtd_cdata.mtd_rx_prod = 0;
        !           484:
        !           485:        return (0);
        !           486: }
        !           487:
        !           488:
        !           489: /*
        !           490:  * Initialize an RX descriptor and attach an MBUF cluster.
        !           491:  */
        !           492: static int
        !           493: mtd_newbuf(struct mtd_softc *sc, int i, struct mbuf *m)
        !           494: {
        !           495:        struct mbuf *m_new = NULL;
        !           496:        struct mtd_rx_desc *c;
        !           497:        bus_dmamap_t map;
        !           498:
        !           499:        c = &sc->mtd_ldata->mtd_rx_list[i];
        !           500:
        !           501:        if (m == NULL) {
        !           502:                MGETHDR(m_new, M_DONTWAIT, MT_DATA);
        !           503:                if (m_new == NULL)
        !           504:                        return (1);
        !           505:
        !           506:                MCLGET(m_new, M_DONTWAIT);
        !           507:                if (!(m_new->m_flags & M_EXT)) {
        !           508:                        m_freem(m_new);
        !           509:                        return (1);
        !           510:                }
        !           511:                m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
        !           512:                if (bus_dmamap_load(sc->sc_dmat, sc->sc_rx_sparemap,
        !           513:                    mtod(m_new, caddr_t), MCLBYTES, NULL,
        !           514:                    BUS_DMA_NOWAIT) != 0) {
        !           515:                        m_freem(m_new);
        !           516:                        return (1);
        !           517:                }
        !           518:                map = sc->mtd_cdata.mtd_rx_chain[i].sd_map;
        !           519:                sc->mtd_cdata.mtd_rx_chain[i].sd_map = sc->sc_rx_sparemap;
        !           520:                sc->sc_rx_sparemap = map;
        !           521:        } else {
        !           522:                m_new = m;
        !           523:                m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
        !           524:                m_new->m_data = m_new->m_ext.ext_buf;
        !           525:        }
        !           526:
        !           527:        m_adj(m_new, sizeof(u_int64_t));
        !           528:
        !           529:        bus_dmamap_sync(sc->sc_dmat, sc->mtd_cdata.mtd_rx_chain[i].sd_map, 0,
        !           530:            sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_mapsize,
        !           531:            BUS_DMASYNC_PREREAD);
        !           532:
        !           533:        sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf = m_new;
        !           534:        c->rd_buf = htole32(
        !           535:            sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_segs[0].ds_addr +
        !           536:            sizeof(u_int64_t));
        !           537:        c->rd_rcw = htole32(ETHER_MAX_DIX_LEN);
        !           538:        c->rd_rsr = htole32(RSR_OWN);
        !           539:
        !           540:        bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
        !           541:            offsetof(struct mtd_list_data, mtd_rx_list[i]),
        !           542:            sizeof(struct mtd_rx_desc),
        !           543:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           544:
        !           545:        return (0);
        !           546: }
        !           547:
        !           548:
        !           549: static void
        !           550: mtd_reset(struct mtd_softc *sc)
        !           551: {
        !           552:        int i;
        !           553:
        !           554:        /* Set software reset bit */
        !           555:        CSR_WRITE_4(MTD_BCR, BCR_SWR);
        !           556:
        !           557:        /*
        !           558:         * Wait until software reset completed.
        !           559:         */
        !           560:        for (i = 0; i < MTD_TIMEOUT; ++i) {
        !           561:                DELAY(10);
        !           562:                if (!(CSR_READ_4(MTD_BCR) & BCR_SWR)) {
        !           563:                        /*
        !           564:                         * Wait a little while for the chip to get
        !           565:                         * its brains in order.
        !           566:                         */
        !           567:                        DELAY(1000);
        !           568:                        return;
        !           569:                }
        !           570:        }
        !           571:
        !           572:        /* Reset timed out. */
        !           573:        printf("%s: reset never completed!\n", sc->sc_dev.dv_xname);
        !           574: }
        !           575:
        !           576:
        !           577: static int
        !           578: mtd_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
        !           579: {
        !           580:        struct mtd_softc *sc = ifp->if_softc;
        !           581:        struct ifreq *ifr = (struct ifreq *)data;
        !           582:        struct ifaddr *ifa = (struct ifaddr *)data;
        !           583:        int s, error;
        !           584:
        !           585:        s = splnet();
        !           586:        if ((error = ether_ioctl(ifp, &sc->sc_arpcom, command, data)) > 0) {
        !           587:                splx(s);
        !           588:                return (error);
        !           589:        }
        !           590:
        !           591:        switch (command) {
        !           592:        case SIOCSIFADDR:
        !           593:                ifp->if_flags |= IFF_UP;
        !           594:                mtd_init(ifp);
        !           595:                switch (ifa->ifa_addr->sa_family) {
        !           596: #ifdef INET
        !           597:                case AF_INET:
        !           598:                        arp_ifinit(&sc->sc_arpcom, ifa);
        !           599:                        break;
        !           600: #endif /* INET */
        !           601:                }
        !           602:                break;
        !           603:        case SIOCSIFMTU:
        !           604:                if (ifr->ifr_mtu >= ETHERMIN && ifr->ifr_mtu <= ETHERMTU)
        !           605:                        ifp->if_mtu = ifr->ifr_mtu;
        !           606:                else
        !           607:                        error = EINVAL;
        !           608:                break;
        !           609:
        !           610:        case SIOCSIFFLAGS:
        !           611:                if (ifp->if_flags & IFF_UP)
        !           612:                        mtd_init(ifp);
        !           613:                else {
        !           614:                        if (ifp->if_flags & IFF_RUNNING)
        !           615:                                mtd_stop(ifp);
        !           616:                }
        !           617:                error = 0;
        !           618:                break;
        !           619:        case SIOCADDMULTI:
        !           620:        case SIOCDELMULTI:
        !           621:                error = (command == SIOCADDMULTI) ?
        !           622:                    ether_addmulti(ifr, &sc->sc_arpcom) :
        !           623:                    ether_delmulti(ifr, &sc->sc_arpcom);
        !           624:
        !           625:                if (error == ENETRESET) {
        !           626:                        /*
        !           627:                         * Multicast list has changed; set the hardware
        !           628:                         * filter accordingly.
        !           629:                         */
        !           630:                        if (ifp->if_flags & IFF_RUNNING)
        !           631:                                mtd_setmulti(sc);
        !           632:                        error = 0;
        !           633:                }
        !           634:                break;
        !           635:        case SIOCGIFMEDIA:
        !           636:        case SIOCSIFMEDIA:
        !           637:                error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
        !           638:                break;
        !           639:        default:
        !           640:                error = EINVAL;
        !           641:                break;
        !           642:        }
        !           643:
        !           644:        splx(s);
        !           645:        return (error);
        !           646: }
        !           647:
        !           648:
        !           649: static void
        !           650: mtd_init(struct ifnet *ifp)
        !           651: {
        !           652:        struct mtd_softc *sc = ifp->if_softc;
        !           653:        int s;
        !           654:
        !           655:        s = splnet();
        !           656:
        !           657:        /*
        !           658:         * Cancel pending I/O and free all RX/TX buffers.
        !           659:         */
        !           660:        mtd_stop(ifp);
        !           661:
        !           662:        /*
        !           663:         * Set cache alignment and burst length.
        !           664:         */
        !           665:        CSR_WRITE_4(MTD_BCR, BCR_PBL8);
        !           666:        CSR_WRITE_4(MTD_TCRRCR, TCR_TFTSF | RCR_RBLEN | RCR_RPBL512);
        !           667:        if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD891) {
        !           668:                CSR_SETBIT(MTD_BCR, BCR_PROG);
        !           669:                CSR_SETBIT(MTD_TCRRCR, TCR_ENHANCED);
        !           670:        }
        !           671:
        !           672:        if (ifp->if_flags & IFF_PROMISC)
        !           673:                CSR_SETBIT(MTD_TCRRCR, RCR_PROM);
        !           674:        else
        !           675:                CSR_CLRBIT(MTD_TCRRCR, RCR_PROM);
        !           676:
        !           677:        if (ifp->if_flags & IFF_BROADCAST)
        !           678:                CSR_SETBIT(MTD_TCRRCR, RCR_AB);
        !           679:        else
        !           680:                CSR_CLRBIT(MTD_TCRRCR, RCR_AB);
        !           681:
        !           682:        mtd_setmulti(sc);
        !           683:
        !           684:        if (mtd_list_rx_init(sc)) {
        !           685:                printf("%s: can't allocate memeory for rx buffers\n",
        !           686:                    sc->sc_dev.dv_xname);
        !           687:                splx(s);
        !           688:                return;
        !           689:        }
        !           690:        mtd_list_tx_init(sc);
        !           691:
        !           692:        CSR_WRITE_4(MTD_RXLBA, sc->sc_listmap->dm_segs[0].ds_addr +
        !           693:            offsetof(struct mtd_list_data, mtd_rx_list[0]));
        !           694:        CSR_WRITE_4(MTD_TXLBA, sc->sc_listmap->dm_segs[0].ds_addr +
        !           695:            offsetof(struct mtd_list_data, mtd_tx_list[0]));
        !           696:
        !           697:        /*
        !           698:         * Enable interrupts.
        !           699:         */
        !           700:        CSR_WRITE_4(MTD_IMR, IMR_INTRS);
        !           701:        CSR_WRITE_4(MTD_ISR, 0xffffffff);
        !           702:
        !           703:        /* Enable receiver and transmitter */
        !           704:        CSR_SETBIT(MTD_TCRRCR, TCR_TE | RCR_RE);
        !           705:        CSR_WRITE_4(MTD_RXPDR, 0xffffffff);
        !           706:
        !           707:        ifp->if_flags |= IFF_RUNNING;
        !           708:        ifp->if_flags &= ~IFF_OACTIVE;
        !           709:        splx(s);
        !           710: }
        !           711:
        !           712:
        !           713: /*
        !           714:  * Main transmit routine. To avoid having to do mbuf copies, we put pointers
        !           715:  * to the mbuf data regions directly in the transmit lists. We also save a
        !           716:  * copy of the pointers since the transmit list fragment pointers are
        !           717:  * physical addresses.
        !           718:  */
        !           719: static void
        !           720: mtd_start(struct ifnet *ifp)
        !           721: {
        !           722:        struct mtd_softc *sc = ifp->if_softc;
        !           723:        struct mbuf *m_head = NULL;
        !           724:        int idx;
        !           725:
        !           726:        if (sc->mtd_cdata.mtd_tx_cnt) {
        !           727:                ifp->if_flags |= IFF_OACTIVE;
        !           728:                return;
        !           729:        }
        !           730:
        !           731:        idx = sc->mtd_cdata.mtd_tx_prod;
        !           732:        while (sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf == NULL) {
        !           733:                IFQ_DEQUEUE(&ifp->if_snd, m_head);
        !           734:                if (m_head == NULL)
        !           735:                        break;
        !           736:
        !           737:                if (mtd_encap(sc, m_head, &idx)) {
        !           738:                        ifp->if_flags |= IFF_OACTIVE;
        !           739:                        break;
        !           740:                }
        !           741:
        !           742:                /*
        !           743:                 * If there's a BPF listener, bounce a copy of this frame
        !           744:                 * to him.
        !           745:                 */
        !           746: #if NBPFILTER > 0
        !           747:                if (ifp->if_bpf != NULL)
        !           748:                        bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
        !           749: #endif
        !           750:        }
        !           751:
        !           752:        if (idx == sc->mtd_cdata.mtd_tx_prod)
        !           753:                return;
        !           754:
        !           755:        /* Transmit */
        !           756:        sc->mtd_cdata.mtd_tx_prod = idx;
        !           757:        CSR_WRITE_4(MTD_TXPDR, 0xffffffff);
        !           758:
        !           759:        /*
        !           760:         * Set a timeout in case the chip goes out to lunch.
        !           761:         */
        !           762:        ifp->if_timer = 5;
        !           763: }
        !           764:
        !           765:
        !           766: static void
        !           767: mtd_stop(struct ifnet *ifp)
        !           768: {
        !           769:        struct mtd_softc *sc = ifp->if_softc;
        !           770:        int i;
        !           771:
        !           772:        ifp->if_timer = 0;
        !           773:        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
        !           774:
        !           775:        CSR_CLRBIT(MTD_TCRRCR, (RCR_RE | TCR_TE));
        !           776:        CSR_WRITE_4(MTD_IMR, 0);
        !           777:        CSR_WRITE_4(MTD_TXLBA, 0);
        !           778:        CSR_WRITE_4(MTD_RXLBA, 0);
        !           779:
        !           780:        /*
        !           781:         * Free data in the RX lists.
        !           782:         */
        !           783:        for (i = 0; i < MTD_RX_LIST_CNT; i++) {
        !           784:                if (sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_nsegs != 0) {
        !           785:                        bus_dmamap_t map = sc->mtd_cdata.mtd_rx_chain[i].sd_map;
        !           786:
        !           787:                        bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
        !           788:                            BUS_DMASYNC_POSTREAD);
        !           789:                        bus_dmamap_unload(sc->sc_dmat, map);
        !           790:                }
        !           791:                if (sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf != NULL) {
        !           792:                        m_freem(sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf);
        !           793:                        sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf = NULL;
        !           794:                }
        !           795:        }
        !           796:        bzero((char *)&sc->mtd_ldata->mtd_rx_list,
        !           797:                sizeof(sc->mtd_ldata->mtd_rx_list));
        !           798:
        !           799:        /*
        !           800:         * Free the TX list buffers.
        !           801:         */
        !           802:        for (i = 0; i < MTD_TX_LIST_CNT; i++) {
        !           803:                if (sc->mtd_cdata.mtd_tx_chain[i].sd_map->dm_nsegs != 0) {
        !           804:                        bus_dmamap_t map = sc->mtd_cdata.mtd_tx_chain[i].sd_map;
        !           805:
        !           806:                        bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
        !           807:                            BUS_DMASYNC_POSTWRITE);
        !           808:                        bus_dmamap_unload(sc->sc_dmat, map);
        !           809:                }
        !           810:                if (sc->mtd_cdata.mtd_tx_chain[i].sd_mbuf != NULL) {
        !           811:                        m_freem(sc->mtd_cdata.mtd_tx_chain[i].sd_mbuf);
        !           812:                        sc->mtd_cdata.mtd_tx_chain[i].sd_mbuf = NULL;
        !           813:                }
        !           814:        }
        !           815:
        !           816:        bzero((char *)&sc->mtd_ldata->mtd_tx_list,
        !           817:                sizeof(sc->mtd_ldata->mtd_tx_list));
        !           818:
        !           819: }
        !           820:
        !           821:
        !           822: static void
        !           823: mtd_watchdog(struct ifnet *ifp)
        !           824: {
        !           825:        struct mtd_softc *sc = ifp->if_softc;
        !           826:
        !           827:        ifp->if_oerrors++;
        !           828:        printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
        !           829:
        !           830:        mtd_stop(ifp);
        !           831:        mtd_reset(sc);
        !           832:        mtd_init(ifp);
        !           833:
        !           834:        if (!IFQ_IS_EMPTY(&ifp->if_snd))
        !           835:                mtd_start(ifp);
        !           836: }
        !           837:
        !           838:
        !           839: int
        !           840: mtd_intr(void *xsc)
        !           841: {
        !           842:        struct mtd_softc *sc = xsc;
        !           843:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !           844:        u_int32_t status;
        !           845:        int claimed = 0;
        !           846:
        !           847:        /* Supress unwanted interrupts */
        !           848:        if (!(ifp->if_flags & IFF_RUNNING)) {
        !           849:                if (CSR_READ_4(MTD_ISR) & ISR_INTRS)
        !           850:                        mtd_stop(ifp);
        !           851:                return (claimed);
        !           852:        }
        !           853:
        !           854:        /* Disable interrupts. */
        !           855:        CSR_WRITE_4(MTD_IMR, 0);
        !           856:
        !           857:        while((status = CSR_READ_4(MTD_ISR)) & ISR_INTRS) {
        !           858:                claimed = 1;
        !           859:
        !           860:                CSR_WRITE_4(MTD_ISR, status);
        !           861:
        !           862:                /* RX interrupt. */
        !           863:                if (status & ISR_RI) {
        !           864:                        int curpkts = ifp->if_ipackets;
        !           865:
        !           866:                        mtd_rxeof(sc);
        !           867:                        if (curpkts == ifp->if_ipackets)
        !           868:                                while(mtd_rx_resync(sc))
        !           869:                                        mtd_rxeof(sc);
        !           870:                }
        !           871:
        !           872:                /* RX error interrupt. */
        !           873:                if (status & (ISR_RXERI | ISR_RBU))
        !           874:                        ifp->if_ierrors++;
        !           875:
        !           876:                /* TX interrupt. */
        !           877:                if (status & (ISR_TI | ISR_ETI | ISR_TBU))
        !           878:                        mtd_txeof(sc);
        !           879:
        !           880:                /* Fatal bus error interrupt. */
        !           881:                if (status & ISR_FBE) {
        !           882:                        mtd_reset(sc);
        !           883:                        mtd_start(ifp);
        !           884:                }
        !           885:        }
        !           886:
        !           887:        /* Re-enable interrupts. */
        !           888:        CSR_WRITE_4(MTD_IMR, IMR_INTRS);
        !           889:
        !           890:        if (!IFQ_IS_EMPTY(&ifp->if_snd))
        !           891:                mtd_start(ifp);
        !           892:
        !           893:        return (claimed);
        !           894: }
        !           895:
        !           896:
        !           897: /*
        !           898:  * A frame has been uploaded: pass the resulting mbuf chain up to
        !           899:  * the higher level protocols.
        !           900:  */
        !           901: static void
        !           902: mtd_rxeof(struct mtd_softc *sc)
        !           903: {
        !           904:        struct mbuf *m;
        !           905:        struct ifnet *ifp;
        !           906:        struct mtd_rx_desc *cur_rx;
        !           907:        int i, total_len = 0;
        !           908:        u_int32_t rxstat;
        !           909:
        !           910:        ifp = &sc->sc_arpcom.ac_if;
        !           911:        i = sc->mtd_cdata.mtd_rx_prod;
        !           912:
        !           913:        while(!(sc->mtd_ldata->mtd_rx_list[i].rd_rsr & htole32(RSR_OWN))) {
        !           914:                struct mbuf *m0 = NULL;
        !           915:
        !           916:                bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
        !           917:                    offsetof(struct mtd_list_data, mtd_rx_list[i]),
        !           918:                    sizeof(struct mtd_rx_desc),
        !           919:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !           920:
        !           921:                cur_rx = &sc->mtd_ldata->mtd_rx_list[i];
        !           922:                rxstat = letoh32(cur_rx->rd_rsr);
        !           923:                m = sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf;
        !           924:                total_len = RSR_FLNG_GET(rxstat);
        !           925:
        !           926:                sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf = NULL;
        !           927:
        !           928:                /*
        !           929:                 * If an error occurs, update stats, clear the
        !           930:                 * status word and leave the mbuf cluster in place:
        !           931:                 * it should simply get re-used next time this descriptor
        !           932:                 * comes up in the ring.
        !           933:                 */
        !           934:                if (rxstat & RSR_RXER) {
        !           935:                        ifp->if_ierrors++;
        !           936:                        mtd_newbuf(sc, i, m);
        !           937:                        if (rxstat & RSR_CRC) {
        !           938:                                i = (i + 1) % MTD_RX_LIST_CNT;
        !           939:                                continue;
        !           940:                        } else {
        !           941:                                mtd_init(ifp);
        !           942:                                return;
        !           943:                        }
        !           944:                }
        !           945:
        !           946:                /* No errors; receive the packet. */
        !           947:                total_len -= ETHER_CRC_LEN;
        !           948:
        !           949:                bus_dmamap_sync(sc->sc_dmat, sc->mtd_cdata.mtd_rx_chain[i].sd_map,
        !           950:                    0, sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_mapsize,
        !           951:                    BUS_DMASYNC_POSTREAD);
        !           952:
        !           953:                m0 = m_devget(mtod(m, char *) - ETHER_ALIGN, total_len + ETHER_ALIGN,
        !           954:                    0, ifp, NULL);
        !           955:                mtd_newbuf(sc, i, m);
        !           956:                i = (i + 1) % MTD_RX_LIST_CNT;
        !           957:                if (m0 == NULL) {
        !           958:                        ifp->if_ierrors++;
        !           959:                        continue;
        !           960:                }
        !           961:                m_adj(m0, ETHER_ALIGN);
        !           962:                m = m0;
        !           963:
        !           964:                ifp->if_ipackets++;
        !           965:
        !           966: #if NBPFILTER > 0
        !           967:                if (ifp->if_bpf)
        !           968:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
        !           969: #endif
        !           970:                ether_input_mbuf(ifp, m);
        !           971:        }
        !           972:
        !           973:        sc->mtd_cdata.mtd_rx_prod = i;
        !           974: }
        !           975:
        !           976:
        !           977: /*
        !           978:  * This routine searches the RX ring for dirty descriptors in the
        !           979:  * event that the rxeof routine falls out of sync with the chip's
        !           980:  * current descriptor pointer. This may happen sometimes as a result
        !           981:  * of a "no RX buffer available" condition that happens when the chip
        !           982:  * consumes all of the RX buffers before the driver has a chance to
        !           983:  * process the RX ring. This routine may need to be called more than
        !           984:  * once to bring the driver back in sync with the chip, however we
        !           985:  * should still be getting RX DONE interrupts to drive the search
        !           986:  * for new packets in the RX ring, so we should catch up eventually.
        !           987:  */
        !           988: static int
        !           989: mtd_rx_resync(sc)
        !           990:        struct mtd_softc *sc;
        !           991: {
        !           992:        int i, pos;
        !           993:        struct mtd_rx_desc *cur_rx;
        !           994:
        !           995:        pos = sc->mtd_cdata.mtd_rx_prod;
        !           996:
        !           997:        for (i = 0; i < MTD_RX_LIST_CNT; i++) {
        !           998:                bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
        !           999:                    offsetof(struct mtd_list_data, mtd_rx_list[pos]),
        !          1000:                    sizeof(struct mtd_rx_desc),
        !          1001:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !          1002:
        !          1003:                cur_rx = &sc->mtd_ldata->mtd_rx_list[pos];
        !          1004:                if (!(cur_rx->rd_rsr & htole32(RSR_OWN)))
        !          1005:                        break;
        !          1006:                pos = (pos + 1) % MTD_RX_LIST_CNT;
        !          1007:        }
        !          1008:
        !          1009:        /* If the ring really is empty, then just return. */
        !          1010:        if (i == MTD_RX_LIST_CNT)
        !          1011:                return (0);
        !          1012:
        !          1013:        /* We've fallen behind the chip: catch it. */
        !          1014:        sc->mtd_cdata.mtd_rx_prod = pos;
        !          1015:
        !          1016:        return (EAGAIN);
        !          1017: }
        !          1018:
        !          1019:
        !          1020: /*
        !          1021:  * A frame was downloaded to the chip. It's safe for us to clean up
        !          1022:  * the list buffers.
        !          1023:  */
        !          1024: static void
        !          1025: mtd_txeof(struct mtd_softc *sc)
        !          1026: {
        !          1027:        struct mtd_tx_desc *cur_tx = NULL;
        !          1028:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        !          1029:        int idx;
        !          1030:
        !          1031:        /* Clear the timeout timer. */
        !          1032:        ifp->if_timer = 0;
        !          1033:
        !          1034:        /*
        !          1035:         * Go through our tx list and free mbufs for those
        !          1036:         * frames that have been transmitted.
        !          1037:         */
        !          1038:        idx = sc->mtd_cdata.mtd_tx_cons;
        !          1039:        while(idx != sc->mtd_cdata.mtd_tx_prod) {
        !          1040:                u_int32_t txstat;
        !          1041:
        !          1042:                bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
        !          1043:                    offsetof(struct mtd_list_data, mtd_tx_list[idx]),
        !          1044:                    sizeof(struct mtd_tx_desc),
        !          1045:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !          1046:
        !          1047:                cur_tx = &sc->mtd_ldata->mtd_tx_list[idx];
        !          1048:                txstat = letoh32(cur_tx->td_tsw);
        !          1049:
        !          1050:                if (txstat & TSW_OWN || txstat == TSW_UNSENT)
        !          1051:                        break;
        !          1052:
        !          1053:                if (!(cur_tx->td_tcw & htole32(TCW_LD))) {
        !          1054:                        sc->mtd_cdata.mtd_tx_cnt--;
        !          1055:                        idx = (idx + 1) % MTD_TX_LIST_CNT;
        !          1056:                        continue;
        !          1057:                }
        !          1058:
        !          1059:                if (CSR_READ_4(MTD_TCRRCR) & TCR_ENHANCED)
        !          1060:                        ifp->if_collisions += TSR_NCR_GET(CSR_READ_4(MTD_TSR));
        !          1061:                else {
        !          1062:                        if (txstat & TSW_TXERR) {
        !          1063:                                ifp->if_oerrors++;
        !          1064:                                if (txstat & TSW_EC)
        !          1065:                                        ifp->if_collisions++;
        !          1066:                                if (txstat & TSW_LC)
        !          1067:                                        ifp->if_collisions++;
        !          1068:                        }
        !          1069:                        ifp->if_collisions += TSW_NCR_GET(txstat);
        !          1070:                }
        !          1071:
        !          1072:                ifp->if_opackets++;
        !          1073:                if (sc->mtd_cdata.mtd_tx_chain[idx].sd_map->dm_nsegs != 0) {
        !          1074:                        bus_dmamap_t map =
        !          1075:                            sc->mtd_cdata.mtd_tx_chain[idx].sd_map;
        !          1076:                        bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
        !          1077:                            BUS_DMASYNC_POSTWRITE);
        !          1078:                        bus_dmamap_unload(sc->sc_dmat, map);
        !          1079:                }
        !          1080:                if (sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf != NULL) {
        !          1081:                        m_freem(sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf);
        !          1082:                        sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf = NULL;
        !          1083:                }
        !          1084:                sc->mtd_cdata.mtd_tx_cnt--;
        !          1085:                idx = (idx + 1) % MTD_TX_LIST_CNT;
        !          1086:        }
        !          1087:
        !          1088:        if (cur_tx != NULL) {
        !          1089:                ifp->if_flags &= ~IFF_OACTIVE;
        !          1090:                sc->mtd_cdata.mtd_tx_cons = idx;
        !          1091:        } else
        !          1092:                if (sc->mtd_ldata->mtd_tx_list[idx].td_tsw ==
        !          1093:                    htole32(TSW_UNSENT)) {
        !          1094:                        sc->mtd_ldata->mtd_tx_list[idx].td_tsw =
        !          1095:                            htole32(TSW_OWN);
        !          1096:                        ifp->if_timer = 5;
        !          1097:                        CSR_WRITE_4(MTD_TXPDR, 0xffffffff);
        !          1098:                }
        !          1099: }
        !          1100:
        !          1101: struct cfdriver mtd_cd = {
        !          1102:        0, "mtd", DV_IFNET
        !          1103: };

CVSweb