Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+25 -18
+2 -2
arch/arm/include/asm/switch_to.h
··· 3 3 #define __ASM_ARM_SWITCH_TO_H 4 4 5 5 #include <linux/thread_info.h> 6 + #include <asm/smp_plat.h> 6 7 7 8 /* 8 9 * For v7 SMP cores running a preemptible kernel we may be pre-empted ··· 41 40 do { \ 42 41 __complete_pending_tlbi(); \ 43 42 set_ti_cpu(next); \ 44 - if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || \ 45 - IS_ENABLED(CONFIG_SMP)) \ 43 + if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || is_smp()) \ 46 44 __this_cpu_write(__entry_task, next); \ 47 45 last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \ 48 46 } while (0)
+16 -6
arch/arm/include/asm/tls.h
··· 18 18 .endm 19 19 20 20 .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2 21 + #ifdef CONFIG_SMP 22 + ALT_SMP(nop) 23 + ALT_UP_B(.L0_\@) 24 + .subsection 1 25 + #endif 26 + .L0_\@: 21 27 ldr_va \tmp1, elf_hwcap 22 28 mov \tmp2, #0xffff0fff 23 29 tst \tmp1, #HWCAP_TLS @ hardware TLS available? 24 30 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 25 - mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register 26 - #ifndef CONFIG_SMP 27 - mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register 31 + beq .L2_\@ 32 + mcr p15, 0, \tp, c13, c0, 3 @ yes, set TLS register 33 + #ifdef CONFIG_SMP 34 + b .L1_\@ 35 + .previous 28 36 #endif 29 - mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register 30 - strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it 37 + .L1_\@: switch_tls_v6k \base, \tp, \tpuser, \tmp1, \tmp2 38 + .L2_\@: 31 39 .endm 32 40 33 41 .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2 34 42 mov \tmp1, #0xffff0fff 35 43 str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0 36 44 .endm 45 + #else 46 + #include <asm/smp_plat.h> 37 47 #endif 38 48 39 49 #ifdef CONFIG_TLS_REG_EMUL ··· 54 44 #elif defined(CONFIG_CPU_V6) 55 45 #define tls_emu 0 56 46 #define has_tls_reg (elf_hwcap & HWCAP_TLS) 57 - #define defer_tls_reg_update IS_ENABLED(CONFIG_SMP) 47 + #define defer_tls_reg_update is_smp() 58 48 #define switch_tls switch_tls_v6 59 49 #elif defined(CONFIG_CPU_32v6K) 60 50 #define tls_emu 0
+7 -10
arch/arm/kernel/entry-header.S
··· 292 292 293 293 294 294 .macro restore_user_regs, fast = 0, offset = 0 295 - #if defined(CONFIG_CPU_32v6K) || defined(CONFIG_SMP) 296 - #if defined(CONFIG_CPU_V6) && defined(CONFIG_SMP) 297 - ALT_SMP(b .L1_\@ ) 298 - ALT_UP( nop ) 299 - ldr_va r1, elf_hwcap 300 - tst r1, #HWCAP_TLS @ hardware TLS available? 301 - beq .L2_\@ 302 - .L1_\@: 295 + #if defined(CONFIG_CPU_32v6K) && \ 296 + (!defined(CONFIG_CPU_V6) || defined(CONFIG_SMP)) 297 + #ifdef CONFIG_CPU_V6 298 + ALT_SMP(nop) 299 + ALT_UP_B(.L1_\@) 303 300 #endif 304 301 @ The TLS register update is deferred until return to user space so we 305 302 @ can use it for other things while running in the kernel 306 - get_thread_info r1 303 + mrc p15, 0, r1, c13, c0, 3 @ get current_thread_info pointer 307 304 ldr r1, [r1, #TI_TP_VALUE] 308 305 mcr p15, 0, r1, c13, c0, 3 @ set TLS register 309 - .L2_\@: 306 + .L1_\@: 310 307 #endif 311 308 312 309 uaccess_enable r1, isb=0