|
@@ -297,6 +297,54 @@ static void __init pnv_smp_probe(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int pnv_system_reset_exception(struct pt_regs *regs)
|
|
|
+{
|
|
|
+ if (smp_handle_nmi_ipi(regs))
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int pnv_cause_nmi_ipi(int cpu)
|
|
|
+{
|
|
|
+ int64_t rc;
|
|
|
+
|
|
|
+ if (cpu >= 0) {
|
|
|
+ rc = opal_signal_system_reset(get_hard_smp_processor_id(cpu));
|
|
|
+ if (rc != OPAL_SUCCESS)
|
|
|
+ return 0;
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ } else if (cpu == NMI_IPI_ALL_OTHERS) {
|
|
|
+ bool success = true;
|
|
|
+ int c;
|
|
|
+
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We do not use broadcasts (yet), because it's not clear
|
|
|
+ * exactly what semantics Linux wants or the firmware should
|
|
|
+ * provide.
|
|
|
+ */
|
|
|
+ for_each_online_cpu(c) {
|
|
|
+ if (c == smp_processor_id())
|
|
|
+ continue;
|
|
|
+
|
|
|
+ rc = opal_signal_system_reset(
|
|
|
+ get_hard_smp_processor_id(c));
|
|
|
+ if (rc != OPAL_SUCCESS)
|
|
|
+ success = false;
|
|
|
+ }
|
|
|
+ if (success)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Caller will fall back to doorbells, which may pick
|
|
|
+ * up the remainders.
|
|
|
+ */
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct smp_ops_t pnv_smp_ops = {
|
|
|
.message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
|
|
|
.cause_ipi = NULL, /* Filled at runtime by pnv_smp_probe() */
|
|
@@ -315,6 +363,10 @@ static struct smp_ops_t pnv_smp_ops = {
|
|
|
/* This is called very early during platform setup_arch */
|
|
|
void __init pnv_smp_init(void)
|
|
|
{
|
|
|
+ if (opal_check_token(OPAL_SIGNAL_SYSTEM_RESET)) {
|
|
|
+ ppc_md.system_reset_exception = pnv_system_reset_exception;
|
|
|
+ pnv_smp_ops.cause_nmi_ipi = pnv_cause_nmi_ipi;
|
|
|
+ }
|
|
|
smp_ops = &pnv_smp_ops;
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|