powerpc/64e/interrupt: NMI save irq soft-mask state in C
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. 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?) Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20210316104206.407354-6-npiggin@gmail.com
This commit is contained in:
parent
0c2472de23
commit
3db8aa10de
|
@ -149,18 +149,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;
|
||||
|
||||
|
@ -173,9 +187,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);
|
||||
}
|
||||
|
@ -204,16 +217,14 @@ static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct inter
|
|||
*/
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -426,6 +437,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);
|
||||
|
@ -449,7 +461,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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -1078,6 +1078,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,
|
||||
|
@ -2181,10 +2191,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
|
||||
|
||||
|
|
Loading…
Reference in New Issue