summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpuidle-t3.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-01-30 21:00:31 -0800
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-02-03 06:18:47 -0800
commit1e91b2b0ed0e04dfaad01c71be23cc794dd87b8e (patch)
tree5b6ba4a6500bb07af3b8ee6a9dc4730f4d4b409d /arch/arm/mach-tegra/cpuidle-t3.c
parent98e66926adcf7af88c87f467a11fba35c143f663 (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.c33
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
}