summaryrefslogtreecommitdiff
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2023-07-31 21:03:09 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2023-08-03 22:37:03 +0200
commit04bae4e2267d49eb9cfec403acd0462b8d00d637 (patch)
tree0d7d4222ac6fa05122e92e1370fca913a5c9ce75 /drivers/cpuidle
parent3f0b0966b30982e843950b170b7a9ddfd8094428 (diff)
downloadlwn-04bae4e2267d49eb9cfec403acd0462b8d00d637.tar.gz
lwn-04bae4e2267d49eb9cfec403acd0462b8d00d637.zip
cpuidle: teo: Avoid stopping the tick unnecessarily when bailing out
When teo_select() is going to return early in some special cases, make it avoid stopping the tick if the idle state to be returned is shallow. In particular, never stop the tick if state 0 is to be returned. Link: https://lore.kernel.org/linux-pm/CAJZ5v0jJxHj65r2HXBTd3wfbZtsg=_StzwO1kA5STDnaPe_dWA@mail.gmail.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-and-tested-by: Kajetan Puchalski <kajetan.puchalski@arm.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/governors/teo.c56
1 files changed, 33 insertions, 23 deletions
diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c
index 2cdc711679a5..1b76db3689d0 100644
--- a/drivers/cpuidle/governors/teo.c
+++ b/drivers/cpuidle/governors/teo.c
@@ -382,12 +382,13 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
/* Check if there is any choice in the first place. */
if (drv->state_count < 2) {
idx = 0;
- goto end;
+ goto out_tick;
}
+
if (!dev->states_usage[0].disable) {
idx = 0;
if (drv->states[1].target_residency_ns > duration_ns)
- goto end;
+ goto out_tick;
}
cpu_data->utilized = teo_cpu_is_utilized(dev->cpu, cpu_data);
@@ -408,11 +409,12 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* anyway.
*/
if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
- teo_time_ok(duration_ns)) || dev->states_usage[1].disable)
+ teo_time_ok(duration_ns)) || dev->states_usage[1].disable) {
idx = 0;
- else /* Assume that state 1 is not a polling one and use it. */
- idx = 1;
-
+ goto out_tick;
+ }
+ /* Assume that state 1 is not a polling one and use it. */
+ idx = 1;
goto end;
}
@@ -459,8 +461,15 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
/* Avoid unnecessary overhead. */
if (idx < 0) {
idx = 0; /* No states enabled, must use 0. */
- goto end;
- } else if (idx == idx0) {
+ goto out_tick;
+ }
+
+ if (idx == idx0) {
+ /*
+ * This is the first enabled idle state, so use it, but do not
+ * allow the tick to be stopped it is shallow enough.
+ */
+ duration_ns = drv->states[idx].target_residency_ns;
goto end;
}
@@ -566,24 +575,25 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
end:
/*
- * Don't stop the tick if the selected state is a polling one or if the
- * expected idle duration is shorter than the tick period length.
+ * Allow the tick to be stopped unless the selected state is a polling
+ * one or the expected idle duration is shorter than the tick period
+ * length.
*/
- if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) ||
- duration_ns < TICK_NSEC) && !tick_nohz_tick_stopped()) {
- *stop_tick = false;
+ if ((!(drv->states[idx].flags & CPUIDLE_FLAG_POLLING) &&
+ duration_ns >= TICK_NSEC) || tick_nohz_tick_stopped())
+ return idx;
- /*
- * The tick is not going to be stopped, so if the target
- * residency of the state to be returned is not within the time
- * till the closest timer including the tick, try to correct
- * that.
- */
- if (idx > idx0 &&
- drv->states[idx].target_residency_ns > delta_tick)
- idx = teo_find_shallower_state(drv, dev, idx, delta_tick, false);
- }
+ /*
+ * The tick is not going to be stopped, so if the target residency of
+ * the state to be returned is not within the time till the closest
+ * timer including the tick, try to correct that.
+ */
+ if (idx > idx0 &&
+ drv->states[idx].target_residency_ns > delta_tick)
+ idx = teo_find_shallower_state(drv, dev, idx, delta_tick, false);
+out_tick:
+ *stop_tick = false;
return idx;
}