summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/sleep.S21
-rw-r--r--arch/arm/mach-tegra/sleep.h41
2 files changed, 39 insertions, 23 deletions
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index d243c05e1081..64ba9c2eadfd 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -402,27 +402,6 @@ tegra_cpu_resume:
* r1 = physical address to jump to with mmu off
*/
ENTRY(tegra_turn_off_mmu)
- /*
- * change page table pointer to tegra_pgd_phys, so that IRAM
- * and MMU shut-off will be mapped virtual == physical
- */
- mrc p15, 0, r2, c2, c0, 0 @ TTB 0
- mov32 r3, ~PAGE_MASK
- and r2, r2, r3
- ldr r3, tegra_pgd_phys_address
- ldr r3, [r3]
- orr r3, r3, r2
- mov r2, #0
- mcr p15, 0, r2, c13, c0, 1 @ reserved context
- isb
- mcr p15, 0, r3, c2, c0, 0 @ TTB 0
- isb
-
- mov r2, #0
- mcr p15, 0, r2, c8, c3, 0 @ invalidate TLB
- mcr p15, 0, r2, c7, c5, 6 @ flush BTAC
- mcr p15, 0, r2, c7, c5, 0 @ flush instruction cache
-
mov32 r3, tegra_shut_off_mmu
add r3, r3, r0
mov r0, r1
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index a77fd08e7df5..fcc6503d7e64 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -125,17 +125,54 @@
.macro push_ctx_regs, tmp1
push_stack_token \tmp1 @ debug check word
stmfd sp!, {r4 - r11, lr}
+ /* Save the current TTB0 and CONTEXTID registers. */
+ mrc p15, 0, r5, c2, c0, 0 @ TTB 0
+ mrc p15, 0, r6, c13, c0, 1 @ CONTEXTID
#if USE_TEGRA_DIAG_REG_SAVE
mrc p15, 0, r4, c15, c0, 1 @ read diagnostic register
- stmfd sp!, {r4}
+ stmfd sp!, {r4-r6}
+#else
+ stmfd sp!, {r5-r6}
#endif
+ /* Switch to the tegra_pgd so that IRAM and the MMU shut-off code
+ will be flat mapped (VA==PA). We also do this because the common
+ ARM CPU state save/restore code doesn't support an external L2
+ cache controller. If the current PGD is left active, the common
+ ARM MMU restore may (and eventually will) damage the currently
+ running page tables by adding a temporary flat section mapping
+ that could be picked up by other CPUs from the L2 cache
+ resulting in a kernel panic. */
+ ldr r6, tegra_pgd_phys_address
+ ldr r6, [r6]
+ mov r7, #0
+ dsb
+ mcr p15, 0, r7, c13, c0, 1 @ CONTEXTID = reserved context
+ isb
+ mcr p15, 0, r6, c2, c0, 0 @ TTB 0
+ isb
+ mcr p15, 0, r7, c8, c3, 0 @ invalidate TLB
+ mcr p15, 0, r7, c7, c5, 6 @ flush BTAC
+ mcr p15, 0, r7, c7, c5, 0 @ flush instruction cache
+ dsb
.endm
.macro pop_ctx_regs, tmp1, tmp2
#if USE_TEGRA_DIAG_REG_SAVE
- ldmfd sp!, {r4}
+ ldmfd sp!, {r4-r6}
mcr p15, 0, r4, c15, c0, 1 @ write diagnostic register
+#else
+ ldmfd sp!, {r5-r6}
#endif
+ dsb
+ mcr p15, 0, r5, c2, c0, 0 @ TTB 0
+ isb
+ mcr p15, 0, r6, c13, c0, 1 @ CONTEXTID = reserved context
+ isb
+ mov r7, #0
+ mcr p15, 0, r7, c8, c3, 0 @ invalidate TLB
+ mcr p15, 0, r7, c7, c5, 6 @ flush BTAC
+ mcr p15, 0, r7, c7, c5, 0 @ flush instruction cache
+ dsb
ldmfd sp!, {r4 - r11, lr}
pop_stack_token \tmp1, \tmp2 @ debug stack debug token
.endm