summaryrefslogtreecommitdiffstats
path: root/arch/arm/include/asm/insn.h
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2021-11-25 10:26:44 +0100
committerArd Biesheuvel <ardb@kernel.org>2021-12-06 12:49:17 +0100
commit7b9896c352073156a325c3bb0dc4c46e06e2a468 (patch)
treea9e6e3be8a6a2b91a147f3e9ae82dfb7fbd860e5 /arch/arm/include/asm/insn.h
parentARM: assembler: add optimized ldr/str macros to load variables from memory (diff)
downloadlinux-7b9896c352073156a325c3bb0dc4c46e06e2a468.tar.xz
linux-7b9896c352073156a325c3bb0dc4c46e06e2a468.zip
ARM: percpu: add SMP_ON_UP support
Permit the use of the TPIDRPRW system register for carrying the per-CPU offset in generic SMP configurations that also target non-SMP capable ARMv6 cores. This uses the SMP_ON_UP code patching framework to turn all TPIDRPRW accesses into reads/writes of entry #0 in the __per_cpu_offset array. While at it, switch over some existing direct TPIDRPRW accesses in asm code to invocations of a new helper that is patched in the same way when necessary. Note that CPU_V6+SMP without SMP_ON_UP results in a kernel that does not boot on v6 CPUs without SMP extensions, so add this dependency to Kconfig as well. Acked-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Nicolas Pitre <nico@fluxnic.net> Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Tested-by: Marc Zyngier <maz@kernel.org> Tested-by: Vladimir Murzin <vladimir.murzin@arm.com> # ARMv7M
Diffstat (limited to 'arch/arm/include/asm/insn.h')
-rw-r--r--arch/arm/include/asm/insn.h24
1 files changed, 24 insertions, 0 deletions
diff --git a/arch/arm/include/asm/insn.h b/arch/arm/include/asm/insn.h
index 5475cbf9fb6b..a160ed3ea427 100644
--- a/arch/arm/include/asm/insn.h
+++ b/arch/arm/include/asm/insn.h
@@ -2,6 +2,30 @@
#ifndef __ASM_ARM_INSN_H
#define __ASM_ARM_INSN_H
+#include <linux/types.h>
+
+/*
+ * Avoid a literal load by emitting a sequence of ADD/LDR instructions with the
+ * appropriate relocations. The combined sequence has a range of -/+ 256 MiB,
+ * which should be sufficient for the core kernel as well as modules loaded
+ * into the module region. (Not supported by LLD before release 14)
+ */
+#if !(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) && \
+ !(defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 140000)
+#define LOAD_SYM_ARMV6(reg, sym) \
+ " .globl " #sym " \n\t" \
+ " .reloc 10f, R_ARM_ALU_PC_G0_NC, " #sym " \n\t" \
+ " .reloc 11f, R_ARM_ALU_PC_G1_NC, " #sym " \n\t" \
+ " .reloc 12f, R_ARM_LDR_PC_G2, " #sym " \n\t" \
+ "10: sub " #reg ", pc, #8 \n\t" \
+ "11: sub " #reg ", " #reg ", #4 \n\t" \
+ "12: ldr " #reg ", [" #reg ", #0] \n\t"
+#else
+#define LOAD_SYM_ARMV6(reg, sym) \
+ " ldr " #reg ", =" #sym " \n\t" \
+ " ldr " #reg ", [" #reg "] \n\t"
+#endif
+
static inline unsigned long
arm_gen_nop(void)
{