summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpuidle-t2.c
diff options
context:
space:
mode:
authorScott Williams <scwilliams@nvidia.com>2011-08-04 18:35:45 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:47:02 -0800
commit75602437e212d6aa0deac3f5d644ddb2c2939bd0 (patch)
tree426d27207b6295d2c713a10bc347b830f0d7a2ea /arch/arm/mach-tegra/cpuidle-t2.c
parentf312f55cb9bd593591432db3d4a5c1677b419a39 (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/cpuidle-t2.c')
-rw-r--r--arch/arm/mach-tegra/cpuidle-t2.c25
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