aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/xmon/xmon.c
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2013-12-23 07:46:04 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-02-10 19:24:50 -0500
commit730efb6193f8568354fd80849612291afa9fa81e (patch)
treeb66d851be73038d03b3322442f720d04138ff97b /arch/powerpc/xmon/xmon.c
parentb4d6c06c8de81517320a9964b0c26e096aeadd7b (diff)
powerpc/xmon: Don't loop forever in get_output_lock()
If we enter with xmon_speaker != 0 we skip the first cmpxchg(), we also skip the while loop because xmon_speaker != last_speaker (0) - meaning we skip the second cmpxchg() also. Following that code path the compiler sees no memory barriers and so is within its rights to never reload xmon_speaker. The end result is we loop forever. This manifests as all cpus being in xmon ('c' command), but they refuse to take control when you switch to them ('c x' for cpu # x). I have seen this deadlock in practice and also checked the generated code to confirm this is what's happening. The simplest fix is just to always try the cmpxchg(). Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/xmon/xmon.c')
-rw-r--r--arch/powerpc/xmon/xmon.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index a90731b3d44a..598cdc7c7adc 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -309,12 +309,12 @@ static void get_output_lock(void)
309 309
310 if (xmon_speaker == me) 310 if (xmon_speaker == me)
311 return; 311 return;
312
312 for (;;) { 313 for (;;) {
313 if (xmon_speaker == 0) { 314 last_speaker = cmpxchg(&xmon_speaker, 0, me);
314 last_speaker = cmpxchg(&xmon_speaker, 0, me); 315 if (last_speaker == 0)
315 if (last_speaker == 0) 316 return;
316 return; 317
317 }
318 timeout = 10000000; 318 timeout = 10000000;
319 while (xmon_speaker == last_speaker) { 319 while (xmon_speaker == last_speaker) {
320 if (--timeout > 0) 320 if (--timeout > 0)