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/beri/beri_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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
    5  * Copyright (c) 2013 SRI International
    6  * All rights reserved.
    7  *
    8  * This software was developed by SRI International and the University of
    9  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
   10  * ("CTSRD"), as part of the DARPA CRASH research programme.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 #include "opt_platform.h"
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD: releng/12.0/sys/mips/beri/beri_pic.c 326259 2017-11-27 15:07:26Z pfg $");
   38 
   39 #include <sys/param.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/malloc.h>
   43 #include <sys/module.h>
   44 #include <sys/mutex.h>
   45 #include <sys/proc.h>
   46 #include <sys/systm.h>
   47 #include <sys/bus.h>
   48 
   49 #include <machine/bus.h>
   50 #include <machine/intr.h>
   51 
   52 #ifdef SMP
   53 #include <mips/beri/beri_mp.h>
   54 #endif
   55 
   56 #include <dev/fdt/fdt_common.h>
   57 #include <dev/ofw/openfirm.h>
   58 #include <dev/ofw/ofw_bus.h>
   59 #include <dev/ofw/ofw_bus_subr.h>
   60 
   61 #include "pic_if.h"
   62 
   63 #define BP_NUM_HARD_IRQS        5
   64 #define BP_NUM_IRQS             32
   65 /* We use hard irqs 15-31 as soft */
   66 #define BP_FIRST_SOFT           16
   67 
   68 #define BP_CFG_IRQ_S            0
   69 #define BP_CFG_IRQ_M            (0xf << BP_CFG_IRQ_S)
   70 #define BP_CFG_TID_S            8
   71 #define BP_CFG_TID_M            (0x7FFFFF << BP_CFG_TID_S)
   72 #define BP_CFG_ENABLE           (1 << 31)
   73 
   74 enum {
   75         BP_CFG,
   76         BP_IP_READ,
   77         BP_IP_SET,
   78         BP_IP_CLEAR
   79 };
   80 
   81 struct beripic_softc;
   82 
   83 struct beri_pic_isrc {
   84         struct intr_irqsrc      isrc;
   85         u_int                   irq;
   86         uint32_t                mips_hard_irq;
   87 };
   88 
   89 struct hirq {
   90         uint32_t                irq;
   91         struct beripic_softc    *sc;
   92 };
   93 
   94 struct beripic_softc {
   95         device_t                dev;
   96         uint32_t                nirqs;
   97         struct beri_pic_isrc    irqs[BP_NUM_IRQS];
   98         struct resource         *res[4 + BP_NUM_HARD_IRQS];
   99         void                    *ih[BP_NUM_HARD_IRQS];
  100         struct hirq             hirq[BP_NUM_HARD_IRQS];
  101         uint8_t                 mips_hard_irq_idx;
  102 };
  103 
  104 static struct resource_spec beri_pic_spec[] = {
  105         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  106         { SYS_RES_MEMORY,       1,      RF_ACTIVE },
  107         { SYS_RES_MEMORY,       2,      RF_ACTIVE },
  108         { SYS_RES_MEMORY,       3,      RF_ACTIVE },
  109         { SYS_RES_IRQ,          0,      RF_ACTIVE },
  110         { SYS_RES_IRQ,          1,      RF_ACTIVE },
  111         { SYS_RES_IRQ,          2,      RF_ACTIVE },
  112         { SYS_RES_IRQ,          3,      RF_ACTIVE },
  113         { SYS_RES_IRQ,          4,      RF_ACTIVE },
  114         { -1, 0 }
  115 };
  116 
  117 static int
  118 beri_pic_intr(void *arg)
  119 {
  120         struct beripic_softc *sc;
  121         struct intr_irqsrc *isrc;
  122         struct hirq *h;
  123         uint64_t intr;
  124         uint64_t reg;
  125         int i;
  126 
  127         h = arg;
  128         sc = h->sc;
  129 
  130         intr = bus_read_8(sc->res[BP_IP_READ], 0);
  131         while ((i = fls(intr)) != 0) {
  132                 i--;
  133                 intr &= ~(1u << i);
  134 
  135                 isrc = &sc->irqs[i].isrc;
  136 
  137                 reg = bus_read_8(sc->res[BP_CFG], i * 8);
  138                 if ((reg & BP_CFG_IRQ_M) != h->irq) {
  139                         continue;
  140                 }
  141                 if ((reg & (BP_CFG_ENABLE)) == 0) {
  142                         continue;
  143                 }
  144 
  145                 if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) {
  146                         device_printf(sc->dev, "Stray interrupt %u detected\n", i);
  147                 }
  148 
  149                 bus_write_8(sc->res[BP_IP_CLEAR], 0, (1 << i));
  150         }
  151 
  152         return (FILTER_HANDLED);
  153 }
  154 
  155 static int
  156 beripic_probe(device_t dev)
  157 {
  158 
  159         if (!ofw_bus_status_okay(dev))
  160                 return (ENXIO);
  161 
  162         if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-pic"))
  163                 return (ENXIO);
  164                 
  165         device_set_desc(dev, "BERI Programmable Interrupt Controller");
  166 
  167         return (BUS_PROBE_DEFAULT);
  168 }
  169 
  170 static int
  171 beripic_attach(device_t dev)
  172 {
  173         struct beripic_softc *sc;
  174         struct beri_pic_isrc *pic_isrc;
  175         const char *name;
  176         struct intr_irqsrc *isrc;
  177         intptr_t xref;
  178         uint32_t unit;
  179         int err;
  180         int i;
  181 
  182         sc = device_get_softc(dev);
  183         sc->dev = dev;
  184 
  185         if (bus_alloc_resources(dev, beri_pic_spec, sc->res)) {
  186                 device_printf(dev, "could not allocate resources\n");
  187                 return (ENXIO);
  188         }
  189 
  190         xref = OF_xref_from_node(ofw_bus_get_node(dev));
  191         name = device_get_nameunit(dev);
  192         unit = device_get_unit(dev);
  193         sc->nirqs = BP_NUM_IRQS;
  194 
  195         for (i = 0; i < sc->nirqs; i++) {
  196                 sc->irqs[i].irq = i;
  197                 isrc = &sc->irqs[i].isrc;
  198 
  199                 /* Assign mips hard irq number. */
  200                 pic_isrc = (struct beri_pic_isrc *)isrc;
  201                 pic_isrc->mips_hard_irq = sc->mips_hard_irq_idx++;
  202                 /* Last IRQ is used for IPIs. */
  203                 if (sc->mips_hard_irq_idx >= (BP_NUM_HARD_IRQS - 1)) {
  204                         sc->mips_hard_irq_idx = 0;
  205                 }
  206 
  207                 err = intr_isrc_register(isrc, sc->dev,
  208                     0, "pic%d,%d", unit, i);
  209                 bus_write_8(sc->res[BP_CFG], i * 8, 0);
  210         }
  211 
  212         /*
  213          * Now, when everything is initialized, it's right time to
  214          * register interrupt controller to interrupt framefork.
  215          */
  216         if (intr_pic_register(dev, xref) == NULL) {
  217                 device_printf(dev, "could not register PIC\n");
  218                 return (ENXIO);
  219         }
  220 
  221         /* Last IRQ is used for IPIs. */
  222         for (i = 0; i < (BP_NUM_HARD_IRQS - 1); i++) {
  223                 sc->hirq[i].sc = sc;
  224                 sc->hirq[i].irq = i;
  225                 if (bus_setup_intr(dev, sc->res[4+i], INTR_TYPE_CLK,
  226                     beri_pic_intr, NULL, &sc->hirq[i], sc->ih[i])) {
  227                         device_printf(dev, "could not setup irq handler\n");
  228                         intr_pic_deregister(dev, xref);
  229                         return (ENXIO);
  230                 }
  231         }
  232 
  233         return (0);
  234 }
  235 
  236 static void
  237 beri_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  238 {
  239         struct beri_pic_isrc *pic_isrc;
  240         struct beripic_softc *sc;
  241         uint64_t reg;
  242 
  243         sc = device_get_softc(dev);
  244         pic_isrc = (struct beri_pic_isrc *)isrc;
  245 
  246         reg = BP_CFG_ENABLE;
  247         reg |= (pic_isrc->mips_hard_irq << BP_CFG_IRQ_S);
  248         bus_write_8(sc->res[BP_CFG], pic_isrc->irq * 8, reg);
  249 }
  250 
  251 static void
  252 beri_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  253 {
  254         struct beri_pic_isrc *pic_isrc;
  255         struct beripic_softc *sc;
  256         uint64_t reg;
  257 
  258         sc = device_get_softc(dev);
  259         pic_isrc = (struct beri_pic_isrc *)isrc;
  260 
  261         reg = bus_read_8(sc->res[BP_CFG], pic_isrc->irq * 8);
  262         reg &= ~BP_CFG_ENABLE;
  263         bus_write_8(sc->res[BP_CFG], pic_isrc->irq * 8, reg);
  264 }
  265 
  266 static int
  267 beri_pic_map_intr(device_t dev, struct intr_map_data *data,
  268     struct intr_irqsrc **isrcp)
  269 {
  270         struct beripic_softc *sc;
  271         struct intr_map_data_fdt *daf;
  272         uint32_t irq;
  273 
  274         sc = device_get_softc(dev);
  275         daf = (struct intr_map_data_fdt *)data;
  276 
  277         if (data == NULL || data->type != INTR_MAP_DATA_FDT ||
  278             daf->ncells != 1 || daf->cells[0] >= sc->nirqs)
  279                 return (EINVAL);
  280 
  281         irq = daf->cells[0];
  282 
  283         *isrcp = &sc->irqs[irq].isrc;
  284 
  285         return (0);
  286 }
  287 
  288 static void
  289 beri_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  290 {
  291 
  292         beri_pic_enable_intr(dev, isrc);
  293 }
  294 
  295 static void
  296 beri_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  297 {
  298 
  299         beri_pic_disable_intr(dev, isrc);
  300 }
  301 
  302 #ifdef SMP
  303 void
  304 beripic_setup_ipi(device_t dev, u_int tid, u_int ipi_irq)
  305 {
  306         struct beripic_softc *sc;
  307         uint64_t reg;
  308 
  309         sc = device_get_softc(dev);
  310 
  311         reg = (BP_CFG_ENABLE);
  312         reg |= (ipi_irq << BP_CFG_IRQ_S);
  313         reg |= (tid << BP_CFG_TID_S);
  314         bus_write_8(sc->res[BP_CFG], ((BP_FIRST_SOFT + tid) * 8), reg);
  315 }
  316 
  317 void
  318 beripic_send_ipi(device_t dev, u_int tid)
  319 {
  320         struct beripic_softc *sc;
  321         uint64_t bit;
  322 
  323         sc = device_get_softc(dev);
  324 
  325         bit = (BP_FIRST_SOFT + tid);
  326         KASSERT(bit < BP_NUM_IRQS, ("tid (%d) to large\n", tid));
  327 
  328         bus_write_8(sc->res[BP_IP_SET], 0x0, (1 << bit));
  329 }
  330 
  331 void
  332 beripic_clear_ipi(device_t dev, u_int tid)
  333 {
  334         struct beripic_softc *sc;
  335         uint64_t bit;
  336 
  337         sc = device_get_softc(dev);
  338 
  339         bit = (BP_FIRST_SOFT + tid);
  340         KASSERT(bit < BP_NUM_IRQS, ("tid (%d) to large\n", tid));
  341 
  342         bus_write_8(sc->res[BP_IP_CLEAR], 0x0, (1 << bit));
  343 }
  344 #endif
  345 
  346 static device_method_t beripic_fdt_methods[] = {
  347         /* Device interface */
  348         DEVMETHOD(device_probe,         beripic_probe),
  349         DEVMETHOD(device_attach,        beripic_attach),
  350 
  351         /* Interrupt controller interface */
  352         DEVMETHOD(pic_enable_intr,      beri_pic_enable_intr),
  353         DEVMETHOD(pic_disable_intr,     beri_pic_disable_intr),
  354         DEVMETHOD(pic_map_intr,         beri_pic_map_intr),
  355         DEVMETHOD(pic_post_ithread,     beri_pic_post_ithread),
  356         DEVMETHOD(pic_pre_ithread,      beri_pic_pre_ithread),
  357 
  358         DEVMETHOD_END
  359 };
  360 
  361 devclass_t beripic_devclass;
  362 
  363 static driver_t beripic_driver = {
  364         "beripic",
  365         beripic_fdt_methods,
  366         sizeof(struct beripic_softc)
  367 };
  368 
  369 EARLY_DRIVER_MODULE(beripic, ofwbus, beripic_driver, beripic_devclass, 0, 0,
  370     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);

Cache object: 811e03d1b7cf3f10c1b02b752a1063c7


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