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

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

1.1     ! nbrk        1: /*     $OpenBSD: if_le_ledma.c,v 1.13 2007/05/31 17:23:14 sobrado Exp $        */
        !             2: /*     $NetBSD: if_le_ledma.c,v 1.14 2001/05/30 11:46:35 mrg Exp $     */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
        !            10:  * Simulation Facility, NASA Ames Research Center; Paul Kranenburg.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *     This product includes software developed by the NetBSD
        !            23:  *     Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: #include "bpfilter.h"
        !            42:
        !            43: #include <sys/param.h>
        !            44: #include <sys/systm.h>
        !            45: #include <sys/mbuf.h>
        !            46: #include <sys/syslog.h>
        !            47: #include <sys/socket.h>
        !            48: #include <sys/device.h>
        !            49: #include <sys/malloc.h>
        !            50:
        !            51: #include <net/if.h>
        !            52: #include <net/if_media.h>
        !            53:
        !            54: #ifdef INET
        !            55: #include <netinet/in.h>
        !            56: #include <netinet/if_ether.h>
        !            57: #endif
        !            58:
        !            59: #include <machine/bus.h>
        !            60: #include <machine/intr.h>
        !            61: #include <machine/autoconf.h>
        !            62:
        !            63: #include <dev/sbus/sbusvar.h>
        !            64:
        !            65: #include <dev/ic/lsi64854reg.h>
        !            66: #include <dev/ic/lsi64854var.h>
        !            67:
        !            68: #include <dev/ic/am7990reg.h>
        !            69: #include <dev/ic/am7990var.h>
        !            70:
        !            71: /*
        !            72:  * LANCE registers.
        !            73:  */
        !            74: #define LEREG1_RDP     0       /* Register Data port */
        !            75: #define LEREG1_RAP     2       /* Register Address port */
        !            76:
        !            77: struct le_softc {
        !            78:        struct  am7990_softc    sc_am7990;      /* glue to MI code */
        !            79:        bus_space_tag_t         sc_bustag;
        !            80:        bus_dmamap_t            sc_dmamap;
        !            81:        bus_space_handle_t      sc_reg;         /* LANCE registers */
        !            82:        struct  lsi64854_softc  *sc_dma;        /* pointer to my dma */
        !            83:        u_int                   sc_laddr;       /* LANCE DMA address */
        !            84: };
        !            85:
        !            86: #define MEMSIZE                (16*1024)       /* LANCE memory size */
        !            87: #define LEDMA_BOUNDARY (16*1024*1024)  /* must not cross 16MB boundary */
        !            88:
        !            89: int    lematch_ledma(struct device *, void *, void *);
        !            90: void   leattach_ledma(struct device *, struct device *, void *);
        !            91:
        !            92: /*
        !            93:  * Media types supported by the Sun4m.
        !            94:  */
        !            95:
        !            96: void   le_ledma_setutp(struct am7990_softc *);
        !            97: void   le_ledma_setaui(struct am7990_softc *);
        !            98:
        !            99: int    lemediachange(struct ifnet *);
        !           100: void   lemediastatus(struct ifnet *, struct ifmediareq *);
        !           101:
        !           102: struct cfattach le_ledma_ca = {
        !           103:        sizeof(struct le_softc), lematch_ledma, leattach_ledma
        !           104: };
        !           105:
        !           106: void le_ledma_wrcsr(struct am7990_softc *, u_int16_t, u_int16_t);
        !           107: u_int16_t le_ledma_rdcsr(struct am7990_softc *, u_int16_t);
        !           108: void le_ledma_hwreset(struct am7990_softc *);
        !           109: void le_ledma_hwinit(struct am7990_softc *);
        !           110: void le_ledma_nocarrier(struct am7990_softc *);
        !           111:
        !           112: void
        !           113: le_ledma_wrcsr(struct am7990_softc *sc, u_int16_t port, u_int16_t val)
        !           114: {
        !           115:        struct le_softc *lesc = (struct le_softc *)sc;
        !           116:
        !           117:        bus_space_write_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, port);
        !           118:        bus_space_barrier(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, 2,
        !           119:            BUS_SPACE_BARRIER_WRITE);
        !           120:        bus_space_write_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RDP, val);
        !           121:        bus_space_barrier(lesc->sc_bustag, lesc->sc_reg, LEREG1_RDP, 2,
        !           122:            BUS_SPACE_BARRIER_WRITE);
        !           123:
        !           124: #if defined(SUN4M)
        !           125:        /*
        !           126:         * We need to flush the SBus->MBus write buffers. This can most
        !           127:         * easily be accomplished by reading back the register that we
        !           128:         * just wrote (thanks to Chris Torek for this solution).
        !           129:         */
        !           130:        if (CPU_ISSUN4M) {
        !           131:                volatile u_int16_t discard;
        !           132:                discard = bus_space_read_2(lesc->sc_bustag, lesc->sc_reg,
        !           133:                                           LEREG1_RDP);
        !           134:        }
        !           135: #endif
        !           136: }
        !           137:
        !           138: u_int16_t
        !           139: le_ledma_rdcsr(struct am7990_softc *sc, u_int16_t port)
        !           140: {
        !           141:        struct le_softc *lesc = (struct le_softc *)sc;
        !           142:
        !           143:        bus_space_write_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, port);
        !           144:        bus_space_barrier(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, 2,
        !           145:            BUS_SPACE_BARRIER_WRITE);
        !           146:        return (bus_space_read_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RDP));
        !           147: }
        !           148:
        !           149: void
        !           150: le_ledma_setutp(struct am7990_softc *sc)
        !           151: {
        !           152:        struct lsi64854_softc *dma = ((struct le_softc *)sc)->sc_dma;
        !           153:        u_int32_t csr;
        !           154:
        !           155:        csr = L64854_GCSR(dma);
        !           156:        csr |= E_TP_AUI;
        !           157:        L64854_SCSR(dma, csr);
        !           158:        delay(20000);   /* must not touch le for 20ms */
        !           159: }
        !           160:
        !           161: void
        !           162: le_ledma_setaui(struct am7990_softc *sc)
        !           163: {
        !           164:        struct lsi64854_softc *dma = ((struct le_softc *)sc)->sc_dma;
        !           165:        u_int32_t csr;
        !           166:
        !           167:        csr = L64854_GCSR(dma);
        !           168:        csr &= ~E_TP_AUI;
        !           169:        L64854_SCSR(dma, csr);
        !           170:        delay(20000);   /* must not touch le for 20ms */
        !           171: }
        !           172:
        !           173: int
        !           174: lemediachange(struct ifnet *ifp)
        !           175: {
        !           176:        struct am7990_softc *sc = ifp->if_softc;
        !           177:        struct ifmedia *ifm = &sc->sc_ifmedia;
        !           178:
        !           179:        if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
        !           180:                return (EINVAL);
        !           181:
        !           182:        /*
        !           183:         * Switch to the selected media.  If autoselect is
        !           184:         * set, we don't really have to do anything.  We'll
        !           185:         * switch to the other media when we detect loss of
        !           186:         * carrier.
        !           187:         */
        !           188:        switch (IFM_SUBTYPE(ifm->ifm_media)) {
        !           189:        case IFM_10_T:
        !           190:                le_ledma_setutp(sc);
        !           191:                break;
        !           192:
        !           193:        case IFM_10_5:
        !           194:                le_ledma_setaui(sc);
        !           195:                break;
        !           196:
        !           197:        case IFM_AUTO:
        !           198:                break;
        !           199:
        !           200:        default:
        !           201:                return (EINVAL);
        !           202:        }
        !           203:
        !           204:        return (0);
        !           205: }
        !           206:
        !           207: void
        !           208: lemediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
        !           209: {
        !           210:        struct am7990_softc *sc = ifp->if_softc;
        !           211:        struct lsi64854_softc *dma = ((struct le_softc *)sc)->sc_dma;
        !           212:
        !           213:        /*
        !           214:         * Notify the world which media we're currently using.
        !           215:         */
        !           216:        if (L64854_GCSR(dma) & E_TP_AUI)
        !           217:                ifmr->ifm_active = IFM_ETHER|IFM_10_T;
        !           218:        else
        !           219:                ifmr->ifm_active = IFM_ETHER|IFM_10_5;
        !           220: }
        !           221:
        !           222: void
        !           223: le_ledma_hwreset(struct am7990_softc *sc)
        !           224: {
        !           225:        struct le_softc *lesc = (struct le_softc *)sc;
        !           226:        struct lsi64854_softc *dma = lesc->sc_dma;
        !           227:        u_int32_t csr;
        !           228:        u_int aui_bit;
        !           229:
        !           230:        /*
        !           231:         * Reset DMA channel.
        !           232:         */
        !           233:        csr = L64854_GCSR(dma);
        !           234:        aui_bit = csr & E_TP_AUI;
        !           235:        DMA_RESET(dma);
        !           236:
        !           237:        /* Write bits 24-31 of Lance address */
        !           238:        bus_space_write_4(dma->sc_bustag, dma->sc_regs, L64854_REG_ENBAR,
        !           239:                          lesc->sc_laddr & 0xff000000);
        !           240:
        !           241:        DMA_ENINTR(dma);
        !           242:
        !           243:        /*
        !           244:         * Disable E-cache invalidates on chip writes.
        !           245:         * Retain previous cable selection bit.
        !           246:         */
        !           247:        csr = L64854_GCSR(dma);
        !           248:        csr |= (E_DSBL_WR_INVAL | aui_bit);
        !           249:        L64854_SCSR(dma, csr);
        !           250:        delay(20000);   /* must not touch le for 20ms */
        !           251: }
        !           252:
        !           253: void
        !           254: le_ledma_hwinit(struct am7990_softc *sc)
        !           255: {
        !           256:
        !           257:        /*
        !           258:         * Make sure we're using the currently-enabled media type.
        !           259:         * XXX Actually, this is probably unnecessary, now.
        !           260:         */
        !           261:        switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_cur->ifm_media)) {
        !           262:        case IFM_10_T:
        !           263:                le_ledma_setutp(sc);
        !           264:                break;
        !           265:
        !           266:        case IFM_10_5:
        !           267:                le_ledma_setaui(sc);
        !           268:                break;
        !           269:        }
        !           270: }
        !           271:
        !           272: void
        !           273: le_ledma_nocarrier(struct am7990_softc *sc)
        !           274: {
        !           275:        struct le_softc *lesc = (struct le_softc *)sc;
        !           276:
        !           277:        /*
        !           278:         * Check if the user has requested a certain cable type, and
        !           279:         * if so, honor that request.
        !           280:         */
        !           281:
        !           282:        if (L64854_GCSR(lesc->sc_dma) & E_TP_AUI) {
        !           283:                switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
        !           284:                case IFM_10_5:
        !           285:                case IFM_AUTO:
        !           286:                        printf("%s: lost carrier on UTP port"
        !           287:                            ", switching to AUI port\n", sc->sc_dev.dv_xname);
        !           288:                        le_ledma_setaui(sc);
        !           289:                }
        !           290:        } else {
        !           291:                switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
        !           292:                case IFM_10_T:
        !           293:                case IFM_AUTO:
        !           294:                        printf("%s: lost carrier on AUI port"
        !           295:                            ", switching to UTP port\n", sc->sc_dev.dv_xname);
        !           296:                        le_ledma_setutp(sc);
        !           297:                }
        !           298:        }
        !           299: }
        !           300:
        !           301: int
        !           302: lematch_ledma(struct device *parent, void *vcf, void *aux)
        !           303: {
        !           304:        struct cfdata *cf = vcf;
        !           305:        struct sbus_attach_args *sa = aux;
        !           306:
        !           307:        return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
        !           308: }
        !           309:
        !           310:
        !           311: void
        !           312: leattach_ledma(struct device *parent, struct device *self, void *aux)
        !           313: {
        !           314:        struct sbus_attach_args *sa = aux;
        !           315:        struct le_softc *lesc = (struct le_softc *)self;
        !           316:        struct lsi64854_softc *lsi = (struct lsi64854_softc *)parent;
        !           317:        struct am7990_softc *sc = &lesc->sc_am7990;
        !           318:        bus_dma_tag_t dmatag = sa->sa_dmatag;
        !           319:        bus_dma_segment_t seg;
        !           320:        int rseg, error;
        !           321:        /* XXX the following declarations should be elsewhere */
        !           322:        extern void myetheraddr(u_char *);
        !           323:
        !           324:        lesc->sc_bustag = sa->sa_bustag;
        !           325:
        !           326:        /* Establish link to `ledma' device */
        !           327:        lesc->sc_dma = lsi;
        !           328:        lesc->sc_dma->sc_client = lesc;
        !           329:
        !           330:        /* Map device registers */
        !           331:        if (sbus_bus_map(sa->sa_bustag,
        !           332:                           sa->sa_slot,
        !           333:                           sa->sa_offset,
        !           334:                           sa->sa_size,
        !           335:                           BUS_SPACE_MAP_LINEAR,
        !           336:                           0, &lesc->sc_reg) != 0) {
        !           337:                printf("%s @ ledma: cannot map registers\n", self->dv_xname);
        !           338:                return;
        !           339:        }
        !           340:
        !           341:        /* Allocate buffer memory */
        !           342:        sc->sc_memsize = MEMSIZE;
        !           343:
        !           344:        /* Get a DMA handle */
        !           345:        if ((error = bus_dmamap_create(dmatag, MEMSIZE, 1, MEMSIZE,
        !           346:                                        LEDMA_BOUNDARY, BUS_DMA_NOWAIT,
        !           347:                                        &lesc->sc_dmamap)) != 0) {
        !           348:                printf("%s: DMA map create error %d\n", self->dv_xname, error);
        !           349:                return;
        !           350:        }
        !           351:
        !           352:        /* Allocate DMA buffer */
        !           353:        if ((error = bus_dmamem_alloc(dmatag, MEMSIZE, 0, LEDMA_BOUNDARY,
        !           354:                                 &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
        !           355:                printf("%s @ ledma: DMA buffer alloc error %d\n",
        !           356:                        self->dv_xname, error);
        !           357:                return;
        !           358:        }
        !           359:
        !           360:        /* Map DMA buffer into kernel space */
        !           361:        if ((error = bus_dmamem_map(dmatag, &seg, rseg, MEMSIZE,
        !           362:                               (caddr_t *)&sc->sc_mem,
        !           363:                               BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
        !           364:                printf("%s @ ledma: DMA buffer map error %d\n",
        !           365:                        self->dv_xname, error);
        !           366:                bus_dmamem_free(dmatag, &seg, rseg);
        !           367:                return;
        !           368:        }
        !           369:
        !           370:        /* Load DMA buffer */
        !           371:        if ((error = bus_dmamap_load(dmatag, lesc->sc_dmamap, sc->sc_mem,
        !           372:                        MEMSIZE, NULL, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
        !           373:                printf("%s: DMA buffer map load error %d\n",
        !           374:                        self->dv_xname, error);
        !           375:                bus_dmamem_free(dmatag, &seg, rseg);
        !           376:                bus_dmamem_unmap(dmatag, sc->sc_mem, MEMSIZE);
        !           377:                return;
        !           378:        }
        !           379:
        !           380:        lesc->sc_laddr = lesc->sc_dmamap->dm_segs[0].ds_addr;
        !           381:        sc->sc_addr = lesc->sc_laddr & 0xffffff;
        !           382:        sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
        !           383:
        !           384:        ifmedia_init(&sc->sc_ifmedia, 0, lemediachange, lemediastatus);
        !           385:        ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
        !           386:        ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
        !           387:        ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
        !           388:        ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO);
        !           389:        sc->sc_hasifmedia = 1;
        !           390:
        !           391:        myetheraddr(sc->sc_arpcom.ac_enaddr);
        !           392:
        !           393:        sc->sc_copytodesc = am7990_copytobuf_contig;
        !           394:        sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
        !           395:        sc->sc_copytobuf = am7990_copytobuf_contig;
        !           396:        sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
        !           397:        sc->sc_zerobuf = am7990_zerobuf_contig;
        !           398:
        !           399:        sc->sc_rdcsr = le_ledma_rdcsr;
        !           400:        sc->sc_wrcsr = le_ledma_wrcsr;
        !           401:        sc->sc_hwinit = le_ledma_hwinit;
        !           402:        sc->sc_nocarrier = le_ledma_nocarrier;
        !           403:        sc->sc_hwreset = le_ledma_hwreset;
        !           404:
        !           405:        /* Establish interrupt handler */
        !           406:        if (sa->sa_nintr != 0)
        !           407:                (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_NET, 0,
        !           408:                                         am7990_intr, sc, self->dv_xname);
        !           409:
        !           410:        am7990_config(&lesc->sc_am7990);
        !           411:
        !           412:        /* now initialize DMA */
        !           413:        le_ledma_hwreset(sc);
        !           414: }

CVSweb