feat(psci): check that CPUs handled a pabandon

Up to now PSCI assumed that if a pabandon happened then the CPU driver
will have handled it. This patch adds a simple protocol to make sure
that this is indeed the case. The chosen method is with a return value
that is highly unlikely on cores that are unaware of pabandon (x0 will
be primed with 1 and if used should be overwritten with the value of
CPUPWRCTLR_EL1 which should have its last bit set to power off and its
top bits RES0; the ACK value is chosen to be the exact opposite). An
alternative method would have been to add a field in cpu_ops, however
that would have required more major refactoring across many cpus and
would have taken up more memory on older platforms, so it was not
chosen.

Change-Id: I5826c0e4802e104d295c4ecbd80b5f676d2cd871
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 04917ea..08e27ac 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -1196,7 +1196,7 @@
 	return (n_valid > 1U) ? 1 : 0;
 }
 
-static void call_cpu_pwr_dwn(unsigned int power_level)
+static u_register_t call_cpu_pwr_dwn(unsigned int power_level)
 {
 	struct cpu_ops *ops = get_cpu_data(cpu_ops_ptr);
 
@@ -1213,7 +1213,25 @@
 
 static void prepare_cpu_pwr_dwn(unsigned int power_level)
 {
-	call_cpu_pwr_dwn(power_level);
+	/* ignore the return, all cpus should behave the same */
+	(void)call_cpu_pwr_dwn(power_level);
+}
+
+static void prepare_cpu_pwr_up(unsigned int power_level)
+{
+	/*
+	 * Call the pwr_dwn cpu hook again, indicating that an abandon happened.
+	 * The cpu driver is expected to clean up. We ask it to return
+	 * PABANDON_ACK to indicate that it has handled this. This is a
+	 * heuristic: the value has been chosen such that an unported CPU is
+	 * extremely unlikely to return this value.
+	 */
+	u_register_t ret = call_cpu_pwr_dwn(power_level);
+
+	/* unreachable on AArch32 so cast down to calm the compiler */
+	if (ret != (u_register_t) PABANDON_ACK) {
+		panic();
+	}
 }
 
 /*******************************************************************************
@@ -1321,10 +1339,9 @@
 	/*
 	 * Begin unwinding. Everything can be shared with CPU_ON and co later,
 	 * except the CPU specific bit. Cores that have hardware-assisted
-	 * coherency don't have much to do so just calling the hook again is
-	 * the simplest way to achieve this
+	 * coherency should be able to handle this.
 	 */
-	prepare_cpu_pwr_dwn(power_level);
+	prepare_cpu_pwr_up(power_level);
 }
 
 /*******************************************************************************