OSDN Git Service

clk: ti: clkctrl: use fallback udelay approach if timekeeping is suspended
authorTero Kristo <t-kristo@ti.com>
Tue, 15 Aug 2017 08:42:17 +0000 (11:42 +0300)
committerTero Kristo <t-kristo@ti.com>
Fri, 1 Dec 2017 13:15:38 +0000 (15:15 +0200)
In certain cases it is possible that the timekeeping has been suspended
already when attempting to disable/enable a clkctrl clock. This will
happen at least on am43xx platform when attempting to enable / disable
the clockevent source itself, burping out a warning from timekeeping core.

The sequence of events leading to this:
-> timekeeping_suspend()
 -> clockevents_suspend()
  -> omap_clkevt_idle()
   -> omap_hwmod_idle()
    -> _omap4_clkctrl_clk_disable()
     -> _omap4_is_timeout()

Avoid the issue by checking if the timekeeping is suspended and using
the fallback udelay approach for checking timeouts.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Stephen Boyd <sboyd@codeaurora.org>
drivers/clk/ti/clkctrl.c

index 284ba44..38dbcc1 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of_address.h>
 #include <linux/clk/ti.h>
 #include <linux/delay.h>
+#include <linux/timekeeping.h>
 #include "clock.h"
 
 #define NO_IDLEST                      0x1
@@ -90,7 +91,18 @@ static bool _omap4_is_ready(u32 val)
 
 static bool _omap4_is_timeout(union omap4_timeout *time, u32 timeout)
 {
-       if (unlikely(_early_timeout)) {
+       /*
+        * There are two special cases where ktime_to_ns() can't be
+        * used to track the timeouts. First one is during early boot
+        * when the timers haven't been initialized yet. The second
+        * one is during suspend-resume cycle while timekeeping is
+        * being suspended / resumed. Clocksource for the system
+        * can be from a timer that requires pm_runtime access, which
+        * will eventually bring us here with timekeeping_suspended,
+        * during both suspend entry and resume paths. This happens
+        * at least on am43xx platform.
+        */
+       if (unlikely(_early_timeout || timekeeping_suspended)) {
                if (time->cycles++ < timeout) {
                        udelay(1);
                        return false;