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>

+30 -1
+30 -1
drivers/sh/intc.c
··· 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 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) | \ ··· 235 234 unsigned int cpu; 236 235 237 236 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { 237 + #ifdef CONFIG_SMP 238 + if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) 239 + continue; 240 + #endif 238 241 addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); 239 242 intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ 240 243 [_INTC_FN(handle)], irq); ··· 258 253 unsigned int cpu; 259 254 260 255 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { 256 + #ifdef CONFIG_SMP 257 + if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) 258 + continue; 259 + #endif 261 260 addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); 262 261 intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\ 263 262 [_INTC_FN(handle)], irq); ··· 309 300 { 310 301 return 0; /* allow wakeup, but setup hardware in intc_suspend() */ 311 302 } 303 + 304 + #ifdef CONFIG_SMP 305 + /* 306 + * This is held with the irq desc lock held, so we don't require any 307 + * additional locking here at the intc desc level. The affinity mask is 308 + * later tested in the enable/disable paths. 309 + */ 310 + static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask) 311 + { 312 + if (!cpumask_intersects(cpumask, cpu_online_mask)) 313 + return -1; 314 + 315 + cpumask_copy(irq_to_desc(irq)->affinity, cpumask); 316 + 317 + return 0; 318 + } 319 + #endif 312 320 313 321 static void intc_mask_ack(unsigned int irq) 314 322 { ··· 869 843 d->chip.shutdown = intc_disable; 870 844 d->chip.set_type = intc_set_sense; 871 845 d->chip.set_wake = intc_set_wake; 846 + #ifdef CONFIG_SMP 847 + d->chip.set_affinity = intc_set_affinity; 848 + #endif 872 849 873 850 if (hw->ack_regs) { 874 851 for (i = 0; i < hw->nr_ack_regs; i++)