ARM: tegra: Catch early LP2 exits
Scott Williams [Fri, 22 Jul 2011 00:44:21 +0000 (17:44 -0700)]
Change-Id: I107d301ec8e8cd3b69ea293faab15b8d766e38f4
Signed-off-by: Scott Williams <scwilliams@nvidia.com>
DW: Split into logical changes
Signed-off-by: Dan Willemsen <dwillemsen@nvidia.com>

Rebase-Id: R9f8f016c1850e2c65f30f2f67241a94acf8a7755

arch/arm/mach-tegra/cpuidle-t2.c
arch/arm/mach-tegra/cpuidle.h
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/pm.h

index c1f872c..2ef98a2 100644 (file)
@@ -151,6 +151,7 @@ bool tegra2_lp2_is_allowed(struct cpuidle_device *dev,
 static int tegra2_idle_lp2_last(struct cpuidle_device *dev,
                        struct cpuidle_state *state, s64 request)
 {
+       bool sleep_completed = false;
        int i;
 
        while (tegra2_cpu_is_resettable_soon())
@@ -165,7 +166,10 @@ static int tegra2_idle_lp2_last(struct cpuidle_device *dev,
                return -EBUSY;
        }
 
-       tegra_idle_lp2_last(request, 0);
+       if (tegra_idle_lp2_last(request, 0) == 0)
+               sleep_completed = true;
+       else
+               idle_stats.lp2_int_count[tegra_pending_interrupt()]++;
 
        for_each_online_cpu(i) {
                if (i != dev->cpu) {
@@ -174,6 +178,13 @@ static int tegra2_idle_lp2_last(struct cpuidle_device *dev,
                }
        }
 
+       if (sleep_completed) {
+               /*
+                * Stayed in LP2 for the full time until the next tick
+                */
+               pr_debug("%lld\n", request);
+       }
+
        return 0;
 }
 
index 8f17ba6..35c3360 100644 (file)
@@ -73,6 +73,15 @@ static inline int tegra_lp2_debug_show(struct seq_file *s, void *data)
 }
 #endif
 
+static inline int tegra_pending_interrupt(void)
+{
+       void __iomem *gic_cpu = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100);
+       u32 reg = readl(gic_cpu + 0x18);
+       reg &= 0x3FF;
+
+       return reg;
+}
+
 #ifdef CONFIG_CPU_IDLE
 void tegra_lp2_in_idle(bool enable);
 #else
index f3b8787..c5f616e 100644 (file)
@@ -414,9 +414,10 @@ bool tegra_set_cpu_in_lp2(int cpu)
        return last_cpu;
 }
 
-void tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
+unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
 {
        u32 reg;
+       unsigned int remain;
 
        /* Only the last cpu down does the final suspend steps */
        reg = readl(pmc + PMC_CTRL);
@@ -458,6 +459,7 @@ void tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
        restore_cpu_complex();
        cpu_cluster_pm_exit();
 
+       remain = tegra_lp2_timer_remain();
        if (sleep_time)
                tegra_lp2_set_trigger(0);
 
@@ -480,6 +482,7 @@ void tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
                        tegra_cluster_switch_times[tegra_cluster_switch_time_id_start]);
        }
 #endif
+       return remain;
 }
 
 static int tegra_common_suspend(void)
index 350c745..2fd0024 100644 (file)
@@ -95,7 +95,7 @@ u64 tegra_rtc_read_ms(void);
  */
 extern void (*tegra_deep_sleep)(int);
 
-void tegra_idle_lp2_last(unsigned int us, unsigned int flags);
+unsigned int tegra_idle_lp2_last(unsigned int us, unsigned int flags);
 
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC