From 49cdbf3b800933bfb25a49ef1cbad918a072574e Mon Sep 17 00:00:00 2001
From: Alex Shi <alex.shi@linaro.org>
Date: Thu, 19 Jun 2014 13:47:35 +0800
Subject: [PATCH] HMP: use per cpu cpuidle driver to fix deadlock in
 hmp_idle_pull

Using per cpu cpuidle driver to fix deadlock in hmp_idle_pull.
Otherwise a deadlock happened when do bl_idle_init.

[  113.878664] other info that might help us debug this:
[  113.878667]  Possible unsafe locking scenario:
[  113.878667]
[  113.878670]        CPU0
[  113.878673]        ----
[  113.878681]   lock(cpuidle_driver_lock);
[  113.878684]   <Interrupt>
[  113.878691]     lock(cpuidle_driver_lock);
[  113.878693]
[  113.878693]  *** DEADLOCK ***
[  113.878693]
[  113.878697] 1 lock held by ksoftirqd/4/28:
[  113.878719]  #0:  (hmp_force_migration){+.....}, at: [<c0054da5>]
hmp_idle_pull+0x49/0x508

This patch is just a quick/cheap workaround for cpuidle_driver_lock
deadlock. It works for TC2 and any other platform where the idle
driver cannot be changed at runtime.

Signed-off-by: Alex Shi <alex.shi@linaro.org>
---
 kernel/sched/fair.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 71da724..0269273 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3587,10 +3587,12 @@ static enum hrtimer_restart hmp_cpu_keepalive_notify(struct hrtimer *hrtimer)
  * 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)
+static void hmp_keepalive_delay(int cpu, unsigned int *ns_delay)
 {
+	struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
 	struct cpuidle_driver *drv;
-	drv = cpuidle_driver_ref();
+
+	drv = cpuidle_get_cpu_driver(dev);
 	if (drv) {
 		unsigned int us_delay = UINT_MAX;
 		unsigned int us_max_delay = *ns_delay / 1000;
@@ -3609,7 +3611,6 @@ static void hmp_keepalive_delay(unsigned int *ns_delay)
 		else
 			*ns_delay = 1000 * (us_delay - 1);
 	}
-	cpuidle_driver_unref();
 }
 
 static void hmp_cpu_keepalive_trigger(void)
@@ -3623,7 +3624,7 @@ static void hmp_cpu_keepalive_trigger(void)
 				CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
 		keepalive->timer.function = hmp_cpu_keepalive_notify;
 
-		hmp_keepalive_delay(&ns_delay);
+		hmp_keepalive_delay(cpu, &ns_delay);
 		keepalive->delay = ns_to_ktime(ns_delay);
 		keepalive->init = true;
 	}
-- 
1.9.1
