Skip to content

Commit

Permalink
powerpc: move NMI entry/exit code into wrapper
Browse files Browse the repository at this point in the history
This moves the common NMI entry and exit code into the interrupt handler
wrappers.

This changes the behaviour of soft-NMI (watchdog) and HMI interrupts, and
also MCE interrupts on 64e, by adding missing parts of the NMI entry to
them.

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-40-npiggin@gmail.com
  • Loading branch information
Nicholas Piggin authored and Michael Ellerman committed Feb 8, 2021
1 parent 74c3354 commit 118178e
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 46 deletions.
28 changes: 28 additions & 0 deletions arch/powerpc/include/asm/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,42 @@ static inline void interrupt_async_exit_prepare(struct pt_regs *regs, struct int
}

struct interrupt_nmi_state {
#ifdef CONFIG_PPC64
u8 ftrace_enabled;
#endif
};

static inline void interrupt_nmi_enter_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state)
{
#ifdef CONFIG_PPC64
/* Allow DEC and PMI to be traced when they are soft-NMI */
if (TRAP(regs) != 0x900 && TRAP(regs) != 0xf00 && TRAP(regs) != 0x260) {
state->ftrace_enabled = this_cpu_get_ftrace_enabled();
this_cpu_set_ftrace_enabled(0);
}
#endif

/*
* Do not use nmi_enter() for pseries hash guest taking a real-mode
* NMI because not everything it touches is within the RMA limit.
*/
if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64) ||
!firmware_has_feature(FW_FEATURE_LPAR) ||
radix_enabled() || (mfmsr() & MSR_DR))
nmi_enter();
}

static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state)
{
if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64) ||
!firmware_has_feature(FW_FEATURE_LPAR) ||
radix_enabled() || (mfmsr() & MSR_DR))
nmi_exit();

#ifdef CONFIG_PPC64
if (TRAP(regs) != 0x900 && TRAP(regs) != 0xf00 && TRAP(regs) != 0x260)
this_cpu_set_ftrace_enabled(state->ftrace_enabled);
#endif
}

/**
Expand Down
11 changes: 0 additions & 11 deletions arch/powerpc/kernel/mce.c
Original file line number Diff line number Diff line change
Expand Up @@ -587,12 +587,6 @@ EXPORT_SYMBOL_GPL(machine_check_print_event_info);
DEFINE_INTERRUPT_HANDLER_NMI(machine_check_early)
{
long handled = 0;
u8 ftrace_enabled = this_cpu_get_ftrace_enabled();

this_cpu_set_ftrace_enabled(0);
/* Do not use nmi_enter/exit for pseries hpte guest */
if (radix_enabled() || !firmware_has_feature(FW_FEATURE_LPAR))
nmi_enter();

hv_nmi_check_nonrecoverable(regs);

Expand All @@ -602,11 +596,6 @@ DEFINE_INTERRUPT_HANDLER_NMI(machine_check_early)
if (ppc_md.machine_check_early)
handled = ppc_md.machine_check_early(regs);

if (radix_enabled() || !firmware_has_feature(FW_FEATURE_LPAR))
nmi_exit();

this_cpu_set_ftrace_enabled(ftrace_enabled);

return handled;
}

Expand Down
35 changes: 6 additions & 29 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,6 @@ DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception)
{
unsigned long hsrr0, hsrr1;
bool saved_hsrrs = false;
u8 ftrace_enabled = this_cpu_get_ftrace_enabled();

this_cpu_set_ftrace_enabled(0);

nmi_enter();

/*
* System reset can interrupt code where HSRRs are live and MSR[RI]=1.
Expand Down Expand Up @@ -514,10 +509,6 @@ DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception)
mtspr(SPRN_HSRR1, hsrr1);
}

nmi_exit();

this_cpu_set_ftrace_enabled(ftrace_enabled);

/* What should we do here? We could issue a shutdown or hard reset. */

return 0;
Expand Down Expand Up @@ -809,6 +800,12 @@ void die_mce(const char *str, struct pt_regs *regs, long err)
}
NOKPROBE_SYMBOL(die_mce);

/*
* BOOK3S_64 does not 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).
*/
#ifdef CONFIG_PPC_BOOK3S_64
DEFINE_INTERRUPT_HANDLER_ASYNC(machine_check_exception)
#else
Expand All @@ -817,20 +814,6 @@ DEFINE_INTERRUPT_HANDLER_NMI(machine_check_exception)
{
int recover = 0;

/*
* BOOK3S_64 does not 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).
*
* This is silly. The BOOK3S_64 should just call a different function
* rather than expecting semantics to magically change. Something
* like 'non_nmi_machine_check_exception()', perhaps?
*/
const bool nmi = !IS_ENABLED(CONFIG_PPC_BOOK3S_64);

if (nmi) nmi_enter();

__this_cpu_inc(irq_stat.mce_exceptions);

add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
Expand Down Expand Up @@ -862,8 +845,6 @@ DEFINE_INTERRUPT_HANDLER_NMI(machine_check_exception)
if (!(regs->msr & MSR_RI))
die_mce("Unrecoverable Machine check", regs, SIGBUS);

if (nmi) nmi_exit();

#ifdef CONFIG_PPC_BOOK3S_64
return;
#else
Expand Down Expand Up @@ -1892,14 +1873,10 @@ DEFINE_INTERRUPT_HANDLER(vsx_unavailable_tm)
DECLARE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi);
DEFINE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi)
{
nmi_enter();

__this_cpu_inc(irq_stat.pmu_irqs);

perf_irq(regs);

nmi_exit();

return 0;
}
#endif
Expand Down
10 changes: 4 additions & 6 deletions arch/powerpc/kernel/watchdog.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,19 +255,20 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
int cpu = raw_smp_processor_id();
u64 tb;

/* should only arrive from kernel, with irqs disabled */
WARN_ON_ONCE(!arch_irq_disabled_regs(regs));

if (!cpumask_test_cpu(cpu, &wd_cpus_enabled))
return 0;

nmi_enter();

__this_cpu_inc(irq_stat.soft_nmi_irqs);

tb = get_tb();
if (tb - per_cpu(wd_timer_tb, cpu) >= wd_panic_timeout_tb) {
wd_smp_lock(&flags);
if (cpumask_test_cpu(cpu, &wd_smp_cpus_stuck)) {
wd_smp_unlock(&flags);
goto out;
return 0;
}
set_cpu_stuck(cpu, tb);

Expand All @@ -291,9 +292,6 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
if (wd_panic_timeout_tb < 0x7fffffff)
mtspr(SPRN_DEC, wd_panic_timeout_tb);

out:
nmi_exit();

return 0;
}

Expand Down

0 comments on commit 118178e

Please sign in to comment.