]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00222134 MX6x - Fix race-conditions in low power code.
authorRanjani Vaidyanathan <ra5478@freescale.com>
Thu, 30 Aug 2012 20:02:32 +0000 (15:02 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:21 +0000 (08:35 +0200)
Fix couple of race-conditions associated with low power IDLE code:
1. Ensure that bus freq mutex is used in the suspend/resume function
2. Ensure that the usecount of pll2 is incremented/decremented when
ARM is switched to run from PLL2_PFD_400. And PLL2 is enabled/disabled
when necessary.

Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
arch/arm/mach-mx6/bus_freq.c
arch/arm/mach-mx6/clock.c
arch/arm/mach-mx6/clock_mx6sl.c

index 23f56d5deaf14f65ed9c336771502d72086e4612..151b4ee27eb6caf4d852c7ac2eb08af6d975d25c 100644 (file)
@@ -501,6 +501,8 @@ static int busfreq_suspend(struct platform_device *pdev, pm_message_t message)
 static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event,
        void *dummy)
 {
+       mutex_lock(&bus_freq_mutex);
+
        if (event == PM_SUSPEND_PREPARE) {
                set_high_bus_freq(1);
                busfreq_suspended = 1;
@@ -508,6 +510,8 @@ static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event,
                busfreq_suspended = 0;
        }
 
+       mutex_unlock(&bus_freq_mutex);
+
        return NOTIFY_OK;
 }
 static int busfreq_resume(struct platform_device *pdev)
index c2bf201779096b28c5b0e1535d070d520cd948dc..8b75aee7896490d6902b188fed0fc9bb65636eb0 100644 (file)
@@ -1261,7 +1261,16 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
                  * PLL2_PFD_400M.
                  */
                if (pll1_sw_clk.parent != &pll2_pfd_400M) {
-                       pll2_pfd_400M.enable(&pll2_pfd_400M);
+                       if (pll2_pfd_400M.usecount == 0) {
+                               /* Check if PLL2 needs to be enabled also. */
+                               if (pll2_528_bus_main_clk.usecount == 0)
+                                       pll2_528_bus_main_clk.enable(&pll2_528_bus_main_clk);
+                               /* Ensure parent usecount is
+                                 * also incremented.
+                                 */
+                               pll2_528_bus_main_clk.usecount++;
+                               pll2_pfd_400M.enable(&pll2_pfd_400M);
+                       }
                        pll2_pfd_400M.usecount++;
                        arm_needs_pll2_400 = true;
                        pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd_400M);
@@ -1288,11 +1297,19 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
                /* Make sure pll1_sw_clk is from pll1_sys_main_clk */
                pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk);
                pll1_sw_clk.parent = &pll1_sys_main_clk;
-               if (arm_needs_pll2_400)
+               if (arm_needs_pll2_400) {
                        pll2_pfd_400M.usecount--;
+                       if (pll2_pfd_400M.usecount == 0) {
+                               pll2_pfd_400M.disable(&pll2_pfd_400M);
+                               /* Ensure parent usecount is
+                                 * also decremented.
+                                 */
+                               pll2_528_bus_main_clk.usecount--;
+                               if (pll2_528_bus_main_clk.usecount == 0)
+                                       pll2_528_bus_main_clk.disable(&pll2_528_bus_main_clk);
+                       }
+               }
                arm_needs_pll2_400 = false;
-               if (pll2_pfd_400M.usecount == 0)
-                       pll2_pfd_400M.disable(&pll2_pfd_400M);
        }
        parent_rate = clk_get_rate(clk->parent);
        div = parent_rate / rate;
index 43b2bd1baac20e2031c74c5417545050d6d0d6ed..6bd818ae71394500942cc9da0c35d1b8d3ffcbb0 100755 (executable)
@@ -1167,7 +1167,16 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
                  * PLL2_PFD2_400M.
                  */
                if (pll1_sw_clk.parent != &pll2_pfd2_400M) {
-                       pll2_pfd2_400M.enable(&pll2_pfd2_400M);
+                       if (pll2_pfd2_400M.usecount == 0) {
+                               /* Check if PLL2 needs to be enabled also. */
+                               if (pll2_528_bus_main_clk.usecount == 0)
+                                       pll2_528_bus_main_clk.enable(&pll2_528_bus_main_clk);
+                               /* Ensure parent usecount is
+                                 * also incremented.
+                                 */
+                               pll2_528_bus_main_clk.usecount++;
+                               pll2_pfd2_400M.enable(&pll2_pfd2_400M);
+                       }
                        arm_needs_pll2_400 = true;
                        pll2_pfd2_400M.usecount++;
                        pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd2_400M);
@@ -1192,11 +1201,19 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
                pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk);
                pll1_sw_clk.parent = &pll1_sys_main_clk;
 
-               if (arm_needs_pll2_400)
+               if (arm_needs_pll2_400) {
                        pll2_pfd2_400M.usecount--;
+                       if (pll2_pfd2_400M.usecount == 0) {
+                               pll2_pfd2_400M.disable(&pll2_pfd2_400M);
+                               /* Ensure parent usecount is
+                                 * also decremented.
+                                 */
+                               pll2_528_bus_main_clk.usecount--;
+                               if (pll2_528_bus_main_clk.usecount == 0)
+                                       pll2_528_bus_main_clk.disable(&pll2_528_bus_main_clk);
+                       }
+               }
                arm_needs_pll2_400 = false;
-               if (pll2_pfd2_400M.usecount == 0)
-                       pll2_pfd2_400M.disable(&pll2_pfd2_400M);
        }
        parent_rate = clk_get_rate(clk->parent);
        div = parent_rate / rate;