ARM: tegra: cpuquiet: Honor G->LP delay on last core down
Peter Boonstoppel [Thu, 31 Jan 2013 21:22:02 +0000 (13:22 -0800)]
We cluster switch G->LP when 2 conditions are met:
1) we are in single core mode
2) CPU freq reaches idle_bottom_freq

After these 2 conditions are met, we wait for down_delay ms before
cluster switching. This patch ensures the timeout is also honored when
the first condition is met last.

Bug 1226607

Change-Id: Ic36f9cab09a5967b71409e44dbe89290f39cb26b
Signed-off-by: Peter Boonstoppel <pboonstoppel@nvidia.com>
Reviewed-on: http://git-master/r/196171
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>

arch/arm/mach-tegra/cpuquiet.c

index 4fec35a..2fcfb54 100644 (file)
@@ -383,16 +383,31 @@ static int max_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
 static int __cpuinit cpu_online_notify(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
-       if (action != CPU_POST_DEAD)
-               return NOTIFY_OK;
+       switch (action) {
+       case CPU_POST_DEAD:
+               if (num_online_cpus() == 1 &&
+                   tegra_getspeed(0) <= idle_bottom_freq) {
+                       mutex_lock(tegra_cpu_lock);
 
-       if (num_online_cpus() == 1 && tegra_getspeed(0) <= idle_bottom_freq) {
-               mutex_lock(tegra_cpu_lock);
+                       cpq_target_cluster_state = TEGRA_CPQ_LP;
+                       mod_timer(&updown_timer, jiffies + down_delay);
 
-               cpq_target_cluster_state = TEGRA_CPQ_LP;
-               queue_work(cpuquiet_wq, &cpuquiet_work);
+                       mutex_unlock(tegra_cpu_lock);
+               }
+               break;
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
+               if (cpq_target_cluster_state == TEGRA_CPQ_LP) {
+                       mutex_lock(tegra_cpu_lock);
+
+                       if (cpq_target_cluster_state == TEGRA_CPQ_LP) {
+                               cpq_target_cluster_state = TEGRA_CPQ_G;
+                               del_timer(&updown_timer);
+                       }
 
-               mutex_unlock(tegra_cpu_lock);
+                       mutex_unlock(tegra_cpu_lock);
+               }
+               break;
        }
 
        return NOTIFY_OK;