|
@@ -162,18 +162,62 @@ static void pnv_shutdown(void)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_KEXEC
|
|
|
+static void pnv_kexec_wait_secondaries_down(void)
|
|
|
+{
|
|
|
+ int my_cpu, i, notified = -1;
|
|
|
+
|
|
|
+ my_cpu = get_cpu();
|
|
|
+
|
|
|
+ for_each_online_cpu(i) {
|
|
|
+ uint8_t status;
|
|
|
+ int64_t rc;
|
|
|
+
|
|
|
+ if (i == my_cpu)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ rc = opal_query_cpu_status(get_hard_smp_processor_id(i),
|
|
|
+ &status);
|
|
|
+ if (rc != OPAL_SUCCESS || status != OPAL_THREAD_STARTED)
|
|
|
+ break;
|
|
|
+ barrier();
|
|
|
+ if (i != notified) {
|
|
|
+ printk(KERN_INFO "kexec: waiting for cpu %d "
|
|
|
+ "(physical %d) to enter OPAL\n",
|
|
|
+ i, paca[i].hw_cpu_id);
|
|
|
+ notified = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
|
|
|
{
|
|
|
xics_kexec_teardown_cpu(secondary);
|
|
|
|
|
|
- /* Return secondary CPUs to firmware on OPAL v3 */
|
|
|
- if (firmware_has_feature(FW_FEATURE_OPALv3) && secondary) {
|
|
|
+ /* On OPAL v3, we return all CPUs to firmware */
|
|
|
+
|
|
|
+ if (!firmware_has_feature(FW_FEATURE_OPALv3))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (secondary) {
|
|
|
+ /* Return secondary CPUs to firmware on OPAL v3 */
|
|
|
mb();
|
|
|
get_paca()->kexec_state = KEXEC_STATE_REAL_MODE;
|
|
|
mb();
|
|
|
|
|
|
/* Return the CPU to OPAL */
|
|
|
opal_return_cpu();
|
|
|
+ } else if (crash_shutdown) {
|
|
|
+ /*
|
|
|
+ * On crash, we don't wait for secondaries to go
|
|
|
+ * down as they might be unreachable or hung, so
|
|
|
+ * instead we just wait a bit and move on.
|
|
|
+ */
|
|
|
+ mdelay(1);
|
|
|
+ } else {
|
|
|
+ /* Primary waits for the secondaries to have reached OPAL */
|
|
|
+ pnv_kexec_wait_secondaries_down();
|
|
|
}
|
|
|
}
|
|
|
#endif /* CONFIG_KEXEC */
|