Commit 118178e6 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc: move NMI entry/exit code into wrapper



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: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210130130852.2952424-40-npiggin@gmail.com
parent 74c3354b
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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
}

/**
+0 −11
Original line number Diff line number Diff line
@@ -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);

@@ -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;
}

+6 −29
Original line number Diff line number Diff line
@@ -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.
@@ -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;
@@ -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
@@ -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);
@@ -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
@@ -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
+4 −6
Original line number Diff line number Diff line
@@ -255,11 +255,12 @@ 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();
@@ -267,7 +268,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
		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);

@@ -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;
}