Allow platforms to provide an NMI IPI, and wire that to the NMI
system.
---
 arch/powerpc/include/asm/smp.h            |  5 +++++
 arch/powerpc/kernel/smp.c                 | 21 ++++++++++++++++-----
 arch/powerpc/platforms/85xx/smp.c         |  1 +
 arch/powerpc/platforms/86xx/mpc86xx_smp.c |  1 +
 arch/powerpc/platforms/chrp/smp.c         |  1 +
 arch/powerpc/platforms/powermac/smp.c     |  1 +
 arch/powerpc/platforms/powernv/smp.c      |  1 +
 arch/powerpc/platforms/pseries/smp.c      |  1 +
 8 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 055918d..15521c1 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -37,11 +37,15 @@ extern int cpu_to_chip_id(int cpu);
 
 #ifdef CONFIG_SMP
 
+#define SMP_OP_NMI_TYPE_SAFE   1
+#define SMP_OP_NMI_TYPE_HARD   2
+
 struct smp_ops_t {
        void  (*message_pass)(int cpu, int msg);
 #ifdef CONFIG_PPC_SMP_MUXED_IPI
        void  (*cause_ipi)(int cpu, unsigned long data);
 #endif
+       int   (*cause_nmi_ipi)(int cpu, int type);
        void  (*probe)(void);
        int   (*kick_cpu)(int nr);
        void  (*setup_cpu)(int nr);
@@ -53,6 +57,7 @@ struct smp_ops_t {
        int   (*cpu_bootable)(unsigned int nr);
 };
 
+extern int smp_handle_nmi_ipi(struct pt_regs *regs);
 extern void smp_send_debugger_break(void);
 extern void start_secondary_resume(void);
 extern void smp_generic_give_timebase(void);
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 959d9dc..b3133e9 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -425,8 +425,10 @@ int smp_handle_nmi_ipi(struct pt_regs *regs)
        return ret;
 }
 
-static void do_smp_send_nmi_ipi(int cpu)
+static void do_smp_send_nmi_ipi(int cpu, int type)
 {
+       if (smp_ops->cause_nmi_ipi && smp_ops->cause_nmi_ipi(cpu, type))
+               return;
        do_message_pass(cpu, PPC_MSG_NMI_IPI_SAFE);
 }
 
@@ -453,9 +455,6 @@ int smp_send_nmi_ipi(int cpu, int function, void *data,
        if (unlikely(!smp_ops))
                return 0;
 
-       /* Have no real NMI capability yet */
-       safe_udelay += hard_udelay;
-
        get_online_cpus();
 
        /* Take the nmi_ipi_busy count/lock with interrupts hard disabled */
@@ -482,7 +481,7 @@ int smp_send_nmi_ipi(int cpu, int function, void *data,
 
        if (safe_udelay) {
                for_each_cpu(c, &nmi_ipi_pending_mask)
-                       do_smp_send_nmi_ipi(c);
+                       do_smp_send_nmi_ipi(c, SMP_OP_NMI_TYPE_SAFE);
 
                do {
                        safe_udelay--;
@@ -492,6 +491,18 @@ int smp_send_nmi_ipi(int cpu, int function, void *data,
                } while (safe_udelay);
        }
 
+       if (hard_udelay) {
+               for_each_cpu(c, &nmi_ipi_pending_mask)
+                       do_smp_send_nmi_ipi(c, SMP_OP_NMI_TYPE_HARD);
+
+               do {
+                       hard_udelay--;
+                       udelay(1);
+                       if (cpumask_empty(&nmi_ipi_pending_mask))
+                               goto done;
+               } while (hard_udelay);
+       }
+
        ret = 0; /* Could not gather all CPUs */
        cpumask_clear(&nmi_ipi_pending_mask);
 done:
diff --git a/arch/powerpc/platforms/85xx/smp.c 
b/arch/powerpc/platforms/85xx/smp.c
index fe9f19e..cde7beb 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -343,6 +343,7 @@ static int smp_85xx_kick_cpu(int nr)
 }
 
 struct smp_ops_t smp_85xx_ops = {
+       .cause_nmi_ipi = NULL,
        .kick_cpu = smp_85xx_kick_cpu,
        .cpu_bootable = smp_generic_cpu_bootable,
 #ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c 
b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index af09bae..020e84a 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -105,6 +105,7 @@ smp_86xx_setup_cpu(int cpu_nr)
 
 
 struct smp_ops_t smp_86xx_ops = {
+       .cause_nmi_ipi = NULL,
        .message_pass = smp_mpic_message_pass,
        .probe = smp_mpic_probe,
        .kick_cpu = smp_86xx_kick_cpu,
diff --git a/arch/powerpc/platforms/chrp/smp.c 
b/arch/powerpc/platforms/chrp/smp.c
index b6c9a0d..1451504 100644
--- a/arch/powerpc/platforms/chrp/smp.c
+++ b/arch/powerpc/platforms/chrp/smp.c
@@ -44,6 +44,7 @@ static void smp_chrp_setup_cpu(int cpu_nr)
 
 /* CHRP with openpic */
 struct smp_ops_t chrp_smp_ops = {
+       .cause_nmi_ipi = NULL,
        .message_pass = smp_mpic_message_pass,
        .probe = smp_mpic_probe,
        .kick_cpu = smp_chrp_kick_cpu,
diff --git a/arch/powerpc/platforms/powermac/smp.c 
b/arch/powerpc/platforms/powermac/smp.c
index c9eb7d6..1d76e15 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -446,6 +446,7 @@ void __init smp_psurge_give_timebase(void)
 struct smp_ops_t psurge_smp_ops = {
        .message_pass   = NULL, /* Use smp_muxed_ipi_message_pass */
        .cause_ipi      = smp_psurge_cause_ipi,
+       .cause_nmi_ipi  = NULL,
        .probe          = smp_psurge_probe,
        .kick_cpu       = smp_psurge_kick_cpu,
        .setup_cpu      = smp_psurge_setup_cpu,
diff --git a/arch/powerpc/platforms/powernv/smp.c 
b/arch/powerpc/platforms/powernv/smp.c
index c789258..092ec1f 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -244,6 +244,7 @@ static int pnv_cpu_bootable(unsigned int nr)
 static struct smp_ops_t pnv_smp_ops = {
        .message_pass   = smp_muxed_ipi_message_pass,
        .cause_ipi      = NULL, /* Filled at runtime by xics_smp_probe() */
+       .cause_nmi_ipi  = NULL,
        .probe          = xics_smp_probe,
        .kick_cpu       = pnv_smp_kick_cpu,
        .setup_cpu      = pnv_smp_setup_cpu,
diff --git a/arch/powerpc/platforms/pseries/smp.c 
b/arch/powerpc/platforms/pseries/smp.c
index f6f83ae..0f6522c 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -209,6 +209,7 @@ static __init void pSeries_smp_probe(void)
 static struct smp_ops_t pseries_smp_ops = {
        .message_pass   = NULL, /* Use smp_muxed_ipi_message_pass */
        .cause_ipi      = NULL, /* Filled at runtime by pSeries_smp_probe() */
+       .cause_nmi_ipi  = NULL,
        .probe          = pSeries_smp_probe,
        .kick_cpu       = smp_pSeries_kick_cpu,
        .setup_cpu      = smp_setup_cpu,
-- 
2.10.2

Reply via email to