msm: hotplug: Change the pen variable in one place

Other WFI based hotplug implementations set the pen variable to
-1 in C code and do the appropriate flushing operations in one
location. They also don't try to invalidate the cache on a
spurious wakeup and report how many spurious wakeups there were.
Let's do the same in our code so that we can remove our
dependence on the dmac_{inv,flush}_range() functions (which are
no longer upstream) and easily report spurious wakeups to the
kernel logs.

This does delay the time we set the pen back to its default
value, but that doesn't actually matter because generic ARM
hotplug code already waits for a completion before continuing.

Change-Id: Ic36fbf744fe8abeda20ad9859a207b5e37c5e63c
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index 8fccce9..6ae2129 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -35,8 +35,6 @@
 	 * we've been released from the holding pen: secondary_stack
 	 * should now contain the SVC stack for this core
 	 */
-	mvn	r7, #0			@ -1 to registers
-	str r7,[r6]			@ back to the pen for ack
 	b	secondary_startup
 ENDPROC(msm_secondary_startup)
 
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 1a5fd5b..5cd5057 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -43,7 +43,7 @@
 {
 }
 
-static inline void platform_do_lowpower(unsigned int cpu)
+static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
 {
 	/* Just enter wfi for now. TODO: Properly shut off the cpu. */
 	for (;;) {
@@ -53,9 +53,6 @@
 			/*
 			 * OK, proper wakeup, we're done
 			 */
-			pen_release = -1;
-			dmac_flush_range((char *)&pen_release,
-				(char *)&pen_release + sizeof(pen_release));
 			break;
 		}
 
@@ -67,9 +64,7 @@
 		 * possible, since we are currently running incoherently, and
 		 * therefore cannot safely call printk() or anything else
 		 */
-		dmac_inv_range((char *)&pen_release,
-			       (char *)&pen_release + sizeof(pen_release));
-		pr_debug("CPU%u: spurious wakeup call\n", cpu);
+		(*spurious)++;
 	}
 }
 
@@ -85,6 +80,8 @@
  */
 void platform_cpu_die(unsigned int cpu)
 {
+	int spurious = 0;
+
 	if (unlikely(cpu != smp_processor_id())) {
 		pr_crit("%s: running on %u, should be %u\n",
 			__func__, smp_processor_id(), cpu);
@@ -95,10 +92,13 @@
 	 * we're ready for shutdown now, so do it
 	 */
 	cpu_enter_lowpower();
-	platform_do_lowpower(cpu);
+	platform_do_lowpower(cpu, &spurious);
 
 	pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__);
 	cpu_leave_lowpower();
+
+	if (spurious)
+		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
 }
 
 int platform_cpu_disable(unsigned int cpu)
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 1f98a67..d3c7797 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -42,6 +42,19 @@
  */
 volatile int pen_release = -1;
 
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
 static DEFINE_SPINLOCK(boot_lock);
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -56,6 +69,12 @@
 	gic_secondary_init(0);
 
 	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
 	 * Synchronise with the boot thread.
 	 */
 	spin_lock(&boot_lock);
@@ -220,9 +239,7 @@
 	 * Note that "pen_release" is the hardware CPU ID, whereas
 	 * "cpu" is Linux's internal ID.
 	 */
-	pen_release = cpu_logical_map(cpu);
-	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
-	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+	write_pen_release(cpu_logical_map(cpu));
 
 	/*
 	 * Send the secondary CPU a soft interrupt, thereby causing
@@ -237,8 +254,6 @@
 		if (pen_release == -1)
 			break;
 
-		dmac_inv_range((char *)&pen_release,
-			       (char *)&pen_release + sizeof(pen_release));
 		udelay(10);
 	}