Re: [PATCH 2/3] cpuidle,menu: use interactivity_req to disable polling

From: Rafael J. Wysocki
Date: Thu Jan 14 2016 - 19:45:38 EST


On Thursday, January 14, 2016 10:40:44 AM Sudeep Holla wrote:
>
> On 13/01/16 22:07, Rafael J. Wysocki wrote:
> > On Wednesday, January 13, 2016 10:58:13 PM Rafael J. Wysocki wrote:
>
> [..]
>
> >
> > So I'm wondering if the appended patch helps by any chance?
> >
>
> Yes it does fix. As you mentioned earlier, CPUIDLE_DRIVER_STATE_START is
> 0 on ARM platforms and hence data->last_state_idx ended up as -1.
>
> You can add by Tested-by when you push this change. Thanks for the quick
> fix.

No problem, thanks for testing!

Below it goes again with a changelog and all.

---
From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
Subject: [PATCH] cpuidle: menu: Fix menu_select() for CPUIDLE_DRIVER_STATE_START == 0

Commit a9ceb78bc75c (cpuidle,menu: use interactivity_req to disable
polling) exposed a bug in menu_select() causing it to return -1
on systems with CPUIDLE_DRIVER_STATE_START equal to zero, although
it should have returned 0. As a result, idle states are not entered
by CPUs on those systems.

Namely, on the systems in question data->last_state_idx is initially
equal to -1 and the above commit modified the condition that would
have caused it to be changed to 0 to be less likely to trigger which
exposed the problem. However, setting data->last_state_idx initially
to -1 doesn't make sense at all and on the affected systems it should
always be set to CPUIDLE_DRIVER_STATE_START (ie. 0) unconditionally,
so make that happen.

Fixes: a9ceb78bc75c (cpuidle,menu: use interactivity_req to disable polling)
Reported-and-tested-by: Sudeep Holla <sudeep.holla@xxxxxxx>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
---
drivers/cpuidle/governors/menu.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)

Index: linux-pm/drivers/cpuidle/governors/menu.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/menu.c
+++ linux-pm/drivers/cpuidle/governors/menu.c
@@ -294,8 +294,6 @@ static int menu_select(struct cpuidle_dr
data->needs_update = 0;
}

- data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1;
-
/* Special case when user has set very strict latency requirement */
if (unlikely(latency_req == 0))
return 0;
@@ -326,14 +324,19 @@ static int menu_select(struct cpuidle_dr
if (latency_req > interactivity_req)
latency_req = interactivity_req;

- /*
- * We want to default to C1 (hlt), not to busy polling
- * unless the timer is happening really really soon.
- */
- if (interactivity_req > 20 &&
- !drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
- dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
+ if (CPUIDLE_DRIVER_STATE_START > 0) {
+ data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1;
+ /*
+ * We want to default to C1 (hlt), not to busy polling
+ * unless the timer is happening really really soon.
+ */
+ if (interactivity_req > 20 &&
+ !drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
+ dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
+ data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
+ } else {
data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
+ }

/*
* Find the idle state with the lowest power while satisfying