summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2010-06-23 22:33:03 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2010-06-23 22:33:03 +0000
commitd7c1d40d534867476888e6e606958e8fbd40c9ed (patch)
treeff8b1d63cb631f68a84a7e7f36db92e471009d87 /sys/powerpc
parent9f1a0b6386f1d24c42f4060d8550ee46b014b2ec (diff)
downloadFreeBSD-src-d7c1d40d534867476888e6e606958e8fbd40c9ed.zip
FreeBSD-src-d7c1d40d534867476888e6e606958e8fbd40c9ed.tar.gz
Configure interrupts on SMP systems to be distributed among all online
CPUs by default, and provide a functional version of BUS_BIND_INTR(). While here, fix some potential concurrency problems in the interrupt handling code.
Diffstat (limited to 'sys/powerpc')
-rw-r--r--sys/powerpc/aim/nexus.c27
-rw-r--r--sys/powerpc/include/intr_machdep.h1
-rw-r--r--sys/powerpc/include/openpicvar.h1
-rw-r--r--sys/powerpc/mpc85xx/opic.c1
-rw-r--r--sys/powerpc/powermac/cpcht.c1
-rw-r--r--sys/powerpc/powermac/openpic_macio.c1
-rw-r--r--sys/powerpc/powerpc/intr_machdep.c55
-rw-r--r--sys/powerpc/powerpc/openpic.c19
-rw-r--r--sys/powerpc/powerpc/pic_if.m7
9 files changed, 110 insertions, 3 deletions
diff --git a/sys/powerpc/aim/nexus.c b/sys/powerpc/aim/nexus.c
index a9cf125..53a9dd1 100644
--- a/sys/powerpc/aim/nexus.c
+++ b/sys/powerpc/aim/nexus.c
@@ -119,6 +119,12 @@ static device_t nexus_add_child(device_t, int, const char *, int);
static void nexus_probe_nomatch(device_t, device_t);
static int nexus_read_ivar(device_t, device_t, int, uintptr_t *);
static int nexus_write_ivar(device_t, device_t, int, uintptr_t);
+#ifdef SMP
+static int nexus_bind_intr(device_t dev, device_t child,
+ struct resource *irq, int cpu);
+#endif
+static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+ enum intr_polarity pol);
static int nexus_setup_intr(device_t, device_t, struct resource *, int,
driver_filter_t *, driver_intr_t *, void *, void **);
static int nexus_teardown_intr(device_t, device_t, struct resource *,
@@ -162,6 +168,10 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_write_ivar, nexus_write_ivar),
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
+#ifdef SMP
+ DEVMETHOD(bus_bind_intr, nexus_bind_intr),
+#endif
+ DEVMETHOD(bus_config_intr, nexus_config_intr),
DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
@@ -363,6 +373,23 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
return (powerpc_teardown_intr(cookie));
}
+#ifdef SMP
+static int
+nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
+{
+
+ return (powerpc_bind_intr(rman_get_start(irq), cpu));
+}
+#endif
+
+static int
+nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+ enum intr_polarity pol)
+{
+
+ return (powerpc_config_intr(irq, trig, pol));
+}
+
/*
* Allocate resources at the behest of a child. This only handles interrupts,
* since I/O resources are handled by child busses.
diff --git a/sys/powerpc/include/intr_machdep.h b/sys/powerpc/include/intr_machdep.h
index 96f9acc..5a0e04a 100644
--- a/sys/powerpc/include/intr_machdep.h
+++ b/sys/powerpc/include/intr_machdep.h
@@ -56,6 +56,7 @@ int powerpc_enable_intr(void);
int powerpc_setup_intr(const char *, u_int, driver_filter_t, driver_intr_t,
void *, enum intr_type, void **);
int powerpc_teardown_intr(void *);
+int powerpc_bind_intr(u_int irq, u_char cpu);
int powerpc_config_intr(int, enum intr_trigger, enum intr_polarity);
#endif /* _MACHINE_INTR_MACHDEP_H_ */
diff --git a/sys/powerpc/include/openpicvar.h b/sys/powerpc/include/openpicvar.h
index 5f28734..5468542 100644
--- a/sys/powerpc/include/openpicvar.h
+++ b/sys/powerpc/include/openpicvar.h
@@ -57,6 +57,7 @@ int openpic_attach(device_t);
/*
* PIC interface.
*/
+void openpic_bind(device_t dev, u_int irq, cpumask_t cpumask);
void openpic_config(device_t, u_int, enum intr_trigger, enum intr_polarity);
void openpic_dispatch(device_t, struct trapframe *);
void openpic_enable(device_t, u_int, u_int);
diff --git a/sys/powerpc/mpc85xx/opic.c b/sys/powerpc/mpc85xx/opic.c
index f2c5ef8..812febd 100644
--- a/sys/powerpc/mpc85xx/opic.c
+++ b/sys/powerpc/mpc85xx/opic.c
@@ -57,6 +57,7 @@ static device_method_t openpic_ocpbus_methods[] = {
DEVMETHOD(device_attach, openpic_attach),
/* PIC interface */
+ DEVMETHOD(pic_bind, openpic_bind),
DEVMETHOD(pic_config, openpic_config),
DEVMETHOD(pic_dispatch, openpic_dispatch),
DEVMETHOD(pic_enable, openpic_enable),
diff --git a/sys/powerpc/powermac/cpcht.c b/sys/powerpc/powermac/cpcht.c
index aaa02d2..3af4d60 100644
--- a/sys/powerpc/powermac/cpcht.c
+++ b/sys/powerpc/powermac/cpcht.c
@@ -751,6 +751,7 @@ static device_method_t openpic_cpcht_methods[] = {
DEVMETHOD(device_attach, openpic_cpcht_attach),
/* PIC interface */
+ DEVMETHOD(pic_bind, openpic_bind),
DEVMETHOD(pic_config, openpic_cpcht_config),
DEVMETHOD(pic_dispatch, openpic_dispatch),
DEVMETHOD(pic_enable, openpic_cpcht_enable),
diff --git a/sys/powerpc/powermac/openpic_macio.c b/sys/powerpc/powermac/openpic_macio.c
index 4a0eaf4..77d12d9 100644
--- a/sys/powerpc/powermac/openpic_macio.c
+++ b/sys/powerpc/powermac/openpic_macio.c
@@ -67,6 +67,7 @@ static device_method_t openpic_macio_methods[] = {
DEVMETHOD(device_attach, openpic_attach),
/* PIC interface */
+ DEVMETHOD(pic_bind, openpic_bind),
DEVMETHOD(pic_config, openpic_config),
DEVMETHOD(pic_dispatch, openpic_dispatch),
DEVMETHOD(pic_enable, openpic_enable),
diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c
index 85291b1..e48cd42 100644
--- a/sys/powerpc/powerpc/intr_machdep.c
+++ b/sys/powerpc/powerpc/intr_machdep.c
@@ -73,6 +73,7 @@
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
+#include <sys/smp.h>
#include <sys/syslog.h>
#include <sys/vmmeter.h>
#include <sys/proc.h>
@@ -96,6 +97,7 @@ struct powerpc_intr {
device_t pic;
u_int intline;
u_int vector;
+ cpumask_t cpu;
enum intr_trigger trig;
enum intr_polarity pol;
};
@@ -127,6 +129,23 @@ intr_init(void *dummy __unused)
}
SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
+#ifdef SMP
+static void
+smp_intr_init(void *dummy __unused)
+{
+ struct powerpc_intr *i;
+ int vector;
+
+ for (vector = 0; vector < nvectors; vector++) {
+ i = powerpc_intrs[vector];
+ if (i != NULL && i->pic == root_pic)
+ PIC_BIND(i->pic, i->intline, i->cpu);
+ }
+}
+
+SYSINIT(smp_intr_init, SI_SUB_SMP, SI_ORDER_ANY, smp_intr_init, NULL);
+#endif
+
static void
intrcnt_setname(const char *name, int index)
{
@@ -150,11 +169,12 @@ intr_lookup(u_int irq)
return (i);
}
}
- mtx_unlock(&intr_table_lock);
i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
- if (i == NULL)
+ if (i == NULL) {
+ mtx_unlock(&intr_table_lock);
return (NULL);
+ }
i->event = NULL;
i->cntp = NULL;
@@ -164,7 +184,12 @@ intr_lookup(u_int irq)
i->pic = NULL;
i->vector = -1;
- mtx_lock(&intr_table_lock);
+#ifdef SMP
+ i->cpu = all_cpus;
+#else
+ i->cpu = 1;
+#endif
+
for (vector = 0; vector < INTR_VECTORS && vector <= nvectors;
vector++) {
iscan = powerpc_intrs[vector];
@@ -359,6 +384,9 @@ powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
i->pol != INTR_POLARITY_CONFORM))
PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
+ if (!error && i->pic == root_pic)
+ PIC_BIND(i->pic, i->intline, i->cpu);
+
if (!error && enable)
PIC_ENABLE(i->pic, i->intline, i->vector);
}
@@ -372,6 +400,27 @@ powerpc_teardown_intr(void *cookie)
return (intr_event_remove_handler(cookie));
}
+#ifdef SMP
+int
+powerpc_bind_intr(u_int irq, u_char cpu)
+{
+ struct powerpc_intr *i;
+
+ i = intr_lookup(irq);
+ if (i == NULL)
+ return (ENOMEM);
+
+ if (cpu == NOCPU)
+ i->cpu = all_cpus;
+ else
+ i->cpu = 1 << cpu;
+
+ PIC_BIND(i->pic, i->intline, i->cpu);
+
+ return (intr_event_bind(i->event, cpu));
+}
+#endif
+
int
powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
{
diff --git a/sys/powerpc/powerpc/openpic.c b/sys/powerpc/powerpc/openpic.c
index eca7947..5aed449 100644
--- a/sys/powerpc/powerpc/openpic.c
+++ b/sys/powerpc/powerpc/openpic.c
@@ -30,7 +30,9 @@
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
+#include <sys/proc.h>
#include <sys/rman.h>
+#include <sys/sched.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -72,11 +74,13 @@ openpic_set_priority(struct openpic_softc *sc, int pri)
u_int tpr;
uint32_t x;
+ sched_pin();
tpr = OPENPIC_PCPU_TPR(PCPU_GET(cpuid));
x = openpic_read(sc, tpr);
x &= ~OPENPIC_TPR_MASK;
x |= pri;
openpic_write(sc, tpr, x);
+ sched_unpin();
}
int
@@ -228,6 +232,19 @@ openpic_attach(device_t dev)
*/
void
+openpic_bind(device_t dev, u_int irq, cpumask_t cpumask)
+{
+ struct openpic_softc *sc;
+
+ /* If we aren't directly connected to the CPU, this won't work */
+ if (dev != root_pic)
+ return;
+
+ sc = device_get_softc(dev);
+ openpic_write(sc, OPENPIC_IDEST(irq), cpumask);
+}
+
+void
openpic_config(device_t dev, u_int irq, enum intr_trigger trig,
enum intr_polarity pol)
{
@@ -313,8 +330,10 @@ openpic_ipi(device_t dev, u_int cpu)
struct openpic_softc *sc;
sc = device_get_softc(dev);
+ sched_pin();
openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0),
1u << cpu);
+ sched_unpin();
}
void
diff --git a/sys/powerpc/powerpc/pic_if.m b/sys/powerpc/powerpc/pic_if.m
index a472993..04f1c1e 100644
--- a/sys/powerpc/powerpc/pic_if.m
+++ b/sys/powerpc/powerpc/pic_if.m
@@ -32,6 +32,12 @@
INTERFACE pic;
+METHOD void bind {
+ device_t dev;
+ u_int irq;
+ cpumask_t cpumask;
+};
+
METHOD void config {
device_t dev;
u_int irq;
@@ -73,3 +79,4 @@ METHOD void unmask {
device_t dev;
u_int irq;
};
+
OpenPOWER on IntegriCloud