diff options
author | Gary King <gking@nvidia.com> | 2010-03-04 21:27:18 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-03-05 21:21:51 -0800 |
commit | 227af643e6253e9a5c2a2f74468f855686c44117 (patch) | |
tree | ac1ad28ac905bc1e0fe8c7bd552230b198cfb8bb | |
parent | da64ef9eab8bf0fc07cd8abbbdf494b67c9971f1 (diff) |
[arm] implement TLS register workaround for Tegra errata 657451
tegra 2 systems have a hardware errata which causes bit 20 of the
TLS register (CP15 c13, operations 2-4) to be unreliable.
in common user space threading libraries (glibc pthreads, bionic
pthreads), the value stored in this register is guaranteed to be
at least word-aligned, leaving bit 0 free.
the work-around for this hardware errata is storing bit 20 of the
user space-provided TLS value into bit 0 of the register inside
__set_tls, and restoring it in the get_tls helper.
Change-Id: I06439378edc01dc897708e3298cd91b5721c6e50
Reviewed-on: http://git-master/r/779
Reviewed-by: Trivikram Kasivajhula <tkasivajhula@nvidia.com>
Reviewed-by: Arthur Spence <aspence@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
Tested-by: Gary King <gking@nvidia.com>
-rw-r--r-- | arch/arm/Kconfig | 13 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 12 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 6 |
3 files changed, 31 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 434e3dd75c91..d63633f566b3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -737,6 +737,19 @@ if !MMU source "arch/arm/Kconfig-nommu" endif +config TEGRA_ERRATA_657451 + bool "Store bit 20 of CP15 TLS register c13,3 in bit 0" + depends on ARCH_TEGRA_2x_SOC && HAS_TLS_REG + default y + help + This option enables a workaround for the 657451 Tegra 2 errata + which causes unreliable reads from bit 20 of the thread storage + register c13, 3 (used by the __set_tls system call). It stores the + value intended for bit 20 into bit 0 instead; in most user-space + environments, the value saved by __set_tls is an aligned address, + so repurposing bit 0 will not cause ill effects. + + config ARM_ERRATA_364296 bool "Enable partial low interrupt latency mode for ARM1136" depends on CPU_V6 && !SMP diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index fc08364c408c..18f872df092c 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -766,6 +766,10 @@ ENTRY(__switch_to) ldr r6, [r2, #TI_CPU_DOMAIN] #endif #if defined(CONFIG_HAS_TLS_REG) +#if defined(CONFIG_TEGRA_ERRATA_657451) + and r4, r3, #(1<<20) + orr r3, r3, r4, lsr #20 +#endif mcr p15, 0, r3, c13, c0, 3 @ set TLS register #elif !defined(CONFIG_TLS_REG_EMUL) mov r4, #0xffff0fff @@ -1046,10 +1050,18 @@ __kuser_get_tls: @ 0xffff0fe0 ldr r0, [pc, #(16 - 8)] @ TLS stored at 0xffff0ff0 #else mrc p15, 0, r0, c13, c0, 3 @ read TLS register +#if defined(CONFIG_TEGRA_ERRATA_657451) + bfi r0, r0, #20, #1 + bic r0, r0, #1 +#endif #endif usr_ret lr +#if defined(CONFIG_TEGRA_ERRATA_657451) + .rep 3 +#else .rep 5 +#endif .word 0 @ pad up to __kuser_helper_version .endr diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 6977342aa139..2d056006c31f 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -495,7 +495,13 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) case NR(set_tls): thread->tp_value = regs->ARM_r0; #if defined(CONFIG_HAS_TLS_REG) +#if defined(CONFIG_TEGRA_ERRATA_657451) + BUG_ON(regs->ARM_r0 & 0x1); + asm ("mcr p15, 0, %0, c13, c0, 3" : : + "r" ((regs->ARM_r0) | ((regs->ARM_r0>>20) & 0x1))); +#else asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) ); +#endif #elif !defined(CONFIG_TLS_REG_EMUL) /* * User space must never try to access this directly. |