summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-09-28 20:41:30 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:36 -0800
commitf6c9111abff52b32e62d13e7e54d1d7cb9458ad2 (patch)
treef45a65ff38eca3c18574c31e41dd116a40666882
parentf7b2a737ff608e14a97f5941e50d707ad94d8786 (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.c46
-rw-r--r--arch/arm/mach-tegra/cpuidle.c13
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;