diff options
author | Alex Frid <afrid@nvidia.com> | 2012-01-30 13:42:05 -0800 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2012-02-03 06:17:59 -0800 |
commit | 98e66926adcf7af88c87f467a11fba35c143f663 (patch) | |
tree | 16fa23ae25a97a8b557d31048b38a53ad068f292 | |
parent | 3563d218e037805c363771df34adc3b8c666e8c1 (diff) |
ARM: tegra: power: Separate lp2 latency for G/LP CPU modes
Do not use common lp2 exit latency for Tegra3 CPU G and CPU LP modes.
Separately measure and adjust latency in each mode; restart calculation
after mode switch from the last measured latency in the target mode.
Reviewed-on: http://git-master/r/78344
Change-Id: I54803c6abf4107a578aa1fed8feaa4a419a9c07f
Signed-off-by: Alex Frid <afrid@nvidia.com>
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Reviewed-on: http://git-master/r/78902
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t3.c | 24 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuidle.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuidle.h | 10 |
3 files changed, 42 insertions, 7 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c index fb51e25e75e9..a4e158f06095 100644 --- a/arch/arm/mach-tegra/cpuidle-t3.c +++ b/arch/arm/mach-tegra/cpuidle-t3.c @@ -76,6 +76,8 @@ module_param(lp2_n_in_idle, bool, 0644); static struct clk *cpu_clk_for_dvfs; static struct clk *twd_clk; +static int lp2_exit_latencies[5]; + static struct { unsigned int cpu_ready_count[5]; unsigned int tear_down_count[5]; @@ -149,6 +151,11 @@ bool tegra3_lp2_is_allowed(struct cpuidle_device *dev, } request = ktime_to_us(tick_nohz_get_sleep_length()); + if (state->exit_latency != lp2_exit_latencies[cpu_number(dev->cpu)]) { + /* possible on the 1st entry after cluster switch*/ + state->exit_latency = lp2_exit_latencies[cpu_number(dev->cpu)]; + tegra_lp2_update_target_residency(state); + } if (request < state->target_residency) { /* Not enough time left to enter LP2 */ return false; @@ -224,7 +231,8 @@ static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev, #endif if (request > state->target_residency) { - s64 sleep_time = request - tegra_lp2_exit_latency; + s64 sleep_time = request - + lp2_exit_latencies[cpu_number(dev->cpu)]; bin = time_to_bin((u32)request / 1000); idle_stats.tear_down_count[cpu_number(dev->cpu)]++; @@ -274,9 +282,12 @@ static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev, */ int offset = ktime_to_us(ktime_sub(exit_time, entry_time)) - request; - int latency = tegra_lp2_exit_latency + offset / 16; + 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(); idle_stats.lp2_completed_count++; @@ -326,6 +337,9 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, tegra_cpu_wake_by_time[dev->cpu] = LLONG_MAX; + /* 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)); #endif @@ -350,8 +364,14 @@ void tegra3_idle_lp2(struct cpuidle_device *dev, int tegra3_cpudile_init_soc(void) { + int i; + cpu_clk_for_dvfs = tegra_get_clock_by_name("cpu_g"); twd_clk = tegra_get_clock_by_name("twd"); + + for (i = 0; i < ARRAY_SIZE(lp2_exit_latencies); i++) + lp2_exit_latencies[i] = tegra_lp2_exit_latency; + return 0; } diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c index f8a274b5f313..47d5996e5961 100644 --- a/arch/arm/mach-tegra/cpuidle.c +++ b/arch/arm/mach-tegra/cpuidle.c @@ -97,6 +97,14 @@ void tegra_lp2_in_idle(bool enable) } } +void tegra_lp2_update_target_residency(struct cpuidle_state *state) +{ + state->target_residency = state->exit_latency + + tegra_lp2_power_off_time; + if (state->target_residency < tegra_lp2_min_residency) + state->target_residency = tegra_lp2_min_residency; +} + static int tegra_idle_enter_lp2(struct cpuidle_device *dev, struct cpuidle_state *state) { @@ -127,11 +135,8 @@ static int tegra_idle_enter_lp2(struct cpuidle_device *dev, /* Update LP2 latency provided no fall back to LP3 */ if (state == dev->last_state) { - state->exit_latency = tegra_lp2_exit_latency; - state->target_residency = tegra_lp2_exit_latency + - tegra_lp2_power_off_time; - if (state->target_residency < tegra_lp2_min_residency) - state->target_residency = tegra_lp2_min_residency; + tegra_lp2_set_global_latency(state); + tegra_lp2_update_target_residency(state); } tegra_cpu_idle_stats_lp2_time(dev->cpu, us); diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h index 12a29ff2e236..ce6eab940fd8 100644 --- a/arch/arm/mach-tegra/cpuidle.h +++ b/arch/arm/mach-tegra/cpuidle.h @@ -98,6 +98,16 @@ static inline bool tegra_lp2_is_allowed(struct cpuidle_device *dev, #endif } +static inline void tegra_lp2_set_global_latency(struct cpuidle_state *state) +{ +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + state->exit_latency = tegra_lp2_exit_latency; +#endif + /* Tegra3 does not use global exit latency */ +} + +void tegra_lp2_update_target_residency(struct cpuidle_state *state); + #ifdef CONFIG_DEBUG_FS static inline int tegra_lp2_debug_show(struct seq_file *s, void *data) { |