diff options
author | Tony Lindgren <tony@atomide.com> | 2010-07-05 09:53:10 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-07-09 09:41:35 -0400 |
commit | f159f4ed55bb0fa5470800641e03a13a7e0eae6e (patch) | |
tree | c2ed54b103c2a1c58fa4b50740fec462ccfeec74 | |
parent | c1b2d9704c77ddaec46d5d681e1360ac40268743 (diff) |
ARM: 6207/1: Replace CONFIG_HAS_TLS_REG with HWCAP_TLS and check for it on V6
The TLS register is only available on ARM1136 r1p0 and later.
Set HWCAP_TLS flags if hardware TLS is available and test for
it if CONFIG_CPU_32v6K is not set for V6.
Note that we set the TLS instruction in __kuser_get_tls
dynamically as suggested by Jamie Lokier <jamie@shareable.org>.
Also the __switch_to code is optimized out in most cases as
suggested by Nicolas Pitre <nico@fluxnic.net>.
Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/include/asm/hwcap.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/tls.h | 46 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 23 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 17 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 41 | ||||
-rw-r--r-- | arch/arm/mm/Kconfig | 11 | ||||
-rw-r--r-- | arch/arm/mm/proc-v6.S | 5 | ||||
-rw-r--r-- | arch/arm/mm/proc-v7.S | 2 |
8 files changed, 105 insertions, 41 deletions
diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h index f7bd52b1c365..c1062c317103 100644 --- a/arch/arm/include/asm/hwcap.h +++ b/arch/arm/include/asm/hwcap.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #define HWCAP_NEON 4096 | 19 | #define HWCAP_NEON 4096 |
20 | #define HWCAP_VFPv3 8192 | 20 | #define HWCAP_VFPv3 8192 |
21 | #define HWCAP_VFPv3D16 16384 | 21 | #define HWCAP_VFPv3D16 16384 |
22 | #define HWCAP_TLS 32768 | ||
22 | 23 | ||
23 | #if defined(__KERNEL__) && !defined(__ASSEMBLY__) | 24 | #if defined(__KERNEL__) && !defined(__ASSEMBLY__) |
24 | /* | 25 | /* |
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h new file mode 100644 index 000000000000..e71d6ff8d104 --- /dev/null +++ b/arch/arm/include/asm/tls.h | |||
@@ -0,0 +1,46 @@ | |||
1 | #ifndef __ASMARM_TLS_H | ||
2 | #define __ASMARM_TLS_H | ||
3 | |||
4 | #ifdef __ASSEMBLY__ | ||
5 | .macro set_tls_none, tp, tmp1, tmp2 | ||
6 | .endm | ||
7 | |||
8 | .macro set_tls_v6k, tp, tmp1, tmp2 | ||
9 | mcr p15, 0, \tp, c13, c0, 3 @ set TLS register | ||
10 | .endm | ||
11 | |||
12 | .macro set_tls_v6, tp, tmp1, tmp2 | ||
13 | ldr \tmp1, =elf_hwcap | ||
14 | ldr \tmp1, [\tmp1, #0] | ||
15 | mov \tmp2, #0xffff0fff | ||
16 | tst \tmp1, #HWCAP_TLS @ hardware TLS available? | ||
17 | mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register | ||
18 | streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 | ||
19 | .endm | ||
20 | |||
21 | .macro set_tls_software, tp, tmp1, tmp2 | ||
22 | mov \tmp1, #0xffff0fff | ||
23 | str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0 | ||
24 | .endm | ||
25 | #endif | ||
26 | |||
27 | #ifdef CONFIG_TLS_REG_EMUL | ||
28 | #define tls_emu 1 | ||
29 | #define has_tls_reg 1 | ||
30 | #define set_tls set_tls_none | ||
31 | #elif __LINUX_ARM_ARCH__ >= 7 || \ | ||
32 | (__LINUX_ARM_ARCH__ == 6 && defined(CONFIG_CPU_32v6K)) | ||
33 | #define tls_emu 0 | ||
34 | #define has_tls_reg 1 | ||
35 | #define set_tls set_tls_v6k | ||
36 | #elif __LINUX_ARM_ARCH__ == 6 | ||
37 | #define tls_emu 0 | ||
38 | #define has_tls_reg (elf_hwcap & HWCAP_TLS) | ||
39 | #define set_tls set_tls_v6 | ||
40 | #else | ||
41 | #define tls_emu 0 | ||
42 | #define has_tls_reg 0 | ||
43 | #define set_tls set_tls_software | ||
44 | #endif | ||
45 | |||
46 | #endif /* __ASMARM_TLS_H */ | ||
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7ee48e7f8f31..a6cfb1791af3 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/thread_notify.h> | 22 | #include <asm/thread_notify.h> |
23 | #include <asm/unwind.h> | 23 | #include <asm/unwind.h> |
24 | #include <asm/unistd.h> | 24 | #include <asm/unistd.h> |
25 | #include <asm/tls.h> | ||
25 | 26 | ||
26 | #include "entry-header.S" | 27 | #include "entry-header.S" |
27 | 28 | ||
@@ -739,12 +740,7 @@ ENTRY(__switch_to) | |||
739 | #ifdef CONFIG_MMU | 740 | #ifdef CONFIG_MMU |
740 | ldr r6, [r2, #TI_CPU_DOMAIN] | 741 | ldr r6, [r2, #TI_CPU_DOMAIN] |
741 | #endif | 742 | #endif |
742 | #if defined(CONFIG_HAS_TLS_REG) | 743 | set_tls r3, r4, r5 |
743 | mcr p15, 0, r3, c13, c0, 3 @ set TLS register | ||
744 | #elif !defined(CONFIG_TLS_REG_EMUL) | ||
745 | mov r4, #0xffff0fff | ||
746 | str r3, [r4, #-15] @ TLS val at 0xffff0ff0 | ||
747 | #endif | ||
748 | #ifdef CONFIG_MMU | 744 | #ifdef CONFIG_MMU |
749 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register | 745 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register |
750 | #endif | 746 | #endif |
@@ -1009,17 +1005,12 @@ kuser_cmpxchg_fixup: | |||
1009 | */ | 1005 | */ |
1010 | 1006 | ||
1011 | __kuser_get_tls: @ 0xffff0fe0 | 1007 | __kuser_get_tls: @ 0xffff0fe0 |
1012 | 1008 | ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init | |
1013 | #if !defined(CONFIG_HAS_TLS_REG) && !defined(CONFIG_TLS_REG_EMUL) | ||
1014 | ldr r0, [pc, #(16 - 8)] @ TLS stored at 0xffff0ff0 | ||
1015 | #else | ||
1016 | mrc p15, 0, r0, c13, c0, 3 @ read TLS register | ||
1017 | #endif | ||
1018 | usr_ret lr | 1009 | usr_ret lr |
1019 | 1010 | mrc p15, 0, r0, c13, c0, 3 @ 0xffff0fe8 hardware TLS code | |
1020 | .rep 5 | 1011 | .rep 4 |
1021 | .word 0 @ pad up to __kuser_helper_version | 1012 | .word 0 @ 0xffff0ff0 software TLS value, then |
1022 | .endr | 1013 | .endr @ pad up to __kuser_helper_version |
1023 | 1014 | ||
1024 | /* | 1015 | /* |
1025 | * Reference declaration: | 1016 | * Reference declaration: |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 7ae65dc594a4..648c3c1e16c4 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -269,6 +269,21 @@ static void __init cacheid_init(void) | |||
269 | extern struct proc_info_list *lookup_processor_type(unsigned int); | 269 | extern struct proc_info_list *lookup_processor_type(unsigned int); |
270 | extern struct machine_desc *lookup_machine_type(unsigned int); | 270 | extern struct machine_desc *lookup_machine_type(unsigned int); |
271 | 271 | ||
272 | static void __init feat_v6_fixup(void) | ||
273 | { | ||
274 | int id = read_cpuid_id(); | ||
275 | |||
276 | if ((id & 0xff0f0000) != 0x41070000) | ||
277 | return; | ||
278 | |||
279 | /* | ||
280 | * HWCAP_TLS is available only on 1136 r1p0 and later, | ||
281 | * see also kuser_get_tls_init. | ||
282 | */ | ||
283 | if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0)) | ||
284 | elf_hwcap &= ~HWCAP_TLS; | ||
285 | } | ||
286 | |||
272 | static void __init setup_processor(void) | 287 | static void __init setup_processor(void) |
273 | { | 288 | { |
274 | struct proc_info_list *list; | 289 | struct proc_info_list *list; |
@@ -311,6 +326,8 @@ static void __init setup_processor(void) | |||
311 | elf_hwcap &= ~HWCAP_THUMB; | 326 | elf_hwcap &= ~HWCAP_THUMB; |
312 | #endif | 327 | #endif |
313 | 328 | ||
329 | feat_v6_fixup(); | ||
330 | |||
314 | cacheid_init(); | 331 | cacheid_init(); |
315 | cpu_proc_init(); | 332 | cpu_proc_init(); |
316 | } | 333 | } |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 1621e5327b2a..cda78d59aa31 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/unistd.h> | 30 | #include <asm/unistd.h> |
31 | #include <asm/traps.h> | 31 | #include <asm/traps.h> |
32 | #include <asm/unwind.h> | 32 | #include <asm/unwind.h> |
33 | #include <asm/tls.h> | ||
33 | 34 | ||
34 | #include "ptrace.h" | 35 | #include "ptrace.h" |
35 | #include "signal.h" | 36 | #include "signal.h" |
@@ -518,17 +519,20 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
518 | 519 | ||
519 | case NR(set_tls): | 520 | case NR(set_tls): |
520 | thread->tp_value = regs->ARM_r0; | 521 | thread->tp_value = regs->ARM_r0; |
521 | #if defined(CONFIG_HAS_TLS_REG) | 522 | if (tls_emu) |
522 | asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) ); | 523 | return 0; |
523 | #elif !defined(CONFIG_TLS_REG_EMUL) | 524 | if (has_tls_reg) { |
524 | /* | 525 | asm ("mcr p15, 0, %0, c13, c0, 3" |
525 | * User space must never try to access this directly. | 526 | : : "r" (regs->ARM_r0)); |
526 | * Expect your app to break eventually if you do so. | 527 | } else { |
527 | * The user helper at 0xffff0fe0 must be used instead. | 528 | /* |
528 | * (see entry-armv.S for details) | 529 | * User space must never try to access this directly. |
529 | */ | 530 | * Expect your app to break eventually if you do so. |
530 | *((unsigned int *)0xffff0ff0) = regs->ARM_r0; | 531 | * The user helper at 0xffff0fe0 must be used instead. |
531 | #endif | 532 | * (see entry-armv.S for details) |
533 | */ | ||
534 | *((unsigned int *)0xffff0ff0) = regs->ARM_r0; | ||
535 | } | ||
532 | return 0; | 536 | return 0; |
533 | 537 | ||
534 | #ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG | 538 | #ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG |
@@ -743,6 +747,16 @@ void __init trap_init(void) | |||
743 | return; | 747 | return; |
744 | } | 748 | } |
745 | 749 | ||
750 | static void __init kuser_get_tls_init(unsigned long vectors) | ||
751 | { | ||
752 | /* | ||
753 | * vectors + 0xfe0 = __kuser_get_tls | ||
754 | * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8 | ||
755 | */ | ||
756 | if (tls_emu || has_tls_reg) | ||
757 | memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4); | ||
758 | } | ||
759 | |||
746 | void __init early_trap_init(void) | 760 | void __init early_trap_init(void) |
747 | { | 761 | { |
748 | unsigned long vectors = CONFIG_VECTORS_BASE; | 762 | unsigned long vectors = CONFIG_VECTORS_BASE; |
@@ -761,6 +775,11 @@ void __init early_trap_init(void) | |||
761 | memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); | 775 | memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); |
762 | 776 | ||
763 | /* | 777 | /* |
778 | * Do processor specific fixups for the kuser helpers | ||
779 | */ | ||
780 | kuser_get_tls_init(vectors); | ||
781 | |||
782 | /* | ||
764 | * Copy signal return handlers into the vector page, and | 783 | * Copy signal return handlers into the vector page, and |
765 | * set sigreturn to be a pointer to these. | 784 | * set sigreturn to be a pointer to these. |
766 | */ | 785 | */ |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 346ae14824a5..71d5d5efceef 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -717,17 +717,6 @@ config TLS_REG_EMUL | |||
717 | a few prototypes like that in existence) and therefore access to | 717 | a few prototypes like that in existence) and therefore access to |
718 | that required register must be emulated. | 718 | that required register must be emulated. |
719 | 719 | ||
720 | config HAS_TLS_REG | ||
721 | bool | ||
722 | depends on !TLS_REG_EMUL | ||
723 | default y if SMP || CPU_32v7 | ||
724 | help | ||
725 | This selects support for the CP15 thread register. | ||
726 | It is defined to be available on some ARMv6 processors (including | ||
727 | all SMP capable ARMv6's) or later processors. User space may | ||
728 | assume directly accessing that register and always obtain the | ||
729 | expected value only on ARMv7 and above. | ||
730 | |||
731 | config NEEDS_SYSCALL_FOR_CMPXCHG | 720 | config NEEDS_SYSCALL_FOR_CMPXCHG |
732 | bool | 721 | bool |
733 | help | 722 | help |
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 7a5337ed7d68..2f5a3c23a0fe 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S | |||
@@ -239,7 +239,8 @@ __v6_proc_info: | |||
239 | b __v6_setup | 239 | b __v6_setup |
240 | .long cpu_arch_name | 240 | .long cpu_arch_name |
241 | .long cpu_elf_name | 241 | .long cpu_elf_name |
242 | .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA | 242 | /* See also feat_v6_fixup() for HWCAP_TLS */ |
243 | .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA|HWCAP_TLS | ||
243 | .long cpu_v6_name | 244 | .long cpu_v6_name |
244 | .long v6_processor_functions | 245 | .long v6_processor_functions |
245 | .long v6wbi_tlb_fns | 246 | .long v6wbi_tlb_fns |
@@ -262,7 +263,7 @@ __pj4_v6_proc_info: | |||
262 | b __v6_setup | 263 | b __v6_setup |
263 | .long cpu_arch_name | 264 | .long cpu_arch_name |
264 | .long cpu_elf_name | 265 | .long cpu_elf_name |
265 | .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP | 266 | .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS |
266 | .long cpu_pj4_name | 267 | .long cpu_pj4_name |
267 | .long v6_processor_functions | 268 | .long v6_processor_functions |
268 | .long v6wbi_tlb_fns | 269 | .long v6wbi_tlb_fns |
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 7aaf88a3b7aa..8071bcd4c995 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S | |||
@@ -344,7 +344,7 @@ __v7_proc_info: | |||
344 | b __v7_setup | 344 | b __v7_setup |
345 | .long cpu_arch_name | 345 | .long cpu_arch_name |
346 | .long cpu_elf_name | 346 | .long cpu_elf_name |
347 | .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP | 347 | .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS |
348 | .long cpu_v7_name | 348 | .long cpu_v7_name |
349 | .long v7_processor_functions | 349 | .long v7_processor_functions |
350 | .long v7wbi_tlb_fns | 350 | .long v7wbi_tlb_fns |