Commit fed55f49 authored by D Scott Phillips's avatar D Scott Phillips Committed by Marc Zyngier
Browse files

arm64: errata: Work around AmpereOne's erratum AC04_CPU_23



On AmpereOne AC04, updates to HCR_EL2 can rarely corrupt simultaneous
translations for data addresses initiated by load/store instructions.
Only instruction initiated translations are vulnerable, not translations
from prefetches for example. A DSB before the store to HCR_EL2 is
sufficient to prevent older instructions from hitting the window for
corruption, and an ISB after is sufficient to prevent younger
instructions from hitting the window for corruption.

Signed-off-by: default avatarD Scott Phillips <scott@os.amperecomputing.com>
Reviewed-by: default avatarOliver Upton <oliver.upton@linux.dev>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20250513184514.2678288-1-scott@os.amperecomputing.com


Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 92c749e4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Ampere         | AmpereOne AC04  | AC04_CPU_10     | AMPERE_ERRATUM_AC03_CPU_38  |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere         | AmpereOne AC04  | AC04_CPU_23     | AMPERE_ERRATUM_AC04_CPU_23  |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | Cortex-A510     | #2457168        | ARM64_ERRATUM_2457168       |
+----------------+-----------------+-----------------+-----------------------------+
+17 −0
Original line number Diff line number Diff line
@@ -464,6 +464,23 @@ config AMPERE_ERRATUM_AC03_CPU_38

	  If unsure, say Y.

config AMPERE_ERRATUM_AC04_CPU_23
        bool "AmpereOne: AC04_CPU_23:  Failure to synchronize writes to HCR_EL2 may corrupt address translations."
	default y
	help
	  This option adds an alternative code sequence to work around Ampere
	  errata AC04_CPU_23 on AmpereOne.

	  Updates to HCR_EL2 can rarely corrupt simultaneous translations for
	  data addresses initiated by load/store instructions. Only
	  instruction initiated translations are vulnerable, not translations
	  from prefetches for example. A DSB before the store to HCR_EL2 is
	  sufficient to prevent older instructions from hitting the window
	  for corruption, and an ISB after is sufficient to prevent younger
	  instructions from hitting the window for corruption.

	  If unsure, say Y.

config ARM64_WORKAROUND_CLEAN_CACHE
	bool

+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@

	orr	x0, x0, #HCR_E2H
.LnVHE_\@:
	msr	hcr_el2, x0
	msr_hcr_el2 x0
	isb
.endm

+2 −2
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ do { \
									\
	___hcr = read_sysreg(hcr_el2);					\
	if (!(___hcr & HCR_TGE)) {					\
		write_sysreg(___hcr | HCR_TGE, hcr_el2);		\
		write_sysreg_hcr(___hcr | HCR_TGE);			\
		isb();							\
	}								\
	/*								\
@@ -82,7 +82,7 @@ do { \
	 */								\
	barrier();							\
	if (!___ctx->cnt && !(___hcr & HCR_TGE))			\
		write_sysreg(___hcr, hcr_el2);				\
		write_sysreg_hcr(___hcr);				\
} while (0)

static inline void ack_bad_irq(unsigned int irq)
+27 −0
Original line number Diff line number Diff line
@@ -1091,6 +1091,15 @@
	__emit_inst(0xd5000000|(\sreg)|(.L__gpr_num_\rt))
	.endm

	.macro	msr_hcr_el2, reg
#if IS_ENABLED(CONFIG_AMPERE_ERRATUM_AC04_CPU_23)
	dsb	nsh
	msr	hcr_el2, \reg
	isb
#else
	msr	hcr_el2, \reg
#endif
	.endm
#else

#include <linux/bitfield.h>
@@ -1178,6 +1187,13 @@
		write_sysreg(__scs_new, sysreg);			\
} while (0)

#define sysreg_clear_set_hcr(clear, set) do {				\
	u64 __scs_val = read_sysreg(hcr_el2);				\
	u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set);		\
	if (__scs_new != __scs_val)					\
		write_sysreg_hcr(__scs_new);			\
} while (0)

#define sysreg_clear_set_s(sysreg, clear, set) do {			\
	u64 __scs_val = read_sysreg_s(sysreg);				\
	u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set);		\
@@ -1185,6 +1201,17 @@
		write_sysreg_s(__scs_new, sysreg);			\
} while (0)

#define write_sysreg_hcr(__val) do {					\
	if (IS_ENABLED(CONFIG_AMPERE_ERRATUM_AC04_CPU_23) &&		\
	   (!system_capabilities_finalized() ||				\
	    alternative_has_cap_unlikely(ARM64_WORKAROUND_AMPERE_AC04_CPU_23))) \
		asm volatile("dsb nsh; msr hcr_el2, %x0; isb"		\
			     : : "rZ" (__val));				\
	else								\
		asm volatile("msr hcr_el2, %x0"				\
			     : : "rZ" (__val));				\
} while (0)

#define read_sysreg_par() ({						\
	u64 par;							\
	asm(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412));	\
Loading