sched: Ensure watchdog is enabled before disabling

There is a race between watchdog being enabled by hotplug and core
isolation disabling the watchdog. When a CPU is hotplugged in and
the hotplug lock has been released the watchdog thread might not
have run yet to enable the watchdog.  We have to wait for the
watchdog to be enabled before proceeding.

Change-Id: I88f73603b6d389a46f8e819d9b490091d5ba4fe9
Signed-off-by: Olav Haugan <ohaugan@codeaurora.org>
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 3c3898d..f3631a3 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -586,17 +586,13 @@
 	sched_setscheduler(current, policy, &param);
 }
 
-/* Must be called with hotplug lock (lock_device_hotplug()) held. */
 void watchdog_enable(unsigned int cpu)
 {
 	struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer);
 	unsigned int *enabled = raw_cpu_ptr(&watchdog_en);
 
-	lock_device_hotplug_assert();
-
 	if (*enabled)
 		return;
-	*enabled = 1;
 
 	/* kick off the timer for the hardlockup detector */
 	hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
@@ -612,24 +608,40 @@
 	/* initialize timestamp */
 	watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1);
 	__touch_watchdog();
+
+	/*
+	 * Need to ensure above operations are observed by other CPUs before
+	 * indicating that timer is enabled. This is to synchronize core
+	 * isolation and hotplug. Core isolation will wait for this flag to be
+	 * set.
+	 */
+	mb();
+	*enabled = 1;
 }
 
-/* Must be called with hotplug lock (lock_device_hotplug()) held. */
 void watchdog_disable(unsigned int cpu)
 {
 	struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer);
 	unsigned int *enabled = raw_cpu_ptr(&watchdog_en);
 
-	lock_device_hotplug_assert();
-
 	if (!*enabled)
 		return;
-	*enabled = 0;
 
 	watchdog_set_prio(SCHED_NORMAL, 0);
 	hrtimer_cancel(hrtimer);
 	/* disable the perf event */
 	watchdog_nmi_disable(cpu);
+
+	/*
+	 * No need for barrier here since disabling the watchdog is
+	 * synchronized with hotplug lock
+	 */
+	*enabled = 0;
+}
+
+bool watchdog_configured(unsigned int cpu)
+{
+	return *per_cpu_ptr(&watchdog_en, cpu);
 }
 
 static void watchdog_cleanup(unsigned int cpu, bool online)