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.
This commit is contained in:
parent
bd077006c0
commit
08393b3efa
@ -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 void nexus_probe_nomatch(device_t, device_t);
|
||||||
static int nexus_read_ivar(device_t, device_t, int, uintptr_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);
|
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,
|
static int nexus_setup_intr(device_t, device_t, struct resource *, int,
|
||||||
driver_filter_t *, driver_intr_t *, void *, void **);
|
driver_filter_t *, driver_intr_t *, void *, void **);
|
||||||
static int nexus_teardown_intr(device_t, device_t, struct resource *,
|
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_write_ivar, nexus_write_ivar),
|
||||||
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
|
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
|
||||||
DEVMETHOD(bus_teardown_intr, nexus_teardown_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_alloc_resource, nexus_alloc_resource),
|
||||||
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
|
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
|
||||||
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_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));
|
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,
|
* Allocate resources at the behest of a child. This only handles interrupts,
|
||||||
* since I/O resources are handled by child busses.
|
* since I/O resources are handled by child busses.
|
||||||
|
@ -56,6 +56,7 @@ int powerpc_enable_intr(void);
|
|||||||
int powerpc_setup_intr(const char *, u_int, driver_filter_t, driver_intr_t,
|
int powerpc_setup_intr(const char *, u_int, driver_filter_t, driver_intr_t,
|
||||||
void *, enum intr_type, void **);
|
void *, enum intr_type, void **);
|
||||||
int powerpc_teardown_intr(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);
|
int powerpc_config_intr(int, enum intr_trigger, enum intr_polarity);
|
||||||
|
|
||||||
#endif /* _MACHINE_INTR_MACHDEP_H_ */
|
#endif /* _MACHINE_INTR_MACHDEP_H_ */
|
||||||
|
@ -57,6 +57,7 @@ int openpic_attach(device_t);
|
|||||||
/*
|
/*
|
||||||
* PIC interface.
|
* 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_config(device_t, u_int, enum intr_trigger, enum intr_polarity);
|
||||||
void openpic_dispatch(device_t, struct trapframe *);
|
void openpic_dispatch(device_t, struct trapframe *);
|
||||||
void openpic_enable(device_t, u_int, u_int);
|
void openpic_enable(device_t, u_int, u_int);
|
||||||
|
@ -57,6 +57,7 @@ static device_method_t openpic_ocpbus_methods[] = {
|
|||||||
DEVMETHOD(device_attach, openpic_attach),
|
DEVMETHOD(device_attach, openpic_attach),
|
||||||
|
|
||||||
/* PIC interface */
|
/* PIC interface */
|
||||||
|
DEVMETHOD(pic_bind, openpic_bind),
|
||||||
DEVMETHOD(pic_config, openpic_config),
|
DEVMETHOD(pic_config, openpic_config),
|
||||||
DEVMETHOD(pic_dispatch, openpic_dispatch),
|
DEVMETHOD(pic_dispatch, openpic_dispatch),
|
||||||
DEVMETHOD(pic_enable, openpic_enable),
|
DEVMETHOD(pic_enable, openpic_enable),
|
||||||
|
@ -751,6 +751,7 @@ static device_method_t openpic_cpcht_methods[] = {
|
|||||||
DEVMETHOD(device_attach, openpic_cpcht_attach),
|
DEVMETHOD(device_attach, openpic_cpcht_attach),
|
||||||
|
|
||||||
/* PIC interface */
|
/* PIC interface */
|
||||||
|
DEVMETHOD(pic_bind, openpic_bind),
|
||||||
DEVMETHOD(pic_config, openpic_cpcht_config),
|
DEVMETHOD(pic_config, openpic_cpcht_config),
|
||||||
DEVMETHOD(pic_dispatch, openpic_dispatch),
|
DEVMETHOD(pic_dispatch, openpic_dispatch),
|
||||||
DEVMETHOD(pic_enable, openpic_cpcht_enable),
|
DEVMETHOD(pic_enable, openpic_cpcht_enable),
|
||||||
|
@ -67,6 +67,7 @@ static device_method_t openpic_macio_methods[] = {
|
|||||||
DEVMETHOD(device_attach, openpic_attach),
|
DEVMETHOD(device_attach, openpic_attach),
|
||||||
|
|
||||||
/* PIC interface */
|
/* PIC interface */
|
||||||
|
DEVMETHOD(pic_bind, openpic_bind),
|
||||||
DEVMETHOD(pic_config, openpic_config),
|
DEVMETHOD(pic_config, openpic_config),
|
||||||
DEVMETHOD(pic_dispatch, openpic_dispatch),
|
DEVMETHOD(pic_dispatch, openpic_dispatch),
|
||||||
DEVMETHOD(pic_enable, openpic_enable),
|
DEVMETHOD(pic_enable, openpic_enable),
|
||||||
|
@ -73,6 +73,7 @@
|
|||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#include <sys/mutex.h>
|
#include <sys/mutex.h>
|
||||||
#include <sys/pcpu.h>
|
#include <sys/pcpu.h>
|
||||||
|
#include <sys/smp.h>
|
||||||
#include <sys/syslog.h>
|
#include <sys/syslog.h>
|
||||||
#include <sys/vmmeter.h>
|
#include <sys/vmmeter.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
@ -96,6 +97,7 @@ struct powerpc_intr {
|
|||||||
device_t pic;
|
device_t pic;
|
||||||
u_int intline;
|
u_int intline;
|
||||||
u_int vector;
|
u_int vector;
|
||||||
|
cpumask_t cpu;
|
||||||
enum intr_trigger trig;
|
enum intr_trigger trig;
|
||||||
enum intr_polarity pol;
|
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);
|
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
|
static void
|
||||||
intrcnt_setname(const char *name, int index)
|
intrcnt_setname(const char *name, int index)
|
||||||
{
|
{
|
||||||
@ -150,11 +169,12 @@ intr_lookup(u_int irq)
|
|||||||
return (i);
|
return (i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mtx_unlock(&intr_table_lock);
|
|
||||||
|
|
||||||
i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
|
i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
|
||||||
if (i == NULL)
|
if (i == NULL) {
|
||||||
|
mtx_unlock(&intr_table_lock);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
i->event = NULL;
|
i->event = NULL;
|
||||||
i->cntp = NULL;
|
i->cntp = NULL;
|
||||||
@ -164,7 +184,12 @@ intr_lookup(u_int irq)
|
|||||||
i->pic = NULL;
|
i->pic = NULL;
|
||||||
i->vector = -1;
|
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;
|
for (vector = 0; vector < INTR_VECTORS && vector <= nvectors;
|
||||||
vector++) {
|
vector++) {
|
||||||
iscan = powerpc_intrs[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))
|
i->pol != INTR_POLARITY_CONFORM))
|
||||||
PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
|
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)
|
if (!error && enable)
|
||||||
PIC_ENABLE(i->pic, i->intline, i->vector);
|
PIC_ENABLE(i->pic, i->intline, i->vector);
|
||||||
}
|
}
|
||||||
@ -372,6 +400,27 @@ powerpc_teardown_intr(void *cookie)
|
|||||||
return (intr_event_remove_handler(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
|
int
|
||||||
powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
|
powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,9 @@
|
|||||||
#include <sys/bus.h>
|
#include <sys/bus.h>
|
||||||
#include <sys/conf.h>
|
#include <sys/conf.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
#include <sys/rman.h>
|
#include <sys/rman.h>
|
||||||
|
#include <sys/sched.h>
|
||||||
|
|
||||||
#include <machine/bus.h>
|
#include <machine/bus.h>
|
||||||
#include <machine/intr.h>
|
#include <machine/intr.h>
|
||||||
@ -72,11 +74,13 @@ openpic_set_priority(struct openpic_softc *sc, int pri)
|
|||||||
u_int tpr;
|
u_int tpr;
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
|
|
||||||
|
sched_pin();
|
||||||
tpr = OPENPIC_PCPU_TPR(PCPU_GET(cpuid));
|
tpr = OPENPIC_PCPU_TPR(PCPU_GET(cpuid));
|
||||||
x = openpic_read(sc, tpr);
|
x = openpic_read(sc, tpr);
|
||||||
x &= ~OPENPIC_TPR_MASK;
|
x &= ~OPENPIC_TPR_MASK;
|
||||||
x |= pri;
|
x |= pri;
|
||||||
openpic_write(sc, tpr, x);
|
openpic_write(sc, tpr, x);
|
||||||
|
sched_unpin();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -227,6 +231,19 @@ openpic_attach(device_t dev)
|
|||||||
* PIC I/F methods
|
* PIC I/F methods
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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
|
void
|
||||||
openpic_config(device_t dev, u_int irq, enum intr_trigger trig,
|
openpic_config(device_t dev, u_int irq, enum intr_trigger trig,
|
||||||
enum intr_polarity pol)
|
enum intr_polarity pol)
|
||||||
@ -313,8 +330,10 @@ openpic_ipi(device_t dev, u_int cpu)
|
|||||||
struct openpic_softc *sc;
|
struct openpic_softc *sc;
|
||||||
|
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
|
sched_pin();
|
||||||
openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0),
|
openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0),
|
||||||
1u << cpu);
|
1u << cpu);
|
||||||
|
sched_unpin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -32,6 +32,12 @@
|
|||||||
|
|
||||||
INTERFACE pic;
|
INTERFACE pic;
|
||||||
|
|
||||||
|
METHOD void bind {
|
||||||
|
device_t dev;
|
||||||
|
u_int irq;
|
||||||
|
cpumask_t cpumask;
|
||||||
|
};
|
||||||
|
|
||||||
METHOD void config {
|
METHOD void config {
|
||||||
device_t dev;
|
device_t dev;
|
||||||
u_int irq;
|
u_int irq;
|
||||||
@ -73,3 +79,4 @@ METHOD void unmask {
|
|||||||
device_t dev;
|
device_t dev;
|
||||||
u_int irq;
|
u_int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user