[PATCH v2] arm64: errata: Work around AmpereOne's erratum AC04_CPU_23

D Scott Phillips posted 1 patch 9 months, 2 weeks ago
There is a newer version of this series
arch/arm64/Kconfig                      | 17 +++++++++++++++++
arch/arm64/include/asm/hardirq.h        |  4 ++--
arch/arm64/include/asm/sysreg.h         | 10 ++++++++++
arch/arm64/kernel/cpu_errata.c          | 14 ++++++++++++++
arch/arm64/kvm/at.c                     |  8 ++++----
arch/arm64/kvm/hyp/include/hyp/switch.h |  2 +-
arch/arm64/kvm/hyp/nvhe/mem_protect.c   |  2 +-
arch/arm64/kvm/hyp/nvhe/switch.c        |  2 +-
arch/arm64/kvm/hyp/vhe/switch.c         |  2 +-
arch/arm64/kvm/hyp/vhe/tlb.c            |  4 ++--
arch/arm64/tools/cpucaps                |  1 +
11 files changed, 54 insertions(+), 12 deletions(-)
[PATCH v2] arm64: errata: Work around AmpereOne's erratum AC04_CPU_23
Posted by D Scott Phillips 9 months, 2 weeks ago
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: D Scott Phillips <scott@os.amperecomputing.com>
---
v1: https://lore.kernel.org/kvmarm/20250415154711.1698544-2-scott@os.amperecomputing.com/
Changes since v1:
 - Add a write_sysreg_hcr() helper (Oliver)
 - Add more specific wording in the errata description (Oliver & Marc)

 arch/arm64/Kconfig                      | 17 +++++++++++++++++
 arch/arm64/include/asm/hardirq.h        |  4 ++--
 arch/arm64/include/asm/sysreg.h         | 10 ++++++++++
 arch/arm64/kernel/cpu_errata.c          | 14 ++++++++++++++
 arch/arm64/kvm/at.c                     |  8 ++++----
 arch/arm64/kvm/hyp/include/hyp/switch.h |  2 +-
 arch/arm64/kvm/hyp/nvhe/mem_protect.c   |  2 +-
 arch/arm64/kvm/hyp/nvhe/switch.c        |  2 +-
 arch/arm64/kvm/hyp/vhe/switch.c         |  2 +-
 arch/arm64/kvm/hyp/vhe/tlb.c            |  4 ++--
 arch/arm64/tools/cpucaps                |  1 +
 11 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index a182295e6f08b..3ae4e80e3002b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -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
 
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index cbfa7b6f2e098..77d6b8c63d4e6 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -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)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 2639d3633073d..d41eeba7f8201 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -1185,6 +1185,16 @@
 		write_sysreg_s(__scs_new, sysreg);			\
 } while (0)
 
+#define write_sysreg_hcr(__val) do {					\
+	if(IS_ENABLED(CONFIG_AMPERE_ERRATUM_AC04_CPU_23) &&		\
+	   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));	\
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index b55f5f7057502..60f1b70fc0845 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -557,6 +557,13 @@ static const struct midr_range erratum_ac03_cpu_38_list[] = {
 };
 #endif
 
+#ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
+static const struct midr_range erratum_ac04_cpu_23_list[] = {
+	MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
+	{},
+};
+#endif
+
 const struct arm64_cpu_capabilities arm64_errata[] = {
 #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
 	{
@@ -875,6 +882,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 		.capability = ARM64_WORKAROUND_AMPERE_AC03_CPU_38,
 		ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_38_list),
 	},
+#endif
+#ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
+	{
+		.desc = "AmpereOne erratum AC04_CPU_23",
+		.capability = ARM64_WORKAROUND_AMPERE_AC04_CPU_23,
+		ERRATA_MIDR_RANGE_LIST(erratum_ac04_cpu_23_list),
+	},
 #endif
 	{
 		.desc = "Broken CNTVOFF_EL2",
diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c
index f74a66ce3064b..9c13e70fadf5e 100644
--- a/arch/arm64/kvm/at.c
+++ b/arch/arm64/kvm/at.c
@@ -516,7 +516,7 @@ static void __mmu_config_save(struct mmu_config *config)
 
 static void __mmu_config_restore(struct mmu_config *config)
 {
-	write_sysreg(config->hcr,	hcr_el2);
+	write_sysreg_hcr(config->hcr);
 
 	/*
 	 * ARM errata 1165522 and 1530923 require TGE to be 1 before
@@ -1267,7 +1267,7 @@ static u64 __kvm_at_s1e01_fast(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
 
 skip_mmu_switch:
 	/* Clear TGE, enable S2 translation, we're rolling */
-	write_sysreg((config.hcr & ~HCR_TGE) | HCR_VM,	hcr_el2);
+	write_sysreg_hcr((config.hcr & ~HCR_TGE) | HCR_VM);
 	isb();
 
 	switch (op) {
@@ -1350,7 +1350,7 @@ void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
 		if (!vcpu_el2_e2h_is_set(vcpu))
 			val |= HCR_NV | HCR_NV1;
 
-		write_sysreg(val, hcr_el2);
+		write_sysreg_hcr(val);
 		isb();
 
 		par = SYS_PAR_EL1_F;
@@ -1375,7 +1375,7 @@ void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
 		if (!fail)
 			par = read_sysreg_par();
 
-		write_sysreg(hcr, hcr_el2);
+		write_sysreg_hcr(hcr);
 		isb();
 	}
 
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index b741ea6aefa58..06aa37dbc957d 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -301,7 +301,7 @@ static inline void ___activate_traps(struct kvm_vcpu *vcpu, u64 hcr)
 	if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM))
 		hcr |= HCR_TVM;
 
-	write_sysreg(hcr, hcr_el2);
+	write_sysreg_hcr(hcr);
 
 	if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index 2a5284f749b42..3aca6278d2f6d 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -309,7 +309,7 @@ int __pkvm_prot_finalize(void)
 	 */
 	kvm_flush_dcache_to_poc(params, sizeof(*params));
 
-	write_sysreg(params->hcr_el2, hcr_el2);
+	write_sysreg_hcr(params->hcr_el2);
 	__load_stage2(&host_mmu.arch.mmu, &host_mmu.arch);
 
 	/*
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index 7d2ba6ef02618..4024fafbe3594 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -142,7 +142,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
 
 	__deactivate_traps_common(vcpu);
 
-	write_sysreg(this_cpu_ptr(&kvm_init_params)->hcr_el2, hcr_el2);
+	write_sysreg_hcr(this_cpu_ptr(&kvm_init_params)->hcr_el2);
 
 	__deactivate_cptr_traps(vcpu);
 	write_sysreg(__kvm_hyp_host_vector, vbar_el2);
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 731a0378ed132..faacdfb328af6 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -184,7 +184,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
 
 	___deactivate_traps(vcpu);
 
-	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
+	write_sysreg_hcr(HCR_HOST_VHE_FLAGS);
 
 	if (has_cntpoff()) {
 		struct timer_map map;
diff --git a/arch/arm64/kvm/hyp/vhe/tlb.c b/arch/arm64/kvm/hyp/vhe/tlb.c
index 3d50a1bd2bdbc..ec25698186297 100644
--- a/arch/arm64/kvm/hyp/vhe/tlb.c
+++ b/arch/arm64/kvm/hyp/vhe/tlb.c
@@ -63,7 +63,7 @@ static void enter_vmid_context(struct kvm_s2_mmu *mmu,
 	__load_stage2(mmu, mmu->arch);
 	val = read_sysreg(hcr_el2);
 	val &= ~HCR_TGE;
-	write_sysreg(val, hcr_el2);
+	write_sysreg_hcr(val);
 	isb();
 }
 
@@ -73,7 +73,7 @@ static void exit_vmid_context(struct tlb_inv_context *cxt)
 	 * We're done with the TLB operation, let's restore the host's
 	 * view of HCR_EL2.
 	 */
-	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
+	write_sysreg_hcr(HCR_HOST_VHE_FLAGS);
 	isb();
 
 	/* ... and the stage-2 MMU context that we switched away from */
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 772c1b008e437..72f10b74ce807 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -94,6 +94,7 @@ WORKAROUND_2457168
 WORKAROUND_2645198
 WORKAROUND_2658417
 WORKAROUND_AMPERE_AC03_CPU_38
+WORKAROUND_AMPERE_AC04_CPU_23
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
 WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
-- 
2.49.0
Re: [PATCH v2] arm64: errata: Work around AmpereOne's erratum AC04_CPU_23
Posted by Marc Zyngier 9 months, 1 week ago
On Fri, 25 Apr 2025 03:47:41 +0100,
D Scott Phillips <scott@os.amperecomputing.com> wrote:
> 
> 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: D Scott Phillips <scott@os.amperecomputing.com>
> ---
> v1: https://lore.kernel.org/kvmarm/20250415154711.1698544-2-scott@os.amperecomputing.com/
> Changes since v1:
>  - Add a write_sysreg_hcr() helper (Oliver)
>  - Add more specific wording in the errata description (Oliver & Marc)
> 
>  arch/arm64/Kconfig                      | 17 +++++++++++++++++
>  arch/arm64/include/asm/hardirq.h        |  4 ++--
>  arch/arm64/include/asm/sysreg.h         | 10 ++++++++++
>  arch/arm64/kernel/cpu_errata.c          | 14 ++++++++++++++
>  arch/arm64/kvm/at.c                     |  8 ++++----
>  arch/arm64/kvm/hyp/include/hyp/switch.h |  2 +-
>  arch/arm64/kvm/hyp/nvhe/mem_protect.c   |  2 +-
>  arch/arm64/kvm/hyp/nvhe/switch.c        |  2 +-
>  arch/arm64/kvm/hyp/vhe/switch.c         |  2 +-
>  arch/arm64/kvm/hyp/vhe/tlb.c            |  4 ++--
>  arch/arm64/tools/cpucaps                |  1 +
>  11 files changed, 54 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index a182295e6f08b..3ae4e80e3002b 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -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
>  
> diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
> index cbfa7b6f2e098..77d6b8c63d4e6 100644
> --- a/arch/arm64/include/asm/hardirq.h
> +++ b/arch/arm64/include/asm/hardirq.h
> @@ -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)
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 2639d3633073d..d41eeba7f8201 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -1185,6 +1185,16 @@
>  		write_sysreg_s(__scs_new, sysreg);			\
>  } while (0)
>  
> +#define write_sysreg_hcr(__val) do {					\
> +	if(IS_ENABLED(CONFIG_AMPERE_ERRATUM_AC04_CPU_23) &&		\
> +	   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)
> +

I'm worried that some of these accesses may occur before we compute
the capabilities. I'd be more confident if the default was to have the
workaround, and only to relax it once we know we're not on a broken
system.

But that leaves the question of the early stuff that runs before we
get to C code. Are you sure this isn't affected by this issue (for
example, the code in head.S, hyp-stub.S, and el2-setup.h)?

>  #define read_sysreg_par() ({						\
>  	u64 par;							\
>  	asm(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412));	\
> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index b55f5f7057502..60f1b70fc0845 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -557,6 +557,13 @@ static const struct midr_range erratum_ac03_cpu_38_list[] = {
>  };
>  #endif
>  
> +#ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
> +static const struct midr_range erratum_ac04_cpu_23_list[] = {
> +	MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
> +	{},
> +};
> +#endif
> +
>  const struct arm64_cpu_capabilities arm64_errata[] = {
>  #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
>  	{
> @@ -875,6 +882,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
>  		.capability = ARM64_WORKAROUND_AMPERE_AC03_CPU_38,
>  		ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_38_list),
>  	},
> +#endif
> +#ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
> +	{
> +		.desc = "AmpereOne erratum AC04_CPU_23",
> +		.capability = ARM64_WORKAROUND_AMPERE_AC04_CPU_23,
> +		ERRATA_MIDR_RANGE_LIST(erratum_ac04_cpu_23_list),
> +	},
>  #endif

This needs to be captured in Documentation/arch/arm64/silicon-errata.rst.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.
Re: [PATCH v2] arm64: errata: Work around AmpereOne's erratum AC04_CPU_23
Posted by D Scott Phillips 9 months, 1 week ago
Marc Zyngier <maz@kernel.org> writes:

> On Fri, 25 Apr 2025 03:47:41 +0100,
> D Scott Phillips <scott@os.amperecomputing.com> wrote:
>> 
>> 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: D Scott Phillips <scott@os.amperecomputing.com>
>> ---
>> v1: https://lore.kernel.org/kvmarm/20250415154711.1698544-2-scott@os.amperecomputing.com/
>> Changes since v1:
>>  - Add a write_sysreg_hcr() helper (Oliver)
>>  - Add more specific wording in the errata description (Oliver & Marc)
>> 
>>  arch/arm64/Kconfig                      | 17 +++++++++++++++++
>>  arch/arm64/include/asm/hardirq.h        |  4 ++--
>>  arch/arm64/include/asm/sysreg.h         | 10 ++++++++++
>>  arch/arm64/kernel/cpu_errata.c          | 14 ++++++++++++++
>>  arch/arm64/kvm/at.c                     |  8 ++++----
>>  arch/arm64/kvm/hyp/include/hyp/switch.h |  2 +-
>>  arch/arm64/kvm/hyp/nvhe/mem_protect.c   |  2 +-
>>  arch/arm64/kvm/hyp/nvhe/switch.c        |  2 +-
>>  arch/arm64/kvm/hyp/vhe/switch.c         |  2 +-
>>  arch/arm64/kvm/hyp/vhe/tlb.c            |  4 ++--
>>  arch/arm64/tools/cpucaps                |  1 +
>>  11 files changed, 54 insertions(+), 12 deletions(-)
>> 
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index a182295e6f08b..3ae4e80e3002b 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -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
>>  
>> diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
>> index cbfa7b6f2e098..77d6b8c63d4e6 100644
>> --- a/arch/arm64/include/asm/hardirq.h
>> +++ b/arch/arm64/include/asm/hardirq.h
>> @@ -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)
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index 2639d3633073d..d41eeba7f8201 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -1185,6 +1185,16 @@
>>  		write_sysreg_s(__scs_new, sysreg);			\
>>  } while (0)
>>  
>> +#define write_sysreg_hcr(__val) do {					\
>> +	if(IS_ENABLED(CONFIG_AMPERE_ERRATUM_AC04_CPU_23) &&		\
>> +	   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)
>> +
>
> I'm worried that some of these accesses may occur before we compute
> the capabilities. I'd be more confident if the default was to have the
> workaround, and only to relax it once we know we're not on a broken
> system.

OK, will do

> But that leaves the question of the early stuff that runs before we
> get to C code. Are you sure this isn't affected by this issue (for
> example, the code in head.S, hyp-stub.S, and el2-setup.h)?

Ya, that's a good point. The corrupted translations can happen
speculatively, so there's every reason to think all those places also
need to be considered. I'll take a look everywhere now, not just at C.

>>  #define read_sysreg_par() ({						\
>>  	u64 par;							\
>>  	asm(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412));	\
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index b55f5f7057502..60f1b70fc0845 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -557,6 +557,13 @@ static const struct midr_range erratum_ac03_cpu_38_list[] = {
>>  };
>>  #endif
>>  
>> +#ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
>> +static const struct midr_range erratum_ac04_cpu_23_list[] = {
>> +	MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
>> +	{},
>> +};
>> +#endif
>> +
>>  const struct arm64_cpu_capabilities arm64_errata[] = {
>>  #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
>>  	{
>> @@ -875,6 +882,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
>>  		.capability = ARM64_WORKAROUND_AMPERE_AC03_CPU_38,
>>  		ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_38_list),
>>  	},
>> +#endif
>> +#ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
>> +	{
>> +		.desc = "AmpereOne erratum AC04_CPU_23",
>> +		.capability = ARM64_WORKAROUND_AMPERE_AC04_CPU_23,
>> +		ERRATA_MIDR_RANGE_LIST(erratum_ac04_cpu_23_list),
>> +	},
>>  #endif
>
> This needs to be captured in Documentation/arch/arm64/silicon-errata.rst.

OK, will do, thanks Marc.