[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

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