diff options
author | Anton Blanchard <anton@samba.org> | 2012-01-09 09:29:15 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-01-10 19:54:20 -0500 |
commit | a5ccfee05a439b803640e94584056204501db31c (patch) | |
tree | 2545bab092fe62924d5ccba8920c137b1e771ba6 | |
parent | 7b3480f8b701170c046e1ed362946f5f0d005e13 (diff) |
powerpc: Fix RCU idle and hcall tracing
Tracepoints should not be called inside an rcu_idle_enter/rcu_idle_exit
region. Since pSeries calls H_CEDE in the idle loop, we were violating
this rule.
commit a7b152d5342c (powerpc: Tell RCU about idle after hcall tracing)
tried to work around it by delaying the rcu_idle_enter until after we
called the hcall tracepoint, but there are a number of issues with it.
The hcall tracepoint trampoline code is called conditionally when the
tracepoint is enabled. If the tracepoint is not enabled we never call
rcu_idle_enter. The idle_uses_rcu check was also done at compile time
which breaks multiplatform builds.
The simple fix is to avoid tracing H_CEDE and rely on other tracepoints
and the hypervisor dispatch trace log to work out if we called H_CEDE.
This fixes a hang during boot on pSeries.
Signed-off-by: Anton Blanchard <anton@samba.org>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/kernel/idle.c | 12 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 14 |
2 files changed, 12 insertions, 14 deletions
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 7c66ce13da89..0a48bf5db6c8 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c | |||
@@ -50,12 +50,6 @@ static int __init powersave_off(char *arg) | |||
50 | } | 50 | } |
51 | __setup("powersave=off", powersave_off); | 51 | __setup("powersave=off", powersave_off); |
52 | 52 | ||
53 | #if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_TRACEPOINTS) | ||
54 | static const bool idle_uses_rcu = 1; | ||
55 | #else | ||
56 | static const bool idle_uses_rcu; | ||
57 | #endif | ||
58 | |||
59 | /* | 53 | /* |
60 | * The body of the idle task. | 54 | * The body of the idle task. |
61 | */ | 55 | */ |
@@ -67,8 +61,7 @@ void cpu_idle(void) | |||
67 | set_thread_flag(TIF_POLLING_NRFLAG); | 61 | set_thread_flag(TIF_POLLING_NRFLAG); |
68 | while (1) { | 62 | while (1) { |
69 | tick_nohz_idle_enter(); | 63 | tick_nohz_idle_enter(); |
70 | if (!idle_uses_rcu) | 64 | rcu_idle_enter(); |
71 | rcu_idle_enter(); | ||
72 | 65 | ||
73 | while (!need_resched() && !cpu_should_die()) { | 66 | while (!need_resched() && !cpu_should_die()) { |
74 | ppc64_runlatch_off(); | 67 | ppc64_runlatch_off(); |
@@ -106,8 +99,7 @@ void cpu_idle(void) | |||
106 | 99 | ||
107 | HMT_medium(); | 100 | HMT_medium(); |
108 | ppc64_runlatch_on(); | 101 | ppc64_runlatch_on(); |
109 | if (!idle_uses_rcu) | 102 | rcu_idle_exit(); |
110 | rcu_idle_exit(); | ||
111 | tick_nohz_idle_exit(); | 103 | tick_nohz_idle_exit(); |
112 | preempt_enable_no_resched(); | 104 | preempt_enable_no_resched(); |
113 | if (cpu_should_die()) | 105 | if (cpu_should_die()) |
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 948e0e3b3547..7bc73af6c7b9 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -546,6 +546,13 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) | |||
546 | unsigned long flags; | 546 | unsigned long flags; |
547 | unsigned int *depth; | 547 | unsigned int *depth; |
548 | 548 | ||
549 | /* | ||
550 | * We cannot call tracepoints inside RCU idle regions which | ||
551 | * means we must not trace H_CEDE. | ||
552 | */ | ||
553 | if (opcode == H_CEDE) | ||
554 | return; | ||
555 | |||
549 | local_irq_save(flags); | 556 | local_irq_save(flags); |
550 | 557 | ||
551 | depth = &__get_cpu_var(hcall_trace_depth); | 558 | depth = &__get_cpu_var(hcall_trace_depth); |
@@ -556,8 +563,6 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) | |||
556 | (*depth)++; | 563 | (*depth)++; |
557 | preempt_disable(); | 564 | preempt_disable(); |
558 | trace_hcall_entry(opcode, args); | 565 | trace_hcall_entry(opcode, args); |
559 | if (opcode == H_CEDE) | ||
560 | rcu_idle_enter(); | ||
561 | (*depth)--; | 566 | (*depth)--; |
562 | 567 | ||
563 | out: | 568 | out: |
@@ -570,6 +575,9 @@ void __trace_hcall_exit(long opcode, unsigned long retval, | |||
570 | unsigned long flags; | 575 | unsigned long flags; |
571 | unsigned int *depth; | 576 | unsigned int *depth; |
572 | 577 | ||
578 | if (opcode == H_CEDE) | ||
579 | return; | ||
580 | |||
573 | local_irq_save(flags); | 581 | local_irq_save(flags); |
574 | 582 | ||
575 | depth = &__get_cpu_var(hcall_trace_depth); | 583 | depth = &__get_cpu_var(hcall_trace_depth); |
@@ -578,8 +586,6 @@ void __trace_hcall_exit(long opcode, unsigned long retval, | |||
578 | goto out; | 586 | goto out; |
579 | 587 | ||
580 | (*depth)++; | 588 | (*depth)++; |
581 | if (opcode == H_CEDE) | ||
582 | rcu_idle_exit(); | ||
583 | trace_hcall_exit(opcode, retval, retbuf); | 589 | trace_hcall_exit(opcode, retval, retbuf); |
584 | preempt_enable(); | 590 | preempt_enable(); |
585 | (*depth)--; | 591 | (*depth)--; |