diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-01-19 10:20:58 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 11:47:36 -0400 |
commit | d1877392b4dce5d4c74d329777980d2a3ccede99 (patch) | |
tree | 115e10ba46f06e4f0780f25c1518bfdcd5c1d86f | |
parent | a6218ee909f993a8bd5138a5eb1bde620c12a2a9 (diff) |
ARM: fix rcu stalls on SMP platforms
commit 7deabca0acfe02b8e18f59a4c95676012f49a304 upstream.
We can stall RCU processing on SMP platforms if a CPU sits in its idle
loop for a long time. This happens because we don't call irq_enter()
and irq_exit() around generic_smp_call_function_interrupt() and
friends. Add the necessary calls, and remove the one from within
ipi_timer(), so that they're all in a common place.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
[add irq_enter()/irq_exit() in do_local_timer]
Signed-off-by: UCHINO Satoshi <satoshi.uchino@toshiba.co.jp>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | arch/arm/kernel/smp.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index fea97f64221..4469924d683 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -445,9 +445,7 @@ static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); | |||
445 | static void ipi_timer(void) | 445 | static void ipi_timer(void) |
446 | { | 446 | { |
447 | struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); | 447 | struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); |
448 | irq_enter(); | ||
449 | evt->event_handler(evt); | 448 | evt->event_handler(evt); |
450 | irq_exit(); | ||
451 | } | 449 | } |
452 | 450 | ||
453 | #ifdef CONFIG_LOCAL_TIMERS | 451 | #ifdef CONFIG_LOCAL_TIMERS |
@@ -458,7 +456,9 @@ asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs) | |||
458 | 456 | ||
459 | if (local_timer_ack()) { | 457 | if (local_timer_ack()) { |
460 | __inc_irq_stat(cpu, local_timer_irqs); | 458 | __inc_irq_stat(cpu, local_timer_irqs); |
459 | irq_enter(); | ||
461 | ipi_timer(); | 460 | ipi_timer(); |
461 | irq_exit(); | ||
462 | } | 462 | } |
463 | 463 | ||
464 | set_irq_regs(old_regs); | 464 | set_irq_regs(old_regs); |
@@ -568,7 +568,9 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) | |||
568 | 568 | ||
569 | switch (ipinr) { | 569 | switch (ipinr) { |
570 | case IPI_TIMER: | 570 | case IPI_TIMER: |
571 | irq_enter(); | ||
571 | ipi_timer(); | 572 | ipi_timer(); |
573 | irq_exit(); | ||
572 | break; | 574 | break; |
573 | 575 | ||
574 | case IPI_RESCHEDULE: | 576 | case IPI_RESCHEDULE: |
@@ -576,15 +578,21 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) | |||
576 | break; | 578 | break; |
577 | 579 | ||
578 | case IPI_CALL_FUNC: | 580 | case IPI_CALL_FUNC: |
581 | irq_enter(); | ||
579 | generic_smp_call_function_interrupt(); | 582 | generic_smp_call_function_interrupt(); |
583 | irq_exit(); | ||
580 | break; | 584 | break; |
581 | 585 | ||
582 | case IPI_CALL_FUNC_SINGLE: | 586 | case IPI_CALL_FUNC_SINGLE: |
587 | irq_enter(); | ||
583 | generic_smp_call_function_single_interrupt(); | 588 | generic_smp_call_function_single_interrupt(); |
589 | irq_exit(); | ||
584 | break; | 590 | break; |
585 | 591 | ||
586 | case IPI_CPU_STOP: | 592 | case IPI_CPU_STOP: |
593 | irq_enter(); | ||
587 | ipi_cpu_stop(cpu); | 594 | ipi_cpu_stop(cpu); |
595 | irq_exit(); | ||
588 | break; | 596 | break; |
589 | 597 | ||
590 | default: | 598 | default: |