powerpc/64s: Fix unrecoverable MCE calling async handler from NMI
[sfrench/cifs-2.6.git] / arch / powerpc / kernel / traps.c
index e453b666613bba041f86568f6a4ed5d2c7ea9761..11741703d26e0719b7b2d7488ebb54203fa2026d 100644 (file)
@@ -796,24 +796,22 @@ void die_mce(const char *str, struct pt_regs *regs, long err)
         * do_exit() checks for in_interrupt() and panics in that case, so
         * exit the irq/nmi before calling die.
         */
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_64))
-               irq_exit();
-       else
+       if (in_nmi())
                nmi_exit();
+       else
+               irq_exit();
        die(str, regs, err);
 }
 
 /*
- * BOOK3S_64 does not call this handler as a non-maskable interrupt
+ * BOOK3S_64 does not usually call this handler as a non-maskable interrupt
  * (it uses its own early real-mode handler to handle the MCE proper
  * and then raises irq_work to call this handler when interrupts are
- * enabled).
+ * enabled). The only time when this is not true is if the early handler
+ * is unrecoverable, then it does call this directly to try to get a
+ * message out.
  */
-#ifdef CONFIG_PPC_BOOK3S_64
-DEFINE_INTERRUPT_HANDLER_ASYNC(machine_check_exception)
-#else
-DEFINE_INTERRUPT_HANDLER_NMI(machine_check_exception)
-#endif
+static void __machine_check_exception(struct pt_regs *regs)
 {
        int recover = 0;
 
@@ -847,12 +845,19 @@ bail:
        /* Must die if the interrupt is not recoverable */
        if (regs_is_unrecoverable(regs))
                die_mce("Unrecoverable Machine check", regs, SIGBUS);
+}
 
 #ifdef CONFIG_PPC_BOOK3S_64
-       return;
-#else
-       return 0;
+DEFINE_INTERRUPT_HANDLER_ASYNC(machine_check_exception_async)
+{
+       __machine_check_exception(regs);
+}
 #endif
+DEFINE_INTERRUPT_HANDLER_NMI(machine_check_exception)
+{
+       __machine_check_exception(regs);
+
+       return 0;
 }
 
 DEFINE_INTERRUPT_HANDLER(SMIException) /* async? */