aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/include/asm/compiler.h
diff options
context:
space:
mode:
authorMark Charlebois <charlebm@gmail.com>2014-03-11 10:43:45 -0700
committerBehan Webster <behanw@converseincode.com>2014-03-31 00:07:21 -0700
commitcfb5300b065aec89d943e4bf80314024fce935c8 (patch)
treef2f4a25d361fdba0e1857484da049b481417a60d /arch/arm/include/asm/compiler.h
parentf5841fc320d50027b692ddb57a2e21affe145ead (diff)
LLVMLinux: Remove use of named register for ARM percpu
The use of sp as a named register variable is not supported in clang and the behavior they are working around in GCC may not even be present in clang. See commit 509eb76ebf97 Unfortunately, GCC doesn't treat a "memory" clobber on a non-volatile asm block as a side-effect, and will happily re-order it before other memory clobbers (including those in prempt_disable()) and cache the value. This has been observed to break the cmpxchg logic in the slub allocator, leading to livelock in kmem_cache_alloc in mainline kernels. Because the GCC workaround causes numerous warnings, revert the change until it can be verified that it is in fact an issue for clang. Signed-off-by: Mark Charlebois <charlebm@gmail.com> Signed-off-by: Behan Webster <behanw@converseincode.com>
Diffstat (limited to 'arch/arm/include/asm/compiler.h')
-rw-r--r--arch/arm/include/asm/compiler.h32
1 files changed, 32 insertions, 0 deletions
diff --git a/arch/arm/include/asm/compiler.h b/arch/arm/include/asm/compiler.h
index 8155db2f7fa..009eafa2ea0 100644
--- a/arch/arm/include/asm/compiler.h
+++ b/arch/arm/include/asm/compiler.h
@@ -11,5 +11,37 @@
*/
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
+#if defined(CONFIG_SMP) && !defined(CONFIG_CPU_V6)
+/*
+ * Read TPIDRPRW.
+ * GCC requires a workaround as it does not treat a "memory" clobber on a
+ * non-volatile asm block as a side-effect.
+ * We want to allow caching the value, so for GCC avoid using volatile and
+ * instead use a fake stack read to hazard against barrier().
+ */
+#if defined(__clang__)
+static inline unsigned long read_TPIDRPRW(void)
+{
+ unsigned long off;
+
+ /*
+ * Read TPIDRPRW.
+ */
+ asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (off) : : "memory");
+
+ return off;
+}
+#else
+static inline unsigned long read_TPIDRPRW(void)
+{
+ unsigned long off;
+ register unsigned long *sp asm ("sp");
+
+ asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (off) : "Q" (*sp));
+
+ return off;
+}
+#endif
+#endif
#endif /* __ASM_ARM_COMPILER_H */