From df74672faf8421bf0f133d7fe7422a7cd2f757a1 Mon Sep 17 00:00:00 2001 From: Srivatsa Vaddagiri Date: Fri, 20 Dec 2013 18:56:07 -0800 Subject: cpufreq: cpu-boost: Resolve deadlock when waking up sync thread CPU boost driver receives notification from scheduler when threads migrate towards a cpu and in turn wakes up a sync thread associated with that cpu to handle any required frequency transitions. The wakeup call however can lead to a deadlock inside scheduler under some circumstance. The deadlock is seen when sync thread is the only thread running on a cpu and goes to sleep (say by calling wait_event() -> schedule()). Midway through this sleep (schedule()) call, while cpu is still running in context of sync thread, scheduler attempts a load balance (realizing that cpu is about to become idle) which can result in tasks being migrated towards the cpu going idle. This will cause migration notification to be issued and in turn a wakeup on sync thread. The wakeup call however gets stuck in below while() loop inside scheduler: try_to_wake_up(struct task_struct *p, ...) { /* * If the owning (remote) cpu is still in the middle of * schedule() with this task as prev, wait until its done * referencing the task. */ while (p->on_cpu) cpu_relax(); } A possible fix could be to teach try_to_wake_up() about this special case. Another fix, implemented in this patch and that helps minimize scheduler changes, is to have cpu boost driver not issue a wakeup under this special circumstance, which was found to occur very infrequently. Change-Id: I92bc68a22d51595a208673fe2a1eedfa97004f9e Signed-off-by: Srivatsa Vaddagiri --- drivers/cpufreq/cpu-boost.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c index 9846eb77d2ad..f9ec03a92bdb 100644 --- a/drivers/cpufreq/cpu-boost.c +++ b/drivers/cpufreq/cpu-boost.c @@ -181,6 +181,10 @@ static int boost_migration_notify(struct notifier_block *nb, if (!boost_ms) return NOTIFY_OK; + /* Avoid deadlock in try_to_wake_up() */ + if (s->thread == current) + return NOTIFY_OK; + pr_debug("Migration: CPU%d --> CPU%d\n", (int) arg, (int) dest_cpu); spin_lock_irqsave(&s->lock, flags); s->pending = true; -- cgit v1.2.3