From 30c2639346a3fab2df3eac7ded37404d818802e4 Mon Sep 17 00:00:00 2001 From: Lianwei Wang Date: Fri, 26 Apr 2013 10:59:24 +0800 Subject: [PATCH] cpuidle: wakeup processor on a smaller latency Checking the PM-Qos latency and cpu idle sleep latency, and only wakeup the cpu if the requested PM-Qos latency is smaller than its idle sleep latency. This can reduce at least 50% cpu wakeup count on PM-Qos updated. The PM-Qos is not updated most of time, especially for home idle case. But for some specific case, the PM-Qos may be updated too frequently. (E.g. my measurement show that it is changed frequently between 2us/3us/200us/200s for bootup and usb case.) The battery current drain is measured from PMIC or battery eliminator. Although this is just a little saving, it is still reasonable to improve it. Change-Id: If564fd0d9c53cf100bd85247bfd509dfeaf54c13 Signed-off-by: Lianwei Wang --- drivers/cpuidle/cpuidle.c | 26 +++++++++++++++++++++++++- 1 files changed, 25 insertions(+), 1 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 2f0083a..e1f618f 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "cpuidle.h" @@ -462,11 +463,34 @@ static void smp_callback(void *v) * requirement. This means we need to get all processors out of their C-state, * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that * wakes them all right up. + * l - > latency in us */ static int cpuidle_latency_notify(struct notifier_block *b, unsigned long l, void *v) { - smp_call_function(smp_callback, NULL, 1); + cpumask_var_t cpus; + + if (!alloc_cpumask_var(&cpus, GFP_ATOMIC)) + smp_call_function(smp_callback, NULL, 1); + else { + int cpu, rcpu = smp_processor_id(); + s64 s; /* sleep_length in us */ + struct tick_device *td; + + for_each_online_cpu(cpu) { + if (cpu == rcpu) + continue; + td = tick_get_device(cpu); + s = ktime_us_delta(td->evtdev->next_event, ktime_get()); + if ((long)l < (long)s) + cpumask_set_cpu(cpu, cpus); + } + preempt_disable(); + smp_call_function_many(cpus, smp_callback, NULL, 1); + preempt_enable(); + free_cpumask_var(cpus); + } + return NOTIFY_OK; } -- 1.7.4.1