summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2016-02-11 06:09:27 +0000
committeradrian <adrian@FreeBSD.org>2016-02-11 06:09:27 +0000
commitdd3b3e6ad6132826c9ed9aee3801196746a8a0c2 (patch)
tree2fa5a544d4d3c19d15f70e155844785e015ee561 /sys/mips
parent8ad8436c9cc43ec166d6bd0e04fe8feae34845e9 (diff)
downloadFreeBSD-src-dd3b3e6ad6132826c9ed9aee3801196746a8a0c2.zip
FreeBSD-src-dd3b3e6ad6132826c9ed9aee3801196746a8a0c2.tar.gz
Begin the MIPS_INTRNG support.
This is a prelude to intr-ng support for MIPS boards that need it - notably the CI20 port from kan@ that's upcoming, but also work that Stanislav is doing for the Mediatek platforms. This is the initial platform dependent bits in include/intr.h, some #defines for the nexus code for the intrng initialisation/runtime bits, some changed naming (which I'll fix later to be the same, much like what I did for ARM intr-ng) in exception.S, and the first cut at a PIC. Stanislav and I refactored out the common code for intrng support, so the mips intrng definitions are quite small (sys/mips/include/intr.h.) This is all work done by kan@, which stanislav has been cherry picking into common code for his mediatek chipset work. Tested: * Carambola2 - no regressions (not intr-ng though!) Submitted by: Stanislav Galabov <sgalabov@gmail.com> Reviewed by: kan (original author) Differential Revision: https://reviews.freebsd.org/D5182
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/include/intr.h67
-rw-r--r--sys/mips/include/smp.h5
-rw-r--r--sys/mips/mips/exception.S10
-rw-r--r--sys/mips/mips/mips_pic.c512
-rw-r--r--sys/mips/mips/nexus.c87
5 files changed, 679 insertions, 2 deletions
diff --git a/sys/mips/include/intr.h b/sys/mips/include/intr.h
new file mode 100644
index 0000000..28f798f
--- /dev/null
+++ b/sys/mips/include/intr.h
@@ -0,0 +1,67 @@
+/* $NetBSD: intr.h,v 1.7 2003/06/16 20:01:00 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _MACHINE_INTR_H_
+#define _MACHINE_INTR_H_
+
+#ifdef MIPS_INTRNG
+
+#ifdef FDT
+#include <dev/ofw/openfirm.h>
+#endif
+
+#include <sys/intr.h>
+
+#ifndef NIRQ
+#define NIRQ 128
+#endif
+
+#define INTR_IRQ_NSPC_SWI 4
+
+/* MIPS compatibility for legacy mips code */
+void cpu_init_interrupts(void);
+void cpu_establish_hardintr(const char *, driver_filter_t *, driver_intr_t *,
+ void *, int, int, void **);
+void cpu_establish_softintr(const char *, driver_filter_t *, void (*)(void*),
+ void *, int, int, void **);
+/* MIPS interrupt C entry point */
+void cpu_intr(struct trapframe *);
+
+#endif /* MIPS_INTRNG */
+
+#endif /* _MACHINE_INTR_H */
diff --git a/sys/mips/include/smp.h b/sys/mips/include/smp.h
index 0fcca9a..fa4cb5c 100644
--- a/sys/mips/include/smp.h
+++ b/sys/mips/include/smp.h
@@ -21,6 +21,11 @@
#include <machine/pcb.h>
+#ifdef MIPS_INTRNG
+# define MIPS_IPI_COUNT 1
+# define INTR_IPI_COUNT MIPS_IPI_COUNT
+#endif
+
/*
* Interprocessor interrupts for SMP.
*/
diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S
index 01fd210..ebfd84d 100644
--- a/sys/mips/mips/exception.S
+++ b/sys/mips/mips/exception.S
@@ -646,7 +646,11 @@ NESTED_NOPROFILE(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
* Call the interrupt handler. a0 points at the saved frame.
*/
PTR_LA gp, _C_LABEL(_gp)
+#ifdef MIPS_INTRNG
+ PTR_LA k0, _C_LABEL(intr_irq_handler)
+#else
PTR_LA k0, _C_LABEL(cpu_intr)
+#endif
jalr k0
REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
@@ -758,7 +762,11 @@ NESTED_NOPROFILE(MipsUserIntr, CALLFRAME_SIZ, ra)
/*
* Call the interrupt handler.
*/
+#ifdef MIPS_INTRNG
+ PTR_LA k0, _C_LABEL(intr_irq_handler)
+#else
PTR_LA k0, _C_LABEL(cpu_intr)
+#endif
jalr k0
REG_S a3, CALLFRAME_RA(sp) # for debugging
@@ -1190,6 +1198,7 @@ FPReturn:
PTR_ADDU sp, sp, CALLFRAME_SIZ
END(MipsFPTrap)
+#ifndef MIPS_INTRNG
/*
* Interrupt counters for vmstat.
*/
@@ -1216,6 +1225,7 @@ sintrcnt:
#else
.int INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
#endif
+#endif /* MIPS_INTRNG */
/*
diff --git a/sys/mips/mips/mips_pic.c b/sys/mips/mips/mips_pic.c
new file mode 100644
index 0000000..c20bc8d
--- /dev/null
+++ b/sys/mips/mips/mips_pic.c
@@ -0,0 +1,512 @@
+/*-
+ * Copyright (c) 2015 Alexander Kabaev
+ * Copyright (c) 2006 Oleksandr Tymoshenko
+ * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+#include "opt_hwpmc_hooks.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/cpuset.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+#include <sys/sched.h>
+
+#include <machine/bus.h>
+#include <machine/hwfunc.h>
+#include <machine/intr.h>
+#include <machine/smp.h>
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+
+#include "pic_if.h"
+
+#define NHARD_IRQS 6
+#define NSOFT_IRQS 2
+#define NREAL_IRQS (NHARD_IRQS + NSOFT_IRQS)
+
+static int mips_pic_intr(void *);
+
+struct mips_pic_softc {
+ device_t pic_dev;
+ struct intr_irqsrc * pic_irqs[NREAL_IRQS];
+ struct mtx mutex;
+ uint32_t nirqs;
+};
+
+static struct mips_pic_softc *pic_sc;
+
+#ifdef FDT
+static struct ofw_compat_data compat_data[] = {
+ {"mti,cpu-interrupt-controller", true},
+ {NULL, false}
+};
+#endif
+
+#ifndef FDT
+static void
+mips_pic_identify(driver_t *drv, device_t parent)
+{
+
+ BUS_ADD_CHILD(parent, 0, "cpupic", 0);
+}
+#endif
+
+static int
+mips_pic_probe(device_t dev)
+{
+
+#ifdef FDT
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+#endif
+ device_set_desc(dev, "MIPS32 Interrupt Controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static inline void
+pic_irq_unmask(struct mips_pic_softc *sc, u_int irq)
+{
+
+ mips_wr_status(mips_rd_status() | ((1 << irq) << 8));
+}
+
+static inline void
+pic_irq_mask(struct mips_pic_softc *sc, u_int irq)
+{
+
+ mips_wr_status(mips_rd_status() & ~((1 << irq) << 8));
+}
+
+#ifdef SMP
+static void
+mips_pic_init_secondary(device_t dev)
+{
+}
+#endif /* SMP */
+
+static inline intptr_t
+pic_xref(device_t dev)
+{
+#ifdef FDT
+ return (OF_xref_from_node(ofw_bus_get_node(dev)));
+#else
+ return (0);
+#endif
+}
+
+static int
+mips_pic_attach(device_t dev)
+{
+ struct mips_pic_softc *sc;
+ intptr_t xref = pic_xref(dev);
+
+ if (pic_sc)
+ return (ENXIO);
+
+ sc = device_get_softc(dev);
+
+ sc->pic_dev = dev;
+ pic_sc = sc;
+
+ /* Initialize mutex */
+ mtx_init(&sc->mutex, "PIC lock", "", MTX_SPIN);
+
+ /* Set the number of interrupts */
+ sc->nirqs = nitems(sc->pic_irqs);
+
+ /*
+ * Now, when everything is initialized, it's right time to
+ * register interrupt controller to interrupt framefork.
+ */
+ if (intr_pic_register(dev, xref) != 0) {
+ device_printf(dev, "could not register PIC\n");
+ goto cleanup;
+ }
+
+ /* Claim our root controller role */
+ if (intr_pic_claim_root(dev, xref, mips_pic_intr, sc, 0) != 0) {
+ device_printf(dev, "could not set PIC as a root\n");
+ intr_pic_unregister(dev, xref);
+ goto cleanup;
+ }
+
+ return (0);
+
+cleanup:
+ return(ENXIO);
+}
+
+int
+mips_pic_intr(void *arg)
+{
+ struct mips_pic_softc *sc = arg;
+ register_t cause, status;
+ struct intr_irqsrc *isrc;
+ int i, intr;
+
+ cause = mips_rd_cause();
+ status = mips_rd_status();
+ intr = (cause & MIPS_INT_MASK) >> 8;
+ /*
+ * Do not handle masked interrupts. They were masked by
+ * pre_ithread function (mips_mask_XXX_intr) and will be
+ * unmasked once ithread is through with handler
+ */
+ intr &= (status & MIPS_INT_MASK) >> 8;
+ while ((i = fls(intr)) != 0) {
+ i--; /* Get a 0-offset interrupt. */
+ intr &= ~(1 << i);
+
+ isrc = sc->pic_irqs[i];
+ if (isrc == NULL) {
+ device_printf(sc->pic_dev,
+ "Stray interrupt %u detected\n", i);
+ pic_irq_mask(sc, i);
+ continue;
+ }
+
+ intr_irq_dispatch(isrc, curthread->td_intr_frame);
+ }
+
+ KASSERT(i == 0, ("all interrupts handled"));
+
+#ifdef HWPMC_HOOKS
+ if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN))
+ pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf);
+#endif
+ return (FILTER_HANDLED);
+}
+
+static int
+pic_attach_isrc(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int irq)
+{
+
+ /*
+ * 1. The link between ISRC and controller must be set atomically.
+ * 2. Just do things only once in rare case when consumers
+ * of shared interrupt came here at the same moment.
+ */
+ mtx_lock_spin(&sc->mutex);
+ if (sc->pic_irqs[irq] != NULL) {
+ mtx_unlock_spin(&sc->mutex);
+ return (sc->pic_irqs[irq] == isrc ? 0 : EEXIST);
+ }
+ sc->pic_irqs[irq] = isrc;
+ isrc->isrc_data = irq;
+ mtx_unlock_spin(&sc->mutex);
+
+ if (irq < NSOFT_IRQS)
+ intr_irq_set_name(isrc, "sint%u", irq);
+ else if (irq < NREAL_IRQS)
+ intr_irq_set_name(isrc, "int%u", irq - NSOFT_IRQS);
+ else
+ panic("Invalid irq %u", irq);
+ return (0);
+}
+
+static int
+pic_detach_isrc(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int irq)
+{
+
+ mtx_lock_spin(&sc->mutex);
+ if (sc->pic_irqs[irq] != isrc) {
+ mtx_unlock_spin(&sc->mutex);
+ return (sc->pic_irqs[irq] == NULL ? 0 : EINVAL);
+ }
+ sc->pic_irqs[irq] = NULL;
+ isrc->isrc_data = 0;
+ mtx_unlock_spin(&sc->mutex);
+
+ intr_irq_set_name(isrc, "%s", "");
+ return (0);
+}
+
+static int
+pic_irq_from_nspc(struct mips_pic_softc *sc, u_int type, u_int num, u_int *irqp)
+{
+
+ switch (type) {
+ case INTR_IRQ_NSPC_PLAIN:
+ *irqp = num;
+ return (*irqp < sc->nirqs ? 0 : EINVAL);
+
+ case INTR_IRQ_NSPC_SWI:
+ *irqp = num;
+ return (num < NSOFT_IRQS ? 0 : EINVAL);
+
+ case INTR_IRQ_NSPC_IRQ:
+ *irqp = num + NSOFT_IRQS;
+ return (num < NHARD_IRQS ? 0 : EINVAL);
+
+ default:
+ return (EINVAL);
+ }
+}
+
+static int
+pic_map_nspc(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp)
+{
+ int error;
+
+ error = pic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num,
+ irqp);
+ if (error != 0)
+ return (error);
+ return (pic_attach_isrc(sc, isrc, *irqp));
+}
+
+#ifdef FDT
+static int
+pic_map_fdt(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp)
+{
+ u_int irq;
+ int error;
+
+ irq = isrc->isrc_cells[0];
+
+ if (irq >= sc->nirqs)
+ return (EINVAL);
+
+ error = pic_attach_isrc(sc, isrc, irq);
+ if (error != 0)
+ return (error);
+
+ isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN;
+ isrc->isrc_nspc_num = irq;
+ isrc->isrc_trig = INTR_TRIGGER_CONFORM;
+ isrc->isrc_pol = INTR_POLARITY_CONFORM;
+
+ *irqp = irq;
+ return (0);
+}
+#endif
+
+static int
+mips_pic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu)
+{
+ struct mips_pic_softc *sc = device_get_softc(dev);
+ u_int irq;
+ int error;
+
+ if (isrc->isrc_type == INTR_ISRCT_NAMESPACE)
+ error = pic_map_nspc(sc, isrc, &irq);
+#ifdef FDT
+ else if (isrc->isrc_type == INTR_ISRCT_FDT)
+ error = pic_map_fdt(sc, isrc, &irq);
+#endif
+ else
+ return (EINVAL);
+
+ if (error == 0)
+ *is_percpu = TRUE;
+ return (error);
+}
+
+static void
+mips_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ if (isrc->isrc_trig == INTR_TRIGGER_CONFORM)
+ isrc->isrc_trig = INTR_TRIGGER_LEVEL;
+}
+
+static void
+mips_pic_enable_source(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct mips_pic_softc *sc = device_get_softc(dev);
+ u_int irq = isrc->isrc_data;
+
+ pic_irq_unmask(sc, irq);
+}
+
+static void
+mips_pic_disable_source(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct mips_pic_softc *sc = device_get_softc(dev);
+ u_int irq = isrc->isrc_data;
+
+ pic_irq_mask(sc, irq);
+}
+
+static int
+mips_pic_unregister(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct mips_pic_softc *sc = device_get_softc(dev);
+ u_int irq = isrc->isrc_data;
+
+ return (pic_detach_isrc(sc, isrc, irq));
+}
+
+static void
+mips_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ mips_pic_disable_source(dev, isrc);
+}
+
+static void
+mips_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ mips_pic_enable_source(dev, isrc);
+}
+
+static void
+mips_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+}
+
+#ifdef SMP
+static int
+mips_pic_bind(device_t dev, struct intr_irqsrc *isrc)
+{
+ return (EOPNOTSUPP);
+}
+
+static void
+mips_pic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus)
+{
+}
+#endif
+
+static device_method_t mips_pic_methods[] = {
+ /* Device interface */
+#ifndef FDT
+ DEVMETHOD(device_identify, mips_pic_identify),
+#endif
+ DEVMETHOD(device_probe, mips_pic_probe),
+ DEVMETHOD(device_attach, mips_pic_attach),
+ /* Interrupt controller interface */
+ DEVMETHOD(pic_disable_source, mips_pic_disable_source),
+ DEVMETHOD(pic_enable_intr, mips_pic_enable_intr),
+ DEVMETHOD(pic_enable_source, mips_pic_enable_source),
+ DEVMETHOD(pic_post_filter, mips_pic_post_filter),
+ DEVMETHOD(pic_post_ithread, mips_pic_post_ithread),
+ DEVMETHOD(pic_pre_ithread, mips_pic_pre_ithread),
+ DEVMETHOD(pic_register, mips_pic_register),
+ DEVMETHOD(pic_unregister, mips_pic_unregister),
+#ifdef SMP
+ DEVMETHOD(pic_bind, mips_pic_bind),
+ DEVMETHOD(pic_init_secondary, mips_pic_init_secondary),
+ DEVMETHOD(pic_ipi_send, mips_pic_ipi_send),
+#endif
+ { 0, 0 }
+};
+
+static driver_t mips_pic_driver = {
+ "cpupic",
+ mips_pic_methods,
+ sizeof(struct mips_pic_softc),
+};
+
+static devclass_t mips_pic_devclass;
+
+#ifdef FDT
+DRIVER_MODULE(cpupic, ofwbus, mips_pic_driver, mips_pic_devclass, 0, 0);
+#else
+DRIVER_MODULE(cpupic, nexus, mips_pic_driver, mips_pic_devclass, 0, 0);
+#endif
+
+void
+cpu_init_interrupts(void)
+{
+}
+
+void
+cpu_establish_hardintr(const char *name, driver_filter_t *filt,
+ void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
+{
+ u_int vec;
+ int res;
+
+ /*
+ * We have 6 levels, but thats 0 - 5 (not including 6)
+ */
+ if (irq < 0 || irq >= NHARD_IRQS)
+ panic("%s called for unknown hard intr %d", __func__, irq);
+
+ KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
+ vec = intr_namespace_map_irq(pic_sc->pic_dev, INTR_IRQ_NSPC_IRQ, irq);
+ KASSERT(vec != NIRQ, ("Unable to map hard IRQ %d\n", irq));
+
+ res = intr_irq_add_handler(pic_sc->pic_dev, filt, handler, arg, vec,
+ flags, cookiep);
+ if (res != 0) panic("Unable to add hard IRQ %d handler", irq);
+
+ (void)pic_irq_from_nspc(pic_sc, INTR_IRQ_NSPC_IRQ, irq, &vec);
+ KASSERT(pic_sc->pic_irqs[vec] != NULL,
+ ("Hard IRQ %d not registered\n", irq));
+ intr_irq_set_name(pic_sc->pic_irqs[vec], "%s", name);
+}
+
+void
+cpu_establish_softintr(const char *name, driver_filter_t *filt,
+ void (*handler)(void*), void *arg, int irq, int flags,
+ void **cookiep)
+{
+ u_int vec;
+ int res;
+
+ if (irq < 0 || irq > NSOFT_IRQS)
+ panic("%s called for unknown soft intr %d", __func__, irq);
+
+ KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
+ vec = intr_namespace_map_irq(pic_sc->pic_dev, INTR_IRQ_NSPC_SWI, irq);
+ KASSERT(vec <= NIRQ, ("Unable to map soft IRQ %d\n", irq));
+
+ intr_irq_add_handler(pic_sc->pic_dev, filt, handler, arg, vec,
+ flags, cookiep);
+ if (res != 0) panic("Unable to add soft IRQ %d handler", irq);
+
+ (void)pic_irq_from_nspc(pic_sc, INTR_IRQ_NSPC_SWI, irq, &vec);
+ KASSERT(pic_sc->pic_irqs[vec] != NULL,
+ ("Soft IRQ %d not registered\n", irq));
+ intr_irq_set_name(pic_sc->pic_irqs[vec], "%s", name);
+}
+
diff --git a/sys/mips/mips/nexus.c b/sys/mips/mips/nexus.c
index d2ee6af..fb52fa9 100644
--- a/sys/mips/mips/nexus.c
+++ b/sys/mips/mips/nexus.c
@@ -36,6 +36,7 @@
* this code implements the core resource managers for interrupt
* requests and memory address space.
*/
+#include "opt_platform.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -53,13 +54,23 @@ __FBSDID("$FreeBSD$");
#include <vm/pmap.h>
#include <machine/bus.h>
-#include <machine/intr_machdep.h>
#include <machine/pmap.h>
#include <machine/resource.h>
#include <machine/vmparam.h>
+#ifdef MIPS_INTRNG
+#include <machine/intr.h>
+#else
+#include <machine/intr_machdep.h>
+#endif
+
#include "opt_platform.h"
+#ifdef FDT
+#include <machine/fdt.h>
+#include "ofw_bus_if.h"
+#endif
+
#undef NEXUS_DEBUG
#ifdef NEXUS_DEBUG
#define dprintf printf
@@ -107,6 +118,19 @@ static int nexus_setup_intr(device_t dev, device_t child,
driver_intr_t *intr, void *arg, void **cookiep);
static int nexus_teardown_intr(device_t, device_t, struct resource *,
void *);
+#ifdef MIPS_INTRNG
+#ifdef SMP
+static int nexus_bind_intr(device_t, device_t, struct resource *, int);
+#endif
+#ifdef FDT
+static int nexus_ofw_map_intr(device_t dev, device_t child,
+ phandle_t iparent, int icells, pcell_t *intr);
+#endif
+static int nexus_describe_intr(device_t dev, device_t child,
+ struct resource *irq, void *cookie, const char *descr);
+static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+ enum intr_polarity pol);
+#endif
static device_method_t nexus_methods[] = {
/* Device interface */
@@ -127,6 +151,16 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_activate_resource,nexus_activate_resource),
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
DEVMETHOD(bus_hinted_child, nexus_hinted_child),
+#ifdef MIPS_INTRNG
+ DEVMETHOD(bus_config_intr, nexus_config_intr),
+ DEVMETHOD(bus_describe_intr, nexus_describe_intr),
+#ifdef SMP
+ DEVMETHOD(bus_bind_intr, nexus_bind_intr),
+#endif
+#ifdef FDT
+ DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr),
+#endif
+#endif
{ 0, 0 }
};
@@ -416,9 +450,16 @@ static int
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
{
- register_t s;
int irq;
+#ifdef MIPS_INTRNG
+ for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) {
+ intr_irq_add_handler(child, filt, intr, arg, irq, flags,
+ cookiep);
+ }
+#else
+ register_t s;
+
s = intr_disable();
irq = rman_get_start(res);
if (irq >= NUM_MIPS_IRQS) {
@@ -429,6 +470,7 @@ nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg,
irq, flags, cookiep);
intr_restore(s);
+#endif
return (0);
}
@@ -436,9 +478,50 @@ static int
nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
{
+#ifdef MIPS_INTRNG
+ return (intr_irq_remove_handler(child, rman_get_start(r), ih));
+#else
printf("Unimplemented %s at %s:%d\n", __func__, __FILE__, __LINE__);
return (0);
+#endif
+}
+
+#ifdef MIPS_INTRNG
+static int
+nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+ enum intr_polarity pol)
+{
+
+ return (intr_irq_config(irq, trig, pol));
+}
+
+static int
+nexus_describe_intr(device_t dev, device_t child, struct resource *irq,
+ void *cookie, const char *descr)
+{
+
+ return (intr_irq_describe(rman_get_start(irq), cookie, descr));
+}
+
+#ifdef SMP
+static int
+nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
+{
+
+ return (intr_irq_bind(rman_get_start(irq), cpu));
+}
+#endif
+
+#ifdef FDT
+static int
+nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
+ pcell_t *intr)
+{
+
+ return (intr_fdt_map_irq(iparent, intr, icells));
}
+#endif
+#endif /* MIPS_INTRNG */
static void
nexus_hinted_child(device_t bus, const char *dname, int dunit)
OpenPOWER on IntegriCloud