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/quicc/quicc_core.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 2006 by Juniper Networks.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/8.4/sys/dev/quicc/quicc_core.c 176772 2008-03-03 18:20:17Z raj $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/conf.h>
   36 #include <sys/endian.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/queue.h>
   40 #include <sys/serial.h>
   41 
   42 #include <machine/bus.h>
   43 #include <machine/resource.h>
   44 #include <sys/rman.h>
   45 
   46 #include <dev/ic/quicc.h>
   47 
   48 #include <dev/quicc/quicc_bfe.h>
   49 #include <dev/quicc/quicc_bus.h>
   50 
   51 #define quicc_read2(r, o)       \
   52         bus_space_read_2((r)->r_bustag, (r)->r_bushandle, o)
   53 #define quicc_read4(r, o)       \
   54         bus_space_read_4((r)->r_bustag, (r)->r_bushandle, o)
   55 
   56 #define quicc_write2(r, o, v)   \
   57         bus_space_write_2((r)->r_bustag, (r)->r_bushandle, o, v)
   58 #define quicc_write4(r, o, v)   \
   59         bus_space_write_4((r)->r_bustag, (r)->r_bushandle, o, v)
   60 
   61 devclass_t quicc_devclass;
   62 char quicc_driver_name[] = "quicc";
   63 
   64 MALLOC_DEFINE(M_QUICC, "QUICC", "QUICC driver");
   65 
   66 struct quicc_device {
   67         struct rman     *qd_rman;
   68         struct resource_list qd_rlist;
   69         device_t        qd_dev;
   70         int             qd_devtype;
   71 
   72         driver_filter_t *qd_ih;
   73         void            *qd_ih_arg;
   74 };
   75 
   76 static int
   77 quicc_bfe_intr(void *arg)
   78 {
   79         struct quicc_device *qd;
   80         struct quicc_softc *sc = arg;
   81         uint32_t sipnr;
   82 
   83         sipnr = quicc_read4(sc->sc_rres, QUICC_REG_SIPNR_L);
   84         if (sipnr & 0x00f00000)
   85                 qd = sc->sc_device;
   86         else
   87                 qd = NULL;
   88 
   89         if (qd == NULL || qd->qd_ih == NULL) {
   90                 device_printf(sc->sc_dev, "Stray interrupt %08x\n", sipnr);
   91                 return (FILTER_STRAY);
   92         }
   93 
   94         return ((*qd->qd_ih)(qd->qd_ih_arg));
   95 }
   96 
   97 int
   98 quicc_bfe_attach(device_t dev)
   99 {
  100         struct quicc_device *qd;
  101         struct quicc_softc *sc;
  102         struct resource_list_entry *rle;
  103         const char *sep;
  104         u_long size, start;
  105         int error;
  106 
  107         sc = device_get_softc(dev);
  108 
  109         /*
  110          * Re-allocate. We expect that the softc contains the information
  111          * collected by quicc_bfe_probe() intact.
  112          */
  113         sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
  114             0, ~0, 0, RF_ACTIVE);
  115         if (sc->sc_rres == NULL)
  116                 return (ENXIO);
  117 
  118         start = rman_get_start(sc->sc_rres);
  119         size = rman_get_size(sc->sc_rres);
  120 
  121         sc->sc_rman.rm_start = start;
  122         sc->sc_rman.rm_end = start + size - 1;
  123         sc->sc_rman.rm_type = RMAN_ARRAY;
  124         sc->sc_rman.rm_descr = "QUICC resources";
  125         error = rman_init(&sc->sc_rman);
  126         if (!error)
  127                 error = rman_manage_region(&sc->sc_rman, start,
  128                     start + size - 1);
  129         if (error) {
  130                 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid,
  131                     sc->sc_rres);
  132                 return (error);
  133         }
  134 
  135         /*
  136          * Allocate interrupt resource.
  137          */
  138         sc->sc_irid = 0;
  139         sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
  140             RF_ACTIVE | RF_SHAREABLE);
  141 
  142         if (sc->sc_ires != NULL) {
  143                 error = bus_setup_intr(dev, sc->sc_ires,
  144                     INTR_TYPE_TTY, quicc_bfe_intr, NULL, sc, &sc->sc_icookie);
  145                 if (error) {
  146                         error = bus_setup_intr(dev, sc->sc_ires,
  147                             INTR_TYPE_TTY | INTR_MPSAFE, NULL,
  148                             (driver_intr_t *)quicc_bfe_intr, sc,
  149                             &sc->sc_icookie);
  150                 } else
  151                         sc->sc_fastintr = 1;
  152                 if (error) {
  153                         device_printf(dev, "could not activate interrupt\n");
  154                         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
  155                             sc->sc_ires);
  156                         sc->sc_ires = NULL;
  157                 }
  158         }
  159 
  160         if (sc->sc_ires == NULL)
  161                 sc->sc_polled = 1;
  162 
  163         if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
  164                 sep = "";
  165                 device_print_prettyname(dev);
  166                 if (sc->sc_fastintr) {
  167                         printf("%sfast interrupt", sep);
  168                         sep = ", ";
  169                 }
  170                 if (sc->sc_polled) {
  171                         printf("%spolled mode", sep);
  172                         sep = ", ";
  173                 }
  174                 printf("\n");
  175         }
  176 
  177         sc->sc_device = qd = malloc(sizeof(struct quicc_device), M_QUICC,
  178             M_WAITOK | M_ZERO);
  179 
  180         qd->qd_devtype = QUICC_DEVTYPE_SCC;
  181         qd->qd_rman = &sc->sc_rman;
  182         resource_list_init(&qd->qd_rlist);
  183 
  184         resource_list_add(&qd->qd_rlist, sc->sc_rtype, 0, start,
  185             start + size - 1, size);
  186 
  187         resource_list_add(&qd->qd_rlist, SYS_RES_IRQ, 0, 0xf00, 0xf00, 1);
  188         rle = resource_list_find(&qd->qd_rlist, SYS_RES_IRQ, 0);
  189         rle->res = sc->sc_ires;
  190 
  191         qd->qd_dev = device_add_child(dev, NULL, -1);
  192         device_set_ivars(qd->qd_dev, (void *)qd);
  193         error = device_probe_and_attach(qd->qd_dev);
  194 
  195         /* Enable all SCC interrupts. */
  196         quicc_write4(sc->sc_rres, QUICC_REG_SIMR_L, 0x00f00000);
  197 
  198         /* Clear all pending interrupts. */
  199         quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_H, ~0);
  200         quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_L, ~0);
  201         return (error);
  202 }
  203 
  204 int
  205 quicc_bfe_detach(device_t dev)
  206 {
  207         struct quicc_softc *sc;
  208 
  209         sc = device_get_softc(dev);
  210 
  211         bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  212         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
  213         bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
  214         return (0);
  215 }
  216 
  217 int
  218 quicc_bfe_probe(device_t dev, u_int clock)
  219 {
  220         struct quicc_softc *sc;
  221         uint16_t rev;
  222 
  223         sc = device_get_softc(dev);
  224         sc->sc_dev = dev;
  225         if (device_get_desc(dev) == NULL)
  226                 device_set_desc(dev,
  227                     "Quad integrated communications controller");
  228 
  229         sc->sc_rrid = 0;
  230         sc->sc_rtype = SYS_RES_MEMORY;
  231         sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
  232             0, ~0, 0, RF_ACTIVE);
  233         if (sc->sc_rres == NULL) {
  234                 sc->sc_rrid = 0;
  235                 sc->sc_rtype = SYS_RES_IOPORT;
  236                 sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype,
  237                     &sc->sc_rrid, 0, ~0, 0, RF_ACTIVE);
  238                 if (sc->sc_rres == NULL)
  239                         return (ENXIO);
  240         }
  241 
  242         sc->sc_clock = clock;
  243 
  244         /*
  245          * Check that the microcode revision is 0x00e8, as documented
  246          * in the MPC8555E PowerQUICC III Integrated Processor Family
  247          * Reference Manual.
  248          */
  249         rev = quicc_read2(sc->sc_rres, QUICC_PRAM_REV_NUM);
  250 
  251         bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
  252         return ((rev == 0x00e8) ? BUS_PROBE_DEFAULT : ENXIO);
  253 }
  254 
  255 struct resource *
  256 quicc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
  257     u_long start, u_long end, u_long count, u_int flags)
  258 {
  259         struct quicc_device *qd;
  260         struct resource_list_entry *rle;
  261 
  262         if (device_get_parent(child) != dev)
  263                 return (NULL);
  264 
  265         /* We only support default allocations. */
  266         if (start != 0UL || end != ~0UL)
  267                 return (NULL);
  268 
  269         qd = device_get_ivars(child);
  270         rle = resource_list_find(&qd->qd_rlist, type, *rid);
  271         if (rle == NULL)
  272                 return (NULL);
  273 
  274         if (rle->res == NULL) {
  275                 rle->res = rman_reserve_resource(qd->qd_rman, rle->start,
  276                     rle->start + rle->count - 1, rle->count, flags, child);
  277                 if (rle->res != NULL) {
  278                         rman_set_bustag(rle->res, &bs_be_tag);
  279                         rman_set_bushandle(rle->res, rle->start);
  280                 }
  281         }
  282         return (rle->res);
  283 }
  284 
  285 int
  286 quicc_bus_get_resource(device_t dev, device_t child, int type, int rid,
  287     u_long *startp, u_long *countp)
  288 {
  289         struct quicc_device *qd;
  290         struct resource_list_entry *rle;
  291 
  292         if (device_get_parent(child) != dev)
  293                 return (EINVAL);
  294 
  295         qd = device_get_ivars(child);
  296         rle = resource_list_find(&qd->qd_rlist, type, rid);
  297         if (rle == NULL)
  298                 return (EINVAL);
  299 
  300         if (startp != NULL)
  301                 *startp = rle->start;
  302         if (countp != NULL)
  303                 *countp = rle->count;
  304         return (0);
  305 }
  306 
  307 int
  308 quicc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  309 {
  310         struct quicc_device *qd;
  311         struct quicc_softc *sc;
  312         uint32_t sccr;
  313 
  314         if (device_get_parent(child) != dev)
  315                 return (EINVAL);
  316 
  317         sc = device_get_softc(dev);
  318         qd = device_get_ivars(child);
  319 
  320         switch (index) {
  321         case QUICC_IVAR_CLOCK:
  322                 *result = sc->sc_clock;
  323                 break;
  324         case QUICC_IVAR_BRGCLK:
  325                 sccr = quicc_read4(sc->sc_rres, QUICC_REG_SCCR) & 3;
  326                 *result = sc->sc_clock / ((1 << (sccr + 1)) << sccr);
  327                 break;
  328         case QUICC_IVAR_DEVTYPE:
  329                 *result = qd->qd_devtype;
  330                 break;
  331         default:
  332                 return (EINVAL);
  333         }
  334         return (0);
  335 }
  336 
  337 int
  338 quicc_bus_release_resource(device_t dev, device_t child, int type, int rid,
  339     struct resource *res)
  340 {
  341         struct quicc_device *qd;
  342         struct resource_list_entry *rle;
  343 
  344         if (device_get_parent(child) != dev)
  345                 return (EINVAL);
  346 
  347         qd = device_get_ivars(child);
  348         rle = resource_list_find(&qd->qd_rlist, type, rid);
  349         return ((rle == NULL) ? EINVAL : 0);
  350 }
  351 
  352 int
  353 quicc_bus_setup_intr(device_t dev, device_t child, struct resource *r,
  354     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg,
  355     void **cookiep)
  356 {
  357         struct quicc_device *qd;
  358         struct quicc_softc *sc;
  359 
  360         if (device_get_parent(child) != dev)
  361                 return (EINVAL);
  362 
  363         /* Interrupt handlers must be FAST or MPSAFE. */
  364         if (filt == NULL && !(flags & INTR_MPSAFE))
  365                 return (EINVAL);
  366 
  367         sc = device_get_softc(dev);
  368         if (sc->sc_polled)
  369                 return (ENXIO);
  370 
  371         if (sc->sc_fastintr && filt == NULL) {
  372                 sc->sc_fastintr = 0;
  373                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  374                 bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE,
  375                     NULL, (driver_intr_t *)quicc_bfe_intr, sc, &sc->sc_icookie);
  376         }
  377 
  378         qd = device_get_ivars(child);
  379         qd->qd_ih = (filt != NULL) ? filt : (driver_filter_t *)ihand;
  380         qd->qd_ih_arg = arg;
  381         *cookiep = ihand;
  382         return (0);
  383 }
  384 
  385 int
  386 quicc_bus_teardown_intr(device_t dev, device_t child, struct resource *r,
  387     void *cookie)
  388 {
  389         struct quicc_device *qd;
  390 
  391         if (device_get_parent(child) != dev)
  392                 return (EINVAL);
  393 
  394         qd = device_get_ivars(child);
  395         if (qd->qd_ih != cookie)
  396                 return (EINVAL);
  397 
  398         qd->qd_ih = NULL;
  399         qd->qd_ih_arg = NULL;
  400         return (0);
  401 }

Cache object: 408af2218a36d72e551738f25e5211da


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