summaryrefslogtreecommitdiff
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2017-06-26 15:38:15 +1000
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-06-29 22:59:17 +0200
commit3ed09c94580de9d5b18cc35d1f97e9f24cd9233b (patch)
tree17e531d2f419ed7a8ec5b611f9c00d3ba0b43915 /drivers/cpuidle
parent654d08a42a5660514df5a5a6ed4dc1b0c978a0a3 (diff)
cpuidle: menu: allow state 0 to be disabled
The menu driver does not allow state0 to be disabled completely. If it is disabled but other enabled states don't meet latency requirements, it is still used. Fix this by starting with the first enabled idle state. Fall back to state 0 if no idle states are enabled (arguably this should be -EINVAL if it is attempted, but this is the minimal fix). Acked-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/governors/menu.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index b2330fd69e34..61b64c2b2cb8 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -286,6 +286,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
struct device *device = get_cpu_device(dev->cpu);
int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
int i;
+ int first_idx;
+ int idx;
unsigned int interactivity_req;
unsigned int expected_interval;
unsigned long nr_iowaiters, cpu_load;
@@ -335,11 +337,11 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
if (data->next_timer_us > polling_threshold &&
latency_req > s->exit_latency && !s->disabled &&
!dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable)
- data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
+ first_idx = CPUIDLE_DRIVER_STATE_START;
else
- data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1;
+ first_idx = CPUIDLE_DRIVER_STATE_START - 1;
} else {
- data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
+ first_idx = 0;
}
/*
@@ -359,20 +361,28 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* Find the idle state with the lowest power while satisfying
* our constraints.
*/
- for (i = data->last_state_idx + 1; i < drv->state_count; i++) {
+ idx = -1;
+ for (i = first_idx; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
struct cpuidle_state_usage *su = &dev->states_usage[i];
if (s->disabled || su->disable)
continue;
+ if (idx == -1)
+ idx = i; /* first enabled state */
if (s->target_residency > data->predicted_us)
break;
if (s->exit_latency > latency_req)
break;
- data->last_state_idx = i;
+ idx = i;
}
+ if (idx == -1)
+ idx = 0; /* No states enabled. Must use 0. */
+
+ data->last_state_idx = idx;
+
return data->last_state_idx;
}