Skip to content

Commit c2ec772

Browse files
committed
cpuidle: teo: Fix alternative idle state lookup
There are three mistakes in the loop in teo_select() that is looking for an alternative candidate idle state. First, it should walk all of the idle states shallower than the current candidate one, including all of the disabled ones, but it terminates after the first enabled idle state. Second, it should not terminate its last step if idle state 0 is disabled (which is related to the first issue). Finally, it may return the current alternative candidate idle state prematurely if the time span criterion is not met by the idle state under consideration at the moment. To address the issues mentioned above, make the loop in question walk all of the idle states shallower than the current candidate idle state all the way down to idle state 0 and rearrange the checks in it. Fixes: 7757755 ("cpuidle: teo: Rework most recent idle duration values treatment") Reported-by: Doug Smythies <dsmythies@telus.net> Tested-by: Doug Smythies <dsmythies@telus.net> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent c500bee commit c2ec772

1 file changed

Lines changed: 27 additions & 13 deletions

File tree

  • drivers/cpuidle/governors

drivers/cpuidle/governors/teo.c

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -397,32 +397,46 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
397397
intercept_sum = 0;
398398
recent_sum = 0;
399399

400-
for (i = idx - 1; i >= idx0; i--) {
400+
for (i = idx - 1; i >= 0; i--) {
401401
struct teo_bin *bin = &cpu_data->state_bins[i];
402402
s64 span_ns;
403403

404404
intercept_sum += bin->intercepts;
405405
recent_sum += bin->recent;
406406

407+
span_ns = teo_middle_of_bin(i, drv);
408+
409+
if ((!alt_recent || 2 * recent_sum > idx_recent_sum) &&
410+
(!alt_intercepts ||
411+
2 * intercept_sum > idx_intercept_sum)) {
412+
if (teo_time_ok(span_ns) &&
413+
!dev->states_usage[i].disable) {
414+
idx = i;
415+
duration_ns = span_ns;
416+
} else {
417+
/*
418+
* The current state is too shallow or
419+
* disabled, so take the first enabled
420+
* deeper state with suitable time span.
421+
*/
422+
idx = last_enabled_idx;
423+
duration_ns = last_enabled_span_ns;
424+
}
425+
break;
426+
}
427+
407428
if (dev->states_usage[i].disable)
408429
continue;
409430

410-
span_ns = teo_middle_of_bin(i, drv);
411431
if (!teo_time_ok(span_ns)) {
412432
/*
413-
* The current state is too shallow, so select
414-
* the first enabled deeper state.
433+
* The current state is too shallow, but if an
434+
* alternative candidate state has been found,
435+
* it may still turn out to be a better choice.
415436
*/
416-
duration_ns = last_enabled_span_ns;
417-
idx = last_enabled_idx;
418-
break;
419-
}
437+
if (last_enabled_idx != idx)
438+
continue;
420439

421-
if ((!alt_recent || 2 * recent_sum > idx_recent_sum) &&
422-
(!alt_intercepts ||
423-
2 * intercept_sum > idx_intercept_sum)) {
424-
idx = i;
425-
duration_ns = span_ns;
426440
break;
427441
}
428442

0 commit comments

Comments
 (0)