|
@@ -387,32 +387,40 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
|
|
{
|
|
|
struct menu_device *data = &__get_cpu_var(menu_devices);
|
|
|
int last_idx = data->last_state_idx;
|
|
|
- unsigned int last_idle_us = cpuidle_get_last_residency(dev);
|
|
|
struct cpuidle_state *target = &drv->states[last_idx];
|
|
|
unsigned int measured_us;
|
|
|
unsigned int new_factor;
|
|
|
|
|
|
/*
|
|
|
- * Ugh, this idle state doesn't support residency measurements, so we
|
|
|
- * are basically lost in the dark. As a compromise, assume we slept
|
|
|
- * for the whole expected time.
|
|
|
+ * Try to figure out how much time passed between entry to low
|
|
|
+ * power state and occurrence of the wakeup event.
|
|
|
+ *
|
|
|
+ * If the entered idle state didn't support residency measurements,
|
|
|
+ * we are basically lost in the dark how much time passed.
|
|
|
+ * As a compromise, assume we slept for the whole expected time.
|
|
|
+ *
|
|
|
+ * Any measured amount of time will include the exit latency.
|
|
|
+ * Since we are interested in when the wakeup begun, not when it
|
|
|
+ * was completed, we must substract the exit latency. However, if
|
|
|
+ * the measured amount of time is less than the exit latency,
|
|
|
+ * assume the state was never reached and the exit latency is 0.
|
|
|
*/
|
|
|
- if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID)))
|
|
|
- last_idle_us = data->next_timer_us;
|
|
|
-
|
|
|
+ if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) {
|
|
|
+ /* Use timer value as is */
|
|
|
+ measured_us = data->next_timer_us;
|
|
|
|
|
|
- measured_us = last_idle_us;
|
|
|
+ } else {
|
|
|
+ /* Use measured value */
|
|
|
+ measured_us = cpuidle_get_last_residency(dev);
|
|
|
|
|
|
- /*
|
|
|
- * We correct for the exit latency; we are assuming here that the
|
|
|
- * exit latency happens after the event that we're interested in.
|
|
|
- */
|
|
|
- if (measured_us > target->exit_latency)
|
|
|
- measured_us -= target->exit_latency;
|
|
|
+ /* Deduct exit latency */
|
|
|
+ if (measured_us > target->exit_latency)
|
|
|
+ measured_us -= target->exit_latency;
|
|
|
|
|
|
- /* Make sure our coefficients do not exceed unity */
|
|
|
- if (measured_us > data->next_timer_us)
|
|
|
- measured_us = data->next_timer_us;
|
|
|
+ /* Make sure our coefficients do not exceed unity */
|
|
|
+ if (measured_us > data->next_timer_us)
|
|
|
+ measured_us = data->next_timer_us;
|
|
|
+ }
|
|
|
|
|
|
/* Update our correction ratio */
|
|
|
new_factor = data->correction_factor[data->bucket];
|
|
@@ -439,7 +447,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
|
|
data->correction_factor[data->bucket] = new_factor;
|
|
|
|
|
|
/* update the repeating-pattern data */
|
|
|
- data->intervals[data->interval_ptr++] = last_idle_us;
|
|
|
+ data->intervals[data->interval_ptr++] = measured_us;
|
|
|
if (data->interval_ptr >= INTERVALS)
|
|
|
data->interval_ptr = 0;
|
|
|
}
|