summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2010-03-09 18:20:31 +0000
committerGary King <gking@nvidia.com>2010-03-10 18:24:16 -0800
commit7877d720173e79b1a7b7549be74b5ef4fabd5525 (patch)
treeed26f0fc9ca2785b23f5cf14b02f02bd6482e747
parent22ecfcb44f6e31c3357aec1b6ac2e614387dc9e0 (diff)
KGDB: add smp_mb() in synchronisation during exception handler exit
KGDB uses atomic variables and busy-wait loops to co-ordinate between multiple CPUs on an SMP system. When an exception is handled, the primary CPU executes kgdb_handle_exception() whilst the others execute kgdb_wait. There comes a point when the waiters are waiting for the primary CPU to finish: /* Wait till primary CPU is done with debugging */ (1) while (atomic_read(&passive_cpu_wait[cpu])) cpu_relax(); /* Do important KGDB stuff */ /* Signal the primary CPU that we are done: */ atomic_set(&cpu_in_kgdb[cpu], 0); In parallel to this, the primary CPU is doing: for (i = NR_CPUS-1; i >= 0; i--) atomic_set(&passive_cpu_wait[i], 0); /* * Wait till all the CPUs have quit * from the debugger. */ for_each_online_cpu(i) { (1) while (atomic_read(&cpu_in_kgdb[i])) cpu_relax(); } There is a potential deadlock situation at point (1) because the previous writes to the passive_cpu_wait variables by the primary CPU may not yet be visible to the other CPUs [for instance, they may be sitting in the local store buffer]. This means that the waiter CPUs will never exit the while loop and therefore never write to the cpu_in_kgdb variables, which the primary CPU is blocked on. Furthermore, because the primary CPU is aggressively performing reads, the store buffer may not necessarily drain so the system will deadlock. This deadlock has been experienced on a quad-core ARM11MPCore platform. The following patch addresses the issue by adding a memory barrier to the primary CPU before the polling loop, therefore forcing the previous atomic_sets to be visible before waiting for the waiters to finish. Cc: KGDB Mailing List <kgdb-bugreport@lists.sourceforge.net> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Will Deacon <will.deacon@arm.com> Change-Id: I93a294896342ca0fd2df86c68d9f8790eec0576c Reviewed-on: http://git-master/r/829 Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Gary King <gking@nvidia.com>
-rw-r--r--kernel/kgdb.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index e4dcfb2272a4..ce73a3e88945 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -1517,6 +1517,7 @@ acquirelock:
* Wait till all the CPUs have quit
* from the debugger.
*/
+ smp_mb();
for_each_online_cpu(i) {
while (atomic_read(&cpu_in_kgdb[i]))
cpu_relax();