The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/le/if_le_cbus.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1994-2000
    3  *      Paul Richards. All rights reserved.
    4  *
    5  * PC-98 port by Chiharu Shibata & FreeBSD(98) porting team.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer,
   12  *    verbatim and that no modifications are made prior to this
   13  *    point in the file.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name Paul Richards may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      from: FreeBSD: src/sys/dev/lnc/if_lnc_cbus.c,v 1.12 2005/11/12 19:14:21
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD$");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/bus.h>
   41 #include <sys/endian.h>
   42 #include <sys/kernel.h>
   43 #include <sys/lock.h>
   44 #include <sys/module.h>
   45 #include <sys/mutex.h>
   46 #include <sys/resource.h>
   47 #include <sys/rman.h>
   48 #include <sys/socket.h>
   49 
   50 #include <net/ethernet.h>
   51 #include <net/if.h>
   52 #include <net/if_media.h>
   53 
   54 #include <machine/bus.h>
   55 #include <machine/resource.h>
   56 
   57 #include <isa/isavar.h>
   58 
   59 #include <dev/le/lancereg.h>
   60 #include <dev/le/lancevar.h>
   61 #include <dev/le/am7990var.h>
   62 
   63 #define LE_CBUS_MEMSIZE (16*1024)
   64 #define CNET98S_IOSIZE  32
   65 #define CNET98S_RDP     0x10
   66 #define CNET98S_RAP     0x12
   67 #define CNET98S_RESET   0x14
   68 #define CNET98S_BDP     0x16
   69 
   70 struct le_cbus_softc {
   71         struct am7990_softc     sc_am7990;      /* glue to MI code */
   72 
   73         struct resource         *sc_rres;
   74 
   75         struct resource         *sc_ires;
   76         void                    *sc_ih;
   77 
   78         bus_dma_tag_t           sc_pdmat;
   79         bus_dma_tag_t           sc_dmat;
   80         bus_dmamap_t            sc_dmam;
   81 };
   82 
   83 static device_probe_t le_cbus_probe;
   84 static device_attach_t le_cbus_attach;
   85 static device_detach_t le_cbus_detach;
   86 static device_resume_t le_cbus_resume;
   87 static device_suspend_t le_cbus_suspend;
   88 
   89 static device_method_t le_cbus_methods[] = {
   90         /* Device interface */
   91         DEVMETHOD(device_probe,         le_cbus_probe),
   92         DEVMETHOD(device_attach,        le_cbus_attach),
   93         DEVMETHOD(device_detach,        le_cbus_detach),
   94         /* We can just use the suspend method here. */
   95         DEVMETHOD(device_shutdown,      le_cbus_suspend),
   96         DEVMETHOD(device_suspend,       le_cbus_suspend),
   97         DEVMETHOD(device_resume,        le_cbus_resume),
   98 
   99         { 0, 0 }
  100 };
  101 
  102 DEFINE_CLASS_0(le, le_cbus_driver, le_cbus_methods, sizeof(struct le_cbus_softc));
  103 DRIVER_MODULE(le, isa, le_cbus_driver, le_devclass, 0, 0);
  104 MODULE_DEPEND(le, ether, 1, 1, 1);
  105 
  106 static bus_addr_t le_ioaddr_cnet98s[CNET98S_IOSIZE] = {
  107         0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
  108         0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
  109         0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407,
  110         0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f,
  111 };
  112 
  113 static void le_cbus_wrbcr(struct lance_softc *, uint16_t, uint16_t);
  114 #ifdef LEDEBUG
  115 static uint16_t le_cbus_rdbcr(struct lance_softc *, uint16_t);
  116 #endif
  117 static void le_cbus_wrcsr(struct lance_softc *, uint16_t, uint16_t);
  118 static uint16_t le_cbus_rdcsr(struct lance_softc *, uint16_t);
  119 static void le_cbus_hwreset(struct lance_softc *);
  120 static bus_dmamap_callback_t le_cbus_dma_callback;
  121 
  122 static void
  123 le_cbus_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val)
  124 {
  125         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
  126 
  127         bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
  128         bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
  129         bus_write_2(lesc->sc_rres, CNET98S_BDP, val);
  130 }
  131 
  132 #ifdef LEDEBUG
  133 static uint16_t
  134 le_cbus_rdbcr(struct lance_softc *sc, uint16_t port)
  135 {
  136         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
  137 
  138         bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
  139         bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
  140         return (bus_read_2(lesc->sc_rres, CNET98S_BDP));
  141 }
  142 #endif
  143 
  144 static void
  145 le_cbus_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
  146 {
  147         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
  148 
  149         bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
  150         bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
  151         bus_write_2(lesc->sc_rres, CNET98S_RDP, val);
  152 }
  153 
  154 static uint16_t
  155 le_cbus_rdcsr(struct lance_softc *sc, uint16_t port)
  156 {
  157         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
  158 
  159         bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
  160         bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
  161         return (bus_read_2(lesc->sc_rres, CNET98S_RDP));
  162 }
  163 
  164 static void
  165 le_cbus_hwreset(struct lance_softc *sc)
  166 {
  167         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
  168 
  169         /*
  170          * NB: These are Contec C-NET(98)S only.
  171          */
  172 
  173         /* Reset the chip. */
  174         bus_write_2(lesc->sc_rres, CNET98S_RESET,
  175             bus_read_2(lesc->sc_rres, CNET98S_RESET));
  176         DELAY(500);
  177 
  178         /* ISA bus configuration */
  179         /* ISACSR0 - set Master Mode Read Active time to 300ns. */
  180         le_cbus_wrbcr(sc, LE_BCR0, 0x0006);
  181         /* ISACSR1 - set Master Mode Write Active time to 300ns. */
  182         le_cbus_wrbcr(sc, LE_BCR1, 0x0006);
  183 #ifdef LEDEBUG
  184         device_printf(dev, "ISACSR2=0x%x\n", le_cbus_rdbcr(sc, LE_BCR2));
  185 #endif
  186         /* ISACSR5 - LED1 */
  187         le_cbus_wrbcr(sc, LE_BCR5, LE_B4_PSE | LE_B4_XMTE);
  188         /* ISACSR6 - LED2 */
  189         le_cbus_wrbcr(sc, LE_BCR6, LE_B4_PSE | LE_B4_RCVE);
  190         /* ISACSR7 - LED3 */
  191         le_cbus_wrbcr(sc, LE_BCR7, LE_B4_PSE | LE_B4_COLE);
  192 }
  193 
  194 static void
  195 le_cbus_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
  196 {
  197         struct lance_softc *sc = (struct lance_softc *)xsc;
  198 
  199         if (error != 0)
  200                 return;
  201         KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
  202         sc->sc_addr = segs[0].ds_addr;
  203 }
  204 
  205 static int
  206 le_cbus_probe(device_t dev)
  207 {
  208         struct le_cbus_softc *lesc;
  209         struct lance_softc *sc;
  210         int error, i;
  211 
  212         /*
  213          * Skip PnP devices as some wedge when trying to probe them as
  214          * C-NET(98)S.
  215          */
  216         if (isa_get_vendorid(dev))
  217                 return (ENXIO);
  218 
  219         lesc = device_get_softc(dev);
  220         sc = &lesc->sc_am7990.lsc;
  221 
  222         i = 0;
  223         lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &i,
  224             le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
  225         if (lesc->sc_rres == NULL)
  226                 return (ENXIO);
  227         isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
  228 
  229         /* Reset the chip. */
  230         bus_write_2(lesc->sc_rres, CNET98S_RESET,
  231             bus_read_2(lesc->sc_rres, CNET98S_RESET));
  232         DELAY(500);
  233 
  234         /* Stop the chip and put it in a known state. */
  235         le_cbus_wrcsr(sc, LE_CSR0, LE_C0_STOP);
  236         DELAY(100);
  237         if (le_cbus_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
  238                 error = ENXIO;
  239                 goto fail;
  240         }
  241         le_cbus_wrcsr(sc, LE_CSR3, 0);
  242         device_set_desc(dev, "C-NET(98)S");
  243         error = BUS_PROBE_DEFAULT;
  244 
  245  fail:
  246         bus_release_resource(dev, SYS_RES_IOPORT,
  247             rman_get_rid(lesc->sc_rres), lesc->sc_rres);
  248         return (error);
  249 }
  250 
  251 static int
  252 le_cbus_attach(device_t dev)
  253 {
  254         struct le_cbus_softc *lesc;
  255         struct lance_softc *sc;
  256         int error, i;
  257 
  258         lesc = device_get_softc(dev);
  259         sc = &lesc->sc_am7990.lsc;
  260 
  261         LE_LOCK_INIT(sc, device_get_nameunit(dev));
  262 
  263         i = 0;
  264         lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &i,
  265             le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
  266         if (lesc->sc_rres == NULL) {
  267                 device_printf(dev, "cannot allocate registers\n");
  268                 error = ENXIO;
  269                 goto fail_mtx;
  270         }
  271         isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
  272 
  273         i = 0;
  274         if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  275             &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
  276                 device_printf(dev, "cannot allocate interrupt\n");
  277                 error = ENXIO;
  278                 goto fail_rres;
  279         }
  280 
  281         error = bus_dma_tag_create(
  282             bus_get_dma_tag(dev),       /* parent */
  283             1, 0,                       /* alignment, boundary */
  284             BUS_SPACE_MAXADDR_24BIT,    /* lowaddr */
  285             BUS_SPACE_MAXADDR,          /* highaddr */
  286             NULL, NULL,                 /* filter, filterarg */
  287             BUS_SPACE_MAXSIZE_32BIT,    /* maxsize */
  288             0,                          /* nsegments */
  289             BUS_SPACE_MAXSIZE_32BIT,    /* maxsegsize */
  290             0,                          /* flags */
  291             NULL, NULL,                 /* lockfunc, lockarg */
  292             &lesc->sc_pdmat);
  293         if (error != 0) {
  294                 device_printf(dev, "cannot allocate parent DMA tag\n");
  295                 goto fail_ires;
  296         }
  297 
  298         sc->sc_memsize = LE_CBUS_MEMSIZE;
  299         /*
  300          * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
  301          * aligned and the ring descriptors must be 8-byte aligned.
  302          */
  303         error = bus_dma_tag_create(
  304             lesc->sc_pdmat,             /* parent */
  305             8, 0,                       /* alignment, boundary */
  306             BUS_SPACE_MAXADDR_24BIT,    /* lowaddr */
  307             BUS_SPACE_MAXADDR,          /* highaddr */
  308             NULL, NULL,                 /* filter, filterarg */
  309             sc->sc_memsize,             /* maxsize */
  310             1,                          /* nsegments */
  311             sc->sc_memsize,             /* maxsegsize */
  312             0,                          /* flags */
  313             NULL, NULL,                 /* lockfunc, lockarg */
  314             &lesc->sc_dmat);
  315         if (error != 0) {
  316                 device_printf(dev, "cannot allocate buffer DMA tag\n");
  317                 goto fail_pdtag;
  318         }
  319 
  320         error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
  321             BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
  322         if (error != 0) {
  323                 device_printf(dev, "cannot allocate DMA buffer memory\n");
  324                 goto fail_dtag;
  325         }
  326 
  327         sc->sc_addr = 0;
  328         error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
  329             sc->sc_memsize, le_cbus_dma_callback, sc, 0);
  330         if (error != 0 || sc->sc_addr == 0) {
  331                 device_printf(dev, "cannot load DMA buffer map\n");
  332                 goto fail_dmem;
  333         }
  334 
  335         sc->sc_flags = 0;
  336         sc->sc_conf3 = 0;
  337 
  338         /*
  339          * Extract the physical MAC address from the ROM.
  340          */
  341         for (i = 0; i < sizeof(sc->sc_enaddr); i++)
  342                 sc->sc_enaddr[i] = bus_read_1(lesc->sc_rres, i * 2);
  343 
  344         sc->sc_copytodesc = lance_copytobuf_contig;
  345         sc->sc_copyfromdesc = lance_copyfrombuf_contig;
  346         sc->sc_copytobuf = lance_copytobuf_contig;
  347         sc->sc_copyfrombuf = lance_copyfrombuf_contig;
  348         sc->sc_zerobuf = lance_zerobuf_contig;
  349 
  350         sc->sc_rdcsr = le_cbus_rdcsr;
  351         sc->sc_wrcsr = le_cbus_wrcsr;
  352         sc->sc_hwreset = le_cbus_hwreset;
  353         sc->sc_hwinit = NULL;
  354         sc->sc_hwintr = NULL;
  355         sc->sc_nocarrier = NULL;
  356         sc->sc_mediachange = NULL;
  357         sc->sc_mediastatus = NULL;
  358         sc->sc_supmedia = NULL;
  359 
  360         error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
  361             device_get_unit(dev));
  362         if (error != 0) {
  363                 device_printf(dev, "cannot attach Am7990\n");
  364                 goto fail_dmap;
  365         }
  366 
  367         error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
  368             NULL, am7990_intr, sc, &lesc->sc_ih);
  369         if (error != 0) {
  370                 device_printf(dev, "cannot set up interrupt\n");
  371                 goto fail_am7990;
  372         }
  373 
  374         return (0);
  375 
  376  fail_am7990:
  377         am7990_detach(&lesc->sc_am7990);
  378  fail_dmap:
  379         bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
  380  fail_dmem:
  381         bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
  382  fail_dtag:
  383         bus_dma_tag_destroy(lesc->sc_dmat);
  384  fail_pdtag:
  385         bus_dma_tag_destroy(lesc->sc_pdmat);
  386  fail_ires:
  387         bus_release_resource(dev, SYS_RES_IRQ,
  388             rman_get_rid(lesc->sc_ires), lesc->sc_ires);
  389  fail_rres:
  390         bus_release_resource(dev, SYS_RES_IOPORT,
  391             rman_get_rid(lesc->sc_rres), lesc->sc_rres);
  392  fail_mtx:
  393         LE_LOCK_DESTROY(sc);
  394         return (error);
  395 }
  396 
  397 static int
  398 le_cbus_detach(device_t dev)
  399 {
  400         struct le_cbus_softc *lesc;
  401         struct lance_softc *sc;
  402 
  403         lesc = device_get_softc(dev);
  404         sc = &lesc->sc_am7990.lsc;
  405 
  406         bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
  407         am7990_detach(&lesc->sc_am7990);
  408         bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
  409         bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
  410         bus_dma_tag_destroy(lesc->sc_dmat);
  411         bus_dma_tag_destroy(lesc->sc_pdmat);
  412         bus_release_resource(dev, SYS_RES_IRQ,
  413             rman_get_rid(lesc->sc_ires), lesc->sc_ires);
  414         bus_release_resource(dev, SYS_RES_IOPORT,
  415             rman_get_rid(lesc->sc_rres), lesc->sc_rres);
  416         LE_LOCK_DESTROY(sc);
  417 
  418         return (0);
  419 }
  420 
  421 static int
  422 le_cbus_suspend(device_t dev)
  423 {
  424         struct le_cbus_softc *lesc;
  425 
  426         lesc = device_get_softc(dev);
  427 
  428         lance_suspend(&lesc->sc_am7990.lsc);
  429 
  430         return (0);
  431 }
  432 
  433 static int
  434 le_cbus_resume(device_t dev)
  435 {
  436         struct le_cbus_softc *lesc;
  437 
  438         lesc = device_get_softc(dev);
  439 
  440         lance_resume(&lesc->sc_am7990.lsc);
  441 
  442         return (0);
  443 }

Cache object: 04d707bafee86e61be56182dbb87e58c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.