From 2d0b4afb5461847dcdf08a87b02015d061b12e85 Mon Sep 17 00:00:00 2001
From: Lianwei Wang <lianwei.wang@gmail.com>
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 <lianwei.wang@gmail.com>
---
 drivers/cpuidle/cpuidle.c |   17 ++++++++++++++++-
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 2f0083a..a0829ad 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -18,6 +18,7 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 #include <linux/module.h>
+#include <linux/tick.h>
 #include <trace/events/power.h>
 
 #include "cpuidle.h"
@@ -462,11 +463,25 @@ 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);
+	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) {
+			smp_call_function_single(cpu, smp_callback, NULL, 1);
+		}
+	}
+
 	return NOTIFY_OK;
 }
 
-- 
1.7.4.1

