|
@@ -2,7 +2,7 @@
|
|
* Shared interrupt handling code for IPR and INTC2 types of IRQs.
|
|
* Shared interrupt handling code for IPR and INTC2 types of IRQs.
|
|
*
|
|
*
|
|
* Copyright (C) 2007, 2008 Magnus Damm
|
|
* Copyright (C) 2007, 2008 Magnus Damm
|
|
- * Copyright (C) 2009 Paul Mundt
|
|
|
|
|
|
+ * Copyright (C) 2009, 2010 Paul Mundt
|
|
*
|
|
*
|
|
* Based on intc2.c and ipr.c
|
|
* Based on intc2.c and ipr.c
|
|
*
|
|
*
|
|
@@ -26,6 +26,7 @@
|
|
#include <linux/list.h>
|
|
#include <linux/list.h>
|
|
#include <linux/topology.h>
|
|
#include <linux/topology.h>
|
|
#include <linux/bitmap.h>
|
|
#include <linux/bitmap.h>
|
|
|
|
+#include <linux/cpumask.h>
|
|
|
|
|
|
#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
|
|
#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
|
|
((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
|
|
((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
|
|
@@ -234,6 +235,10 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle)
|
|
unsigned int cpu;
|
|
unsigned int cpu;
|
|
|
|
|
|
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
|
|
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
|
|
|
|
+#ifdef CONFIG_SMP
|
|
|
|
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
|
|
|
|
+ continue;
|
|
|
|
+#endif
|
|
addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
|
|
addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
|
|
intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
|
|
intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
|
|
[_INTC_FN(handle)], irq);
|
|
[_INTC_FN(handle)], irq);
|
|
@@ -253,6 +258,10 @@ static void intc_disable(unsigned int irq)
|
|
unsigned int cpu;
|
|
unsigned int cpu;
|
|
|
|
|
|
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
|
|
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
|
|
|
|
+#ifdef CONFIG_SMP
|
|
|
|
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
|
|
|
|
+ continue;
|
|
|
|
+#endif
|
|
addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
|
|
addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
|
|
intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
|
|
intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
|
|
[_INTC_FN(handle)], irq);
|
|
[_INTC_FN(handle)], irq);
|
|
@@ -301,6 +310,23 @@ static int intc_set_wake(unsigned int irq, unsigned int on)
|
|
return 0; /* allow wakeup, but setup hardware in intc_suspend() */
|
|
return 0; /* allow wakeup, but setup hardware in intc_suspend() */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef CONFIG_SMP
|
|
|
|
+/*
|
|
|
|
+ * This is held with the irq desc lock held, so we don't require any
|
|
|
|
+ * additional locking here at the intc desc level. The affinity mask is
|
|
|
|
+ * later tested in the enable/disable paths.
|
|
|
|
+ */
|
|
|
|
+static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
|
|
|
+{
|
|
|
|
+ if (!cpumask_intersects(cpumask, cpu_online_mask))
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
static void intc_mask_ack(unsigned int irq)
|
|
static void intc_mask_ack(unsigned int irq)
|
|
{
|
|
{
|
|
struct intc_desc_int *d = get_intc_desc(irq);
|
|
struct intc_desc_int *d = get_intc_desc(irq);
|
|
@@ -847,6 +873,9 @@ void __init register_intc_controller(struct intc_desc *desc)
|
|
d->chip.shutdown = intc_disable;
|
|
d->chip.shutdown = intc_disable;
|
|
d->chip.set_type = intc_set_sense;
|
|
d->chip.set_type = intc_set_sense;
|
|
d->chip.set_wake = intc_set_wake;
|
|
d->chip.set_wake = intc_set_wake;
|
|
|
|
+#ifdef CONFIG_SMP
|
|
|
|
+ d->chip.set_affinity = intc_set_affinity;
|
|
|
|
+#endif
|
|
|
|
|
|
if (hw->ack_regs) {
|
|
if (hw->ack_regs) {
|
|
for (i = 0; i < hw->nr_ack_regs; i++)
|
|
for (i = 0; i < hw->nr_ack_regs; i++)
|