We've found a couple of issues with this patch...
On Mon, 2014-03-24 at 13:47 +0000, Chris Redpath wrote:
[...]
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
[...]
+/*
- Work out if any of the idle states have an exit latency too high for us.
- ns_delay is passed in containing the max we are willing to tolerate.
- If there are none, set ns_delay to zero.
- If there are any, set ns_delay to
- ('target_residency of state with shortest too-big latency' - 1) * 1000.
- */
+static void hmp_keepalive_delay(unsigned int *ns_delay) +{
- struct cpuidle_driver *drv;
- drv = cpuidle_driver_ref();
In Linux 3.10 cpuidle_driver_ref() causes a null pointer reference if there is no cpuidle driver, as on ARMv8 models (see https://bugs.launchpad.net/linaro-stable-kernel/+bug/1304028)
That can be fixed by back-porting from mainline Linux commit 3b9c10e98021 (cpuidle: Check the result of cpuidle_get_driver() against NULL)
Also...
- if (drv) {
unsigned int us_delay = UINT_MAX;
unsigned int us_max_delay = *ns_delay / 1000;
int idx;
/* if cpuidle states are guaranteed to be sorted we
* could stop at the first match.
*/
for (idx = 0; idx < drv->state_count; idx++) {
if (drv->states[idx].exit_latency > us_max_delay &&
drv->states[idx].target_residency < us_delay) {
us_delay = drv->states[idx].target_residency;
}
}
if (us_delay == UINT_MAX)
*ns_delay = 0; /* no timer required */
else
*ns_delay = 1000 * (us_delay - 1);
- }
- cpuidle_driver_unref();
+}
We shouldn't call cpuidle_driver_unref() if cpuidle_driver_ref() returned NULL, because we didn't actually get a reference.
I propose fixing that by moving the cpuidle_driver_unref() up one line to be inside the if() clause.