diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2014-03-04 15:43:41 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-04-28 15:27:15 -0400 |
commit | 8cc3cfc5ccf1680b7c88f874912b6bec2797b76b (patch) | |
tree | 33658295928340d76ca4ce6c30f488c49c7f8043 /drivers/irqchip | |
parent | 62a08ae2a5763aabeee98264605236b001503e0c (diff) |
irqchip: armanda: Sanitize set_irq_affinity()
The set_irq_affinity() function has two issues:
1) It has no protection against selecting an offline cpu from the
given mask.
2) It pointlessly restricts the affinity masks to have a single cpu
set. This collides with the irq migration code of arm.
irq affinity is set to core 3
core 3 goes offline
migration code sets mask to cpu_online_mask and calls the
irq_set_affinity() callback of the irq_chip which fails due to bit
0,1,2 set.
So instead of doing silly for_each_cpu() loops just pick any bit of
the mask which intersects with the online mask.
Get rid of fiddling with the default_irq_affinity as well.
[ Gregory: Fixed the access to the routing register ]
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@elte.hu>
Link: http://lkml.kernel.org/r/20140304203101.088889302@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-armada-370-xp.c | 37 |
1 files changed, 6 insertions, 31 deletions
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 41be897df8d5..304a20d0ad15 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) | 41 | #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) |
42 | #define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34) | 42 | #define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34) |
43 | #define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4) | 43 | #define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4) |
44 | #define ARMADA_370_XP_INT_SOURCE_CPU_MASK 0xF | ||
44 | 45 | ||
45 | #define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) | 46 | #define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) |
46 | #define ARMADA_375_PPI_CAUSE (0x10) | 47 | #define ARMADA_375_PPI_CAUSE (0x10) |
@@ -244,35 +245,18 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock); | |||
244 | static int armada_xp_set_affinity(struct irq_data *d, | 245 | static int armada_xp_set_affinity(struct irq_data *d, |
245 | const struct cpumask *mask_val, bool force) | 246 | const struct cpumask *mask_val, bool force) |
246 | { | 247 | { |
247 | unsigned long reg; | ||
248 | unsigned long new_mask = 0; | ||
249 | unsigned long online_mask = 0; | ||
250 | unsigned long count = 0; | ||
251 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | 248 | irq_hw_number_t hwirq = irqd_to_hwirq(d); |
249 | unsigned long reg, mask; | ||
252 | int cpu; | 250 | int cpu; |
253 | 251 | ||
254 | for_each_cpu(cpu, mask_val) { | 252 | /* Select a single core from the affinity mask which is online */ |
255 | new_mask |= 1 << cpu_logical_map(cpu); | 253 | cpu = cpumask_any_and(mask_val, cpu_online_mask); |
256 | count++; | 254 | mask = 1UL << cpu_logical_map(cpu); |
257 | } | ||
258 | |||
259 | /* | ||
260 | * Forbid mutlicore interrupt affinity | ||
261 | * This is required since the MPIC HW doesn't limit | ||
262 | * several CPUs from acknowledging the same interrupt. | ||
263 | */ | ||
264 | if (count > 1) | ||
265 | return -EINVAL; | ||
266 | |||
267 | for_each_cpu(cpu, cpu_online_mask) | ||
268 | online_mask |= 1 << cpu_logical_map(cpu); | ||
269 | 255 | ||
270 | raw_spin_lock(&irq_controller_lock); | 256 | raw_spin_lock(&irq_controller_lock); |
271 | |||
272 | reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); | 257 | reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); |
273 | reg = (reg & (~online_mask)) | new_mask; | 258 | reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask; |
274 | writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); | 259 | writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); |
275 | |||
276 | raw_spin_unlock(&irq_controller_lock); | 260 | raw_spin_unlock(&irq_controller_lock); |
277 | 261 | ||
278 | return 0; | 262 | return 0; |
@@ -494,15 +478,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, | |||
494 | 478 | ||
495 | #ifdef CONFIG_SMP | 479 | #ifdef CONFIG_SMP |
496 | armada_xp_mpic_smp_cpu_init(); | 480 | armada_xp_mpic_smp_cpu_init(); |
497 | |||
498 | /* | ||
499 | * Set the default affinity from all CPUs to the boot cpu. | ||
500 | * This is required since the MPIC doesn't limit several CPUs | ||
501 | * from acknowledging the same interrupt. | ||
502 | */ | ||
503 | cpumask_clear(irq_default_affinity); | ||
504 | cpumask_set_cpu(smp_processor_id(), irq_default_affinity); | ||
505 | |||
506 | #endif | 481 | #endif |
507 | 482 | ||
508 | armada_370_xp_msi_init(node, main_int_res.start); | 483 | armada_370_xp_msi_init(node, main_int_res.start); |