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/mips/mips_pic.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) 2015 Alexander Kabaev
    3  * Copyright (c) 2006 Oleksandr Tymoshenko
    4  * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org>
    5  * All rights reserved.
    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  *    without modification, immediately at the beginning of the file.
   13  * 2. 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 AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, 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 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include "opt_platform.h"
   34 #include "opt_hwpmc_hooks.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/kernel.h>
   40 #include <sys/ktr.h>
   41 #include <sys/module.h>
   42 #include <sys/malloc.h>
   43 #include <sys/rman.h>
   44 #include <sys/pcpu.h>
   45 #include <sys/proc.h>
   46 #include <sys/cpuset.h>
   47 #include <sys/lock.h>
   48 #include <sys/mutex.h>
   49 #include <sys/smp.h>
   50 #include <sys/sched.h>
   51 #include <sys/pmc.h>
   52 #include <sys/pmckern.h>
   53 
   54 #include <machine/bus.h>
   55 #include <machine/hwfunc.h>
   56 #include <machine/intr.h>
   57 #include <machine/smp.h>
   58 
   59 #ifdef FDT
   60 #include <dev/fdt/fdt_common.h>
   61 #include <dev/ofw/openfirm.h>
   62 #include <dev/ofw/ofw_bus.h>
   63 #include <dev/ofw/ofw_bus_subr.h>
   64 #endif
   65 
   66 #include "pic_if.h"
   67 
   68 #define NHARD_IRQS      6
   69 #define NSOFT_IRQS      2
   70 #define NREAL_IRQS      (NHARD_IRQS + NSOFT_IRQS)
   71 
   72 static int mips_pic_intr(void *);
   73 
   74 struct intr_map_data_mips_pic {
   75         struct intr_map_data    hdr;
   76         u_int                   irq;
   77 };
   78 
   79 struct mips_pic_irqsrc {
   80         struct intr_irqsrc      isrc;
   81         struct resource         *res;
   82         u_int                   irq;
   83 };
   84 
   85 struct mips_pic_softc {
   86         device_t                        pic_dev;
   87         struct mips_pic_irqsrc          pic_irqs[NREAL_IRQS];
   88         struct rman                     pic_irq_rman;
   89         struct mtx                      mutex;
   90         uint32_t                        nirqs;
   91 };
   92 
   93 static struct mips_pic_softc *pic_sc;
   94 
   95 #define PIC_INTR_ISRC(sc, irq)          (&(sc)->pic_irqs[(irq)].isrc)
   96 
   97 #ifdef FDT
   98 static struct ofw_compat_data compat_data[] = {
   99         {"mti,cpu-interrupt-controller",        true},
  100         {NULL,                                  false}
  101 };
  102 #endif
  103 
  104 #ifndef FDT
  105 static void
  106 mips_pic_identify(driver_t *drv, device_t parent)
  107 {
  108 
  109         BUS_ADD_CHILD(parent, 0, "cpupic", 0);
  110 }
  111 #endif
  112 
  113 static int
  114 mips_pic_probe(device_t dev)
  115 {
  116 
  117 #ifdef FDT
  118         if (!ofw_bus_status_okay(dev))
  119                 return (ENXIO);
  120 
  121         if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
  122                 return (ENXIO);
  123 #endif
  124         device_set_desc(dev, "MIPS32 Interrupt Controller");
  125         return (BUS_PROBE_DEFAULT);
  126 }
  127 
  128 static inline void
  129 pic_irq_unmask(struct mips_pic_softc *sc, u_int irq)
  130 {
  131 
  132         mips_wr_status(mips_rd_status() | ((1 << irq) << 8));
  133 }
  134 
  135 static inline void
  136 pic_irq_mask(struct mips_pic_softc *sc, u_int irq)
  137 {
  138 
  139         mips_wr_status(mips_rd_status() & ~((1 << irq) << 8));
  140 }
  141 
  142 static inline intptr_t
  143 pic_xref(device_t dev)
  144 {
  145 #ifdef FDT
  146         return (OF_xref_from_node(ofw_bus_get_node(dev)));
  147 #else
  148         return (0);
  149 #endif
  150 }
  151 
  152 static int
  153 mips_pic_register_isrcs(struct mips_pic_softc *sc)
  154 {
  155         int error;
  156         uint32_t irq, i, tmpirq;
  157         struct intr_irqsrc *isrc;
  158         char *name;
  159 
  160         for (irq = 0; irq < sc->nirqs; irq++) {
  161                 sc->pic_irqs[irq].irq = irq;
  162                 sc->pic_irqs[irq].res = rman_reserve_resource(&sc->pic_irq_rman,
  163                     irq, irq, 1, RF_ACTIVE, sc->pic_dev);
  164                 if (sc->pic_irqs[irq].res == NULL) {
  165                         device_printf(sc->pic_dev,
  166                             "%s failed to alloc resource for irq %u",
  167                             __func__, irq);
  168                         return (ENOMEM);
  169                 }
  170                 isrc = PIC_INTR_ISRC(sc, irq);
  171                 if (irq < NSOFT_IRQS) {
  172                         name = "sint";
  173                         tmpirq = irq;
  174                 } else {
  175                         name = "int";
  176                         tmpirq = irq - NSOFT_IRQS;
  177                 }
  178                 error = intr_isrc_register(isrc, sc->pic_dev, 0, "%s%u",
  179                     name, tmpirq);
  180                 if (error != 0) {
  181                         for (i = 0; i < irq; i++) {
  182                                 intr_isrc_deregister(PIC_INTR_ISRC(sc, i));
  183                         }
  184                         device_printf(sc->pic_dev, "%s failed", __func__);
  185                         return (error);
  186                 }
  187         }
  188 
  189         return (0);
  190 }
  191 
  192 static int
  193 mips_pic_attach(device_t dev)
  194 {
  195         struct          mips_pic_softc *sc;
  196         intptr_t        xref = pic_xref(dev);
  197 
  198         if (pic_sc)
  199                 return (ENXIO);
  200 
  201         sc = device_get_softc(dev);
  202 
  203         sc->pic_dev = dev;
  204         pic_sc = sc;
  205 
  206         /* Initialize mutex */
  207         mtx_init(&sc->mutex, "PIC lock", "", MTX_SPIN);
  208 
  209         /* Set the number of interrupts */
  210         sc->nirqs = nitems(sc->pic_irqs);
  211 
  212         /* Init the IRQ rman */
  213         sc->pic_irq_rman.rm_type = RMAN_ARRAY;
  214         sc->pic_irq_rman.rm_descr = "MIPS PIC IRQs";
  215         if (rman_init(&sc->pic_irq_rman) != 0 ||
  216             rman_manage_region(&sc->pic_irq_rman, 0, sc->nirqs - 1) != 0) {
  217                 device_printf(dev, "failed to setup IRQ rman\n");
  218                 goto cleanup;
  219         }
  220 
  221         /* Register the interrupts */
  222         if (mips_pic_register_isrcs(sc) != 0) {
  223                 device_printf(dev, "could not register PIC ISRCs\n");
  224                 goto cleanup;
  225         }
  226 
  227         /*
  228          * Now, when everything is initialized, it's right time to
  229          * register interrupt controller to interrupt framefork.
  230          */
  231         if (intr_pic_register(dev, xref) == NULL) {
  232                 device_printf(dev, "could not register PIC\n");
  233                 goto cleanup;
  234         }
  235 
  236         /* Claim our root controller role */
  237         if (intr_pic_claim_root(dev, xref, mips_pic_intr, sc, 0) != 0) {
  238                 device_printf(dev, "could not set PIC as a root\n");
  239                 intr_pic_deregister(dev, xref);
  240                 goto cleanup;
  241         }
  242 
  243         return (0);
  244 
  245 cleanup:
  246         return(ENXIO);
  247 }
  248 
  249 int
  250 mips_pic_intr(void *arg)
  251 {
  252         struct mips_pic_softc *sc = arg;
  253         register_t cause, status;
  254         int i, intr;
  255 
  256         cause = mips_rd_cause();
  257         status = mips_rd_status();
  258         intr = (cause & MIPS_INT_MASK) >> 8;
  259         /*
  260          * Do not handle masked interrupts. They were masked by
  261          * pre_ithread function (mips_mask_XXX_intr) and will be
  262          * unmasked once ithread is through with handler
  263          */
  264         intr &= (status & MIPS_INT_MASK) >> 8;
  265         while ((i = fls(intr)) != 0) {
  266                 i--; /* Get a 0-offset interrupt. */
  267                 intr &= ~(1 << i);
  268 
  269                 if (intr_isrc_dispatch(PIC_INTR_ISRC(sc, i),
  270                     curthread->td_intr_frame) != 0) {
  271                         device_printf(sc->pic_dev,
  272                             "Stray interrupt %u detected\n", i);
  273                         pic_irq_mask(sc, i);
  274                         continue;
  275                 }
  276         }
  277 
  278         KASSERT(i == 0, ("all interrupts handled"));
  279 
  280 #ifdef HWPMC_HOOKS
  281         if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN)) {
  282                 struct trapframe *tf = PCPU_GET(curthread)->td_intr_frame;
  283 
  284                 pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf);
  285         }
  286 #endif
  287         return (FILTER_HANDLED);
  288 }
  289 
  290 static void
  291 mips_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  292 {
  293         u_int irq;
  294 
  295         irq = ((struct mips_pic_irqsrc *)isrc)->irq;
  296         pic_irq_mask(device_get_softc(dev), irq);
  297 }
  298 
  299 static void
  300 mips_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  301 {
  302         u_int irq;
  303 
  304         irq = ((struct mips_pic_irqsrc *)isrc)->irq;
  305         pic_irq_unmask(device_get_softc(dev), irq);
  306 }
  307 
  308 static int
  309 mips_pic_map_intr(device_t dev, struct intr_map_data *data,
  310     struct intr_irqsrc **isrcp)
  311 {
  312         struct mips_pic_softc *sc;
  313         int res;
  314 
  315         sc = device_get_softc(dev);
  316         res = 0;
  317 #ifdef FDT
  318         if (data->type == INTR_MAP_DATA_FDT) {
  319                 struct intr_map_data_fdt *daf;
  320 
  321                 daf = (struct intr_map_data_fdt *)data;
  322 
  323                 if (daf->ncells != 1 || daf->cells[0] >= sc->nirqs)
  324                         return (EINVAL);
  325 
  326                 *isrcp = PIC_INTR_ISRC(sc, daf->cells[0]);
  327         } else
  328 #endif
  329         if (data->type == INTR_MAP_DATA_PLAT_1) {
  330                 struct intr_map_data_mips_pic *mpd;
  331 
  332                 mpd = (struct intr_map_data_mips_pic *)data;
  333 
  334                 if (mpd->irq < 0 || mpd->irq >= sc->nirqs)
  335                         return (EINVAL);
  336 
  337                 *isrcp = PIC_INTR_ISRC(sc, mpd->irq);
  338         } else {
  339                 res = ENOTSUP;
  340         }
  341 
  342         return (res);
  343 }
  344 
  345 static void
  346 mips_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  347 {
  348 
  349         mips_pic_disable_intr(dev, isrc);
  350 }
  351 
  352 static void
  353 mips_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  354 {
  355 
  356         mips_pic_enable_intr(dev, isrc);
  357 }
  358 
  359 static void
  360 mips_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
  361 {
  362 }
  363 
  364 static device_method_t mips_pic_methods[] = {
  365         /* Device interface */
  366 #ifndef FDT
  367         DEVMETHOD(device_identify,      mips_pic_identify),
  368 #endif
  369         DEVMETHOD(device_probe,         mips_pic_probe),
  370         DEVMETHOD(device_attach,        mips_pic_attach),
  371 
  372         /* Interrupt controller interface */
  373         DEVMETHOD(pic_disable_intr,     mips_pic_disable_intr),
  374         DEVMETHOD(pic_enable_intr,      mips_pic_enable_intr),
  375         DEVMETHOD(pic_map_intr,         mips_pic_map_intr),
  376         DEVMETHOD(pic_pre_ithread,      mips_pic_pre_ithread),
  377         DEVMETHOD(pic_post_ithread,     mips_pic_post_ithread),
  378         DEVMETHOD(pic_post_filter,      mips_pic_post_filter),
  379 
  380         { 0, 0 }
  381 };
  382 
  383 static driver_t mips_pic_driver = {
  384         "cpupic",
  385         mips_pic_methods,
  386         sizeof(struct mips_pic_softc),
  387 };
  388 
  389 static devclass_t mips_pic_devclass;
  390 
  391 #ifdef FDT
  392 EARLY_DRIVER_MODULE(cpupic, ofwbus, mips_pic_driver, mips_pic_devclass, 0, 0,
  393     BUS_PASS_INTERRUPT);
  394 #else
  395 EARLY_DRIVER_MODULE(cpupic, nexus, mips_pic_driver, mips_pic_devclass, 0, 0,
  396     BUS_PASS_INTERRUPT);
  397 #endif
  398 
  399 void
  400 cpu_init_interrupts(void)
  401 {
  402 }
  403 
  404 int
  405 cpu_create_intr_map(int irq)
  406 {
  407         struct intr_map_data_mips_pic *mips_pic_data;
  408         intptr_t iparent;
  409         size_t len;
  410         u_int new_irq;
  411 
  412         len = sizeof(*mips_pic_data);
  413         iparent = pic_xref(pic_sc->pic_dev);
  414 
  415         /* Allocate mips_pic data and fill it in */
  416         mips_pic_data = (struct intr_map_data_mips_pic *)intr_alloc_map_data(
  417             INTR_MAP_DATA_PLAT_1, len, M_WAITOK | M_ZERO);
  418         mips_pic_data->irq = irq;
  419 
  420         /* Get the new irq number */
  421         new_irq = intr_map_irq(pic_sc->pic_dev, iparent,
  422             (struct intr_map_data *)mips_pic_data);
  423 
  424         /* Adjust the resource accordingly */
  425         rman_set_start(pic_sc->pic_irqs[irq].res, new_irq);
  426         rman_set_end(pic_sc->pic_irqs[irq].res, new_irq);
  427 
  428         /* Activate the new irq */
  429         return (intr_activate_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res));
  430 }
  431 
  432 struct resource *
  433 cpu_get_irq_resource(int irq)
  434 {
  435 
  436         KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
  437 
  438         if (irq < 0 || irq >= pic_sc->nirqs)
  439                 panic("%s called for unknown irq %d", __func__, irq);
  440 
  441         return pic_sc->pic_irqs[irq].res;
  442 }
  443 
  444 void
  445 cpu_establish_hardintr(const char *name, driver_filter_t *filt,
  446     void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
  447 {
  448         int res;
  449 
  450         /*
  451          * We have 6 levels, but thats 0 - 5 (not including 6)
  452          */
  453         if (irq < 0 || irq >= NHARD_IRQS)
  454                 panic("%s called for unknown hard intr %d", __func__, irq);
  455 
  456         KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
  457 
  458         irq += NSOFT_IRQS;
  459 
  460         res = cpu_create_intr_map(irq);
  461         if (res != 0) panic("Unable to create map for hard IRQ %d", irq);
  462 
  463         res = intr_setup_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res, filt,
  464             handler, arg, flags, cookiep);
  465         if (res != 0) panic("Unable to add hard IRQ %d handler", irq);
  466 }
  467 
  468 void
  469 cpu_establish_softintr(const char *name, driver_filter_t *filt,
  470     void (*handler)(void*), void *arg, int irq, int flags,
  471     void **cookiep)
  472 {
  473         int res;
  474 
  475         if (irq < 0 || irq > NSOFT_IRQS)
  476                 panic("%s called for unknown soft intr %d", __func__, irq);
  477 
  478         KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
  479 
  480         res = cpu_create_intr_map(irq);
  481         if (res != 0) panic("Unable to create map for soft IRQ %d", irq);
  482 
  483         res = intr_setup_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res, filt,
  484             handler, arg, flags, cookiep);
  485         if (res != 0) panic("Unable to add soft IRQ %d handler", irq);
  486 }
  487 

Cache object: 95a163c16c3c72ef553ca44d5b1857a0


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