cpuidle / sleep: Use broadcast timer for states that stop local timer
[firefly-linux-kernel-4.4.55.git] / kernel / sched / idle.c
index 84b93b68482a8cc8d3a268e83a8265d8e11ff67b..80014a17834214fcad51add08b2b171463e84128 100644 (file)
@@ -82,6 +82,7 @@ static void cpuidle_idle_call(void)
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int next_state, entered_state;
        unsigned int broadcast;
+       bool reflect;
 
        /*
         * Check if the idle task must be rescheduled. If it is the
@@ -105,6 +106,9 @@ static void cpuidle_idle_call(void)
         */
        rcu_idle_enter();
 
+       if (cpuidle_not_available(drv, dev))
+               goto use_default;
+
        /*
         * Suspend-to-idle ("freeze") is a system state in which all user space
         * has been frozen, all I/O devices have been suspended and the only
@@ -115,15 +119,22 @@ static void cpuidle_idle_call(void)
         * until a proper wakeup interrupt happens.
         */
        if (idle_should_freeze()) {
-               cpuidle_enter_freeze();
-               goto exit_idle;
-       }
+               entered_state = cpuidle_enter_freeze(drv, dev);
+               if (entered_state >= 0) {
+                       local_irq_enable();
+                       goto exit_idle;
+               }
 
-       /*
-        * Ask the cpuidle framework to choose a convenient idle state.
-        * Fall back to the default arch idle method on errors.
-        */
-       next_state = cpuidle_select(drv, dev);
+               reflect = false;
+               next_state = cpuidle_find_deepest_state(drv, dev);
+       } else {
+               reflect = true;
+               /*
+                * Ask the cpuidle framework to choose a convenient idle state.
+                */
+               next_state = cpuidle_select(drv, dev);
+       }
+       /* Fall back to the default arch idle method on errors. */
        if (next_state < 0)
                goto use_default;
 
@@ -170,7 +181,8 @@ static void cpuidle_idle_call(void)
        /*
         * Give the governor an opportunity to reflect on the outcome
         */
-       cpuidle_reflect(dev, entered_state);
+       if (reflect)
+               cpuidle_reflect(dev, entered_state);
 
 exit_idle:
        __current_set_polling();