]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00234217 cpufreq:fix loops_per_jiffy wrong on new suspend flow of cpufreq
authorRobin Gong <b38343@freescale.com>
Tue, 20 Nov 2012 07:08:12 +0000 (15:08 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:44 +0000 (08:35 +0200)
Currently, we use pm_notifier to enter suspend/resume flow. But in the notifier
we only set cpufreq, didn't tell CPUFREQ core what the current cpufreq setting
now. So in the next time if CPUFREQ core find the current cpu frequncy is not
the value that CPUFREQ core want to set before. CPUFREQ core will force to set
the freqs.old with its own rule, which means the freqs.old will be MODIFYED
unexpectedly, and this will cause wrong loops_per_jiffy. We need add cpufreq_
notify_transition in the suspend/resume interface of cpufreq.

Signed-off-by: Robin Gong <b38343@freescale.com>
arch/arm/plat-mxc/cpufreq.c

index 33f85225a21b764286eea47bddbe1a1368803e88..304e5c7a523b79ab26cad878e32b37834f2c6ffc 100755 (executable)
@@ -79,7 +79,6 @@ int set_cpu_freq(int freq)
                        org_pu_volt = cpu_op_tbl[i].pu_voltage;
                }
        }
-
        if (gp_volt == 0)
                return ret;
        /*Set the voltage for the GP domain. */
@@ -244,6 +243,11 @@ static int mxc_set_target(struct cpufreq_policy *policy,
                return ret;
        }
 
+       mutex_lock(&set_cpufreq_lock);
+       if (cpufreq_suspend) {
+               mutex_unlock(&set_cpufreq_lock);
+               return ret;
+       }
        cpufreq_frequency_table_target(policy, imx_freq_table,
                        target_freq, relation, &index);
        freq_Hz = imx_freq_table[index].frequency * 1000;
@@ -252,21 +256,13 @@ static int mxc_set_target(struct cpufreq_policy *policy,
        freqs.new = freq_Hz / 1000;
        freqs.cpu = policy->cpu;
        freqs.flags = 0;
-
        for (i = 0; i < num_cpus; i++) {
                freqs.cpu = i;
                cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        }
-       mutex_lock(&set_cpufreq_lock);
-       if (cpufreq_suspend) {
-               mutex_unlock(&set_cpufreq_lock);
-               return ret;
-       }
        ret = set_cpu_freq(freq_Hz);
-       if (ret) {
-               mutex_unlock(&set_cpufreq_lock);
-               return ret;
-       }
+       if (ret)
+               goto  Set_finish;
 #ifdef CONFIG_SMP
        /* Loops per jiffy is not updated by the CPUFREQ driver for SMP systems.
          * So update it for all CPUs.
@@ -280,11 +276,12 @@ static int mxc_set_target(struct cpufreq_policy *policy,
         * as all CPUs are running at same freq */
        loops_per_jiffy = per_cpu(cpu_data, 0).loops_per_jiffy;
 #endif
-       mutex_unlock(&set_cpufreq_lock);
+Set_finish:
        for (i = 0; i < num_cpus; i++) {
                freqs.cpu = i;
                cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
        }
+       mutex_unlock(&set_cpufreq_lock);
 
        return ret;
 }
@@ -398,17 +395,27 @@ static struct cpufreq_driver mxc_driver = {
 static int cpufreq_pm_notify(struct notifier_block *nb, unsigned long event,
        void *dummy)
 {
-#ifdef CONFIG_SMP
        unsigned int i;
-#endif
+       int num_cpus;
        int ret;
+       struct cpufreq_freqs freqs;
+
+       num_cpus = num_possible_cpus();
        mutex_lock(&set_cpufreq_lock);
        if (event == PM_SUSPEND_PREPARE) {
                pre_suspend_rate = clk_get_rate(cpu_clk);
                if (pre_suspend_rate != (imx_freq_table[0].frequency * 1000)) {
+                       /*notify cpufreq core will raise up cpufreq to highest*/
+                       freqs.old = pre_suspend_rate / 1000;
+                       freqs.new = imx_freq_table[0].frequency;
+                       freqs.flags = 0;
+                       for (i = 0; i < num_cpus; i++) {
+                               freqs.cpu = i;
+                               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+                       }
                        ret = set_cpu_freq(imx_freq_table[0].frequency * 1000);
                        if (ret)
-                               return NOTIFY_OK;/*if update freq error,return*/
+                               goto Notify_finish;/*if update freq error,return*/
 #ifdef CONFIG_SMP
                        for_each_possible_cpu(i)
                                per_cpu(cpu_data, i).loops_per_jiffy =
@@ -419,10 +426,50 @@ static int cpufreq_pm_notify(struct notifier_block *nb, unsigned long event,
                        loops_per_jiffy = cpufreq_scale(loops_per_jiffy,
                                pre_suspend_rate / 1000, imx_freq_table[0].frequency);
 #endif
+                       for (i = 0; i < num_cpus; i++) {
+                               freqs.cpu = i;
+                               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+                       }
                }
                cpufreq_suspend = true;
-       } else if (event == PM_POST_SUSPEND)
+       } else if (event == PM_POST_SUSPEND) {
+               if (clk_get_rate(cpu_clk) != pre_suspend_rate) {
+                       /*notify cpufreq core will restore rate before suspend*/
+                       freqs.old = imx_freq_table[0].frequency;
+                       freqs.new = pre_suspend_rate / 1000;
+                       freqs.flags = 0;
+                       for (i = 0; i < num_cpus; i++) {
+                               freqs.cpu = i;
+                               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+                       }
+                       ret = set_cpu_freq(pre_suspend_rate);
+                       if (ret)
+                               goto Notify_finish;/*if update freq error,return*/
+#ifdef CONFIG_SMP
+                       for_each_possible_cpu(i)
+                               per_cpu(cpu_data, i).loops_per_jiffy =
+                                       cpufreq_scale(per_cpu(cpu_data, i).loops_per_jiffy,
+                                       imx_freq_table[0].frequency, pre_suspend_rate / 1000);
+                       loops_per_jiffy = per_cpu(cpu_data, 0).loops_per_jiffy;
+#else
+                       loops_per_jiffy = cpufreq_scale(loops_per_jiffy,
+                               imx_freq_table[0].frequency, pre_suspend_rate / 1000);
+#endif
+                       for (i = 0; i < num_cpus; i++) {
+                               freqs.cpu = i;
+                               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+                       }
+               }
                cpufreq_suspend = false;
+       }
+       mutex_unlock(&set_cpufreq_lock);
+       return NOTIFY_OK;
+
+Notify_finish:
+       for (i = 0; i < num_cpus; i++) {
+               freqs.cpu = i;
+               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+       }
        mutex_unlock(&set_cpufreq_lock);
        return NOTIFY_OK;
 }