diff options
author | Alex Frid <afrid@nvidia.com> | 2012-01-30 21:00:31 -0800 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2012-02-03 06:18:47 -0800 |
commit | 1e91b2b0ed0e04dfaad01c71be23cc794dd87b8e (patch) | |
tree | 5b6ba4a6500bb07af3b8ee6a9dc4730f4d4b409d /arch/arm/mach-tegra/cpuidle-t3.c | |
parent | 98e66926adcf7af88c87f467a11fba35c143f663 (diff) |
ARM: tegra: power: Separate lp2 latency for secondary CPUs
Do not use common lp2 exit latency for Tegra3 secondary CPUs in
G mode. Separately measure and adjust latency on each slave CPU;
use per-cpu latency to determine target residency threshold for
entering lp2 on each CPU.
Reviewed-on: http://git-master/r/78375
Change-Id: I4470d1b4814d8f12129e21105dd952a903084f1e
Signed-off-by: Alex Frid <afrid@nvidia.com>
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Reviewed-on: http://git-master/r/78903
Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'arch/arm/mach-tegra/cpuidle-t3.c')
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t3.c | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c index a4e158f06095..3ac93fdd3906 100644 --- a/arch/arm/mach-tegra/cpuidle-t3.c +++ b/arch/arm/mach-tegra/cpuidle-t3.c @@ -285,7 +285,6 @@ static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev, int latency = lp2_exit_latencies[cpu_number(dev->cpu)] + offset / 16; latency = clamp(latency, 0, 10000); - tegra_lp2_exit_latency = latency; lp2_exit_latencies[cpu_number(dev->cpu)] = latency; state->exit_latency = latency; /* for idle governor */ smp_wmb(); @@ -303,9 +302,11 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, struct cpuidle_state *state, s64 request) { #ifdef CONFIG_SMP - ktime_t entery_time; + s64 sleep_time; + ktime_t entry_time; struct tegra_twd_context twd_context; unsigned long twd_rate = clk_get_rate(twd_clk); + bool sleep_completed = false; if (!tegra_twd_get_state(&twd_context)) { if ((twd_context.twd_ctrl & TWD_TIMER_CONTROL_ENABLE) && @@ -315,7 +316,7 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, } } - if (request < tegra_lp2_exit_latency) { + if (request < state->target_residency) { /* * Not enough time left to enter LP2 */ @@ -327,21 +328,33 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, trace_power_start(POWER_CSTATE, 2, dev->cpu); - entery_time = ktime_get(); + entry_time = ktime_get(); /* Save time this CPU must be awakened by. */ - tegra_cpu_wake_by_time[dev->cpu] = ktime_to_us(ktime_get()) + request; + tegra_cpu_wake_by_time[dev->cpu] = ktime_to_us(entry_time) + request; smp_wmb(); tegra3_sleep_cpu_secondary(PLAT_PHYS_OFFSET - PAGE_OFFSET); tegra_cpu_wake_by_time[dev->cpu] = LLONG_MAX; + if (!tegra_twd_get_state(&twd_context)) + sleep_completed = (twd_context.twd_cnt == 0); - /* FIXME: find real cpu_n latency */ - lp2_exit_latencies[cpu_number(dev->cpu)] = tegra_lp2_exit_latency; - state->exit_latency = tegra_lp2_exit_latency; /* for idle governor */ - idle_stats.in_lp2_time[cpu_number(dev->cpu)] += - ktime_to_us(ktime_sub(ktime_get(), entery_time)); + sleep_time = ktime_to_us(ktime_sub(ktime_get(), entry_time)); + idle_stats.in_lp2_time[cpu_number(dev->cpu)] += sleep_time; + if (sleep_completed) { + /* + * Stayed in LP2 for the full time until timer expires, + * adjust the exit latency based on measurement + */ + int offset = sleep_time - request; + int latency = (15 * lp2_exit_latencies[cpu_number(dev->cpu)] + + offset) / 16; + latency = clamp(latency, 0, 10000); + lp2_exit_latencies[cpu_number(dev->cpu)] = latency; + state->exit_latency = latency; /* for idle governor */ + smp_wmb(); + } #endif } |