Skip to content

Commit 1e25d80

Browse files
rafaeljwgregkh
authored andcommitted
cpuidle: governors: menu: Avoid using invalid recent intervals data
[ Upstream commit fa3fa55 ] Marc has reported that commit 85975da ("cpuidle: menu: Avoid discarding useful information") caused the number of wakeup interrupts to increase on an idle system [1], which was not expected to happen after merely allowing shallower idle states to be selected by the governor in some cases. However, on the system in question, all of the idle states deeper than WFI are rejected by the driver due to a firmware issue [2]. This causes the governor to only consider the recent interval duriation data corresponding to attempts to enter WFI that are successful and the recent invervals table is filled with values lower than the scheduler tick period. Consequently, the governor predicts an idle duration below the scheduler tick period length and avoids stopping the tick more often which leads to the observed symptom. Address it by modifying the governor to update the recent intervals table also when entering the previously selected idle state fails, so it knows that the short idle intervals might have been the minority had the selected idle states been actually entered every time. Fixes: 85975da ("cpuidle: menu: Avoid discarding useful information") Link: https://lore.kernel.org/linux-pm/[email protected]/ [1] Link: https://lore.kernel.org/linux-pm/[email protected]/ [2] Signed-off-by: Rafael J. Wysocki <[email protected]> Tested-by: Christian Loehle <[email protected]> Tested-by: Marc Zyngier <[email protected]> Reviewed-by: Christian Loehle <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Sasha Levin <[email protected]>
1 parent a8df217 commit 1e25d80

File tree

1 file changed

+17
-4
lines changed
  • drivers/cpuidle/governors

1 file changed

+17
-4
lines changed

drivers/cpuidle/governors/menu.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ static inline int performance_multiplier(unsigned int nr_iowaiters)
153153

154154
static DEFINE_PER_CPU(struct menu_device, menu_devices);
155155

156+
static void menu_update_intervals(struct menu_device *data, unsigned int interval_us)
157+
{
158+
/* Update the repeating-pattern data. */
159+
data->intervals[data->interval_ptr++] = interval_us;
160+
if (data->interval_ptr >= INTERVALS)
161+
data->interval_ptr = 0;
162+
}
163+
156164
static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
157165

158166
/*
@@ -277,6 +285,14 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
277285
if (data->needs_update) {
278286
menu_update(drv, dev);
279287
data->needs_update = 0;
288+
} else if (!dev->last_residency_ns) {
289+
/*
290+
* This happens when the driver rejects the previously selected
291+
* idle state and returns an error, so update the recent
292+
* intervals table to prevent invalid information from being
293+
* used going forward.
294+
*/
295+
menu_update_intervals(data, UINT_MAX);
280296
}
281297

282298
nr_iowaiters = nr_iowait_cpu(dev->cpu);
@@ -546,10 +562,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
546562

547563
data->correction_factor[data->bucket] = new_factor;
548564

549-
/* update the repeating-pattern data */
550-
data->intervals[data->interval_ptr++] = ktime_to_us(measured_ns);
551-
if (data->interval_ptr >= INTERVALS)
552-
data->interval_ptr = 0;
565+
menu_update_intervals(data, ktime_to_us(measured_ns));
553566
}
554567

555568
/**

0 commit comments

Comments
 (0)