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/broadcom/bcm_mips74k.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) 2016 Michael Zhilin <mizhka@gmail.com>
    3  * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
    4  * Copyright (c) 2017 The FreeBSD Foundation
    5  * All rights reserved.
    6  *
    7  * Portions of this software were developed by Landon Fuller
    8  * under sponsorship from the FreeBSD Foundation.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer,
   15  *    without modification.
   16  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   17  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   18  *    redistribution must be conditioned upon including a substantially
   19  *    similar Disclaimer requirement for further binary redistribution.
   20  *
   21  * NO WARRANTY
   22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   25  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   26  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   27  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   30  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   32  * THE POSSIBILITY OF SUCH DAMAGES.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/12.0/sys/mips/broadcom/bcm_mips74k.c 326079 2017-11-21 23:15:20Z landonf $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/kernel.h>
   40 #include <sys/bus.h>
   41 #include <sys/module.h>
   42 #include <sys/proc.h>
   43 
   44 #include <machine/bus.h>
   45 #include <sys/rman.h>
   46 
   47 #include <machine/cpufunc.h>
   48 #include <machine/intr.h>
   49 #include <machine/resource.h>
   50 
   51 #include <dev/bhnd/bhnd.h>
   52 #include <dev/bhnd/bcma/bcma_dmp.h>
   53 
   54 #include "pic_if.h"
   55 
   56 #include "bcm_machdep.h"
   57 
   58 #include "bcm_mipsvar.h"
   59 #include "bcm_mips74kreg.h"
   60 
   61 /*
   62  * Broadcom MIPS74K Core
   63  *
   64  * These cores are only found on bcma(4) chipsets.
   65  */
   66 
   67 struct bcm_mips74k_softc;
   68 
   69 static int      bcm_mips74k_pic_intr(void *arg);
   70 static void     bcm_mips74k_mask_irq(struct bcm_mips74k_softc *sc,
   71                     u_int mips_irq, u_int ivec);
   72 static void     bcm_mips74k_unmask_irq(struct bcm_mips74k_softc *sc,
   73                     u_int mips_irq, u_int ivec);
   74 
   75 static const struct bhnd_device bcm_mips74k_devs[] = {
   76         BHND_DEVICE(MIPS, MIPS74K, NULL, NULL, BHND_DF_SOC),
   77         BHND_DEVICE_END
   78 };
   79 
   80 struct bcm_mips74k_softc {
   81         struct bcm_mips_softc    bcm_mips;      /**< parent softc */
   82         device_t                 dev;
   83         struct resource         *mem;           /**< cpu core registers */
   84         int                      mem_rid;
   85 };
   86 
   87 /* Early routing of the CPU timer interrupt is required */
   88 static void
   89 bcm_mips74k_timer_init(void *unused)
   90 {
   91         struct bcm_platform     *bp;
   92         u_int                    irq;
   93         uint32_t                 mask;
   94 
   95         bp = bcm_get_platform();
   96 
   97         /* Must be a MIPS74K core attached to a BCMA interconnect */
   98         if (!bhnd_core_matches(&bp->cpu_id, &(struct bhnd_core_match) {
   99                 BHND_MATCH_CORE(BHND_MFGID_MIPS, BHND_COREID_MIPS74K)
  100         })) {
  101                 if (bootverbose) {
  102                         BCM_ERR("not a MIPS74K core: %s %s\n",
  103                             bhnd_vendor_name(bp->cpu_id.vendor),
  104                             bhnd_core_name(&bp->cpu_id));
  105                 }
  106 
  107                 return;
  108         }
  109 
  110         if (!BHND_CHIPTYPE_IS_BCMA_COMPATIBLE(bp->cid.chip_type)) {
  111                 if (bootverbose)
  112                         BCM_ERR("not a BCMA device\n");
  113                 return;
  114         }
  115 
  116         /* Route the timer bus ivec to the CPU's timer IRQ, and disable any
  117          * other vectors assigned to the IRQ. */
  118         irq = BCM_MIPS74K_GET_TIMER_IRQ();
  119         mask = BCM_MIPS74K_INTR_SEL_FLAG(BCM_MIPS74K_TIMER_IVEC);
  120 
  121         BCM_CPU_WRITE_4(bp, BCM_MIPS74K_INTR_SEL(irq), mask);
  122 }
  123 
  124 static int
  125 bcm_mips74k_probe(device_t dev)
  126 {
  127         const struct bhnd_device        *id;
  128         const struct bhnd_chipid        *cid;
  129 
  130         id = bhnd_device_lookup(dev, bcm_mips74k_devs,
  131             sizeof(bcm_mips74k_devs[0]));
  132         if (id == NULL)
  133                 return (ENXIO);
  134 
  135         /* Check the chip type; the MIPS74K core should only be found
  136          * on bcma(4) chipsets (and we rely on bcma OOB interrupt
  137          * routing). */
  138         cid = bhnd_get_chipid(dev);
  139         if (!BHND_CHIPTYPE_IS_BCMA_COMPATIBLE(cid->chip_type))
  140                 return (ENXIO);
  141 
  142         bhnd_set_default_core_desc(dev);
  143         return (BUS_PROBE_DEFAULT);
  144 }
  145 
  146 static int
  147 bcm_mips74k_attach(device_t dev)
  148 {
  149         struct bcm_mips74k_softc        *sc;
  150         u_int                            timer_irq;
  151         int                              error;
  152 
  153         sc = device_get_softc(dev);
  154         sc->dev = dev;
  155 
  156         /* Allocate our core's register block */
  157         sc->mem_rid = 0;
  158         sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
  159             RF_ACTIVE);
  160         if (sc->mem == NULL) {
  161                 device_printf(dev, "failed to allocate cpu register block\n");
  162                 return (ENXIO);
  163         }
  164 
  165         /* Clear interrupt map */
  166         timer_irq = BCM_MIPS74K_GET_TIMER_IRQ();
  167         for (size_t i = 0; i < BCM_MIPS74K_NUM_INTR; i++) {
  168                 /* We don't use the timer IRQ; leave it routed to the
  169                  * MIPS CPU */
  170                 if (i == timer_irq)
  171                         continue;
  172 
  173                 bus_write_4(sc->mem, BCM_MIPS74K_INTR_SEL(i), 0);
  174         }
  175 
  176         /* Initialize the generic BHND MIPS driver state */
  177         error = bcm_mips_attach(dev, BCM_MIPS74K_NUM_INTR, timer_irq,
  178             bcm_mips74k_pic_intr);
  179         if (error) {
  180                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
  181                 return (error);
  182         }
  183 
  184         return (0);
  185 }
  186 
  187 static int
  188 bcm_mips74k_detach(device_t dev)
  189 {
  190         struct bcm_mips74k_softc        *sc;
  191         int                              error;
  192 
  193         sc = device_get_softc(dev);
  194 
  195         if ((error = bcm_mips_detach(dev)))
  196                 return (error);
  197 
  198         bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
  199 
  200         return (0);
  201 }
  202 
  203 
  204 /* PIC_DISABLE_INTR() */
  205 static void
  206 bcm_mips74k_pic_disable_intr(device_t dev, struct intr_irqsrc *irqsrc)
  207 {
  208         struct bcm_mips74k_softc        *sc;
  209         struct bcm_mips_irqsrc          *isrc;
  210 
  211         sc = device_get_softc(dev);
  212         isrc = (struct bcm_mips_irqsrc *)irqsrc;
  213 
  214         KASSERT(isrc->cpuirq != NULL, ("no assigned MIPS IRQ"));
  215 
  216         bcm_mips74k_mask_irq(sc, isrc->cpuirq->mips_irq, isrc->ivec);
  217 }
  218 
  219 /* PIC_ENABLE_INTR() */
  220 static void
  221 bcm_mips74k_pic_enable_intr(device_t dev, struct intr_irqsrc *irqsrc)
  222 {
  223         struct bcm_mips74k_softc        *sc;
  224         struct bcm_mips_irqsrc          *isrc;
  225 
  226         sc = device_get_softc(dev);
  227         isrc = (struct bcm_mips_irqsrc *)irqsrc;
  228 
  229         KASSERT(isrc->cpuirq != NULL, ("no assigned MIPS IRQ"));
  230 
  231         bcm_mips74k_unmask_irq(sc, isrc->cpuirq->mips_irq, isrc->ivec);
  232 }
  233 
  234 /* PIC_PRE_ITHREAD() */
  235 static void
  236 bcm_mips74k_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  237 {
  238         bcm_mips74k_pic_disable_intr(dev, isrc);
  239 }
  240 
  241 /* PIC_POST_ITHREAD() */
  242 static void
  243 bcm_mips74k_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  244 {
  245         bcm_mips74k_pic_enable_intr(dev, isrc);
  246 }
  247 
  248 /* PIC_POST_FILTER() */
  249 static void
  250 bcm_mips74k_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
  251 {
  252 }
  253 
  254 /**
  255  * Disable routing of backplane interrupt vector @p ivec to MIPS IRQ
  256  * @p mips_irq.
  257  */
  258 static void
  259 bcm_mips74k_mask_irq(struct bcm_mips74k_softc *sc, u_int mips_irq, u_int ivec)
  260 {
  261         uint32_t oobsel;
  262 
  263         KASSERT(mips_irq < sc->bcm_mips.num_cpuirqs, ("invalid MIPS IRQ %u",
  264             mips_irq));
  265         KASSERT(mips_irq < BCM_MIPS74K_NUM_INTR, ("unsupported MIPS IRQ %u",
  266             mips_irq));
  267         KASSERT(ivec < BCMA_OOB_NUM_BUSLINES, ("invalid backplane ivec"));
  268 
  269         oobsel = bus_read_4(sc->mem, BCM_MIPS74K_INTR_SEL(mips_irq));
  270         oobsel &= ~(BCM_MIPS74K_INTR_SEL_FLAG(ivec));
  271         bus_write_4(sc->mem, BCM_MIPS74K_INTR_SEL(mips_irq), oobsel);
  272 }
  273 
  274 /**
  275  * Enable routing of an interrupt.
  276  */
  277 static void
  278 bcm_mips74k_unmask_irq(struct bcm_mips74k_softc *sc, u_int mips_irq, u_int ivec)
  279 {
  280         uint32_t oobsel;
  281 
  282         KASSERT(mips_irq < sc->bcm_mips.num_cpuirqs, ("invalid MIPS IRQ %u",
  283             mips_irq));
  284         KASSERT(mips_irq < BCM_MIPS74K_NUM_INTR, ("unsupported MIPS IRQ %u",
  285             mips_irq));
  286         KASSERT(ivec < BCMA_OOB_NUM_BUSLINES, ("invalid backplane ivec"));
  287 
  288         oobsel = bus_read_4(sc->mem, BCM_MIPS74K_INTR_SEL(mips_irq));
  289         oobsel |= BCM_MIPS74K_INTR_SEL_FLAG(ivec);
  290         bus_write_4(sc->mem, BCM_MIPS74K_INTR_SEL(mips_irq), oobsel);
  291 }
  292 
  293 /* our MIPS CPU interrupt filter */
  294 static int
  295 bcm_mips74k_pic_intr(void *arg)
  296 {
  297         struct bcm_mips74k_softc        *sc;
  298         struct bcm_mips_cpuirq          *cpuirq;
  299         struct bcm_mips_irqsrc          *isrc_solo;
  300         uint32_t                         oobsel, intr;
  301         u_int                            i;
  302         int                              error;
  303 
  304         cpuirq = arg;
  305         sc = (struct bcm_mips74k_softc*)cpuirq->sc;
  306 
  307         /* Fetch current interrupt state */
  308         intr = bus_read_4(sc->mem, BCM_MIPS74K_INTR_STATUS);
  309 
  310         /* Fetch mask of interrupt vectors routed to this MIPS IRQ */
  311         KASSERT(cpuirq->mips_irq < BCM_MIPS74K_NUM_INTR,
  312             ("invalid irq %u", cpuirq->mips_irq));
  313 
  314         oobsel = bus_read_4(sc->mem, BCM_MIPS74K_INTR_SEL(cpuirq->mips_irq));
  315 
  316         /* Ignore interrupts not routed to this MIPS IRQ */
  317         intr &= oobsel;
  318 
  319         /* Handle isrc_solo direct dispatch path */
  320         isrc_solo = cpuirq->isrc_solo;
  321         if (isrc_solo != NULL) {
  322                 if (intr & BCM_MIPS_IVEC_MASK(isrc_solo)) {
  323                         error = intr_isrc_dispatch(&isrc_solo->isrc,
  324                             curthread->td_intr_frame);
  325                         if (error) {
  326                                 device_printf(sc->dev, "Stray interrupt %u "
  327                                     "detected\n", isrc_solo->ivec);
  328                                 bcm_mips74k_pic_disable_intr(sc->dev,
  329                                     &isrc_solo->isrc);
  330                         }
  331                 }
  332 
  333                 intr &= ~(BCM_MIPS_IVEC_MASK(isrc_solo));
  334                 if (intr == 0)
  335                         return (FILTER_HANDLED);
  336 
  337                 /* Report and mask additional stray interrupts */
  338                 while ((i = fls(intr)) != 0) {
  339                         i--; /* Get a 0-offset interrupt. */
  340                         intr &= ~(1 << i);
  341 
  342                         device_printf(sc->dev, "Stray interrupt %u "
  343                                 "detected\n", i);
  344                         bcm_mips74k_mask_irq(sc, cpuirq->mips_irq, i);
  345                 }
  346 
  347                 return (FILTER_HANDLED);
  348         }
  349 
  350         /* Standard dispatch path  */
  351         while ((i = fls(intr)) != 0) {
  352                 i--; /* Get a 0-offset interrupt. */
  353                 intr &= ~(1 << i);
  354 
  355                 KASSERT(i < nitems(sc->bcm_mips.isrcs), ("invalid ivec %u", i));
  356 
  357                 error = intr_isrc_dispatch(&sc->bcm_mips.isrcs[i].isrc,
  358                     curthread->td_intr_frame);
  359                 if (error) {
  360                         device_printf(sc->dev, "Stray interrupt %u detected\n",
  361                             i);
  362                         bcm_mips74k_mask_irq(sc, cpuirq->mips_irq, i);
  363                         continue;
  364                 }
  365         }
  366 
  367         return (FILTER_HANDLED);
  368 }
  369 
  370 static device_method_t bcm_mips74k_methods[] = {
  371         /* Device interface */
  372         DEVMETHOD(device_probe,         bcm_mips74k_probe),
  373         DEVMETHOD(device_attach,        bcm_mips74k_attach),
  374         DEVMETHOD(device_detach,        bcm_mips74k_detach),
  375 
  376         /* Interrupt controller interface */
  377         DEVMETHOD(pic_disable_intr,     bcm_mips74k_pic_disable_intr),
  378         DEVMETHOD(pic_enable_intr,      bcm_mips74k_pic_enable_intr),
  379         DEVMETHOD(pic_pre_ithread,      bcm_mips74k_pic_pre_ithread),
  380         DEVMETHOD(pic_post_ithread,     bcm_mips74k_pic_post_ithread),
  381         DEVMETHOD(pic_post_filter,      bcm_mips74k_pic_post_filter),
  382 
  383         DEVMETHOD_END
  384 };
  385 
  386 static devclass_t bcm_mips_devclass;
  387 
  388 DEFINE_CLASS_1(bcm_mips, bcm_mips74k_driver, bcm_mips74k_methods, sizeof(struct bcm_mips_softc), bcm_mips_driver);
  389 EARLY_DRIVER_MODULE(bcm_mips74k, bhnd, bcm_mips74k_driver, bcm_mips_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
  390 SYSINIT(cpu_init, SI_SUB_CPU, SI_ORDER_FIRST, bcm_mips74k_timer_init, NULL);
  391 MODULE_VERSION(bcm_mips74k, 1);
  392 MODULE_DEPEND(bcm_mips74k, bhnd, 1, 1, 1);

Cache object: b74eab2b0fc2e00a81b8c355e969b41d


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