Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5080332c authored by Michael Neuling's avatar Michael Neuling Committed by Michael Ellerman
Browse files

powerpc/64s: Add workaround for P9 vector CI load issue



POWER9 DD2.1 and earlier has an issue where some cache inhibited
vector load will return bad data. The workaround is two part, one
firmware/microcode part triggers HMI interrupts when hitting such
loads, the other part is this patch which then emulates the
instructions in Linux.

The affected instructions are limited to lxvd2x, lxvw4x, lxvb16x and
lxvh8x.

When an instruction triggers the HMI, all threads in the core will be
sent to the HMI handler, not just the one running the vector load.

In general, these spurious HMIs are detected by the emulation code and
we just return back to the running process. Unfortunately, if a
spurious interrupt occurs on a vector load that's to normal memory we
have no way to detect that it's spurious (unless we walk the page
tables, which is very expensive). In this case we emulate the load but
we need do so using a vector load itself to ensure 128bit atomicity is
preserved.

Some additional debugfs emulated instruction counters are added also.

Signed-off-by: default avatarMichael Neuling <mikey@neuling.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
[mpe: Switch CONFIG_PPC_BOOK3S_64 to CONFIG_VSX to unbreak the build]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent b9fde58d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -55,6 +55,10 @@ extern struct ppc_emulated {
	struct ppc_emulated_entry mfdscr;
	struct ppc_emulated_entry mtdscr;
	struct ppc_emulated_entry lq_stq;
	struct ppc_emulated_entry lxvw4x;
	struct ppc_emulated_entry lxvh8x;
	struct ppc_emulated_entry lxvd2x;
	struct ppc_emulated_entry lxvb16x;
#endif
} ppc_emulated;

+1 −0
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ struct paca_struct {
	 */
	u16 in_mce;
	u8 hmi_event_available;		/* HMI event is available */
	u8 hmi_p9_special_emu;		/* HMI P9 special emulation */
#endif

	/* Stuff for accurate time accounting */
+17 −0
Original line number Diff line number Diff line
@@ -173,6 +173,23 @@ do { \

extern long __get_user_bad(void);

/*
 * This does an atomic 128 byte aligned load from userspace.
 * Upto caller to do enable_kernel_vmx() before calling!
 */
#define __get_user_atomic_128_aligned(kaddr, uaddr, err)		\
	__asm__ __volatile__(				\
		"1:	lvx  0,0,%1	# get user\n"	\
		" 	stvx 0,0,%2	# put kernel\n"	\
		"2:\n"					\
		".section .fixup,\"ax\"\n"		\
		"3:	li %0,%3\n"			\
		"	b 2b\n"				\
		".previous\n"				\
		EX_TABLE(1b, 3b)			\
		: "=r" (err)			\
		: "b" (uaddr), "b" (kaddr), "i" (-EFAULT), "0" (err))

#define __get_user_asm(x, addr, err, op)		\
	__asm__ __volatile__(				\
		"1:	"op" %1,0(%2)	# get_user\n"	\
+12 −4
Original line number Diff line number Diff line
@@ -1010,6 +1010,8 @@ TRAMP_REAL_BEGIN(hmi_exception_early)
	EXCEPTION_PROLOG_COMMON_3(0xe60)
	addi	r3,r1,STACK_FRAME_OVERHEAD
	BRANCH_LINK_TO_FAR(hmi_exception_realmode) /* Function call ABI */
	cmpdi	cr0,r3,0

	/* Windup the stack. */
	/* Move original HSRR0 and HSRR1 into the respective regs */
	ld	r9,_MSR(r1)
@@ -1026,10 +1028,15 @@ TRAMP_REAL_BEGIN(hmi_exception_early)
	REST_8GPRS(2, r1)
	REST_GPR(10, r1)
	ld	r11,_CCR(r1)
	REST_2GPRS(12, r1)
	bne	1f
	mtcr	r11
	REST_GPR(11, r1)
	REST_2GPRS(12, r1)
	/* restore original r1. */
	ld	r1,GPR1(r1)
	hrfid

1:	mtcr	r11
	REST_GPR(11, r1)
	ld	r1,GPR1(r1)

	/*
@@ -1042,8 +1049,9 @@ hmi_exception_after_realmode:
	EXCEPTION_PROLOG_0(PACA_EXGEN)
	b	tramp_real_hmi_exception

EXC_COMMON_ASYNC(hmi_exception_common, 0xe60, handle_hmi_exception)

EXC_COMMON_BEGIN(hmi_exception_common)
EXCEPTION_COMMON(PACA_EXGEN, 0xe60, hmi_exception_common, handle_hmi_exception,
        ret_from_except, FINISH_NAP;ADD_NVGPRS;ADD_RECONCILE;RUNLATCH_ON)

EXC_REAL_OOL_MASKABLE_HV(h_doorbell, 0xe80, 0x20)
EXC_VIRT_OOL_MASKABLE_HV(h_doorbell, 0x4e80, 0x20, 0xe80)
+29 −1
Original line number Diff line number Diff line
@@ -470,6 +470,34 @@ long hmi_exception_realmode(struct pt_regs *regs)
{
	__this_cpu_inc(irq_stat.hmi_exceptions);

#ifdef CONFIG_PPC_BOOK3S_64
	/* Workaround for P9 vector CI loads (see p9_hmi_special_emu) */
	if (pvr_version_is(PVR_POWER9)) {
		unsigned long hmer = mfspr(SPRN_HMER);

		/* Do we have the debug bit set */
		if (hmer & PPC_BIT(17)) {
			hmer &= ~PPC_BIT(17);
			mtspr(SPRN_HMER, hmer);

			/*
			 * Now to avoid problems with soft-disable we
			 * only do the emulation if we are coming from
			 * user space
			 */
			if (user_mode(regs))
				local_paca->hmi_p9_special_emu = 1;

			/*
			 * Don't bother going to OPAL if that's the
			 * only relevant bit.
			 */
			if (!(hmer & mfspr(SPRN_HMEER)))
				return local_paca->hmi_p9_special_emu;
		}
	}
#endif /* CONFIG_PPC_BOOK3S_64 */

	wait_for_subcore_guest_exit();

	if (ppc_md.hmi_exception_early)
@@ -477,5 +505,5 @@ long hmi_exception_realmode(struct pt_regs *regs)

	wait_for_tb_resync();

	return 0;
	return 1;
}
Loading