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/tsec/if_tsec_ocp.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) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
    3  * Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
   18  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
   20  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   22  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   23  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * OCP attachment driver for Freescale TSEC controller.
   29  */
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/8.4/sys/dev/tsec/if_tsec_ocp.c 188712 2009-02-17 14:59:47Z raj $");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/endian.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/socket.h>
   40 #include <sys/sysctl.h>
   41 
   42 #include <sys/bus.h>
   43 #include <machine/bus.h>
   44 #include <sys/rman.h>
   45 #include <machine/resource.h>
   46 
   47 #include <net/ethernet.h>
   48 #include <net/if.h>
   49 #include <net/if_dl.h>
   50 #include <net/if_media.h>
   51 #include <net/if_arp.h>
   52 
   53 #include <dev/mii/mii.h>
   54 #include <dev/mii/miivar.h>
   55 
   56 #include <machine/bootinfo.h>
   57 #include <machine/ocpbus.h>
   58 
   59 #include <dev/tsec/if_tsec.h>
   60 #include <dev/tsec/if_tsecreg.h>
   61 
   62 #include "miibus_if.h"
   63 
   64 #define OCP_TSEC_RID_TXIRQ      0
   65 #define OCP_TSEC_RID_RXIRQ      1
   66 #define OCP_TSEC_RID_ERRIRQ     2
   67 
   68 extern struct tsec_softc *tsec0_sc;
   69 
   70 static int      tsec_ocp_probe(device_t dev);
   71 static int      tsec_ocp_attach(device_t dev);
   72 static int      tsec_ocp_detach(device_t dev);
   73 static int      tsec_setup_intr(struct tsec_softc *sc, struct resource **ires,
   74     void **ihand, int *irid, driver_intr_t handler, const char *iname);
   75 static void     tsec_release_intr(struct tsec_softc *sc, struct resource *ires,
   76     void *ihand, int irid, const char *iname);
   77 
   78 static device_method_t tsec_methods[] = {
   79         /* Device interface */
   80         DEVMETHOD(device_probe,         tsec_ocp_probe),
   81         DEVMETHOD(device_attach,        tsec_ocp_attach),
   82         DEVMETHOD(device_detach,        tsec_ocp_detach),
   83 
   84         DEVMETHOD(device_shutdown,      tsec_shutdown),
   85         DEVMETHOD(device_suspend,       tsec_suspend),
   86         DEVMETHOD(device_resume,        tsec_resume),
   87 
   88         /* Bus interface */
   89         DEVMETHOD(bus_print_child,      bus_generic_print_child),
   90         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
   91 
   92         /* MII interface */
   93         DEVMETHOD(miibus_readreg,       tsec_miibus_readreg),
   94         DEVMETHOD(miibus_writereg,      tsec_miibus_writereg),
   95         DEVMETHOD(miibus_statchg,       tsec_miibus_statchg),
   96         { 0, 0 }
   97 };
   98 
   99 static driver_t tsec_ocp_driver = {
  100         "tsec",
  101         tsec_methods,
  102         sizeof(struct tsec_softc),
  103 };
  104 
  105 DRIVER_MODULE(tsec, ocpbus, tsec_ocp_driver, tsec_devclass, 0, 0);
  106 MODULE_DEPEND(tsec, ocpbus, 1, 1, 1);
  107 MODULE_DEPEND(tsec, ether, 1, 1, 1);
  108 
  109 static int
  110 tsec_ocp_probe(device_t dev)
  111 {
  112         struct tsec_softc *sc;
  113         device_t parent;
  114         uintptr_t devtype;
  115         int error;
  116         uint32_t id;
  117 
  118         parent = device_get_parent(dev);
  119 
  120         error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
  121         if (error)
  122                 return (error);
  123         if (devtype != OCPBUS_DEVTYPE_TSEC)
  124                 return (ENXIO);
  125 
  126         sc = device_get_softc(dev);
  127 
  128         sc->sc_rrid = 0;
  129         sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid,
  130             0ul, ~0ul, TSEC_IO_SIZE, RF_ACTIVE);
  131         if (sc->sc_rres == NULL)
  132                 return (ENXIO);
  133 
  134         sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
  135         sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
  136 
  137         /* Check if we are eTSEC (enhanced TSEC) */
  138         id = TSEC_READ(sc, TSEC_REG_ID);
  139         sc->is_etsec = ((id >> 16) == TSEC_ETSEC_ID) ? 1 : 0;
  140         id |= TSEC_READ(sc, TSEC_REG_ID2);
  141 
  142         bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
  143 
  144         if (id == 0) {
  145                 device_printf(dev, "could not identify TSEC type\n");
  146                 return (ENXIO);
  147         }
  148 
  149         if (sc->is_etsec)
  150                 device_set_desc(dev, "Enhanced Three-Speed Ethernet Controller");
  151         else
  152                 device_set_desc(dev, "Three-Speed Ethernet Controller");
  153 
  154         return (BUS_PROBE_DEFAULT);
  155 }
  156 
  157 static int
  158 tsec_ocp_attach(device_t dev)
  159 {
  160         struct tsec_softc *sc;
  161         int error = 0;
  162 
  163         sc = device_get_softc(dev);
  164         sc->dev = dev;
  165 
  166         /* XXX add comment on weird FSL's MII registers access design */
  167         if (device_get_unit(dev) == 0)
  168                 tsec0_sc = sc;
  169 
  170         /* Init timer */
  171         callout_init(&sc->tsec_callout, 1);
  172 
  173         /* Init locks */
  174         mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "TSEC TX lock",
  175             MTX_DEF);
  176         mtx_init(&sc->receive_lock, device_get_nameunit(dev), "TSEC RX lock",
  177             MTX_DEF);
  178         mtx_init(&sc->ic_lock, device_get_nameunit(dev), "TSEC IC lock",
  179             MTX_DEF);
  180         
  181         /* Allocate IO memory for TSEC registers */
  182         sc->sc_rrid = 0;
  183         sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid,
  184             0ul, ~0ul, TSEC_IO_SIZE, RF_ACTIVE);
  185         if (sc->sc_rres == NULL) {
  186                 device_printf(dev, "could not allocate IO memory range!\n");
  187                 goto fail1;
  188         }
  189         sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
  190         sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
  191 
  192         /* TSEC attach */
  193         if (tsec_attach(sc) != 0) {
  194                 device_printf(dev, "could not be configured\n");
  195                 goto fail2;
  196         }
  197 
  198         /* Set up interrupts (TX/RX/ERR) */
  199         sc->sc_transmit_irid = OCP_TSEC_RID_TXIRQ;
  200         error = tsec_setup_intr(sc, &sc->sc_transmit_ires,
  201             &sc->sc_transmit_ihand, &sc->sc_transmit_irid,
  202             tsec_transmit_intr, "TX");
  203         if (error)
  204                 goto fail2;
  205 
  206         sc->sc_receive_irid = OCP_TSEC_RID_RXIRQ;
  207         error = tsec_setup_intr(sc, &sc->sc_receive_ires,
  208             &sc->sc_receive_ihand, &sc->sc_receive_irid,
  209             tsec_receive_intr, "RX");
  210         if (error)
  211                 goto fail3;
  212 
  213         sc->sc_error_irid = OCP_TSEC_RID_ERRIRQ;
  214         error = tsec_setup_intr(sc, &sc->sc_error_ires,
  215             &sc->sc_error_ihand, &sc->sc_error_irid,
  216             tsec_error_intr, "ERR");
  217         if (error)
  218                 goto fail4;
  219 
  220         return (0);
  221 
  222 fail4:
  223         tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand,
  224             sc->sc_receive_irid, "RX");
  225 fail3:
  226         tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand,
  227             sc->sc_transmit_irid, "TX");
  228 fail2:
  229         bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
  230 fail1:
  231         mtx_destroy(&sc->receive_lock);
  232         mtx_destroy(&sc->transmit_lock);
  233         return (ENXIO);
  234 }
  235 
  236 static int
  237 tsec_setup_intr(struct tsec_softc *sc, struct resource **ires, void **ihand,
  238     int *irid, driver_intr_t handler, const char *iname)
  239 {
  240         int error;
  241 
  242         (*ires) = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, irid, RF_ACTIVE);
  243         if ((*ires) == NULL) {
  244                 device_printf(sc->dev, "could not allocate %s IRQ\n", iname);
  245                 return (ENXIO);
  246         }
  247         error = bus_setup_intr(sc->dev, *ires, INTR_TYPE_NET | INTR_MPSAFE,
  248             NULL, handler, sc, ihand);
  249         if (error) {
  250                 device_printf(sc->dev, "failed to set up %s IRQ\n", iname);
  251                 if (bus_release_resource(sc->dev, SYS_RES_IRQ, *irid, *ires))
  252                         device_printf(sc->dev, "could not release %s IRQ\n", iname);
  253                 (*ires) = NULL;
  254                 return (error);
  255         }
  256         return (0);
  257 }
  258 
  259 static void
  260 tsec_release_intr(struct tsec_softc *sc, struct resource *ires, void *ihand,
  261     int irid, const char *iname)
  262 {
  263         int error;
  264 
  265         if (ires == NULL)
  266                 return;
  267 
  268         error = bus_teardown_intr(sc->dev, ires, ihand);
  269         if (error)
  270                 device_printf(sc->dev, "bus_teardown_intr() failed for %s intr"
  271                     ", error %d\n", iname, error);
  272 
  273         error = bus_release_resource(sc->dev, SYS_RES_IRQ, irid, ires);
  274         if (error)
  275                 device_printf(sc->dev, "bus_release_resource() failed for %s "
  276                     "intr, error %d\n", iname, error);
  277 }
  278 
  279 static int
  280 tsec_ocp_detach(device_t dev)
  281 {
  282         struct tsec_softc *sc;
  283         int error;
  284 
  285         sc = device_get_softc(dev);
  286 
  287         /* Wait for stopping watchdog */
  288         callout_drain(&sc->tsec_callout);
  289 
  290         /* Stop and release all interrupts */
  291         tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand,
  292             sc->sc_transmit_irid, "TX");
  293         tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand,
  294             sc->sc_receive_irid, "RX");
  295         tsec_release_intr(sc, sc->sc_error_ires, sc->sc_error_ihand,
  296             sc->sc_error_irid, "ERR");
  297 
  298         /* TSEC detach */
  299         tsec_detach(sc);
  300 
  301         /* Free IO memory handler */
  302         if (sc->sc_rres) {
  303                 error = bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid,
  304                     sc->sc_rres);
  305                 if (error)
  306                         device_printf(dev, "bus_release_resource() failed for"
  307                             " IO memory, error %d\n", error);
  308         }
  309 
  310         /* Destroy locks */
  311         mtx_destroy(&sc->receive_lock);
  312         mtx_destroy(&sc->transmit_lock);
  313         mtx_destroy(&sc->ic_lock);
  314         return (0);
  315 }
  316 
  317 void
  318 tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr)
  319 {
  320         union {
  321                 uint32_t reg[2];
  322                 uint8_t addr[6];
  323         } curmac;
  324         uint32_t a[6];
  325         device_t parent;
  326         uintptr_t macaddr;
  327         int i;
  328 
  329         parent = device_get_parent(sc->dev);
  330         if (BUS_READ_IVAR(parent, sc->dev, OCPBUS_IVAR_MACADDR,
  331             &macaddr) == 0) {
  332                 bcopy((uint8_t *)macaddr, addr, 6);
  333                 return;
  334         }
  335 
  336         /*
  337          * Fall back -- use the currently programmed address in the hope that
  338          * it was set be firmware...
  339          */
  340         curmac.reg[0] = TSEC_READ(sc, TSEC_REG_MACSTNADDR1);
  341         curmac.reg[1] = TSEC_READ(sc, TSEC_REG_MACSTNADDR2);
  342         for (i = 0; i < 6; i++)
  343                 a[5-i] = curmac.addr[i];
  344 
  345         addr[0] = a[0];
  346         addr[1] = a[1];
  347         addr[2] = a[2];
  348         addr[3] = a[3];
  349         addr[4] = a[4];
  350         addr[5] = a[5];
  351 }

Cache object: f2430c5ef4ca282523d594f3fff88b10


[ 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.