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/mips/alchemy/obio.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 /*      $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   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. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD: releng/10.1/sys/mips/alchemy/obio.c 265999 2014-05-14 01:35:43Z ian $");
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/bus.h>
   44 #include <sys/interrupt.h>
   45 #include <sys/kernel.h>
   46 #include <sys/module.h>
   47 #include <sys/rman.h>
   48 #include <sys/malloc.h>
   49 
   50 #include <machine/bus.h>
   51 
   52 #include <mips/adm5120/adm5120reg.h>
   53 #include <mips/adm5120/obiovar.h>
   54 
   55 /* MIPS HW interrupts of IRQ/FIQ respectively */
   56 #define ADM5120_INTR            0
   57 #define ADM5120_FAST_INTR       1
   58 
   59 /* Interrupt levels */
   60 #define INTR_IRQ 0
   61 #define INTR_FIQ 1
   62 
   63 int irq_priorities[NIRQS] = {
   64         INTR_IRQ,       /* flash */
   65         INTR_FIQ,       /* uart0 */
   66         INTR_FIQ,       /* uart1 */
   67         INTR_IRQ,       /* ahci  */
   68         INTR_IRQ,       /* unknown */
   69         INTR_IRQ,       /* unknown */
   70         INTR_IRQ,       /* unknown */
   71         INTR_IRQ,       /* unknown */
   72         INTR_IRQ,       /* unknown */
   73         INTR_IRQ,       /* admsw */
   74         INTR_IRQ,       /* unknown */
   75         INTR_IRQ,       /* unknown */
   76         INTR_IRQ,       /* unknown */
   77         INTR_IRQ,       /* unknown */
   78         INTR_IRQ,       /* unknown */
   79         INTR_IRQ,       /* unknown */
   80         INTR_IRQ,       /* unknown */
   81         INTR_IRQ,       /* unknown */
   82         INTR_IRQ,       /* unknown */
   83         INTR_IRQ,       /* unknown */
   84         INTR_IRQ,       /* unknown */
   85         INTR_IRQ,       /* unknown */
   86         INTR_IRQ,       /* unknown */
   87         INTR_IRQ,       /* unknown */
   88         INTR_IRQ,       /* unknown */
   89         INTR_IRQ,       /* unknown */
   90         INTR_IRQ,       /* unknown */
   91         INTR_IRQ,       /* unknown */
   92         INTR_IRQ,       /* unknown */
   93         INTR_IRQ,       /* unknown */
   94         INTR_IRQ,       /* unknown */
   95         INTR_IRQ,       /* unknown */
   96 };
   97 
   98 
   99 #define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(ADM5120_BASE_ICU + (o)))
  100 #define REG_WRITE(o,v) (REG_READ(o)) = (v)
  101 
  102 static int      obio_activate_resource(device_t, device_t, int, int,
  103                     struct resource *);
  104 static device_t obio_add_child(device_t, u_int, const char *, int);
  105 static struct resource *
  106                 obio_alloc_resource(device_t, device_t, int, int *, u_long,
  107                     u_long, u_long, u_int);
  108 static int      obio_attach(device_t);
  109 static int      obio_deactivate_resource(device_t, device_t, int, int,
  110                     struct resource *);
  111 static struct resource_list *
  112                 obio_get_resource_list(device_t, device_t);
  113 static void     obio_hinted_child(device_t, const char *, int);
  114 static int      obio_intr(void *);
  115 static int      obio_probe(device_t);
  116 static int      obio_release_resource(device_t, device_t, int, int,
  117                     struct resource *);
  118 static int      obio_setup_intr(device_t, device_t, struct resource *, int,
  119                     driver_filter_t *, driver_intr_t *, void *, void **);
  120 static int      obio_teardown_intr(device_t, device_t, struct resource *,
  121                     void *);
  122 
  123 static void 
  124 obio_mask_irq(void *arg)
  125 {
  126   /* XXX need to write */
  127 #if 0
  128         unsigned int irq = (unsigned int)arg;
  129         int ip_bit, mask, mask_register;
  130 
  131         /* mask IRQ */
  132         mask_register = ICU_IRQ_MASK_REG(irq);
  133         ip_bit = ICU_IP_BIT(irq);
  134 
  135         mask = ICU_REG_READ(mask_register);
  136         ICU_REG_WRITE(mask_register, mask | ip_bit);
  137 #endif
  138 }
  139 
  140 static void 
  141 obio_unmask_irq(void *arg)
  142 {
  143   /* XXX need to write */
  144 #if 0
  145         unsigned int irq = (unsigned int)arg;
  146         int ip_bit, mask, mask_register;
  147 
  148         /* unmask IRQ */
  149         mask_register = ICU_IRQ_MASK_REG(irq);
  150         ip_bit = ICU_IP_BIT(irq);
  151 
  152         mask = ICU_REG_READ(mask_register);
  153         ICU_REG_WRITE(mask_register, mask & ~ip_bit);
  154 #endif
  155 }
  156 
  157 static int
  158 obio_probe(device_t dev)
  159 {
  160 
  161         return (BUS_PROBE_NOWILDCARD);
  162 }
  163 
  164 static int
  165 obio_attach(device_t dev)
  166 {
  167         struct obio_softc *sc = device_get_softc(dev);
  168         int rid;
  169 
  170         sc->oba_mem_rman.rm_type = RMAN_ARRAY;
  171         sc->oba_mem_rman.rm_descr = "OBIO memeory";
  172         if (rman_init(&sc->oba_mem_rman) != 0 ||
  173             rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START,
  174                 OBIO_MEM_START + OBIO_MEM_SIZE) != 0)
  175                 panic("obio_attach: failed to set up I/O rman");
  176 
  177         sc->oba_irq_rman.rm_type = RMAN_ARRAY;
  178         sc->oba_irq_rman.rm_descr = "OBIO IRQ";
  179 
  180         if (rman_init(&sc->oba_irq_rman) != 0 ||
  181             rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0)
  182                 panic("obio_attach: failed to set up IRQ rman");
  183 
  184         /* Hook up our interrupt handler. */
  185         if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
  186             ADM5120_INTR, ADM5120_INTR, 1,
  187             RF_SHAREABLE | RF_ACTIVE)) == NULL) {
  188                 device_printf(dev, "unable to allocate IRQ resource\n");
  189                 return (ENXIO);
  190         }
  191 
  192         if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL,
  193             sc, &sc->sc_ih))) {
  194                 device_printf(dev,
  195                     "WARNING: unable to register interrupt handler\n");
  196                 return (ENXIO);
  197         }
  198 
  199         /* Hook up our FAST interrupt handler. */
  200         if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
  201             ADM5120_FAST_INTR, ADM5120_FAST_INTR, 1,
  202             RF_SHAREABLE | RF_ACTIVE)) == NULL) {
  203                 device_printf(dev, "unable to allocate IRQ resource\n");
  204                 return (ENXIO);
  205         }
  206 
  207         if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr,
  208             NULL, sc, &sc->sc_fast_ih))) {
  209                 device_printf(dev,
  210                     "WARNING: unable to register interrupt handler\n");
  211                 return (ENXIO);
  212         }
  213 
  214         /* disable all interrupts */
  215         REG_WRITE(ICU_ENABLE_REG, ICU_INT_MASK);
  216 
  217         bus_generic_probe(dev);
  218         bus_enumerate_hinted_children(dev);
  219         bus_generic_attach(dev);
  220 
  221         return (0);
  222 }
  223 
  224 static struct resource *
  225 obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
  226     u_long start, u_long end, u_long count, u_int flags)
  227 {
  228         struct obio_softc               *sc = device_get_softc(bus);
  229         struct obio_ivar                *ivar = device_get_ivars(child);
  230         struct resource                 *rv;
  231         struct resource_list_entry      *rle;
  232         struct rman                     *rm;
  233         int                              isdefault, needactivate, passthrough;
  234 
  235         isdefault = (start == 0UL && end == ~0UL && count == 1);
  236         needactivate = flags & RF_ACTIVE;
  237         passthrough = (device_get_parent(child) != bus);
  238         rle = NULL;
  239 
  240         if (passthrough)
  241                 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
  242                     rid, start, end, count, flags));
  243 
  244         /*
  245          * If this is an allocation of the "default" range for a given RID,
  246          * and we know what the resources for this device are (ie. they aren't
  247          * maintained by a child bus), then work out the start/end values.
  248          */
  249         if (isdefault) {
  250                 rle = resource_list_find(&ivar->resources, type, *rid);
  251                 if (rle == NULL)
  252                         return (NULL);
  253                 if (rle->res != NULL) {
  254                         panic("%s: resource entry is busy", __func__);
  255                 }
  256                 start = rle->start;
  257                 end = rle->end;
  258                 count = rle->count;
  259         }
  260 
  261         switch (type) {
  262         case SYS_RES_IRQ:
  263                 rm = &sc->oba_irq_rman;
  264                 break;
  265         case SYS_RES_MEMORY:
  266                 rm = &sc->oba_mem_rman;
  267                 break;
  268         default:
  269                 printf("%s: unknown resource type %d\n", __func__, type);
  270                 return (0);
  271         }
  272 
  273         rv = rman_reserve_resource(rm, start, end, count, flags, child);
  274         if (rv == 0) {
  275                 printf("%s: could not reserve resource\n", __func__);
  276                 return (0);
  277         }
  278 
  279         rman_set_rid(rv, *rid);
  280 
  281         if (needactivate) {
  282                 if (bus_activate_resource(child, type, *rid, rv)) {
  283                         printf("%s: could not activate resource\n", __func__);
  284                         rman_release_resource(rv);
  285                         return (0);
  286                 }
  287         }
  288 
  289         return (rv);
  290 }
  291 
  292 static int
  293 obio_activate_resource(device_t bus, device_t child, int type, int rid,
  294     struct resource *r)
  295 {
  296 
  297         /*
  298          * If this is a memory resource, track the direct mapping
  299          * in the uncached MIPS KSEG1 segment.
  300          */
  301         if (type == SYS_RES_MEMORY) {
  302                 void *vaddr;
  303 
  304                 vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r));
  305                 rman_set_virtual(r, vaddr);
  306                 rman_set_bustag(r, mips_bus_space_generic);
  307                 rman_set_bushandle(r, (bus_space_handle_t)vaddr);
  308         }
  309 
  310         return (rman_activate_resource(r));
  311 }
  312 
  313 static int
  314 obio_deactivate_resource(device_t bus, device_t child, int type, int rid,
  315     struct resource *r)
  316 {
  317 
  318         return (rman_deactivate_resource(r));
  319 }
  320 
  321 static int
  322 obio_release_resource(device_t dev, device_t child, int type,
  323     int rid, struct resource *r)
  324 {
  325         struct resource_list *rl;
  326         struct resource_list_entry *rle;
  327 
  328         rl = obio_get_resource_list(dev, child);
  329         if (rl == NULL)
  330                 return (EINVAL);
  331         rle = resource_list_find(rl, type, rid);
  332         if (rle == NULL)
  333                 return (EINVAL);
  334         rman_release_resource(r);
  335         rle->res = NULL;
  336 
  337         return (0);
  338 }
  339 
  340 static int
  341 obio_setup_intr(device_t dev, device_t child, struct resource *ires,
  342                 int flags, driver_filter_t *filt, driver_intr_t *handler,
  343                 void *arg, void **cookiep)
  344 {
  345         struct obio_softc *sc = device_get_softc(dev);
  346         struct intr_event *event;
  347         int irq, error, priority;
  348         uint32_t irqmask;
  349 
  350         irq = rman_get_start(ires);
  351 
  352         if (irq >= NIRQS)
  353                 panic("%s: bad irq %d", __func__, irq);
  354 
  355         event = sc->sc_eventstab[irq];
  356         if (event == NULL) {
  357                 error = intr_event_create(&event, (void *)irq, 0, irq, 
  358                     obio_mask_irq, obio_unmask_irq,
  359                     NULL, NULL,
  360                     "obio intr%d:", irq);
  361 
  362                 sc->sc_eventstab[irq] = event;
  363         }
  364         else
  365                 panic("obio: Can't share IRQs");
  366 
  367         intr_event_add_handler(event, device_get_nameunit(child), filt,
  368             handler, arg, intr_priority(flags), flags, cookiep);
  369 
  370         irqmask = 1 << irq;
  371         priority = irq_priorities[irq];
  372 
  373         if (priority == INTR_FIQ)
  374                 REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) | irqmask);
  375         else
  376                 REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) & ~irqmask);
  377 
  378         /* enable */
  379         REG_WRITE(ICU_ENABLE_REG, irqmask);
  380 
  381         return (0);
  382 }
  383 
  384 static int
  385 obio_teardown_intr(device_t dev, device_t child, struct resource *ires,
  386     void *cookie)
  387 {
  388         struct obio_softc *sc = device_get_softc(dev);
  389         int irq, result;
  390         uint32_t irqmask;
  391 
  392         irq = rman_get_start(ires);
  393         if (irq >= NIRQS)
  394                 panic("%s: bad irq %d", __func__, irq);
  395 
  396         if (sc->sc_eventstab[irq] == NULL)
  397                 panic("Trying to teardown unoccupied IRQ");
  398 
  399         irqmask = 1 << irq;     /* only used as a mask from here on */
  400 
  401         /* disable this irq in HW */
  402         REG_WRITE(ICU_DISABLE_REG, irqmask);
  403 
  404         result = intr_event_remove_handler(cookie);
  405         if (!result) {
  406                 sc->sc_eventstab[irq] = NULL;
  407         }
  408 
  409         return (result);
  410 }
  411 
  412 static int
  413 obio_intr(void *arg)
  414 {
  415         struct obio_softc *sc = arg;
  416         struct intr_event *event;
  417         uint32_t irqstat;
  418         int irq;
  419 
  420         irqstat = REG_READ(ICU_FIQ_STATUS_REG);
  421         irqstat |= REG_READ(ICU_STATUS_REG);
  422 
  423         irq = 0;
  424         while (irqstat != 0) {
  425                 if ((irqstat & 1) == 1) {
  426                         event = sc->sc_eventstab[irq];
  427                         if (!event || TAILQ_EMPTY(&event->ie_handlers))
  428                                 continue;
  429 
  430                         /* TODO: pass frame as an argument*/
  431                         /* TODO: log stray interrupt */
  432                         intr_event_handle(event, NULL);
  433                 }
  434 
  435                 irq++;
  436                 irqstat >>= 1;
  437         }
  438 
  439         return (FILTER_HANDLED);
  440 }
  441 
  442 static void
  443 obio_hinted_child(device_t bus, const char *dname, int dunit)
  444 {
  445         device_t                child;
  446         long                    maddr;
  447         int                     msize;
  448         int                     irq;
  449         int                     result;
  450 
  451         child = BUS_ADD_CHILD(bus, 0, dname, dunit);
  452 
  453         /*
  454          * Set hard-wired resources for hinted child using
  455          * specific RIDs.
  456          */
  457         resource_long_value(dname, dunit, "maddr", &maddr);
  458         resource_int_value(dname, dunit, "msize", &msize);
  459 
  460 
  461         result = bus_set_resource(child, SYS_RES_MEMORY, 0,
  462             maddr, msize);
  463         if (result != 0)
  464                 device_printf(bus, "warning: bus_set_resource() failed\n");
  465 
  466         if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
  467                 result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
  468                 if (result != 0)
  469                         device_printf(bus,
  470                             "warning: bus_set_resource() failed\n");
  471         }
  472 }
  473 
  474 static device_t
  475 obio_add_child(device_t bus, u_int order, const char *name, int unit)
  476 {
  477         device_t                child;
  478         struct obio_ivar        *ivar;
  479 
  480         ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
  481         if (ivar == NULL) {
  482                 printf("Failed to allocate ivar\n");
  483                 return (0);
  484         }
  485         resource_list_init(&ivar->resources);
  486 
  487         child = device_add_child_ordered(bus, order, name, unit);
  488         if (child == NULL) {
  489                 printf("Can't add child %s%d ordered\n", name, unit);
  490                 return (0);
  491         }
  492 
  493         device_set_ivars(child, ivar);
  494 
  495         return (child);
  496 }
  497 
  498 /*
  499  * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
  500  * Provides pointer to resource_list for these routines
  501  */
  502 static struct resource_list *
  503 obio_get_resource_list(device_t dev, device_t child)
  504 {
  505         struct obio_ivar *ivar;
  506 
  507         ivar = device_get_ivars(child);
  508         return (&(ivar->resources));
  509 }
  510 
  511 static device_method_t obio_methods[] = {
  512         DEVMETHOD(bus_activate_resource,        obio_activate_resource),
  513         DEVMETHOD(bus_add_child,                obio_add_child),
  514         DEVMETHOD(bus_alloc_resource,           obio_alloc_resource),
  515         DEVMETHOD(bus_deactivate_resource,      obio_deactivate_resource),
  516         DEVMETHOD(bus_get_resource_list,        obio_get_resource_list),
  517         DEVMETHOD(bus_hinted_child,             obio_hinted_child),
  518         DEVMETHOD(bus_release_resource,         obio_release_resource),
  519         DEVMETHOD(bus_setup_intr,               obio_setup_intr),
  520         DEVMETHOD(bus_teardown_intr,            obio_teardown_intr),
  521         DEVMETHOD(device_attach,                obio_attach),
  522         DEVMETHOD(device_probe,                 obio_probe),
  523         DEVMETHOD(bus_get_resource,             bus_generic_rl_get_resource),
  524         DEVMETHOD(bus_set_resource,             bus_generic_rl_set_resource),
  525 
  526         {0, 0},
  527 };
  528 
  529 static driver_t obio_driver = {
  530         "obio",
  531         obio_methods,
  532         sizeof(struct obio_softc),
  533 };
  534 static devclass_t obio_devclass;
  535 
  536 DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0);

Cache object: 7ffd983c828a76a3a009ec243258ad54


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