summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-03-04 21:27:18 -0800
committerGary King <gking@nvidia.com>2010-03-05 21:21:51 -0800
commit227af643e6253e9a5c2a2f74468f855686c44117 (patch)
treeac1ad28ac905bc1e0fe8c7bd552230b198cfb8bb
parentda64ef9eab8bf0fc07cd8abbbdf494b67c9971f1 (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/Kconfig13
-rw-r--r--arch/arm/kernel/entry-armv.S12
-rw-r--r--arch/arm/kernel/traps.c6
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.