aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/include/asm/compiler.h
diff options
context:
space:
mode:
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 */