aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2010-07-05 09:53:10 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-07-09 09:41:35 -0400
commitf159f4ed55bb0fa5470800641e03a13a7e0eae6e (patch)
treec2ed54b103c2a1c58fa4b50740fec462ccfeec74 /arch
parentc1b2d9704c77ddaec46d5d681e1360ac40268743 (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>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/hwcap.h1
-rw-r--r--arch/arm/include/asm/tls.h46
-rw-r--r--arch/arm/kernel/entry-armv.S23
-rw-r--r--arch/arm/kernel/setup.c17
-rw-r--r--arch/arm/kernel/traps.c41
-rw-r--r--arch/arm/mm/Kconfig11
-rw-r--r--arch/arm/mm/proc-v6.S5
-rw-r--r--arch/arm/mm/proc-v7.S2
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)
269extern struct proc_info_list *lookup_processor_type(unsigned int); 269extern struct proc_info_list *lookup_processor_type(unsigned int);
270extern struct machine_desc *lookup_machine_type(unsigned int); 270extern struct machine_desc *lookup_machine_type(unsigned int);
271 271
272static 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
272static void __init setup_processor(void) 287static 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
750static 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
746void __init early_trap_init(void) 760void __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
720config 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
731config NEEDS_SYSCALL_FOR_CMPXCHG 720config 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