ARM: tegra: power: Fix LP2/LP3 states accounting on Tegra3
Alex Frid [Thu, 29 Sep 2011 03:41:30 +0000 (20:41 -0700)]
- 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

arch/arm/mach-tegra/cpuidle-t3.c
arch/arm/mach-tegra/cpuidle.c

index 99bf2f9..636cc67 100644 (file)
@@ -82,7 +82,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];
@@ -159,6 +159,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)
 {
@@ -172,7 +179,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;
        }
 
@@ -192,7 +199,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;
                }
 
@@ -268,8 +275,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)),
@@ -281,7 +288,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);
@@ -296,7 +303,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;
        }
 
@@ -304,6 +311,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();
@@ -311,6 +320,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
 }
 
@@ -371,22 +383,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");
 
index fa0c944..c591f19 100644 (file)
@@ -154,12 +154,15 @@ static int tegra_idle_enter_lp2(struct cpuidle_device *dev,
        local_irq_enable();
 
        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);
 
        dev->last_residency = us;