summary refs log tree commit diff
path: root/arch/powerpc/xmon
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2013-12-23 23:46:04 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-02-11 11:24:50 +1100
commit730efb6193f8568354fd80849612291afa9fa81e (patch)
treeb66d851be73038d03b3322442f720d04138ff97b /arch/powerpc/xmon
parentb4d6c06c8de81517320a9964b0c26e096aeadd7b (diff)
downloadlinux-730efb6193f8568354fd80849612291afa9fa81e.tar.gz
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')
-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)
 
 	if (xmon_speaker == me)
 		return;
+
 	for (;;) {
-		if (xmon_speaker == 0) {
-			last_speaker = cmpxchg(&xmon_speaker, 0, me);
-			if (last_speaker == 0)
-				return;
-		}
+		last_speaker = cmpxchg(&xmon_speaker, 0, me);
+		if (last_speaker == 0)
+			return;
+
 		timeout = 10000000;
 		while (xmon_speaker == last_speaker) {
 			if (--timeout > 0)