aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/governors/menu.c44
1 files changed, 26 insertions, 18 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f0995dd2469f..b347c101c1f7 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -387,32 +387,40 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
387{ 387{
388 struct menu_device *data = &__get_cpu_var(menu_devices); 388 struct menu_device *data = &__get_cpu_var(menu_devices);
389 int last_idx = data->last_state_idx; 389 int last_idx = data->last_state_idx;
390 unsigned int last_idle_us = cpuidle_get_last_residency(dev);
391 struct cpuidle_state *target = &drv->states[last_idx]; 390 struct cpuidle_state *target = &drv->states[last_idx];
392 unsigned int measured_us; 391 unsigned int measured_us;
393 unsigned int new_factor; 392 unsigned int new_factor;
394 393
395 /* 394 /*
396 * Ugh, this idle state doesn't support residency measurements, so we 395 * Try to figure out how much time passed between entry to low
397 * are basically lost in the dark. As a compromise, assume we slept 396 * power state and occurrence of the wakeup event.
398 * for the whole expected time. 397 *
398 * If the entered idle state didn't support residency measurements,
399 * we are basically lost in the dark how much time passed.
400 * As a compromise, assume we slept for the whole expected time.
401 *
402 * Any measured amount of time will include the exit latency.
403 * Since we are interested in when the wakeup begun, not when it
404 * was completed, we must substract the exit latency. However, if
405 * the measured amount of time is less than the exit latency,
406 * assume the state was never reached and the exit latency is 0.
399 */ 407 */
400 if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) 408 if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) {
401 last_idle_us = data->next_timer_us; 409 /* Use timer value as is */
402 410 measured_us = data->next_timer_us;
403 411
404 measured_us = last_idle_us; 412 } else {
413 /* Use measured value */
414 measured_us = cpuidle_get_last_residency(dev);
405 415
406 /* 416 /* Deduct exit latency */
407 * We correct for the exit latency; we are assuming here that the 417 if (measured_us > target->exit_latency)
408 * exit latency happens after the event that we're interested in. 418 measured_us -= target->exit_latency;
409 */
410 if (measured_us > target->exit_latency)
411 measured_us -= target->exit_latency;
412 419
413 /* Make sure our coefficients do not exceed unity */ 420 /* Make sure our coefficients do not exceed unity */
414 if (measured_us > data->next_timer_us) 421 if (measured_us > data->next_timer_us)
415 measured_us = data->next_timer_us; 422 measured_us = data->next_timer_us;
423 }
416 424
417 /* Update our correction ratio */ 425 /* Update our correction ratio */
418 new_factor = data->correction_factor[data->bucket]; 426 new_factor = data->correction_factor[data->bucket];
@@ -439,7 +447,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
439 data->correction_factor[data->bucket] = new_factor; 447 data->correction_factor[data->bucket] = new_factor;
440 448
441 /* update the repeating-pattern data */ 449 /* update the repeating-pattern data */
442 data->intervals[data->interval_ptr++] = last_idle_us; 450 data->intervals[data->interval_ptr++] = measured_us;
443 if (data->interval_ptr >= INTERVALS) 451 if (data->interval_ptr >= INTERVALS)
444 data->interval_ptr = 0; 452 data->interval_ptr = 0;
445} 453}