diff options
Diffstat (limited to 'drivers/sh/intc.c')
-rw-r--r-- | drivers/sh/intc.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index c2750391fd34..94ad6bd86a00 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Shared interrupt handling code for IPR and INTC2 types of IRQs. | 2 | * Shared interrupt handling code for IPR and INTC2 types of IRQs. |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2008 Magnus Damm | 4 | * Copyright (C) 2007, 2008 Magnus Damm |
5 | * Copyright (C) 2009 Paul Mundt | 5 | * Copyright (C) 2009, 2010 Paul Mundt |
6 | * | 6 | * |
7 | * Based on intc2.c and ipr.c | 7 | * Based on intc2.c and ipr.c |
8 | * | 8 | * |
@@ -20,12 +20,14 @@ | |||
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
24 | #include <linux/sh_intc.h> | 25 | #include <linux/sh_intc.h> |
25 | #include <linux/sysdev.h> | 26 | #include <linux/sysdev.h> |
26 | #include <linux/list.h> | 27 | #include <linux/list.h> |
27 | #include <linux/topology.h> | 28 | #include <linux/topology.h> |
28 | #include <linux/bitmap.h> | 29 | #include <linux/bitmap.h> |
30 | #include <linux/cpumask.h> | ||
29 | 31 | ||
30 | #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ | 32 | #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ |
31 | ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ | 33 | ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ |
@@ -234,6 +236,10 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle) | |||
234 | unsigned int cpu; | 236 | unsigned int cpu; |
235 | 237 | ||
236 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { | 238 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { |
239 | #ifdef CONFIG_SMP | ||
240 | if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) | ||
241 | continue; | ||
242 | #endif | ||
237 | addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); | 243 | addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); |
238 | intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ | 244 | intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ |
239 | [_INTC_FN(handle)], irq); | 245 | [_INTC_FN(handle)], irq); |
@@ -253,6 +259,10 @@ static void intc_disable(unsigned int irq) | |||
253 | unsigned int cpu; | 259 | unsigned int cpu; |
254 | 260 | ||
255 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { | 261 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { |
262 | #ifdef CONFIG_SMP | ||
263 | if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) | ||
264 | continue; | ||
265 | #endif | ||
256 | addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); | 266 | addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); |
257 | intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\ | 267 | intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\ |
258 | [_INTC_FN(handle)], irq); | 268 | [_INTC_FN(handle)], irq); |
@@ -301,6 +311,23 @@ static int intc_set_wake(unsigned int irq, unsigned int on) | |||
301 | return 0; /* allow wakeup, but setup hardware in intc_suspend() */ | 311 | return 0; /* allow wakeup, but setup hardware in intc_suspend() */ |
302 | } | 312 | } |
303 | 313 | ||
314 | #ifdef CONFIG_SMP | ||
315 | /* | ||
316 | * This is held with the irq desc lock held, so we don't require any | ||
317 | * additional locking here at the intc desc level. The affinity mask is | ||
318 | * later tested in the enable/disable paths. | ||
319 | */ | ||
320 | static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask) | ||
321 | { | ||
322 | if (!cpumask_intersects(cpumask, cpu_online_mask)) | ||
323 | return -1; | ||
324 | |||
325 | cpumask_copy(irq_to_desc(irq)->affinity, cpumask); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | #endif | ||
330 | |||
304 | static void intc_mask_ack(unsigned int irq) | 331 | static void intc_mask_ack(unsigned int irq) |
305 | { | 332 | { |
306 | struct intc_desc_int *d = get_intc_desc(irq); | 333 | struct intc_desc_int *d = get_intc_desc(irq); |
@@ -847,6 +874,9 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
847 | d->chip.shutdown = intc_disable; | 874 | d->chip.shutdown = intc_disable; |
848 | d->chip.set_type = intc_set_sense; | 875 | d->chip.set_type = intc_set_sense; |
849 | d->chip.set_wake = intc_set_wake; | 876 | d->chip.set_wake = intc_set_wake; |
877 | #ifdef CONFIG_SMP | ||
878 | d->chip.set_affinity = intc_set_affinity; | ||
879 | #endif | ||
850 | 880 | ||
851 | if (hw->ack_regs) { | 881 | if (hw->ack_regs) { |
852 | for (i = 0; i < hw->nr_ack_regs; i++) | 882 | for (i = 0; i < hw->nr_ack_regs; i++) |