Commit a8941dad1f12b4e8a87a517ed27f29d0209c817c
1 parent
25cf84cf37
Exists in
master
and in
7 other branches
sh: Support CPU affinity masks for INTC controllers.
This hooks up the ->set_affinity() for the INTC controllers, which can be done as just a simple copy of the cpumask. The enable/disable paths already handle SMP register strides, so we just test the affinity mask in these paths to determine which strides to skip over. The early enable/disable path happens prior to the IRQs being registered, so we have no affinity mask established at that point, in which case we just default to CPU_MASK_ALL. This is left as it is to permit the force enable/disable code to retain existing semantics. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Showing 1 changed file with 30 additions and 1 deletions Side-by-side Diff
drivers/sh/intc.c
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | * Shared interrupt handling code for IPR and INTC2 types of IRQs. |
3 | 3 | * |
4 | 4 | * Copyright (C) 2007, 2008 Magnus Damm |
5 | - * Copyright (C) 2009 Paul Mundt | |
5 | + * Copyright (C) 2009, 2010 Paul Mundt | |
6 | 6 | * |
7 | 7 | * Based on intc2.c and ipr.c |
8 | 8 | * |
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | #include <linux/list.h> |
27 | 27 | #include <linux/topology.h> |
28 | 28 | #include <linux/bitmap.h> |
29 | +#include <linux/cpumask.h> | |
29 | 30 | |
30 | 31 | #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ |
31 | 32 | ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ |
... | ... | @@ -234,6 +235,10 @@ |
234 | 235 | unsigned int cpu; |
235 | 236 | |
236 | 237 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { |
238 | +#ifdef CONFIG_SMP | |
239 | + if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) | |
240 | + continue; | |
241 | +#endif | |
237 | 242 | addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); |
238 | 243 | intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ |
239 | 244 | [_INTC_FN(handle)], irq); |
... | ... | @@ -253,6 +258,10 @@ |
253 | 258 | unsigned int cpu; |
254 | 259 | |
255 | 260 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { |
261 | +#ifdef CONFIG_SMP | |
262 | + if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) | |
263 | + continue; | |
264 | +#endif | |
256 | 265 | addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); |
257 | 266 | intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\ |
258 | 267 | [_INTC_FN(handle)], irq); |
... | ... | @@ -301,6 +310,23 @@ |
301 | 310 | return 0; /* allow wakeup, but setup hardware in intc_suspend() */ |
302 | 311 | } |
303 | 312 | |
313 | +#ifdef CONFIG_SMP | |
314 | +/* | |
315 | + * This is held with the irq desc lock held, so we don't require any | |
316 | + * additional locking here at the intc desc level. The affinity mask is | |
317 | + * later tested in the enable/disable paths. | |
318 | + */ | |
319 | +static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask) | |
320 | +{ | |
321 | + if (!cpumask_intersects(cpumask, cpu_online_mask)) | |
322 | + return -1; | |
323 | + | |
324 | + cpumask_copy(irq_to_desc(irq)->affinity, cpumask); | |
325 | + | |
326 | + return 0; | |
327 | +} | |
328 | +#endif | |
329 | + | |
304 | 330 | static void intc_mask_ack(unsigned int irq) |
305 | 331 | { |
306 | 332 | struct intc_desc_int *d = get_intc_desc(irq); |
... | ... | @@ -843,6 +869,9 @@ |
843 | 869 | d->chip.shutdown = intc_disable; |
844 | 870 | d->chip.set_type = intc_set_sense; |
845 | 871 | d->chip.set_wake = intc_set_wake; |
872 | +#ifdef CONFIG_SMP | |
873 | + d->chip.set_affinity = intc_set_affinity; | |
874 | +#endif | |
846 | 875 | |
847 | 876 | if (hw->ack_regs) { |
848 | 877 | for (i = 0; i < hw->nr_ack_regs; i++) |