Page MenuHomeFreeBSD

D40161.diff
No OneTemporary

D40161.diff

diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c
--- a/sys/kern/subr_intr.c
+++ b/sys/kern/subr_intr.c
@@ -94,13 +94,16 @@
MALLOC_DEFINE(M_INTRNG, "intr", "intr interrupt handling");
/* Main interrupt handler called from assembler -> 'hidden' for C code. */
+void intr_irq_handler_type(struct trapframe *tf, uint32_t type);
void intr_irq_handler(struct trapframe *tf);
/* Root interrupt controller stuff. */
device_t intr_irq_root_dev;
+static intr_irq_type_filter_t *irq_root_type_filter;
static intr_irq_filter_t *irq_root_filter;
static void *irq_root_arg;
static u_int irq_root_ipicount;
+static uint32_t irq_root_typemask;
struct intr_pic_child {
SLIST_ENTRY(intr_pic_child) pc_next;
@@ -337,12 +340,23 @@
* from the assembler, where CPU interrupt is served.
*/
void
-intr_irq_handler(struct trapframe *tf)
+intr_irq_handler_type(struct trapframe *tf, uint32_t type)
{
struct trapframe * oldframe;
struct thread * td;
- KASSERT(irq_root_filter != NULL, ("%s: no filter", __func__));
+ KASSERT(irq_root_type_filter != NULL, ("%s: no filter", __func__));
+ KASSERT((irq_root_typemask & type) != 0,
+ ("%s: unknown irq type (%x)", __func__, type));
+
+ /*
+ * We could allow this possibility, but it doesn't make sense at the
+ * moment so we should defend against it early on. Root filter
+ * implementations should be more carefully considered if we start to
+ * allow multiple types firing at once for some reason.
+ */
+ KASSERT((type & ~(1 << (ffs(type) - 1))) == 0,
+ ("%s: multiple irq types specified (%x)", __func__, type));
kasan_mark(tf, sizeof(*tf), sizeof(*tf), 0);
@@ -351,7 +365,7 @@
td = curthread;
oldframe = td->td_intr_frame;
td->td_intr_frame = tf;
- irq_root_filter(irq_root_arg);
+ irq_root_type_filter(irq_root_arg, type);
td->td_intr_frame = oldframe;
critical_exit();
#ifdef HWPMC_HOOKS
@@ -361,6 +375,12 @@
#endif
}
+void
+intr_irq_handler(struct trapframe *tf)
+{
+ intr_irq_handler_type(tf, INTR_TYPE_IRQ);
+}
+
int
intr_child_irq_handler(struct intr_pic *parent, uintptr_t irq)
{
@@ -883,8 +903,9 @@
* an interrupts property and thus no explicit interrupt parent."
*/
int
-intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter,
- void *arg, u_int ipicount)
+intr_pic_claim_root_type(device_t dev, intptr_t xref,
+ intr_irq_type_filter_t *filter, void *arg, u_int ipicount,
+ uint32_t typemask)
{
struct intr_pic *pic;
@@ -903,6 +924,11 @@
return (EINVAL);
}
+ if (typemask == 0) {
+ device_printf(dev, "typemask must be specified\n");
+ return (EINVAL);
+ }
+
/*
* Only one interrupt controllers could be on the root for now.
* Note that we further suppose that there is not threaded interrupt
@@ -914,14 +940,44 @@
}
intr_irq_root_dev = dev;
- irq_root_filter = filter;
+ irq_root_type_filter = filter;
irq_root_arg = arg;
irq_root_ipicount = ipicount;
+ irq_root_typemask = typemask;
debugf("irq root set to %s\n", device_get_nameunit(dev));
return (0);
}
+/*
+ * Shim from a typed filter to an untyped filter. It's expected that if an
+ * interrupt controller used intr_pic_claim_root(), they'll go through this shim
+ * that specifically only handles the basic irq type. This maintains KBI to
+ * avoid needing to touch existing drivers, they can still use a driver_intr_t
+ * compatible filter as long as they don't care about types (i.e., all existing
+ * drivers).
+ */
+static int
+intr_pic_root_type_filter(void *arg, uint32_t type __diagused)
+{
+
+ MPASS(type == INTR_TYPE_IRQ);
+ return (irq_root_filter(arg));
+}
+
+int
+intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter,
+ void *arg, u_int ipicount)
+{
+ int error;
+
+ error = intr_pic_claim_root_type(dev, xref, intr_pic_root_type_filter,
+ arg, ipicount, INTR_TYPE_IRQ);
+ if (error == 0)
+ irq_root_filter = filter;
+ return (error);
+}
+
/*
* Add a handler to manage a sub range of a parents interrupts.
*/
diff --git a/sys/sys/intr.h b/sys/sys/intr.h
--- a/sys/sys/intr.h
+++ b/sys/sys/intr.h
@@ -63,14 +63,31 @@
#ifdef notyet
#define INTR_SOLO INTR_MD1
+typedef int intr_irq_type_filter_t(void *arg, uint32_t type, struct trapframe *tf);
typedef int intr_irq_filter_t(void *arg, struct trapframe *tf);
#else
+typedef int intr_irq_type_filter_t(void *arg, uint32_t type);
typedef int intr_irq_filter_t(void *arg);
#endif
typedef int intr_child_irq_filter_t(void *arg, uintptr_t irq);
#define INTR_ISRC_NAMELEN (MAXCOMLEN + 1)
+/*
+ * For INTR types, the top two bits are reserved for INTRNG usage. Only one of
+ * the two bits is used at this time. The rest of the space is divided in two,
+ * the lower half for machdep reservations and the upper half for platform
+ * reservations.
+ */
+#define INTR_TYPE_MD_FIRST 0x00000001
+#define INTR_TYPE_MD_LAST 0x00004000
+#define INTR_TYPE_PLATFORM_FIRST 0x00008000
+#define INTR_TYPE_PLATFORM_LAST 0x20000000
+#define INTR_TYPE_INTRNG_FIRST 0x40000000
+
+/* INTRNG's slice */
+#define INTR_TYPE_IRQ (INTR_TYPE_INTRNG_FIRST << 0)
+
#define INTR_ISRCF_IPI 0x01 /* IPI interrupt */
#define INTR_ISRCF_PPI 0x02 /* PPI interrupt */
#define INTR_ISRCF_BOUND 0x04 /* bound to a CPU */
@@ -110,6 +127,8 @@
struct intr_pic *intr_pic_register(device_t, intptr_t);
int intr_pic_deregister(device_t, intptr_t);
+int intr_pic_claim_root_type(device_t, intptr_t, intr_irq_type_filter_t *, void *,
+ u_int, uint32_t);
int intr_pic_claim_root(device_t, intptr_t, intr_irq_filter_t *, void *, u_int);
int intr_pic_add_handler(device_t, struct intr_pic *,
intr_child_irq_filter_t *, void *, uintptr_t, uintptr_t);

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 11, 2:40 PM (10 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29541823
Default Alt Text
D40161.diff (5 KB)

Event Timeline