ARM: smp: elide HWCAP_TLS checks or __entry_task updates on SMP+v6
Use the SMP_ON_UP patching framework to elide HWCAP_TLS tests from the context switch and return to userspace code paths, as SMP systems are guaranteed to have this h/w capability. At the same time, omit the update of __entry_task if the system is detected to be UP at runtime, as in that case, the value is never used. Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
parent
d6905849f8
commit
75fa4adc4f
|
@ -3,6 +3,7 @@
|
||||||
#define __ASM_ARM_SWITCH_TO_H
|
#define __ASM_ARM_SWITCH_TO_H
|
||||||
|
|
||||||
#include <linux/thread_info.h>
|
#include <linux/thread_info.h>
|
||||||
|
#include <asm/smp_plat.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For v7 SMP cores running a preemptible kernel we may be pre-empted
|
* For v7 SMP cores running a preemptible kernel we may be pre-empted
|
||||||
|
@ -40,8 +41,7 @@ static inline void set_ti_cpu(struct task_struct *p)
|
||||||
do { \
|
do { \
|
||||||
__complete_pending_tlbi(); \
|
__complete_pending_tlbi(); \
|
||||||
set_ti_cpu(next); \
|
set_ti_cpu(next); \
|
||||||
if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || \
|
if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || is_smp()) \
|
||||||
IS_ENABLED(CONFIG_SMP)) \
|
|
||||||
__this_cpu_write(__entry_task, next); \
|
__this_cpu_write(__entry_task, next); \
|
||||||
last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \
|
last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
|
@ -18,22 +18,32 @@
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
|
.macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
ALT_SMP(nop)
|
||||||
|
ALT_UP_B(.L0_\@)
|
||||||
|
.subsection 1
|
||||||
|
#endif
|
||||||
|
.L0_\@:
|
||||||
ldr_va \tmp1, elf_hwcap
|
ldr_va \tmp1, elf_hwcap
|
||||||
mov \tmp2, #0xffff0fff
|
mov \tmp2, #0xffff0fff
|
||||||
tst \tmp1, #HWCAP_TLS @ hardware TLS available?
|
tst \tmp1, #HWCAP_TLS @ hardware TLS available?
|
||||||
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
|
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
|
||||||
mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
|
beq .L2_\@
|
||||||
#ifndef CONFIG_SMP
|
mcr p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
|
||||||
mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
|
#ifdef CONFIG_SMP
|
||||||
|
b .L1_\@
|
||||||
|
.previous
|
||||||
#endif
|
#endif
|
||||||
mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
|
.L1_\@: switch_tls_v6k \base, \tp, \tpuser, \tmp1, \tmp2
|
||||||
strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
|
.L2_\@:
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
|
.macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
|
||||||
mov \tmp1, #0xffff0fff
|
mov \tmp1, #0xffff0fff
|
||||||
str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
|
str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
|
||||||
.endm
|
.endm
|
||||||
|
#else
|
||||||
|
#include <asm/smp_plat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TLS_REG_EMUL
|
#ifdef CONFIG_TLS_REG_EMUL
|
||||||
|
@ -44,7 +54,7 @@
|
||||||
#elif defined(CONFIG_CPU_V6)
|
#elif defined(CONFIG_CPU_V6)
|
||||||
#define tls_emu 0
|
#define tls_emu 0
|
||||||
#define has_tls_reg (elf_hwcap & HWCAP_TLS)
|
#define has_tls_reg (elf_hwcap & HWCAP_TLS)
|
||||||
#define defer_tls_reg_update IS_ENABLED(CONFIG_SMP)
|
#define defer_tls_reg_update is_smp()
|
||||||
#define switch_tls switch_tls_v6
|
#define switch_tls switch_tls_v6
|
||||||
#elif defined(CONFIG_CPU_32v6K)
|
#elif defined(CONFIG_CPU_32v6K)
|
||||||
#define tls_emu 0
|
#define tls_emu 0
|
||||||
|
|
|
@ -292,21 +292,18 @@
|
||||||
|
|
||||||
|
|
||||||
.macro restore_user_regs, fast = 0, offset = 0
|
.macro restore_user_regs, fast = 0, offset = 0
|
||||||
#if defined(CONFIG_CPU_32v6K) || defined(CONFIG_SMP)
|
#if defined(CONFIG_CPU_32v6K) && \
|
||||||
#if defined(CONFIG_CPU_V6) && defined(CONFIG_SMP)
|
(!defined(CONFIG_CPU_V6) || defined(CONFIG_SMP))
|
||||||
ALT_SMP(b .L1_\@ )
|
#ifdef CONFIG_CPU_V6
|
||||||
ALT_UP( nop )
|
ALT_SMP(nop)
|
||||||
ldr_va r1, elf_hwcap
|
ALT_UP_B(.L1_\@)
|
||||||
tst r1, #HWCAP_TLS @ hardware TLS available?
|
|
||||||
beq .L2_\@
|
|
||||||
.L1_\@:
|
|
||||||
#endif
|
#endif
|
||||||
@ The TLS register update is deferred until return to user space so we
|
@ The TLS register update is deferred until return to user space so we
|
||||||
@ can use it for other things while running in the kernel
|
@ can use it for other things while running in the kernel
|
||||||
get_thread_info r1
|
mrc p15, 0, r1, c13, c0, 3 @ get current_thread_info pointer
|
||||||
ldr r1, [r1, #TI_TP_VALUE]
|
ldr r1, [r1, #TI_TP_VALUE]
|
||||||
mcr p15, 0, r1, c13, c0, 3 @ set TLS register
|
mcr p15, 0, r1, c13, c0, 3 @ set TLS register
|
||||||
.L2_\@:
|
.L1_\@:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uaccess_enable r1, isb=0
|
uaccess_enable r1, isb=0
|
||||||
|
|
Loading…
Reference in New Issue