summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/arm/arm/gic.c22
-rw-r--r--sys/arm/arm/machdep_intr.c153
-rw-r--r--sys/arm/arm/mp_machdep.c24
-rw-r--r--sys/arm/include/intr.h13
-rw-r--r--sys/arm/include/smp.h2
-rw-r--r--sys/kern/pic_if.m13
-rw-r--r--sys/kern/subr_intr.c20
-rw-r--r--sys/sys/intr.h8
8 files changed, 147 insertions, 108 deletions
diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c
index cf72820..124050e 100644
--- a/sys/arm/arm/gic.c
+++ b/sys/arm/arm/gic.c
@@ -121,6 +121,11 @@ __FBSDID("$FreeBSD$");
static u_int gic_irq_cpu;
static int arm_gic_intr(void *);
static int arm_gic_bind(device_t dev, struct intr_irqsrc *isrc);
+
+#ifdef SMP
+u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1];
+#define ISRC_IPI(isrc) sgi_to_ipi[isrc->isrc_data - GIC_FIRST_SGI]
+#endif
#endif
struct arm_gic_softc {
@@ -562,7 +567,7 @@ dispatch_irq:
#ifdef SMP
/* Call EOI for all IPI before dispatch. */
gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
- intr_ipi_dispatch(isrc, tf);
+ intr_ipi_dispatch(ISRC_IPI(isrc), tf);
goto next_irq;
#else
device_printf(sc->gic_dev, "SGI %u on UP system detected\n",
@@ -918,6 +923,20 @@ arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus)
gic_d_write_4(sc, GICD_SGIR(0), val | irq);
}
+
+static int
+arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc *isrc)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ u_int irq;
+ int error;
+
+ error = gic_map_nspc(sc, isrc, &irq);
+ if (error != 0)
+ return (error);
+ sgi_to_ipi[irq - GIC_FIRST_SGI] = ipi;
+ return (0);
+}
#endif
#else
static int
@@ -1146,6 +1165,7 @@ static device_method_t arm_gic_methods[] = {
DEVMETHOD(pic_bind, arm_gic_bind),
DEVMETHOD(pic_init_secondary, arm_gic_init_secondary),
DEVMETHOD(pic_ipi_send, arm_gic_ipi_send),
+ DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup),
#endif
#endif
{ 0, 0 }
diff --git a/sys/arm/arm/machdep_intr.c b/sys/arm/arm/machdep_intr.c
index 875f05e..87a4a46 100644
--- a/sys/arm/arm/machdep_intr.c
+++ b/sys/arm/arm/machdep_intr.c
@@ -64,8 +64,19 @@ __FBSDID("$FreeBSD$");
#include "pic_if.h"
#ifdef SMP
-static struct intr_irqsrc ipi_sources[INTR_IPI_COUNT];
-static u_int ipi_next_num;
+#define INTR_IPI_NAMELEN (MAXCOMLEN + 1)
+
+struct intr_ipi {
+ intr_ipi_handler_t * ii_handler;
+ void * ii_handler_arg;
+ intr_ipi_send_t * ii_send;
+ void * ii_send_arg;
+ char ii_name[INTR_IPI_NAMELEN];
+ u_long * ii_count;
+};
+
+static struct intr_ipi ipi_sources[INTR_IPI_COUNT];
+u_int ipi_next_num;
#endif
#endif
@@ -134,10 +145,7 @@ arm_irq_memory_barrier(uintptr_t irq)
#ifdef ARM_INTRNG
#ifdef SMP
-/*
- * Lookup IPI source.
- */
-static struct intr_irqsrc *
+static inline struct intr_ipi *
intr_ipi_lookup(u_int ipi)
{
@@ -147,112 +155,97 @@ intr_ipi_lookup(u_int ipi)
return (&ipi_sources[ipi]);
}
-/*
- * interrupt controller dispatch function for IPIs. It should
- * be called straight from the interrupt controller, when associated
- * interrupt source is learned. Or from anybody who has an interrupt
- * source mapped.
- */
void
-intr_ipi_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
+intr_ipi_dispatch(u_int ipi, struct trapframe *tf)
{
void *arg;
+ struct intr_ipi *ii;
- KASSERT(isrc != NULL, ("%s: no source", __func__));
+ ii = intr_ipi_lookup(ipi);
+ if (ii->ii_count == NULL)
+ panic("%s: not setup IPI %u", __func__, ipi);
- intr_ipi_increment_count(isrc->isrc_count, PCPU_GET(cpuid));
+ intr_ipi_increment_count(ii->ii_count, PCPU_GET(cpuid));
/*
* Supply ipi filter with trapframe argument
* if none is registered.
*/
- arg = isrc->isrc_arg != NULL ? isrc->isrc_arg : tf;
- isrc->isrc_ipifilter(arg);
+ arg = ii->ii_handler_arg != NULL ? ii->ii_handler_arg : tf;
+ ii->ii_handler(arg);
}
-/*
- * Map IPI into interrupt controller.
- *
- * Not SMP coherent.
- */
-static int
-ipi_map(struct intr_irqsrc *isrc, u_int ipi)
+void
+intr_ipi_send(cpuset_t cpus, u_int ipi)
{
- boolean_t is_percpu;
- int error;
+ struct intr_ipi *ii;
- if (ipi >= INTR_IPI_COUNT)
- panic("%s: no such IPI %u", __func__, ipi);
+ ii = intr_ipi_lookup(ipi);
+ if (ii->ii_count == NULL)
+ panic("%s: not setup IPI %u", __func__, ipi);
- KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+ ii->ii_send(ii->ii_send_arg, cpus);
+}
- isrc->isrc_type = INTR_ISRCT_NAMESPACE;
- isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
- isrc->isrc_nspc_num = ipi_next_num;
+void
+intr_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
+ void *h_arg, intr_ipi_send_t *send, void *s_arg)
+{
+ struct intr_ipi *ii;
- error = PIC_REGISTER(intr_irq_root_dev, isrc, &is_percpu);
- if (error == 0) {
- isrc->isrc_dev = intr_irq_root_dev;
- ipi_next_num++;
- }
- return (error);
+ ii = intr_ipi_lookup(ipi);
+
+ KASSERT(hand != NULL, ("%s: ipi %u no handler", __func__, ipi));
+ KASSERT(send != NULL, ("%s: ipi %u no sender", __func__, ipi));
+ KASSERT(ii->ii_count == NULL, ("%s: ipi %u reused", __func__, ipi));
+
+ ii->ii_handler = hand;
+ ii->ii_handler_arg = h_arg;
+ ii->ii_send = send;
+ ii->ii_send_arg = s_arg;
+ strlcpy(ii->ii_name, name, INTR_IPI_NAMELEN);
+ ii->ii_count = intr_ipi_setup_counters(name);
}
/*
- * Setup IPI handler to interrupt source.
- *
- * Note that there could be more ways how to send and receive IPIs
- * on a platform like fast interrupts for example. In that case,
- * one can call this function with ASIF_NOALLOC flag set and then
- * call intr_ipi_dispatch() when appropriate.
+ * Send IPI thru interrupt controller.
+ */
+static void
+pic_ipi_send(void *arg, cpuset_t cpus)
+{
+
+ KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+ PIC_IPI_SEND(intr_irq_root_dev, arg, cpus);
+}
+
+/*
+ * Setup IPI handler on interrupt controller.
*
* Not SMP coherent.
*/
int
-intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
- void *arg, u_int flags)
+intr_pic_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
+ void *arg)
{
- struct intr_irqsrc *isrc;
int error;
+ struct intr_irqsrc *isrc;
+
+ KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
- if (filter == NULL)
- return(EINVAL);
+ isrc = intr_isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
+ isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
+ isrc->isrc_nspc_num = ipi_next_num;
- isrc = intr_ipi_lookup(ipi);
- if (isrc->isrc_ipifilter != NULL)
- return (EEXIST);
+ error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, isrc);
+ if (error != 0)
+ return (error);
- if ((flags & AISHF_NOALLOC) == 0) {
- error = ipi_map(isrc, ipi);
- if (error != 0)
- return (error);
- }
+ ipi_next_num++;
- isrc->isrc_ipifilter = filter;
- isrc->isrc_arg = arg;
+ isrc->isrc_dev = intr_irq_root_dev;
isrc->isrc_handlers = 1;
- isrc->isrc_count = intr_ipi_setup_counters(name);
- isrc->isrc_index = 0; /* it should not be used in IPI case */
-
- if (isrc->isrc_dev != NULL) {
- PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
- PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
- }
+ intr_ipi_setup(ipi, name, hand, arg, pic_ipi_send, isrc);
return (0);
}
-
-/*
- * Send IPI thru interrupt controller.
- */
-void
-pic_ipi_send(cpuset_t cpus, u_int ipi)
-{
- struct intr_irqsrc *isrc;
-
- isrc = intr_ipi_lookup(ipi);
-
- KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
- PIC_IPI_SEND(intr_irq_root_dev, isrc, cpus);
-}
#endif
#endif
diff --git a/sys/arm/arm/mp_machdep.c b/sys/arm/arm/mp_machdep.c
index 41958a8..699881c 100644
--- a/sys/arm/arm/mp_machdep.c
+++ b/sys/arm/arm/mp_machdep.c
@@ -429,12 +429,11 @@ release_aps(void *dummy __unused)
return;
#ifdef ARM_INTRNG
- intr_ipi_set_handler(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL, 0);
- intr_ipi_set_handler(IPI_AST, "ast", ipi_ast, NULL, 0);
- intr_ipi_set_handler(IPI_STOP, "stop", ipi_stop, NULL, 0);
- intr_ipi_set_handler(IPI_PREEMPT, "preempt", ipi_preempt, NULL, 0);
- intr_ipi_set_handler(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL, 0);
-
+ intr_pic_ipi_setup(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL);
+ intr_pic_ipi_setup(IPI_AST, "ast", ipi_ast, NULL);
+ intr_pic_ipi_setup(IPI_STOP, "stop", ipi_stop, NULL);
+ intr_pic_ipi_setup(IPI_PREEMPT, "preempt", ipi_preempt, NULL);
+ intr_pic_ipi_setup(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL);
#else
#ifdef IPI_IRQ_START
start = IPI_IRQ_START;
@@ -502,7 +501,11 @@ ipi_all_but_self(u_int ipi)
other_cpus = all_cpus;
CPU_CLR(PCPU_GET(cpuid), &other_cpus);
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+#ifdef ARM_INTRNG
+ intr_ipi_send(other_cpus, ipi);
+#else
pic_ipi_send(other_cpus, ipi);
+#endif
}
void
@@ -514,7 +517,11 @@ ipi_cpu(int cpu, u_int ipi)
CPU_SET(cpu, &cpus);
CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
+#ifdef ARM_INTRNG
+ intr_ipi_send(cpus, ipi);
+#else
pic_ipi_send(cpus, ipi);
+#endif
}
void
@@ -522,6 +529,9 @@ ipi_selected(cpuset_t cpus, u_int ipi)
{
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+#ifdef ARM_INTRNG
+ intr_ipi_send(cpus, ipi);
+#else
pic_ipi_send(cpus, ipi);
+#endif
}
-
diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h
index 74d7e4d..a568385 100644
--- a/sys/arm/include/intr.h
+++ b/sys/arm/include/intr.h
@@ -52,14 +52,17 @@
#include <sys/intr.h>
#ifdef SMP
-void intr_ipi_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf);
+typedef void intr_ipi_send_t(void *, cpuset_t);
+typedef void intr_ipi_handler_t(void *);
-#define AISHF_NOALLOC 0x0001
+void intr_ipi_dispatch(u_int, struct trapframe *);
+void intr_ipi_send(cpuset_t, u_int);
-int intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
- void *arg, u_int flags);
-#endif
+void intr_ipi_setup(u_int, const char *, intr_ipi_handler_t *, void *,
+ intr_ipi_send_t *, void *);
+int intr_pic_ipi_setup(u_int, const char *, intr_ipi_handler_t *, void *);
+#endif
#else /* ARM_INTRNG */
/* XXX move to std.* files? */
diff --git a/sys/arm/include/smp.h b/sys/arm/include/smp.h
index e4d6385..e685cc3 100644
--- a/sys/arm/include/smp.h
+++ b/sys/arm/include/smp.h
@@ -37,8 +37,8 @@ void ipi_cpu(int cpu, u_int ipi);
void ipi_selected(cpuset_t cpus, u_int ipi);
/* PIC interface */
-void pic_ipi_send(cpuset_t cpus, u_int ipi);
#ifndef ARM_INTRNG
+void pic_ipi_send(cpuset_t cpus, u_int ipi);
void pic_ipi_clear(int ipi);
int pic_ipi_read(int arg);
#endif
diff --git a/sys/kern/pic_if.m b/sys/kern/pic_if.m
index 2309f0c..04d5f5f 100644
--- a/sys/kern/pic_if.m
+++ b/sys/kern/pic_if.m
@@ -60,6 +60,13 @@ CODE {
{
return;
}
+
+ static int
+ dflt_pic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc *isrc)
+ {
+
+ return (EOPNOTSUPP);
+ }
};
METHOD int register {
@@ -122,3 +129,9 @@ METHOD void ipi_send {
struct intr_irqsrc *isrc;
cpuset_t cpus;
} DEFAULT null_pic_ipi_send;
+
+METHOD int ipi_setup {
+ device_t dev;
+ u_int ipi;
+ struct intr_irqsrc *isrc;
+} DEFAULT dflt_pic_ipi_setup;
diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c
index 1c97fd4..a92c642 100644
--- a/sys/kern/subr_intr.c
+++ b/sys/kern/subr_intr.c
@@ -311,8 +311,8 @@ intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
/*
* Allocate interrupt source.
*/
-static struct intr_irqsrc *
-isrc_alloc(u_int type, u_int extsize)
+struct intr_irqsrc *
+intr_isrc_alloc(u_int type, u_int extsize)
{
struct intr_irqsrc *isrc;
@@ -329,8 +329,8 @@ isrc_alloc(u_int type, u_int extsize)
/*
* Free interrupt source.
*/
-static void
-isrc_free(struct intr_irqsrc *isrc)
+void
+intr_isrc_free(struct intr_irqsrc *isrc)
{
free(isrc, M_INTRNG);
@@ -462,20 +462,20 @@ intr_namespace_map_irq(device_t dev, uint16_t type, uint16_t num)
struct intr_irqsrc *isrc, *new_isrc;
int error;
- new_isrc = isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
+ new_isrc = intr_isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
mtx_lock(&isrc_table_lock);
isrc = isrc_namespace_lookup(dev, type, num);
if (isrc != NULL) {
mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
+ intr_isrc_free(new_isrc);
return (isrc->isrc_irq); /* already mapped */
}
error = isrc_alloc_irq_locked(new_isrc);
if (error != 0) {
mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
+ intr_isrc_free(new_isrc);
return (IRQ_INVALID); /* no space left */
}
@@ -526,20 +526,20 @@ intr_fdt_map_irq(phandle_t node, pcell_t *cells, u_int ncells)
xref = (intptr_t)node; /* It's so simple for now. */
cellsize = ncells * sizeof(*cells);
- new_isrc = isrc_alloc(INTR_ISRCT_FDT, cellsize);
+ new_isrc = intr_isrc_alloc(INTR_ISRCT_FDT, cellsize);
mtx_lock(&isrc_table_lock);
isrc = isrc_fdt_lookup(xref, cells, ncells);
if (isrc != NULL) {
mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
+ intr_isrc_free(new_isrc);
return (isrc->isrc_irq); /* already mapped */
}
error = isrc_alloc_irq_locked(new_isrc);
if (error != 0) {
mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
+ intr_isrc_free(new_isrc);
return (IRQ_INVALID); /* no space left */
}
diff --git a/sys/sys/intr.h b/sys/sys/intr.h
index 5ef2379..e619b3b 100644
--- a/sys/sys/intr.h
+++ b/sys/sys/intr.h
@@ -50,8 +50,6 @@ typedef int intr_irq_filter_t(void *arg);
#define INTR_ISRC_NAMELEN (MAXCOMLEN + 1)
-typedef void intr_ipi_filter_t(void *arg);
-
enum intr_isrc_type {
INTR_ISRCT_NAMESPACE,
INTR_ISRCT_FDT
@@ -81,15 +79,17 @@ struct intr_irqsrc {
struct intr_event * isrc_event;
#ifdef INTR_SOLO
intr_irq_filter_t * isrc_filter;
-#endif
- intr_ipi_filter_t * isrc_ipifilter;
void * isrc_arg;
+#endif
#ifdef FDT
u_int isrc_ncells;
pcell_t isrc_cells[]; /* leave it last */
#endif
};
+struct intr_irqsrc *intr_isrc_alloc(u_int type, u_int extsize);
+void intr_isrc_free(struct intr_irqsrc *isrc);
+
void intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...)
__printflike(2, 3);
OpenPOWER on IntegriCloud