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 /arch/powerpc/platforms/pseries/lpar.c | |
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>
Diffstat (limited to 'arch/powerpc/platforms/pseries/lpar.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 14 |
1 files changed, 10 insertions, 4 deletions
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)--; |