From a8941dad1f12b4e8a87a517ed27f29d0209c817c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 8 Mar 2010 13:33:17 +0900 Subject: [PATCH] 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 --- drivers/sh/intc.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 3a5a17db9474..b8983fed76f5 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -2,7 +2,7 @@ * Shared interrupt handling code for IPR and INTC2 types of IRQs. * * Copyright (C) 2007, 2008 Magnus Damm - * Copyright (C) 2009 Paul Mundt + * Copyright (C) 2009, 2010 Paul Mundt * * Based on intc2.c and ipr.c * @@ -26,6 +26,7 @@ #include #include #include +#include #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ ((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; 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); intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ [_INTC_FN(handle)], irq); @@ -253,6 +258,10 @@ static void intc_disable(unsigned int irq) unsigned int 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); intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\ [_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() */ } +#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) { struct intc_desc_int *d = get_intc_desc(irq); @@ -843,6 +869,9 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.shutdown = intc_disable; d->chip.set_type = intc_set_sense; d->chip.set_wake = intc_set_wake; +#ifdef CONFIG_SMP + d->chip.set_affinity = intc_set_affinity; +#endif if (hw->ack_regs) { for (i = 0; i < hw->nr_ack_regs; i++)