diff options
author | Scott Williams <scwilliams@nvidia.com> | 2011-08-11 13:57:49 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:47:04 -0800 |
commit | 8c2d2cd9c82333bdf813c28675353e3c93a0b7d2 (patch) | |
tree | 36fb8bca383d46c0214f7cb8afd410728963945b /arch/arm/mach-tegra/sleep-t2.S | |
parent | 48e1e48251c6be3f9610ffe33dec9a684f2cf9f0 (diff) |
ARM: tegra2: power: Fix reset race condition between the CPUs
During LP2 for CPU idle on Tegra2, there could be a race condition
between the CPUs. CPU1 cannot autonomously shut itself down (put
itself into reset). CPU1 must be reset by CPU0 but only when it
has no outstanding memory or I/O transactions going on (i.e., it
is in the WFI state). CPU1 indicates its readiness to be reset
by setting status in a PMC scratch register. If CPU1 wakes up
and CPU0 sees CPU1's ready to be reset status before CPU1 can
clear it CPU1 could be reset at inappropriate times resulting
in loss of cache coherency and ultimately a kernel panic.
Eliminate the race condition by ensuring that:
- CPU1's reset ready status is cleared as early as possible
before CPU1 rejoins the coherent world.
- Use writel when updating the IRAM LP2 status flags to ensure
the IRAM and coherent memory views of the flags are consistent.
- If there is not enough time remaining for CPU1 to be in LP2 for
the minimum residency time, clear CPU1's reset status flag
before entering WFI so that CPU0 will not wait for CPU1 to be
ready to reset (since it won't be if there is insufficient time).
Change-Id: I20dc5c6406b1521f20852294d48ce6d67f0926b9
Signed-off-by: Scott Williams <scwilliams@nvidia.com>
Rebase-Id: Rd485f696126d7ca019d15651b839d4f2fc595848
Diffstat (limited to 'arch/arm/mach-tegra/sleep-t2.S')
-rw-r--r-- | arch/arm/mach-tegra/sleep-t2.S | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/arch/arm/mach-tegra/sleep-t2.S b/arch/arm/mach-tegra/sleep-t2.S index 3144368c23f0..e4bf9223e635 100644 --- a/arch/arm/mach-tegra/sleep-t2.S +++ b/arch/arm/mach-tegra/sleep-t2.S @@ -107,8 +107,7 @@ ENTRY(tegra2_cpu_reset) cmp r0, #0 moveq pc, lr @ must not be called for CPU 0 - mov32 r3, TEGRA_PMC_VIRT - add r1, r3, #PMC_SCRATCH41 + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 mov r12, #CPU_RESETTABLE str r12, [r1] @@ -134,14 +133,26 @@ ENDPROC(tegra2_cpu_reset) #ifdef CONFIG_PM_SLEEP /* + * tegra2_cpu_clear_resettable(void) + * + * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when + * it is expected that the secondary CPU will be idle soon. + */ +ENTRY(tegra2_cpu_clear_resettable) + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r12, #CPU_NOT_RESETTABLE + str r12, [r1] + mov pc, lr +ENDPROC(tegra2_cpu_clear_resettable) + +/* * tegra2_cpu_set_resettable_soon(void) * * Called to set the "resettable soon" flag in PMC_SCRATCH41 when * it is expected that the secondary CPU will be idle soon. */ ENTRY(tegra2_cpu_set_resettable_soon) - mov32 r3, TEGRA_PMC_VIRT - add r1, r3, #PMC_SCRATCH41 + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 mov r12, #CPU_RESETTABLE_SOON str r12, [r1] mov pc, lr @@ -154,8 +165,7 @@ ENDPROC(tegra2_cpu_set_resettable_soon) * set because it is expected that the secondary CPU will be idle soon. */ ENTRY(tegra2_cpu_is_resettable_soon) - mov32 r3, TEGRA_PMC_VIRT - add r1, r3, #PMC_SCRATCH41 + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 ldr r12, [r1] cmp r12, #CPU_RESETTABLE_SOON moveq r0, #1 @@ -189,13 +199,16 @@ ENTRY(tegra2_sleep_wfi) b tegra_cpu_save mov r11, r2 - mov32 r3, TEGRA_PMC_VIRT - add r0, r3, #PMC_SCRATCH41 + mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41 mov r3, #CPU_RESETTABLE str r3, [r0] bl tegra_cpu_wfi + mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r3, #CPU_NOT_RESETTABLE + str r3, [r0] + /* * cpu may be reset while in wfi, which will return through * tegra_resume to tegra_cpu_resume_phys to tegra_cpu_resume |