summaryrefslogtreecommitdiffstats
path: root/sys/arm64
diff options
context:
space:
mode:
authorzbb <zbb@FreeBSD.org>2016-02-11 11:58:27 +0000
committerzbb <zbb@FreeBSD.org>2016-02-11 11:58:27 +0000
commit95137856d119ee0d525eb022f97b0b53749fdf8a (patch)
tree4028d1b36723228a7e014ed2eab904a0077dee7c /sys/arm64
parent45b4fa372ea10b8f0881e1f930cfe8e6ece95c1d (diff)
downloadFreeBSD-src-95137856d119ee0d525eb022f97b0b53749fdf8a.zip
FreeBSD-src-95137856d119ee0d525eb022f97b0b53749fdf8a.tar.gz
Introduce bus_bind_intr method for ARM64
It can be used to bind specific interrupt to a particular CPU. Requires PIC support for interrupts binding. Reviewed by: wma Obtained from: Semihalf Sponsored by: Cavium Differential Revision: https://reviews.freebsd.org/D5122
Diffstat (limited to 'sys/arm64')
-rw-r--r--sys/arm64/arm64/intr_machdep.c80
-rw-r--r--sys/arm64/arm64/nexus.c16
-rw-r--r--sys/arm64/arm64/pic_if.m12
-rw-r--r--sys/arm64/include/intr.h1
4 files changed, 103 insertions, 6 deletions
diff --git a/sys/arm64/arm64/intr_machdep.c b/sys/arm64/arm64/intr_machdep.c
index 70902ce..277e0c1 100644
--- a/sys/arm64/arm64/intr_machdep.c
+++ b/sys/arm64/arm64/intr_machdep.c
@@ -38,6 +38,7 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
@@ -84,6 +85,7 @@ struct arm64_intr_entry {
u_int i_hw_irq; /* Physical interrupt number */
u_int i_cntidx; /* Index in intrcnt table */
u_int i_handlers; /* Allocated handlers */
+ u_int i_cpu; /* Assigned CPU */
u_long *i_cntp; /* Interrupt hit counter */
};
@@ -162,6 +164,8 @@ intr_allocate(u_int hw_irq)
if (intr == NULL)
return (NULL);
+ /* The default CPU is 0 but can be changed later by bind or shuffle */
+ intr->i_cpu = 0;
intr->i_event = NULL;
intr->i_handlers = 0;
intr->i_trig = INTR_TRIGGER_CONFORM;
@@ -176,6 +180,44 @@ intr_allocate(u_int hw_irq)
return intr;
}
+static int
+intr_assign_cpu(void *arg, int cpu)
+{
+#ifdef SMP
+ struct arm64_intr_entry *intr;
+ int error;
+
+ if (root_pic == NULL)
+ panic("Cannot assing interrupt to CPU. No PIC configured");
+ /*
+ * Set the interrupt to CPU affinity.
+ * Do not configure this in hardware during early boot.
+ * We will pick up the assignment once the APs are started.
+ */
+ if (cpu != NOCPU) {
+ intr = arg;
+ if (!cold && smp_started) {
+ /*
+ * Bind the interrupt immediately
+ * if SMP is up and running.
+ */
+ error = PIC_BIND(root_pic, intr->i_hw_irq, cpu);
+ if (error == 0)
+ intr->i_cpu = cpu;
+ } else {
+ /* Postpone binding until SMP is operational */
+ intr->i_cpu = cpu;
+ error = 0;
+ }
+ } else
+ error = 0;
+
+ return (error);
+#else
+ return (EOPNOTSUPP);
+#endif
+}
+
static void
intr_pre_ithread(void *arg)
{
@@ -339,7 +381,7 @@ arm_setup_intr(const char *name, driver_filter_t *filt, driver_intr_t handler,
if (intr->i_event == NULL) {
error = intr_event_create(&intr->i_event, (void *)intr, 0,
hw_irq, intr_pre_ithread, intr_post_ithread,
- intr_post_filter, NULL, "irq%u", hw_irq);
+ intr_post_filter, intr_assign_cpu, "irq%u", hw_irq);
if (error)
return (error);
}
@@ -447,6 +489,42 @@ arm_cpu_intr(struct trapframe *tf)
}
#ifdef SMP
+static void
+arm_intr_smp_init(void *dummy __unused)
+{
+ struct arm64_intr_entry *intr;
+ int error;
+
+ if (root_pic == NULL)
+ panic("Cannot assing interrupts to CPUs. No PIC configured");
+
+ mtx_lock_spin(&intr_list_lock);
+ SLIST_FOREACH(intr, &irq_slist_head, entries) {
+ mtx_unlock_spin(&intr_list_lock);
+ error = PIC_BIND(root_pic, intr->i_hw_irq, intr->i_cpu);
+ if (error != 0)
+ intr->i_cpu = 0;
+ mtx_lock_spin(&intr_list_lock);
+ }
+ mtx_unlock_spin(&intr_list_lock);
+}
+SYSINIT(arm_intr_smp_init, SI_SUB_SMP, SI_ORDER_ANY, arm_intr_smp_init, NULL);
+
+/* Attempt to bind the specified IRQ to the specified CPU. */
+int
+arm_intr_bind(u_int hw_irq, int cpu)
+{
+ struct arm64_intr_entry *intr;
+
+ mtx_lock_spin(&intr_list_lock);
+ intr = intr_lookup_locked(hw_irq);
+ mtx_unlock_spin(&intr_list_lock);
+ if (intr == NULL)
+ return (EINVAL);
+
+ return (intr_event_bind(intr->i_event, cpu));
+}
+
void
arm_setup_ipihandler(driver_filter_t *filt, u_int ipi)
{
diff --git a/sys/arm64/arm64/nexus.c b/sys/arm64/arm64/nexus.c
index 8290cff..611addd 100644
--- a/sys/arm64/arm64/nexus.c
+++ b/sys/arm64/arm64/nexus.c
@@ -113,6 +113,9 @@ static int nexus_deactivate_resource(device_t, device_t, int, int,
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);
static int nexus_teardown_intr(device_t, device_t, struct resource *, void *);
+#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,
@@ -131,7 +134,9 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
-
+#ifdef SMP
+ DEVMETHOD(bus_bind_intr, nexus_bind_intr),
+#endif
{ 0, 0 }
};
@@ -293,6 +298,15 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
return (arm_teardown_intr(ih));
}
+#ifdef SMP
+static int
+nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
+{
+
+ return (arm_intr_bind(rman_get_start(irq), cpu));
+}
+#endif
+
static int
nexus_activate_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
diff --git a/sys/arm64/arm64/pic_if.m b/sys/arm64/arm64/pic_if.m
index fe358c6..33d1bcd 100644
--- a/sys/arm64/arm64/pic_if.m
+++ b/sys/arm64/arm64/pic_if.m
@@ -34,7 +34,11 @@
INTERFACE pic;
CODE {
- static pic_translate_code_t pic_translate_code_default;
+ static int pic_bind_default(device_t dev, u_int irq, u_int cpu)
+ {
+
+ return (EOPNOTSUPP);
+ }
static void pic_translate_code_default(device_t dev, u_int irq,
int code, enum intr_trigger *trig, enum intr_polarity *pol)
@@ -60,11 +64,11 @@ CODE {
}
};
-METHOD void bind {
+METHOD int bind {
device_t dev;
u_int irq;
- cpuset_t cpumask;
-};
+ u_int cpu;
+} DEFAULT pic_bind_default;
METHOD void translate_code {
device_t dev;
diff --git a/sys/arm64/include/intr.h b/sys/arm64/include/intr.h
index 067c69b..2d7da21 100644
--- a/sys/arm64/include/intr.h
+++ b/sys/arm64/include/intr.h
@@ -49,6 +49,7 @@ void arm_unmask_irq(u_int);
#ifdef SMP
void arm_init_secondary(void);
+int arm_intr_bind(u_int, int);
void arm_setup_ipihandler(driver_filter_t *, u_int);
void arm_unmask_ipi(u_int);
#endif
OpenPOWER on IntegriCloud