diff options
author | Scott Williams <scwilliams@nvidia.com> | 2011-08-04 18:35:45 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:47:02 -0800 |
commit | 75602437e212d6aa0deac3f5d644ddb2c2939bd0 (patch) | |
tree | 426d27207b6295d2c713a10bc347b830f0d7a2ea /arch/arm/mach-tegra | |
parent | f312f55cb9bd593591432db3d4a5c1677b419a39 (diff) |
ARM: tegra: power: Fix Tegra2 secondary CPU LP2 time calculation
CPU 0 must wake up before CPU 1 therefore CPU 0 must be awake by
the minimum of its or CPU 1's absolute wakeup time. However, the
the CPU idle request time is a duration not an absolute time.
Change the LP2 sleep time calculation to use an absolute "must
be away by" time.
Change-Id: Ia73dcbe071f81d0bd9fc6c5d860837e606575a8c
Signed-off-by: Scott Williams <scwilliams@nvidia.com>
Rebase-Id: R138e6d4ae652932607f7dd411be3aa89ee53e34c
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t2.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t2.c b/arch/arm/mach-tegra/cpuidle-t2.c index 9c2bbcf360ad..034c8bbce1a8 100644 --- a/arch/arm/mach-tegra/cpuidle-t2.c +++ b/arch/arm/mach-tegra/cpuidle-t2.c @@ -73,7 +73,7 @@ static inline unsigned int time_to_bin(unsigned int time) static void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE); static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); -static s64 tegra_cpu1_idle_time = LLONG_MAX; +static s64 tegra_cpu1_wake_by_time = LLONG_MAX; static int tegra2_reset_sleeping_cpu(int cpu) { @@ -161,6 +161,7 @@ static int tegra2_idle_lp2_cpu_0(struct cpuidle_device *dev, { ktime_t entry_time; ktime_t exit_time; + s64 wake_time; bool sleep_completed = false; int bin; int i; @@ -177,8 +178,21 @@ static int tegra2_idle_lp2_cpu_0(struct cpuidle_device *dev, return -EBUSY; } + /* LP2 entry time */ + entry_time = ktime_get(); + + /* LP2 initial targeted wake time */ + wake_time = ktime_to_us(entry_time) + request; + + /* CPU0 must wake up before CPU1. */ + smp_rmb(); + wake_time = min_t(s64, wake_time, tegra_cpu1_wake_by_time); + + /* LP2 actual targeted wake time */ + request = wake_time - ktime_to_us(entry_time); + BUG_ON(wake_time < 0LL); + idle_stats.tear_down_count++; - request = min_t(s64, request, tegra_cpu1_idle_time); entry_time = ktime_get(); if (request > state->target_residency) { @@ -225,7 +239,7 @@ static int tegra2_idle_lp2_cpu_0(struct cpuidle_device *dev, return 0; } -static noinline int tegra2_idle_lp2_cpu_1(struct cpuidle_device *dev, +static void tegra2_idle_lp2_cpu_1(struct cpuidle_device *dev, struct cpuidle_state *state, s64 request) { #ifdef CONFIG_SMP @@ -241,14 +255,15 @@ static noinline int tegra2_idle_lp2_cpu_1(struct cpuidle_device *dev, tegra_gic_cpu_disable(); - tegra_cpu1_idle_time = request - tegra_lp2_exit_latency; + /* Save time this CPU must be awakened by. */ + tegra_cpu1_wake_by_time = ktime_to_us(ktime_get()) + request; smp_wmb(); tegra_twd_suspend(&twd_context); tegra2_sleep_wfi(PLAT_PHYS_OFFSET - PAGE_OFFSET); - tegra_cpu1_idle_time = LLONG_MAX; + tegra_cpu1_wake_by_time = LLONG_MAX; tegra_twd_resume(&twd_context); #endif |