Skip to content

Commit 0a4ec6a

Browse files
Gautham R. Shenoympe
authored andcommitted
cpuidle: powernv: Fix promotion from snooze if next state disabled
The commit 78eaa10 ("cpuidle: powernv/pseries: Auto-promotion of snooze to deeper idle state") introduced a timeout for the snooze idle state so that it could be eventually be promoted to a deeper idle state. The snooze timeout value is static and set to the target residency of the next idle state, which would train the cpuidle governor to pick the next idle state eventually. The unfortunate side-effect of this is that if the next idle state(s) is disabled, the CPU will forever remain in snooze, despite the fact that the system is completely idle, and other deeper idle states are available. This patch fixes the issue by dynamically setting the snooze timeout to the target residency of the next enabled state on the device. Before Patch: POWER8 : Only nap disabled. $ cpupower monitor sleep 30 sleep took 30.01297 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | Nap | Fast 0| 8| 0| 96.41| 0.00| 0.00 0| 8| 1| 96.43| 0.00| 0.00 0| 8| 2| 96.47| 0.00| 0.00 0| 8| 3| 96.35| 0.00| 0.00 0| 8| 4| 96.37| 0.00| 0.00 0| 8| 5| 96.37| 0.00| 0.00 0| 8| 6| 96.47| 0.00| 0.00 0| 8| 7| 96.47| 0.00| 0.00 POWER9: Shallow states (stop0lite, stop1lite, stop2lite, stop0, stop1, stop2) disabled: $ cpupower monitor sleep 30 sleep took 30.05033 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | stop | stop | stop | stop | stop | stop | stop | stop 0| 16| 0| 89.79| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 16| 1| 90.12| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 16| 2| 90.21| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 16| 3| 90.29| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 After Patch: POWER8 : Only nap disabled. $ cpupower monitor sleep 30 sleep took 30.01200 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | Nap | Fast 0| 8| 0| 16.58| 0.00| 77.21 0| 8| 1| 18.42| 0.00| 75.38 0| 8| 2| 4.70| 0.00| 94.09 0| 8| 3| 17.06| 0.00| 81.73 0| 8| 4| 3.06| 0.00| 95.73 0| 8| 5| 7.00| 0.00| 96.80 0| 8| 6| 1.00| 0.00| 98.79 0| 8| 7| 5.62| 0.00| 94.17 POWER9: Shallow states (stop0lite, stop1lite, stop2lite, stop0, stop1, stop2) disabled: $ cpupower monitor sleep 30 sleep took 30.02110 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | stop | stop | stop | stop | stop | stop | stop | stop 0| 0| 0| 0.69| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 9.39| 89.70 0| 0| 1| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.05| 93.21 0| 0| 2| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 89.93 0| 0| 3| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 93.26 Fixes: 78eaa10 ("cpuidle: powernv/pseries: Auto-promotion of snooze to deeper idle state") Cc: [email protected] # v4.2+ Signed-off-by: Gautham R. Shenoy <[email protected]> Reviewed-by: Balbir Singh <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 4155203 commit 0a4ec6a

File tree

1 file changed

+26
-6
lines changed

1 file changed

+26
-6
lines changed

drivers/cpuidle/cpuidle-powernv.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,31 @@ struct stop_psscr_table {
4343

4444
static struct stop_psscr_table stop_psscr_table[CPUIDLE_STATE_MAX] __read_mostly;
4545

46-
static u64 snooze_timeout __read_mostly;
46+
static u64 default_snooze_timeout __read_mostly;
4747
static bool snooze_timeout_en __read_mostly;
4848

49+
static u64 get_snooze_timeout(struct cpuidle_device *dev,
50+
struct cpuidle_driver *drv,
51+
int index)
52+
{
53+
int i;
54+
55+
if (unlikely(!snooze_timeout_en))
56+
return default_snooze_timeout;
57+
58+
for (i = index + 1; i < drv->state_count; i++) {
59+
struct cpuidle_state *s = &drv->states[i];
60+
struct cpuidle_state_usage *su = &dev->states_usage[i];
61+
62+
if (s->disabled || su->disable)
63+
continue;
64+
65+
return s->target_residency * tb_ticks_per_usec;
66+
}
67+
68+
return default_snooze_timeout;
69+
}
70+
4971
static int snooze_loop(struct cpuidle_device *dev,
5072
struct cpuidle_driver *drv,
5173
int index)
@@ -56,7 +78,7 @@ static int snooze_loop(struct cpuidle_device *dev,
5678

5779
local_irq_enable();
5880

59-
snooze_exit_time = get_tb() + snooze_timeout;
81+
snooze_exit_time = get_tb() + get_snooze_timeout(dev, drv, index);
6082
ppc64_runlatch_off();
6183
HMT_very_low();
6284
while (!need_resched()) {
@@ -465,11 +487,9 @@ static int powernv_idle_probe(void)
465487
cpuidle_state_table = powernv_states;
466488
/* Device tree can indicate more idle states */
467489
max_idle_state = powernv_add_idle_states();
468-
if (max_idle_state > 1) {
490+
default_snooze_timeout = TICK_USEC * tb_ticks_per_usec;
491+
if (max_idle_state > 1)
469492
snooze_timeout_en = true;
470-
snooze_timeout = powernv_states[1].target_residency *
471-
tb_ticks_per_usec;
472-
}
473493
} else
474494
return -ENODEV;
475495

0 commit comments

Comments
 (0)