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/cavium/ciu.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) 2010 Juli Mallett <jmallett@FreeBSD.org>
    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  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: releng/8.4/sys/mips/cavium/ciu.c 215938 2010-11-27 12:26:40Z jchandra $
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/8.4/sys/mips/cavium/ciu.c 215938 2010-11-27 12:26:40Z jchandra $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/interrupt.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/rman.h>
   39 #include <sys/malloc.h>
   40 
   41 #include <machine/bus.h>
   42 #include <machine/intr_machdep.h>
   43 
   44 #include <contrib/octeon-sdk/cvmx.h>
   45 #include <contrib/octeon-sdk/cvmx-interrupt.h>
   46 
   47 /*
   48  * This bus sits between devices/buses and nexus and handles CIU interrupts
   49  * and passes everything else through.  It should really be a nexus subclass
   50  * or something, but for now this will be sufficient.
   51  */
   52 
   53 #define CIU_IRQ_HARD            (0)
   54 
   55 #define CIU_IRQ_EN0_BEGIN       CVMX_IRQ_WORKQ0
   56 #define CIU_IRQ_EN0_END         CVMX_IRQ_BOOTDMA
   57 #define CIU_IRQ_EN0_COUNT       ((CIU_IRQ_EN0_END - CIU_IRQ_EN0_BEGIN) + 1)
   58 
   59 #define CIU_IRQ_EN1_BEGIN       CVMX_IRQ_WDOG0
   60 #define CIU_IRQ_EN1_END         CVMX_IRQ_WDOG15
   61 #define CIU_IRQ_EN1_COUNT       ((CIU_IRQ_EN1_END - CIU_IRQ_EN1_BEGIN) + 1)
   62 
   63 struct ciu_softc {
   64         struct rman irq_rman;
   65         struct resource *ciu_irq;
   66 };
   67 
   68 static mips_intrcnt_t ciu_en0_intrcnt[CIU_IRQ_EN0_COUNT];
   69 static mips_intrcnt_t ciu_en1_intrcnt[CIU_IRQ_EN1_COUNT];
   70 
   71 static struct intr_event *ciu_en0_intr_events[CIU_IRQ_EN0_COUNT];
   72 static struct intr_event *ciu_en1_intr_events[CIU_IRQ_EN1_COUNT];
   73 
   74 static int              ciu_probe(device_t);
   75 static int              ciu_attach(device_t);
   76 static struct resource  *ciu_alloc_resource(device_t, device_t, int, int *,
   77                                             u_long, u_long, u_long, u_int);
   78 static int              ciu_setup_intr(device_t, device_t, struct resource *,
   79                                        int, driver_filter_t *, driver_intr_t *,
   80                                        void *, void **);
   81 static int              ciu_teardown_intr(device_t, device_t,
   82                                           struct resource *, void *);
   83 static void             ciu_hinted_child(device_t, const char *, int);
   84 
   85 static void             ciu_en0_intr_mask(void *);
   86 static void             ciu_en0_intr_unmask(void *);
   87 
   88 static void             ciu_en1_intr_mask(void *);
   89 static void             ciu_en1_intr_unmask(void *);
   90 
   91 static int              ciu_intr(void *);
   92 
   93 static int
   94 ciu_probe(device_t dev)
   95 {
   96         if (device_get_unit(dev) != 0)
   97                 return (ENXIO);
   98 
   99         device_set_desc(dev, "Cavium Octeon Central Interrupt Unit");
  100         return (0);
  101 }
  102 
  103 static int
  104 ciu_attach(device_t dev)
  105 {
  106         char name[MAXCOMLEN + 1];
  107         struct ciu_softc *sc;
  108         unsigned i;
  109         int error;
  110         int rid;
  111 
  112         sc = device_get_softc(dev);
  113 
  114         rid = 0;
  115         sc->ciu_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, CIU_IRQ_HARD,
  116                                          CIU_IRQ_HARD, 1, RF_ACTIVE);
  117         if (sc->ciu_irq == NULL) {
  118                 device_printf(dev, "could not allocate irq%d\n", CIU_IRQ_HARD);
  119                 return (ENXIO);
  120         }
  121 
  122         error = bus_setup_intr(dev, sc->ciu_irq, INTR_TYPE_MISC, ciu_intr,
  123                                NULL, sc, NULL);
  124         if (error != 0) {
  125                 device_printf(dev, "bus_setup_intr failed: %d\n", error);
  126                 return (error);
  127         }
  128 
  129         sc->irq_rman.rm_type = RMAN_ARRAY;
  130         sc->irq_rman.rm_descr = "CIU IRQ";
  131         
  132         error = rman_init(&sc->irq_rman);
  133         if (error != 0)
  134                 return (error);
  135 
  136         /*
  137          * We have two contiguous IRQ regions, use a single rman.
  138          */
  139         error = rman_manage_region(&sc->irq_rman, CIU_IRQ_EN0_BEGIN,
  140                                    CIU_IRQ_EN1_END);
  141         if (error != 0)
  142                 return (error);
  143 
  144         for (i = 0; i < CIU_IRQ_EN0_COUNT; i++) {
  145                 snprintf(name, sizeof name, "int%d:", i + CIU_IRQ_EN0_BEGIN);
  146                 ciu_en0_intrcnt[i] = mips_intrcnt_create(name);
  147         }
  148 
  149         for (i = 0; i < CIU_IRQ_EN1_COUNT; i++) {
  150                 snprintf(name, sizeof name, "int%d:", i + CIU_IRQ_EN1_BEGIN);
  151                 ciu_en1_intrcnt[i] = mips_intrcnt_create(name);
  152         }
  153 
  154         bus_generic_probe(dev);
  155         bus_generic_attach(dev);
  156 
  157         return (0);
  158 }
  159 
  160 static struct resource *
  161 ciu_alloc_resource(device_t bus, device_t child, int type, int *rid,
  162                    u_long start, u_long end, u_long count, u_int flags)
  163 {
  164         struct resource *res;
  165         struct ciu_softc *sc;
  166         
  167         sc = device_get_softc(bus);
  168 
  169         switch (type) {
  170         case SYS_RES_IRQ:
  171                 break;
  172         default:
  173                 return (bus_alloc_resource(device_get_parent(bus), type, rid,
  174                                            start, end, count, flags));
  175         }
  176 
  177         /*
  178          * One interrupt at a time for now.
  179          */
  180         if (start != end)
  181                 return (NULL);
  182 
  183         res = rman_reserve_resource(&sc->irq_rman, start, end, count, flags,
  184                                     child);
  185         if (res != NULL)
  186                 return (res);
  187 
  188         return (NULL);
  189 }
  190 
  191 static int
  192 ciu_setup_intr(device_t bus, device_t child, struct resource *res, int flags,
  193                driver_filter_t *filter, driver_intr_t *intr, void *arg,
  194                void **cookiep)
  195 {
  196         struct intr_event *event, **eventp;
  197         void (*mask_func)(void *);
  198         void (*unmask_func)(void *);
  199         mips_intrcnt_t intrcnt;
  200         int error;
  201         int irq;
  202 
  203         irq = rman_get_start(res);
  204         if (irq <= CIU_IRQ_EN0_END) {
  205                 eventp = &ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN];
  206                 intrcnt = ciu_en0_intrcnt[irq - CIU_IRQ_EN0_BEGIN];
  207                 mask_func = ciu_en0_intr_mask;
  208                 unmask_func = ciu_en0_intr_unmask;
  209         } else {
  210                 eventp = &ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN];
  211                 intrcnt = ciu_en1_intrcnt[irq - CIU_IRQ_EN1_BEGIN];
  212                 mask_func = ciu_en1_intr_mask;
  213                 unmask_func = ciu_en1_intr_unmask;
  214         }
  215 
  216         if ((event = *eventp) == NULL) {
  217                 error = intr_event_create(eventp, (void *)(uintptr_t)irq, 0,
  218                     irq, mask_func, unmask_func, NULL, NULL, "int%d", irq);
  219                 if (error != 0)
  220                         return (error);
  221 
  222                 event = *eventp;
  223 
  224                 unmask_func((void *)(uintptr_t)irq);
  225         }
  226 
  227         intr_event_add_handler(event, device_get_nameunit(child),
  228             filter, intr, arg, intr_priority(flags), flags, cookiep);
  229 
  230         mips_intrcnt_setname(intrcnt, event->ie_fullname);
  231 
  232         return (0);
  233 }
  234 
  235 static int
  236 ciu_teardown_intr(device_t bus, device_t child, struct resource *res,
  237                   void *cookie)
  238 {
  239         int error;
  240 
  241         error = intr_event_remove_handler(cookie);
  242         if (error != 0)
  243                 return (error);
  244 
  245         return (0);
  246 }
  247 
  248 static void
  249 ciu_hinted_child(device_t bus, const char *dname, int dunit)
  250 {
  251         BUS_ADD_CHILD(bus, 0, dname, dunit);
  252 }
  253 
  254 static void
  255 ciu_en0_intr_mask(void *arg)
  256 {
  257         uint64_t mask;
  258         int irq;
  259 
  260         irq = (uintptr_t)arg;
  261         mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2));
  262         mask &= ~(1ull << (irq - CIU_IRQ_EN0_BEGIN));
  263         cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), mask);
  264 }
  265 
  266 static void
  267 ciu_en0_intr_unmask(void *arg)
  268 {
  269         uint64_t mask;
  270         int irq;
  271 
  272         irq = (uintptr_t)arg;
  273         mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2));
  274         mask |= 1ull << (irq - CIU_IRQ_EN0_BEGIN);
  275         cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), mask);
  276 }
  277 
  278 static void
  279 ciu_en1_intr_mask(void *arg)
  280 {
  281         uint64_t mask;
  282         int irq;
  283 
  284         irq = (uintptr_t)arg;
  285         mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2));
  286         mask &= ~(1ull << (irq - CIU_IRQ_EN1_BEGIN));
  287         cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), mask);
  288 }
  289 
  290 static void
  291 ciu_en1_intr_unmask(void *arg)
  292 {
  293         uint64_t mask;
  294         int irq;
  295 
  296         irq = (uintptr_t)arg;
  297         mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2));
  298         mask |= 1ull << (irq - CIU_IRQ_EN1_BEGIN);
  299         cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), mask);
  300 }
  301 
  302 static int
  303 ciu_intr(void *arg)
  304 {
  305         struct ciu_softc *sc;
  306         uint64_t en0_sum, en1_sum;
  307         uint64_t en0_mask, en1_mask;
  308         int irq_index;
  309         int error;
  310 
  311         sc = arg;
  312         (void)sc;
  313 
  314         en0_sum = cvmx_read_csr(CVMX_CIU_INTX_SUM0(cvmx_get_core_num()*2));
  315         en1_sum = cvmx_read_csr(CVMX_CIU_INT_SUM1);
  316 
  317         en0_mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2));
  318         en1_mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2));
  319 
  320         en0_sum &= en0_mask;
  321         en1_sum &= en1_mask;
  322 
  323         if (en0_sum == 0 && en1_sum == 0)
  324                 return (FILTER_STRAY);
  325 
  326         irq_index = 0;
  327         for (irq_index = 0; en0_sum != 0; irq_index++, en0_sum >>= 1) {
  328                 if ((en0_sum & 1) == 0)
  329                         continue;
  330 
  331                 mips_intrcnt_inc(ciu_en0_intrcnt[irq_index]);
  332 
  333                 error = intr_event_handle(ciu_en0_intr_events[irq_index], NULL);
  334                 if (error != 0)
  335                         printf("%s: stray en0 irq%d\n", __func__, irq_index);
  336         }
  337 
  338         irq_index = 0;
  339         for (irq_index = 0; en1_sum != 0; irq_index++, en1_sum >>= 1) {
  340                 if ((en1_sum & 1) == 0)
  341                         continue;
  342 
  343                 mips_intrcnt_inc(ciu_en1_intrcnt[irq_index]);
  344 
  345                 error = intr_event_handle(ciu_en1_intr_events[irq_index], NULL);
  346                 if (error != 0)
  347                         printf("%s: stray en1 irq%d\n", __func__, irq_index);
  348         }
  349 
  350         return (FILTER_HANDLED);
  351 }
  352 
  353 static device_method_t ciu_methods[] = {
  354         DEVMETHOD(device_probe,         ciu_probe),
  355         DEVMETHOD(device_attach,        ciu_attach),
  356 
  357         DEVMETHOD(bus_alloc_resource,   ciu_alloc_resource),
  358         DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
  359         DEVMETHOD(bus_setup_intr,       ciu_setup_intr),
  360         DEVMETHOD(bus_teardown_intr,    ciu_teardown_intr),
  361 
  362         DEVMETHOD(bus_add_child,        bus_generic_add_child),
  363         DEVMETHOD(bus_hinted_child,     ciu_hinted_child),
  364 
  365         { 0, 0 }
  366 };
  367 
  368 static driver_t ciu_driver = {
  369         "ciu",
  370         ciu_methods,
  371         sizeof(struct ciu_softc),
  372 };
  373 static devclass_t ciu_devclass;
  374 DRIVER_MODULE(ciu, nexus, ciu_driver, ciu_devclass, 0, 0);

Cache object: 58e450a16e703d68838e34454cd48a08


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