Commit a8941dad1f12b4e8a87a517ed27f29d0209c817c

Authored by Paul Mundt
1 parent 25cf84cf37

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

... ... @@ -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++)