diff options
author | Alex Frid <afrid@nvidia.com> | 2011-09-28 20:41:30 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:49:36 -0800 |
commit | f6c9111abff52b32e62d13e7e54d1d7cb9458ad2 (patch) | |
tree | f45a65ff38eca3c18574c31e41dd116a40666882 | |
parent | f7b2a737ff608e14a97f5941e50d707ad94d8786 (diff) |
ARM: tegra: power: Fix LP2/LP3 states accounting on Tegra3
- Made sure LP3 state is reported as last entered state to cpuidle
governor in case when LP3 is entered as a fall back from LP2 path.
- Accumulate idle time designated to LP2 state by cpuidle governor
and time actually spent in LP2 by each CPU separately. Update LP2
statistic output.
Change-Id: I55b461e94925ba7a41112756ed958f81fc0bc882
Reviewed-on: http://git-master/r/60381
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Tested-by: Gerrit_Virtual_Submit
Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Rebase-Id: R240873bd1de225696d392ac5ba2c3d517c59d86e
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t3.c | 46 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuidle.c | 13 |
2 files changed, 40 insertions, 19 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c index d9645ecb1a0c..e326a9b99875 100644 --- a/arch/arm/mach-tegra/cpuidle-t3.c +++ b/arch/arm/mach-tegra/cpuidle-t3.c @@ -80,7 +80,7 @@ static struct { unsigned int cpu_ready_count[5]; unsigned int tear_down_count[5]; unsigned long long cpu_wants_lp2_time[5]; - unsigned long long in_lp2_time; + unsigned long long in_lp2_time[5]; unsigned int lp2_count; unsigned int lp2_completed_count; unsigned int lp2_count_bin[32]; @@ -157,6 +157,13 @@ bool tegra3_lp2_is_allowed(struct cpuidle_device *dev, return true; } +static inline void tegra3_lp3_fall_back(struct cpuidle_device *dev) +{ + tegra_cpu_wfi(); + /* fall back here from LP2 path - tell cpuidle governor */ + dev->last_state = &dev->states[0]; +} + static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev, struct cpuidle_state *state, s64 request) { @@ -170,7 +177,7 @@ static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev, if (request < state->target_residency) { /* Not enough time left to enter LP2 */ - tegra_cpu_wfi(); + tegra3_lp3_fall_back(dev); return; } @@ -190,7 +197,7 @@ static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev, if (!tegra3_lp2_is_allowed(dev, state)) { /* Yes, re-enable the distributor and LP3. */ tegra_gic_dist_enable(); - tegra_cpu_wfi(); + tegra3_lp3_fall_back(dev); return; } @@ -266,8 +273,8 @@ static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev, idle_stats.lp2_completed_count++; idle_stats.lp2_completed_count_bin[bin]++; - idle_stats.in_lp2_time += ktime_to_us( - ktime_sub(exit_time, entry_time)); + idle_stats.in_lp2_time[cpu_number(dev->cpu)] += + ktime_to_us(ktime_sub(exit_time, entry_time)); pr_debug("%lld %lld %d %d\n", request, ktime_to_us(ktime_sub(exit_time, entry_time)), @@ -279,7 +286,7 @@ 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; u32 twd_cnt; u32 twd_ctrl = readl(twd_base + TWD_TIMER_CONTROL); unsigned long twd_rate = clk_get_rate(twd_clk); @@ -294,7 +301,7 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, /* * Not enough time left to enter LP2 */ - tegra_cpu_wfi(); + tegra3_lp3_fall_back(dev); return; } @@ -302,6 +309,8 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, trace_power_start(POWER_CSTATE, 2, dev->cpu); + entery_time = ktime_get(); + /* Save time this CPU must be awakened by. */ tegra_cpu_wake_by_time[dev->cpu] = ktime_to_us(ktime_get()) + request; smp_wmb(); @@ -309,6 +318,9 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, tegra3_sleep_cpu_secondary(PLAT_PHYS_OFFSET - PAGE_OFFSET); tegra_cpu_wake_by_time[dev->cpu] = LLONG_MAX; + + idle_stats.in_lp2_time[cpu_number(dev->cpu)] += + ktime_to_us(ktime_sub(ktime_get(), entery_time)); #endif } @@ -369,22 +381,28 @@ int tegra3_lp2_debug_show(struct seq_file *s, void *data) div64_u64(idle_stats.cpu_wants_lp2_time[3], 1000), div64_u64(idle_stats.cpu_wants_lp2_time[4], 1000)); - seq_printf(s, "lp2 time: %8llu ms %7d%% %7d%% %7d%% %7d%% %7d%%\n", - div64_u64(idle_stats.in_lp2_time, 1000), + seq_printf(s, "lp2 time: %8llu %8llu %8llu %8llu %8llu ms\n", + div64_u64(idle_stats.in_lp2_time[0], 1000), + div64_u64(idle_stats.in_lp2_time[1], 1000), + div64_u64(idle_stats.in_lp2_time[2], 1000), + div64_u64(idle_stats.in_lp2_time[3], 1000), + div64_u64(idle_stats.in_lp2_time[4], 1000)); + + seq_printf(s, "lp2 %%: %7d%% %7d%% %7d%% %7d%% %7d%%\n", (int)(idle_stats.cpu_wants_lp2_time[0] ? - div64_u64(idle_stats.in_lp2_time * 100, + div64_u64(idle_stats.in_lp2_time[0] * 100, idle_stats.cpu_wants_lp2_time[0]) : 0), (int)(idle_stats.cpu_wants_lp2_time[1] ? - div64_u64(idle_stats.in_lp2_time * 100, + div64_u64(idle_stats.in_lp2_time[1] * 100, idle_stats.cpu_wants_lp2_time[1]) : 0), (int)(idle_stats.cpu_wants_lp2_time[2] ? - div64_u64(idle_stats.in_lp2_time * 100, + div64_u64(idle_stats.in_lp2_time[2] * 100, idle_stats.cpu_wants_lp2_time[2]) : 0), (int)(idle_stats.cpu_wants_lp2_time[3] ? - div64_u64(idle_stats.in_lp2_time * 100, + div64_u64(idle_stats.in_lp2_time[3] * 100, idle_stats.cpu_wants_lp2_time[3]) : 0), (int)(idle_stats.cpu_wants_lp2_time[4] ? - div64_u64(idle_stats.in_lp2_time * 100, + div64_u64(idle_stats.in_lp2_time[4] * 100, idle_stats.cpu_wants_lp2_time[4]) : 0)); seq_printf(s, "\n"); diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c index a51a72a985c3..bdf45f81f9da 100644 --- a/arch/arm/mach-tegra/cpuidle.c +++ b/arch/arm/mach-tegra/cpuidle.c @@ -122,12 +122,15 @@ static int tegra_idle_enter_lp2(struct cpuidle_device *dev, hrtimer_peek_ahead_timers(); smp_rmb(); - 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; + /* 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_cpu_idle_stats_lp2_time(dev->cpu, us); return (int)us; |