64e non-maskable interrupts save the state of the irq soft-mask in
asm. This can be done in C in interrupt wrappers as 64s does.

Signed-off-by: Nicholas Piggin <npig...@gmail.com>

I haven't been able to test this with qemu because it doesn't seem
to cause FSL bookE WDT interrupts.

This makes WatchdogException an NMI interrupt, which affects 32-bit
as well (okay, or create a new handler?)
---
 arch/powerpc/include/asm/interrupt.h | 32 +++++++++++++++++--------
 arch/powerpc/kernel/exceptions-64e.S | 36 ++++------------------------
 arch/powerpc/kernel/traps.c          | 13 +++++++++-
 3 files changed, 38 insertions(+), 43 deletions(-)

diff --git a/arch/powerpc/include/asm/interrupt.h 
b/arch/powerpc/include/asm/interrupt.h
index 7c633896d758..305d7c17a4cf 100644
--- a/arch/powerpc/include/asm/interrupt.h
+++ b/arch/powerpc/include/asm/interrupt.h
@@ -130,18 +130,32 @@ static inline void interrupt_async_exit_prepare(struct 
pt_regs *regs, struct int
 
 struct interrupt_nmi_state {
 #ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_BOOK3S_64
        u8 irq_soft_mask;
        u8 irq_happened;
-#endif
        u8 ftrace_enabled;
 #endif
 };
 
+static inline bool nmi_disables_ftrace(struct pt_regs *regs)
+{
+       /* Allow DEC and PMI to be traced when they are soft-NMI */
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S_64)) {
+               if (TRAP(regs) == 0x900)
+                      return false;
+               if (TRAP(regs) == 0xf00)
+                      return false;
+       }
+       if (IS_ENABLED(CONFIG_PPC_BOOK3E)) {
+               if (TRAP(regs) == 0x260)
+                       return false;
+       }
+
+       return true;
+}
+
 static inline void interrupt_nmi_enter_prepare(struct pt_regs *regs, struct 
interrupt_nmi_state *state)
 {
 #ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_BOOK3S_64
        state->irq_soft_mask = local_paca->irq_soft_mask;
        state->irq_happened = local_paca->irq_happened;
 
@@ -154,9 +168,8 @@ static inline void interrupt_nmi_enter_prepare(struct 
pt_regs *regs, struct inte
        local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
 
        /* Don't do any per-CPU operations until interrupt state is fixed */
-#endif
-       /* Allow DEC and PMI to be traced when they are soft-NMI */
-       if (TRAP(regs) != 0x900 && TRAP(regs) != 0xf00 && TRAP(regs) != 0x260) {
+
+       if (nmi_disables_ftrace(regs)) {
                state->ftrace_enabled = this_cpu_get_ftrace_enabled();
                this_cpu_set_ftrace_enabled(0);
        }
@@ -180,16 +193,14 @@ static inline void interrupt_nmi_exit_prepare(struct 
pt_regs *regs, struct inter
                nmi_exit();
 
 #ifdef CONFIG_PPC64
-       if (TRAP(regs) != 0x900 && TRAP(regs) != 0xf00 && TRAP(regs) != 0x260)
+       if (nmi_disables_ftrace(regs))
                this_cpu_set_ftrace_enabled(state->ftrace_enabled);
 
-#ifdef CONFIG_PPC_BOOK3S_64
        /* Check we didn't change the pending interrupt mask. */
        WARN_ON_ONCE((state->irq_happened | PACA_IRQ_HARD_DIS) != 
local_paca->irq_happened);
        local_paca->irq_happened = state->irq_happened;
        local_paca->irq_soft_mask = state->irq_soft_mask;
 #endif
-#endif
 }
 
 /*
@@ -402,6 +413,7 @@ DECLARE_INTERRUPT_HANDLER(SMIException);
 DECLARE_INTERRUPT_HANDLER(handle_hmi_exception);
 DECLARE_INTERRUPT_HANDLER(unknown_exception);
 DECLARE_INTERRUPT_HANDLER_ASYNC(unknown_async_exception);
+DECLARE_INTERRUPT_HANDLER_NMI(unknown_nmi_exception);
 DECLARE_INTERRUPT_HANDLER(instruction_breakpoint_exception);
 DECLARE_INTERRUPT_HANDLER(RunModeException);
 DECLARE_INTERRUPT_HANDLER(single_step_exception);
@@ -425,7 +437,7 @@ DECLARE_INTERRUPT_HANDLER(altivec_assist_exception);
 DECLARE_INTERRUPT_HANDLER(CacheLockingException);
 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointException);
 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointRoundException);
-DECLARE_INTERRUPT_HANDLER(WatchdogException);
+DECLARE_INTERRUPT_HANDLER_NMI(WatchdogException);
 DECLARE_INTERRUPT_HANDLER(kernel_bad_stack);
 
 /* slb.c */
diff --git a/arch/powerpc/kernel/exceptions-64e.S 
b/arch/powerpc/kernel/exceptions-64e.S
index 7a2e7be33092..18be576fc0b3 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -63,9 +63,6 @@
        ld      reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1)
 
 special_reg_save:
-       lbz     r9,PACAIRQHAPPENED(r13)
-       RECONCILE_IRQ_STATE(r3,r4)
-
        /*
         * We only need (or have stack space) to save this stuff if
         * we interrupted the kernel.
@@ -119,15 +116,11 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_MAS5,r10
        mtspr   SPRN_MAS8,r10
 END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
-       SPECIAL_EXC_STORE(r9,IRQHAPPENED)
-
        mfspr   r10,SPRN_DEAR
        SPECIAL_EXC_STORE(r10,DEAR)
        mfspr   r10,SPRN_ESR
        SPECIAL_EXC_STORE(r10,ESR)
 
-       lbz     r10,PACAIRQSOFTMASK(r13)
-       SPECIAL_EXC_STORE(r10,SOFTE)
        ld      r10,_NIP(r1)
        SPECIAL_EXC_STORE(r10,CSRR0)
        ld      r10,_MSR(r1)
@@ -194,27 +187,6 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_MAS8,r10
 END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
 
-       lbz     r6,PACAIRQSOFTMASK(r13)
-       ld      r5,SOFTE(r1)
-
-       /* Interrupts had better not already be enabled... */
-       tweqi   r6,IRQS_ENABLED
-
-       andi.   r6,r5,IRQS_DISABLED
-       bne     1f
-
-       TRACE_ENABLE_INTS
-       stb     r5,PACAIRQSOFTMASK(r13)
-1:
-       /*
-        * Restore PACAIRQHAPPENED rather than setting it based on
-        * the return MSR[EE], since we could have interrupted
-        * interrupt replay or other inconsistent transitory
-        * states that must remain that way.
-        */
-       SPECIAL_EXC_LOAD(r10,IRQHAPPENED)
-       stb     r10,PACAIRQHAPPENED(r13)
-
        SPECIAL_EXC_LOAD(r10,DEAR)
        mtspr   SPRN_DEAR,r10
        SPECIAL_EXC_LOAD(r10,ESR)
@@ -566,7 +538,7 @@ __end_interrupts:
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      unknown_exception
+       bl      unknown_nmi_exception
        b       ret_from_crit_except
 
 /* Machine Check Interrupt */
@@ -702,7 +674,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #ifdef CONFIG_BOOKE_WDT
        bl      WatchdogException
 #else
-       bl      unknown_exception
+       bl      unknown_nmi_exception
 #endif
        b       ret_from_crit_except
 
@@ -886,7 +858,7 @@ kernel_dbg_exc:
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      unknown_exception
+       bl      unknown_nmi_exception
        b       ret_from_crit_except
 
 /*
@@ -910,7 +882,7 @@ kernel_dbg_exc:
        bl      special_reg_save
        CHECK_NAPPING();
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      unknown_exception
+       bl      unknown_nmi_exception
        b       ret_from_crit_except
 
 /* Hypervisor call */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index c74e7727860a..97b5f3d83ff7 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1079,6 +1079,16 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(unknown_async_exception)
        _exception(SIGTRAP, regs, TRAP_UNK, 0);
 }
 
+DEFINE_INTERRUPT_HANDLER_NMI(unknown_nmi_exception)
+{
+       printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+
+       _exception(SIGTRAP, regs, TRAP_UNK, 0);
+
+       return 0;
+}
+
 DEFINE_INTERRUPT_HANDLER(instruction_breakpoint_exception)
 {
        if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5,
@@ -2183,10 +2193,11 @@ void __attribute__ ((weak)) WatchdogHandler(struct 
pt_regs *regs)
        return;
 }
 
-DEFINE_INTERRUPT_HANDLER(WatchdogException) /* XXX NMI? async? */
+DEFINE_INTERRUPT_HANDLER_NMI(WatchdogException)
 {
        printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n");
        WatchdogHandler(regs);
+       return 0;
 }
 #endif
 
-- 
2.23.0

Reply via email to