cpufreq: interactive: Avoid down_read_trylock if down_write() is held

down_read_trylock is not always non-blocking if the same thread calls
down_write() before.

CPU1					CPU2
					down_read()
down_write()
  __down_write_nested()
    schedule()
      __down_read_trylock()
					up_read()
					  acquires sem->wait_lock
					    __rwsem_wake_one_writer()
	tries to lock sem->wait_lock

Now CPU2 is waiting for CPU1's schedule() to complete, while holding
sem->wait_lock. CPU1 needs sem->wait_lock to continue.

This problem only happens after cpufreq_interactive introduced load
change notification that could be called within schedule().

Add a separate flag to ignore notification if current thread is in
middle of down_write(). This avoids attempting to hold sem->wait_lock.
The additional flag doesn't have any side effects because
down_read_trylock() would have failed anyway.

Change-Id: Iff97cac36c170cf6d03f36de695141289c3d6930
[junjiew@codeaurora.org: Resolved merge conflicts. Dropped changes
 to code that no longer exists.]
Signed-off-by: Junjie Wu <junjiew@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index b4a19f4..bcb60ac 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -54,6 +54,7 @@
 	u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */
 	u64 max_freq_hyst_start_time;
 	struct rw_semaphore enable_sem;
+	bool reject_notification;
 	int governor_enabled;
 	struct cpufreq_interactive_tunables *cached_tunables;
 	int first_cpu;
@@ -723,6 +724,9 @@
 	if (speedchange_task == current)
 		return 0;
 
+	if (pcpu->reject_notification)
+		return 0;
+
 	if (!down_read_trylock(&pcpu->enable_sem))
 		return 0;
 	if (!pcpu->governor_enabled) {
@@ -1607,6 +1611,7 @@
 			pcpu->loc_floor_val_time = pcpu->pol_floor_val_time;
 			pcpu->pol_hispeed_val_time = pcpu->pol_floor_val_time;
 			pcpu->loc_hispeed_val_time = pcpu->pol_floor_val_time;
+			pcpu->reject_notification = true;
 			down_write(&pcpu->enable_sem);
 			del_timer_sync(&pcpu->cpu_timer);
 			del_timer_sync(&pcpu->cpu_slack_timer);
@@ -1614,6 +1619,7 @@
 			cpufreq_interactive_timer_start(tunables, j);
 			pcpu->governor_enabled = 1;
 			up_write(&pcpu->enable_sem);
+			pcpu->reject_notification = false;
 		}
 
 		mutex_unlock(&gov_lock);
@@ -1623,11 +1629,13 @@
 		mutex_lock(&gov_lock);
 		for_each_cpu(j, policy->cpus) {
 			pcpu = &per_cpu(cpuinfo, j);
+			pcpu->reject_notification = true;
 			down_write(&pcpu->enable_sem);
 			pcpu->governor_enabled = 0;
 			del_timer_sync(&pcpu->cpu_timer);
 			del_timer_sync(&pcpu->cpu_slack_timer);
 			up_write(&pcpu->enable_sem);
+			pcpu->reject_notification = false;
 		}
 
 		mutex_unlock(&gov_lock);