]> git.baikalelectronics.ru Git - kernel.git/commitdiff
powerpc: introduce die_mce
authorNicholas Piggin <npiggin@gmail.com>
Sat, 30 Jan 2021 13:08:33 +0000 (23:08 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 8 Feb 2021 13:02:11 +0000 (00:02 +1100)
As explained by commit daf00ae71dad ("powerpc/traps: restore
recoverability of machine_check interrupts"), die() can't be called from
within nmi_enter to nicely kill a process context that was interrupted.
nmi_exit must be called first.

This adds a function die_mce which takes care of this for machine check
handlers.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210130130852.2952424-24-npiggin@gmail.com
arch/powerpc/include/asm/bug.h
arch/powerpc/kernel/traps.c
arch/powerpc/platforms/powernv/opal.c
arch/powerpc/platforms/pseries/ras.c

index 8f09ddae93054ffbd71ae59e0e16f01fcf4add1b..c10ae0a9bbaf3945666c0b8ede666ccef3caa135 100644 (file)
@@ -118,6 +118,7 @@ void do_bad_page_fault_segv(struct pt_regs *regs);
 extern void _exception(int, struct pt_regs *, int, unsigned long);
 extern void _exception_pkey(struct pt_regs *, unsigned long, int);
 extern void die(const char *, struct pt_regs *, long);
+void die_mce(const char *str, struct pt_regs *regs, long err);
 extern bool die_will_crash(void);
 extern void panic_flush_kmsg_start(void);
 extern void panic_flush_kmsg_end(void);
index 6691774fe1fbf299e223813f402f52abbe66f0c2..f9ef183a5454911366f04f196bf2c7e09f2305f3 100644 (file)
@@ -789,6 +789,19 @@ int machine_check_generic(struct pt_regs *regs)
 }
 #endif /* everything else */
 
+void die_mce(const char *str, struct pt_regs *regs, long err)
+{
+       /*
+        * The machine check wants to kill the interrupted context, but
+        * 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))
+               nmi_exit();
+       die(str, regs, err);
+}
+NOKPROBE_SYMBOL(die_mce);
+
 void machine_check_exception(struct pt_regs *regs)
 {
        int recover = 0;
@@ -831,15 +844,11 @@ void machine_check_exception(struct pt_regs *regs)
        if (check_io_access(regs))
                goto bail;
 
-       if (nmi) nmi_exit();
-
-       die("Machine check", regs, SIGBUS);
+       die_mce("Machine check", regs, SIGBUS);
 
        /* Must die if the interrupt is not recoverable */
        if (!(regs->msr & MSR_RI))
-               die("Unrecoverable Machine check", regs, SIGBUS);
-
-       return;
+               die_mce("Unrecoverable Machine check", regs, SIGBUS);
 
 bail:
        if (nmi) nmi_exit();
index c61c3b62c8c628c290c9bc1846b35378d480ccfd..303d7c775740308af7651e2036c2545569106ebd 100644 (file)
@@ -624,7 +624,7 @@ static int opal_recover_mce(struct pt_regs *regs,
                         */
                        recovered = 0;
                } else {
-                       die("Machine check", regs, SIGBUS);
+                       die_mce("Machine check", regs, SIGBUS);
                        recovered = 1;
                }
        }
index d2fca1aa6742aee4580ce6fe63a70969c979565c..92c08fe893cfbac21f09206bf674aeb15071a983 100644 (file)
@@ -808,7 +808,7 @@ static int recover_mce(struct pt_regs *regs, struct machine_check_event *evt)
                         */
                        recovered = 0;
                } else {
-                       die("Machine check", regs, SIGBUS);
+                       die_mce("Machine check", regs, SIGBUS);
                        recovered = 1;
                }
        }