Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153010073
D12385.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D12385.id.diff
View Options
Index: head/sys/mips/include/intr.h
===================================================================
--- head/sys/mips/include/intr.h
+++ head/sys/mips/include/intr.h
@@ -55,16 +55,23 @@
#define NIRQ MIPS_NIRQ
#endif
+#ifndef FDT
+#define MIPS_PIC_XREF 1 /**< unique xref */
+#endif
+
#define INTR_IRQ_NSPC_SWI 4
+/* MIPS32 PIC APIs */
+int mips_pic_map_fixed_intrs(void);
+int mips_pic_activate_intr(device_t child, struct resource *r);
+int mips_pic_deactivate_intr(device_t child, struct resource *r);
+
/* 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 **);
-int cpu_create_intr_map(int);
-struct resource *cpu_get_irq_resource(int);
/* MIPS interrupt C entry point */
void cpu_intr(struct trapframe *);
Index: head/sys/mips/mips/mips_pic.c
===================================================================
--- head/sys/mips/mips/mips_pic.c
+++ head/sys/mips/mips/mips_pic.c
@@ -2,8 +2,12 @@
* Copyright (c) 2015 Alexander Kabaev
* Copyright (c) 2006 Oleksandr Tymoshenko
* Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org>
+ * Copyright (c) 2017 The FreeBSD Foundation
* All rights reserved.
*
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -44,6 +48,7 @@
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/cpuset.h>
+#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/smp.h>
@@ -69,24 +74,56 @@
#define NSOFT_IRQS 2
#define NREAL_IRQS (NHARD_IRQS + NSOFT_IRQS)
-static int mips_pic_intr(void *);
+struct mips_pic_softc;
+static int mips_pic_intr(void *);
+static struct mips_pic_intr *mips_pic_find_intr(struct resource *r);
+static int mips_pic_map_fixed_intr(u_int irq,
+ struct mips_pic_intr **mapping);
+static void cpu_establish_intr(struct mips_pic_softc *sc,
+ const char *name, driver_filter_t *filt,
+ void (*handler)(void*), void *arg, int irq,
+ int flags, void **cookiep);
+
+#define INTR_MAP_DATA_MIPS INTR_MAP_DATA_PLAT_1
+
struct intr_map_data_mips_pic {
struct intr_map_data hdr;
u_int irq;
};
+/**
+ * MIPS interrupt state; available prior to MIPS PIC device attachment.
+ */
+static struct mips_pic_intr {
+ u_int mips_irq; /**< MIPS IRQ# 0-7 */
+ u_int intr_irq; /**< INTRNG IRQ#, or INTR_IRQ_INVALID if unmapped */
+ u_int consumers; /**< INTRNG activation refcount */
+ struct resource *res; /**< resource shared by all interrupt handlers registered via
+ cpu_establish_hardintr() or cpu_establish_softintr(); NULL
+ if no interrupt handlers are yet registered. */
+} mips_pic_intrs[] = {
+ { 0, INTR_IRQ_INVALID, 0, NULL },
+ { 1, INTR_IRQ_INVALID, 0, NULL },
+ { 2, INTR_IRQ_INVALID, 0, NULL },
+ { 3, INTR_IRQ_INVALID, 0, NULL },
+ { 4, INTR_IRQ_INVALID, 0, NULL },
+ { 5, INTR_IRQ_INVALID, 0, NULL },
+ { 6, INTR_IRQ_INVALID, 0, NULL },
+ { 7, INTR_IRQ_INVALID, 0, NULL },
+};
+
+struct mtx mips_pic_mtx;
+MTX_SYSINIT(mips_pic_mtx, &mips_pic_mtx, "mips intr controller mutex", MTX_DEF);
+
struct mips_pic_irqsrc {
struct intr_irqsrc isrc;
- struct resource *res;
u_int irq;
};
struct mips_pic_softc {
device_t pic_dev;
struct mips_pic_irqsrc pic_irqs[NREAL_IRQS];
- struct rman pic_irq_rman;
- struct mtx mutex;
uint32_t nirqs;
};
@@ -145,7 +182,7 @@
#ifdef FDT
return (OF_xref_from_node(ofw_bus_get_node(dev)));
#else
- return (0);
+ return (MIPS_PIC_XREF);
#endif
}
@@ -159,14 +196,7 @@
for (irq = 0; irq < sc->nirqs; irq++) {
sc->pic_irqs[irq].irq = irq;
- sc->pic_irqs[irq].res = rman_reserve_resource(&sc->pic_irq_rman,
- irq, irq, 1, RF_ACTIVE, sc->pic_dev);
- if (sc->pic_irqs[irq].res == NULL) {
- device_printf(sc->pic_dev,
- "%s failed to alloc resource for irq %u",
- __func__, irq);
- return (ENOMEM);
- }
+
isrc = PIC_INTR_ISRC(sc, irq);
if (irq < NSOFT_IRQS) {
name = "sint";
@@ -203,21 +233,9 @@
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);
- /* Init the IRQ rman */
- sc->pic_irq_rman.rm_type = RMAN_ARRAY;
- sc->pic_irq_rman.rm_descr = "MIPS PIC IRQs";
- if (rman_init(&sc->pic_irq_rman) != 0 ||
- rman_manage_region(&sc->pic_irq_rman, 0, sc->nirqs - 1) != 0) {
- device_printf(dev, "failed to setup IRQ rman\n");
- goto cleanup;
- }
-
/* Register the interrupts */
if (mips_pic_register_isrcs(sc) != 0) {
device_printf(dev, "could not register PIC ISRCs\n");
@@ -326,7 +344,7 @@
*isrcp = PIC_INTR_ISRC(sc, daf->cells[0]);
} else
#endif
- if (data->type == INTR_MAP_DATA_PLAT_1) {
+ if (data->type == INTR_MAP_DATA_MIPS) {
struct intr_map_data_mips_pic *mpd;
mpd = (struct intr_map_data_mips_pic *)data;
@@ -396,73 +414,292 @@
BUS_PASS_INTERRUPT);
#endif
-void
-cpu_init_interrupts(void)
+/**
+ * Return the MIPS interrupt map entry for @p r, or NULL if no such entry has
+ * been created.
+ */
+static struct mips_pic_intr *
+mips_pic_find_intr(struct resource *r)
{
+ struct mips_pic_intr *intr;
+ rman_res_t irq;
+
+ irq = rman_get_start(r);
+ if (irq != rman_get_end(r) || rman_get_size(r) != 1)
+ return (NULL);
+
+ mtx_lock(&mips_pic_mtx);
+ for (size_t i = 0; i < nitems(mips_pic_intrs); i++) {
+ intr = &mips_pic_intrs[i];
+
+ if (intr->intr_irq != irq)
+ continue;
+
+ mtx_unlock(&mips_pic_mtx);
+ return (intr);
+ }
+ mtx_unlock(&mips_pic_mtx);
+
+ /* Not found */
+ return (NULL);
}
+/**
+ * Allocate a fixed IRQ mapping for the given MIPS @p irq, or return the
+ * existing mapping if @p irq was previously mapped.
+ *
+ * @param irq The MIPS IRQ to be mapped.
+ * @param[out] mapping On success, will be populated with the interrupt
+ * mapping.
+ *
+ * @retval 0 success
+ * @retval EINVAL if @p irq is not a valid MIPS IRQ#.
+ * @retval non-zero If allocating the MIPS IRQ mapping otherwise fails, a
+ * regular unix error code will be returned.
+ */
+static int
+mips_pic_map_fixed_intr(u_int irq, struct mips_pic_intr **mapping)
+{
+ struct mips_pic_intr *intr;
+ struct intr_map_data_mips_pic *data;
+ device_t pic_dev;
+ uintptr_t xref;
+
+ if (irq < 0 || irq >= nitems(mips_pic_intrs))
+ return (EINVAL);
+
+ mtx_lock(&mips_pic_mtx);
+
+ /* Fetch corresponding interrupt entry */
+ intr = &mips_pic_intrs[irq];
+ KASSERT(intr->mips_irq == irq,
+ ("intr %u found at index %u", intr->mips_irq, irq));
+
+ /* Already mapped? */
+ if (intr->intr_irq != INTR_IRQ_INVALID) {
+ mtx_unlock(&mips_pic_mtx);
+ *mapping = intr;
+ return (0);
+ }
+
+ /* Map the interrupt */
+ data = (struct intr_map_data_mips_pic *)intr_alloc_map_data(
+ INTR_MAP_DATA_MIPS, sizeof(*data), M_WAITOK | M_ZERO);
+ data->irq = intr->mips_irq;
+
+#ifdef FDT
+ /* PIC must be attached on FDT devices */
+ KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
+
+ pic_dev = pic_sc->pic_dev;
+ xref = pic_xref(pic_dev);
+#else /* !FDT */
+ /* PIC has a fixed xref, and may not have been attached yet */
+ pic_dev = NULL;
+ if (pic_sc != NULL)
+ pic_dev = pic_sc->pic_dev;
+
+ xref = MIPS_PIC_XREF;
+#endif /* FDT */
+
+ KASSERT(intr->intr_irq == INTR_IRQ_INVALID, ("duplicate map"));
+ intr->intr_irq = intr_map_irq(pic_dev, xref, &data->hdr);
+ *mapping = intr;
+
+ mtx_unlock(&mips_pic_mtx);
+ return (0);
+}
+
+/**
+ *
+ * Produce fixed IRQ mappings for all MIPS IRQs.
+ *
+ * Non-FDT/OFW MIPS targets do not provide an equivalent to OFW_BUS_MAP_INTR();
+ * it is instead necessary to reserve INTRNG IRQ# 0-7 for use by MIPS device
+ * drivers that assume INTRNG IRQs 0-7 are directly mapped to MIPS IRQs 0-7.
+ *
+ * XXX: There is no support in INTRNG for reserving a fixed IRQ range. However,
+ * we should be called prior to any other interrupt mapping requests, and work
+ * around this by iteratively allocating the required 0-7 MIP IRQ# range.
+ *
+ * @retval 0 success
+ * @retval non-zero If allocating the MIPS IRQ mappings otherwise fails, a
+ * regular unix error code will be returned.
+ */
int
-cpu_create_intr_map(int irq)
+mips_pic_map_fixed_intrs(void)
{
- struct intr_map_data_mips_pic *mips_pic_data;
- intptr_t iparent;
- size_t len;
- u_int new_irq;
+ int error;
- len = sizeof(*mips_pic_data);
- iparent = pic_xref(pic_sc->pic_dev);
+ for (u_int i = 0; i < nitems(mips_pic_intrs); i++) {
+ struct mips_pic_intr *intr;
- /* Allocate mips_pic data and fill it in */
- mips_pic_data = (struct intr_map_data_mips_pic *)intr_alloc_map_data(
- INTR_MAP_DATA_PLAT_1, len, M_WAITOK | M_ZERO);
- mips_pic_data->irq = irq;
+ if ((error = mips_pic_map_fixed_intr(i, &intr)))
+ return (error);
- /* Get the new irq number */
- new_irq = intr_map_irq(pic_sc->pic_dev, iparent,
- (struct intr_map_data *)mips_pic_data);
+ /* INTRNG IRQs 0-7 must be directly mapped to MIPS IRQs 0-7 */
+ if (intr->intr_irq != intr->mips_irq) {
+ panic("invalid IRQ mapping: %u->%u", intr->intr_irq,
+ intr->mips_irq);
+ }
+ }
- /* Adjust the resource accordingly */
- rman_set_start(pic_sc->pic_irqs[irq].res, new_irq);
- rman_set_end(pic_sc->pic_irqs[irq].res, new_irq);
+ return (0);
+}
- /* Activate the new irq */
- return (intr_activate_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res));
+/**
+ * If @p r references a MIPS interrupt mapped by the MIPS32 interrupt
+ * controller, handle interrupt activation internally.
+ *
+ * Otherwise, delegate directly to intr_activate_irq().
+ */
+int
+mips_pic_activate_intr(device_t child, struct resource *r)
+{
+ struct mips_pic_intr *intr;
+ int error;
+
+ /* Is this one of our shared MIPS interrupts? */
+ if ((intr = mips_pic_find_intr(r)) == NULL) {
+ /* Delegate to standard INTRNG activation */
+ return (intr_activate_irq(child, r));
+ }
+
+ /* Bump consumer count and request activation if required */
+ mtx_lock(&mips_pic_mtx);
+ if (intr->consumers == UINT_MAX) {
+ mtx_unlock(&mips_pic_mtx);
+ return (ENOMEM);
+ }
+
+ if (intr->consumers == 0) {
+ if ((error = intr_activate_irq(child, r))) {
+ mtx_unlock(&mips_pic_mtx);
+ return (error);
+ }
+ }
+
+ intr->consumers++;
+ mtx_unlock(&mips_pic_mtx);
+
+ return (0);
}
-struct resource *
-cpu_get_irq_resource(int irq)
+/**
+ * If @p r references a MIPS interrupt mapped by the MIPS32 interrupt
+ * controller, handle interrupt deactivation internally.
+ *
+ * Otherwise, delegate directly to intr_deactivate_irq().
+ */
+int
+mips_pic_deactivate_intr(device_t child, struct resource *r)
{
+ struct mips_pic_intr *intr;
+ int error;
- KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
+ /* Is this one of our shared MIPS interrupts? */
+ if ((intr = mips_pic_find_intr(r)) == NULL) {
+ /* Delegate to standard INTRNG deactivation */
+ return (intr_deactivate_irq(child, r));
+ }
- if (irq < 0 || irq >= pic_sc->nirqs)
- panic("%s called for unknown irq %d", __func__, irq);
+ /* Decrement consumer count and request deactivation if required */
+ mtx_lock(&mips_pic_mtx);
+ KASSERT(intr->consumers > 0, ("refcount overrelease"));
- return pic_sc->pic_irqs[irq].res;
+ if (intr->consumers == 1) {
+ if ((error = intr_deactivate_irq(child, r))) {
+ mtx_unlock(&mips_pic_mtx);
+ return (error);
+ }
+ }
+ intr->consumers--;
+
+ mtx_unlock(&mips_pic_mtx);
+ return (0);
}
void
+cpu_init_interrupts(void)
+{
+}
+
+/**
+ * Provide backwards-compatible support for registering a MIPS interrupt handler
+ * directly, without allocating a bus resource.
+ */
+static void
+cpu_establish_intr(struct mips_pic_softc *sc, const char *name,
+ driver_filter_t *filt, void (*handler)(void*), void *arg, int irq,
+ int flags, void **cookiep)
+{
+ struct mips_pic_intr *intr;
+ struct resource *res;
+ int rid;
+ int error;
+
+ rid = -1;
+
+ /* Fetch (or create) a fixed mapping */
+ if ((error = mips_pic_map_fixed_intr(irq, &intr)))
+ panic("Unable to map IRQ %d: %d", irq, error);
+
+ /* Fetch the backing resource, if any */
+ mtx_lock(&mips_pic_mtx);
+ res = intr->res;
+ mtx_unlock(&mips_pic_mtx);
+
+ /* Allocate our IRQ resource */
+ if (res == NULL) {
+ /* Optimistically perform resource allocation */
+ rid = intr->intr_irq;
+ res = bus_alloc_resource(sc->pic_dev, SYS_RES_IRQ, &rid,
+ intr->intr_irq, intr->intr_irq, 1, RF_SHAREABLE|RF_ACTIVE);
+
+ if (res != NULL) {
+ /* Try to update intr->res */
+ mtx_lock(&mips_pic_mtx);
+ if (intr->res == NULL) {
+ intr->res = res;
+ }
+ mtx_unlock(&mips_pic_mtx);
+
+ /* If intr->res was updated concurrently, free our local
+ * resource allocation */
+ if (intr->res != res) {
+ bus_release_resource(sc->pic_dev, SYS_RES_IRQ,
+ rid, res);
+ }
+ } else {
+ /* Maybe someone else allocated it? */
+ mtx_lock(&mips_pic_mtx);
+ res = intr->res;
+ mtx_unlock(&mips_pic_mtx);
+ }
+
+ if (res == NULL) {
+ panic("Unable to allocate IRQ %d->%u resource", irq,
+ intr->intr_irq);
+ }
+ }
+
+ error = bus_setup_intr(sc->pic_dev, res, flags, filt, handler, arg,
+ cookiep);
+ if (error)
+ panic("Unable to add IRQ %d handler: %d", irq, error);
+}
+
+void
cpu_establish_hardintr(const char *name, driver_filter_t *filt,
void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
{
- int res;
+ KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
- /*
- * 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__));
-
- irq += NSOFT_IRQS;
-
- res = cpu_create_intr_map(irq);
- if (res != 0) panic("Unable to create map for hard IRQ %d", irq);
-
- res = intr_setup_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res, filt,
- handler, arg, flags, cookiep);
- if (res != 0) panic("Unable to add hard IRQ %d handler", irq);
+ cpu_establish_intr(pic_sc, name, filt, handler, arg, irq+NSOFT_IRQS,
+ flags, cookiep);
}
void
@@ -470,18 +707,12 @@
void (*handler)(void*), void *arg, int irq, int flags,
void **cookiep)
{
- int res;
+ KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
- if (irq < 0 || irq > NSOFT_IRQS)
+ if (irq < 0 || irq >= NSOFT_IRQS)
panic("%s called for unknown soft intr %d", __func__, irq);
- KASSERT(pic_sc != NULL, ("%s: no pic", __func__));
-
- res = cpu_create_intr_map(irq);
- if (res != 0) panic("Unable to create map for soft IRQ %d", irq);
-
- res = intr_setup_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res, filt,
- handler, arg, flags, cookiep);
- if (res != 0) panic("Unable to add soft IRQ %d handler", irq);
+ cpu_establish_intr(pic_sc, name, filt, handler, arg, irq, flags,
+ cookiep);
}
Index: head/sys/mips/mips/nexus.c
===================================================================
--- head/sys/mips/mips/nexus.c
+++ head/sys/mips/mips/nexus.c
@@ -76,7 +76,11 @@
#define dprintf(x, arg...)
#endif /* NEXUS_DEBUG */
-#define NUM_MIPS_IRQS 6
+#ifdef INTRNG
+#define NUM_MIPS_IRQS NIRQ /* Any INTRNG-mapped IRQ */
+#else
+#define NUM_MIPS_IRQS 6 /* HW IRQs only */
+#endif
static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
@@ -200,7 +204,13 @@
static int
nexus_attach(device_t dev)
{
+#if defined(INTRNG) && !defined(FDT)
+ int error;
+ if ((error = mips_pic_map_fixed_intrs()))
+ return (error);
+#endif
+
bus_generic_probe(dev);
bus_enumerate_hinted_children(dev);
bus_generic_attach(dev);
@@ -291,7 +301,7 @@
* and we know what the resources for this device are (ie. they aren't
* maintained by a child bus), then work out the start/end values.
*/
- if (isdefault) {
+ if (!passthrough && isdefault) {
rle = resource_list_find(&ndev->nx_resources, type, *rid);
if (rle == NULL)
return (NULL);
@@ -432,21 +442,12 @@
rman_set_bushandle(r, (bus_space_handle_t)(uintptr_t)vaddr);
} else if (type == SYS_RES_IRQ) {
#ifdef INTRNG
-#ifdef FDT
- err = intr_activate_irq(child, r);
+ err = mips_pic_activate_intr(child, r);
if (err != 0) {
rman_deactivate_resource(r);
return (err);
}
-#else
- /*
- * INTRNG without FDT needs to have the interrupt properly
- * mapped first. cpu_create_intr_map() will do that and
- * call intr_activate_irq() at the end.
- */
- cpu_create_intr_map(rman_get_start(r));
#endif
-#endif
}
return (rman_activate_resource(r));
@@ -468,7 +469,7 @@
rman_set_bushandle(r, 0);
} else if (type == SYS_RES_IRQ) {
#ifdef INTRNG
- intr_deactivate_irq(child, r);
+ mips_pic_deactivate_intr(child, r);
#endif
}
@@ -480,12 +481,7 @@
driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
{
#ifdef INTRNG
- struct resource *r = res;
-
-#ifndef FDT
- r = cpu_get_irq_resource(rman_get_start(r));
-#endif
- return (intr_setup_irq(child, r, filt, intr, arg, flags, cookiep));
+ return (intr_setup_irq(child, res, filt, intr, arg, flags, cookiep));
#else
int irq;
register_t s;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 19, 2:53 PM (14 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31766494
Default Alt Text
D12385.id.diff (16 KB)
Attached To
Mode
D12385: Preemptively perform intr_map_irq() on non-FDT MIPS targets.
Attached
Detach File
Event Timeline
Log In to Comment