cpuidle: teo: Update idle duration estimate when choosing shallower state
[linux-2.6-microblaze.git] / drivers / cpuidle / governors / teo.c
index 987fc5f..2cdc711 100644 (file)
@@ -397,13 +397,23 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
         * the shallowest non-polling state and exit.
         */
        if (drv->state_count < 3 && cpu_data->utilized) {
-               for (i = 0; i < drv->state_count; ++i) {
-                       if (!dev->states_usage[i].disable &&
-                           !(drv->states[i].flags & CPUIDLE_FLAG_POLLING)) {
-                               idx = i;
-                               goto end;
-                       }
-               }
+               /* The CPU is utilized, so assume a short idle duration. */
+               duration_ns = teo_middle_of_bin(0, drv);
+               /*
+                * If state 0 is enabled and it is not a polling one, select it
+                * right away unless the scheduler tick has been stopped, in
+                * which case care needs to be taken to leave the CPU in a deep
+                * enough state in case it is not woken up any time soon after
+                * all.  If state 1 is disabled, though, state 0 must be used
+                * anyway.
+                */
+               if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
+                   teo_time_ok(duration_ns)) || dev->states_usage[1].disable)
+                       idx = 0;
+               else /* Assume that state 1 is not a polling one and use it. */
+                       idx = 1;
+
+               goto end;
        }
 
        /*
@@ -539,10 +549,20 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
 
        /*
         * If the CPU is being utilized over the threshold, choose a shallower
-        * non-polling state to improve latency
+        * non-polling state to improve latency, unless the scheduler tick has
+        * been stopped already and the shallower state's target residency is
+        * not sufficiently large.
         */
-       if (cpu_data->utilized)
-               idx = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
+       if (cpu_data->utilized) {
+               s64 span_ns;
+
+               i = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
+               span_ns = teo_middle_of_bin(i, drv);
+               if (teo_time_ok(span_ns)) {
+                       idx = i;
+                       duration_ns = span_ns;
+               }
+       }
 
 end:
        /*