All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29
@ 2026-07-10 22:21 D Scott Phillips
  2026-07-10 22:37 ` sashiko-bot
  2026-07-11  7:37 ` Marc Zyngier
  0 siblings, 2 replies; 5+ messages in thread
From: D Scott Phillips @ 2026-07-10 22:21 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon,
	Jonathan Corbet, Shuah Khan, Joey Gouly, Steffen Eiden,
	Suzuki K Poulose, Zenghui Yu
  Cc: Mark Rutland, Zeng Heng, Wei Xu, Vladimir Murzin, Lucas Wei,
	Kuninori Morimoto, Sascha Bischoff, Yicong Yang, Yeoreum Yun,
	linux-arm-kernel, linux-doc, linux-kernel, kvmarm

On AmpereOne, deactivating a physical interrupt through ICC_DIR_EL1 or
ICC_EOIRx_EL1 (depending on EOImode) which is not active, but is the
highest priority pending interrupt causes the cpu to lose the interrupt
pending state and also prevents the delivery of future interrupts.

Work around this in the vgic, avoiding the cpu issue.

Signed-off-by: D Scott Phillips <scott@os.amperecomputing.com>
---

Hi Marc, we've tracked down the nested virt hang reported
previously[1] to a cpu erratum in AmpereOne[2].

Here I'm just sort of parroting the change you had posted for
debugging. I'm not familiar with the vgic logic well enough to know if
this change is sufficient and doesn't have some unintended
consequences. I guess read this more are as "I've tested this and I'm
not seeing it hang now."

Sorry for sending this half-baked, I didn't want to further delay the
errata details on my ongoing vgic education. I'm happy to take any
advice you can give, otherwise I'll continue familiarizing myself and
will hopefully later have a patch which I can actually claim I think is
correct.

[1]: https://lore.kernel.org/linux-arm-kernel/87ecjybz30.wl-maz@kernel.org/

[2]: https://amperecomputing.com/products/developer-errata

The updates with AC03_CPU_57 and AC04_CPU_29 have not yet been
published at the time I'm writing this. They should be coming
soon. I've reproduced the full entries from those two coming documents
collapsed together below:

| {AC03_CPU_57, AC04_CPU_29}: Deactivation of the non-active, highest
| priority pending interrupt prevents further interrupt delivery.
|
| Functional Unit: CPU
|
| Category: 4
|
| Affected Version(s): AmpereOne AC03 A0, AmpereOne AC03 B0
| Affected Version(s): AmpereOne AC04 A0, AmpereOne AC04_1 A0
|
| Fixed Version(s): Open
|
| Overview:
|
| If software directly deactivates a physical interrupt which is not
| in the active state, and the interrupt is also currently the highest
| priority pending interrupt, then interrupt delivery will cease on
| that PE. Deactivation can happen either through ICC_EOIRx_EL1 if
| ICC_CTLR_EL1.EOIMode==0, or through ICC_DIR_EL1 if
| ICC_CTLR_EL1.EOIMode==1. Deactivation of virtual interrupts that are
| redirected through ICV_ registers will not cause this issue, even
| when the virtual interrupt deactivation triggers a physical
| interrupt deactivation through ICH_LR<n>_EL2.HW=1.
|
| This has been observed with Nested Virtualization starting with
| Linux-KVM v6.19.
|
| Impact:
|
| Physical interrupts will not be delivered after the deactivation of
| the non-active, highest priority pending interrupt. A core may
| appear to be hung.
|
| Workaround:
|
| Software must only deactivate interrupts which are currently active


 Documentation/arch/arm64/silicon-errata.rst |  4 ++++
 arch/arm64/Kconfig                          | 17 +++++++++++++++++
 arch/arm64/kernel/cpu_errata.c              | 15 +++++++++++++++
 arch/arm64/kvm/vgic/vgic-v3.c               |  4 +++-
 arch/arm64/tools/cpucaps                    |  1 +
 5 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index 014aa1c215a16..89130404ce572 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -55,10 +55,14 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | Ampere         | AmpereOne       | AC03_CPU_38     | AMPERE_ERRATUM_AC03_CPU_38  |
 +----------------+-----------------+-----------------+-----------------------------+
+| Ampere         | AmpereOne       | AC03_CPU_57     | AMPERE_ERRATUM_AC03_CPU_57  |
++----------------+-----------------+-----------------+-----------------------------+
 | Ampere         | AmpereOne AC04  | AC04_CPU_10     | AMPERE_ERRATUM_AC03_CPU_38  |
 +----------------+-----------------+-----------------+-----------------------------+
 | Ampere         | AmpereOne AC04  | AC04_CPU_23     | AMPERE_ERRATUM_AC04_CPU_23  |
 +----------------+-----------------+-----------------+-----------------------------+
+| Ampere         | AmpereOne AC04  | AC04_CPU_29     | AMPERE_ERRATUM_AC03_CPU_57  |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A510     | #2457168        | ARM64_ERRATUM_2457168       |
 +----------------+-----------------+-----------------+-----------------------------+
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919b..ee5421283d8df 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -436,6 +436,23 @@ config AMPERE_ERRATUM_AC03_CPU_38
 
 	  If unsure, say Y.
 
+config AMPERE_ERRATUM_AC03_CPU_57
+	bool "AmpereOne: AC03_CPU_57: Deactivation of the non-active, highest priority pending interrupt prevents further interrupt delivery."
+	default y
+	help
+	  This option adds an alternative code sequence to work around Ampere
+	  errata AC03_CPU_57 and AC04_CPU_29 on AmpereOne.
+
+	  Deactivating a physical interrupt through ICC_DIR_EL1 or
+	  ICC_EOIR1_EL1 (depending on EOImode) which is not active, but is the
+	  highest priority pending interrupt causes the cpu to lose the
+	  interrupt pending state and also prevents the delivery of future
+	  interrupts.
+
+	  The workaround is for KVM to not deactivate interrupts for nested vgics.
+
+	  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
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 1995e1198648e..9b03dccd55e09 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -631,6 +631,14 @@ static const struct midr_range erratum_ac03_cpu_38_list[] = {
 };
 #endif
 
+#ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_57
+static const struct midr_range erratum_ac03_cpu_57_list[] = {
+	MIDR_ALL_VERSIONS(MIDR_AMPERE1),
+	MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
+	{},
+};
+#endif
+
 #ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
 static const struct midr_range erratum_ac04_cpu_23_list[] = {
 	MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
@@ -987,6 +995,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 		ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_38_list),
 	},
 #endif
+#ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_57
+	{
+		.desc = "AmpereOne erratum AC03_CPU_57",
+		.capability = ARM64_WORKAROUND_AMPERE_AC03_CPU_57,
+		ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_57_list),
+	},
+#endif
 #ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
 	{
 		.desc = "AmpereOne erratum AC04_CPU_23",
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 9e841e7afd4a7..8f1d10872360c 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -275,7 +275,9 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
 		lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
 	}
 
-	if (lr & ICH_LR_HW)
+	if ((lr & ICH_LR_HW) &&
+	    !(cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_57) &&
+	      vgic_state_is_nested(vcpu)))
 		vgic_v3_deactivate_phys(FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));
 
 	vgic_v3_fold_lr(vcpu, lr);
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 9b85a84f6fd49..7a63f3f7c982b 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -109,6 +109,7 @@ WORKAROUND_2658417
 WORKAROUND_4193714
 WORKAROUND_4311569
 WORKAROUND_AMPERE_AC03_CPU_38
+WORKAROUND_AMPERE_AC03_CPU_57
 WORKAROUND_AMPERE_AC04_CPU_23
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29
  2026-07-10 22:21 [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29 D Scott Phillips
@ 2026-07-10 22:37 ` sashiko-bot
  2026-07-11  7:53   ` Marc Zyngier
  2026-07-11 22:27   ` Marc Zyngier
  2026-07-11  7:37 ` Marc Zyngier
  1 sibling, 2 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-10 22:37 UTC (permalink / raw)
  To: D Scott Phillips; +Cc: Oliver Upton, Marc Zyngier, kvmarm

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [High] The AmpereOne erratum workaround unconditionally skips deactivating physical interrupts for all nested VMs, causing a physical interrupt state leak.

Pre-existing issues:
- [Critical] The AmpereOne erratum workaround fails to mitigate a Guest-to-Host Denial of Service vector for non-nested (L1) guests.
- [High] Dropping `irq->irq_lock` between computing the LR snapshot and folding it creates a race condition that loses concurrent virtual interrupts.
--

--- Patch [1]: [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29 ---
commit d1d195cfc998f3f14be1b81eaa8484fcb7eb08f8
Author: D Scott Phillips <scott@os.amperecomputing.com>

arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29

This commit introduces a workaround for an AmpereOne CPU erratum where
deactivating a non-active physical interrupt that is the highest priority
pending interrupt hangs the CPU. The mitigation avoids physical deactivations
when KVM handles a nested VM context.

Link: https://lore.kernel.org/linux-arm-kernel/87ecjybz30.wl-maz@kernel.org/
Link: https://amperecomputing.com/products/developer-errata

[ ... ]

> diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
> index 9e841e7afd4a7..8f1d10872360c 100644
> --- a/arch/arm64/kvm/vgic/vgic-v3.c
> +++ b/arch/arm64/kvm/vgic/vgic-v3.c
> @@ -275,7 +275,9 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
>  		lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
>  	}
>  
> -	if (lr & ICH_LR_HW)
> +	if ((lr & ICH_LR_HW) &&
> +	    !(cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_57) &&
> +	      vgic_state_is_nested(vcpu)))

[Severity: Critical]
This is a pre-existing issue, but does the system remain vulnerable to the
erratum for L1 guests?

Because vgic_state_is_nested(vcpu) evaluates to false for an L1 guest, KVM
bypasses the workaround and still calls vgic_v3_deactivate_phys(). If an
unprivileged guest operating in GICv2 mode on a GICv3 host writes the INTID of
a hardware-backed interrupt to the GICC_DIR MMIO register while it is inactive,
can this directly trigger the host CPU hang?

[Severity: High]
Does unconditionally bypassing the physical deactivation for nested VMs cause
a physical interrupt state leak?

When an L2 guest legitimately deactivates an active hardware-backed
interrupt and it traps to KVM, vgic_v3_deactivate() is called. Since
vgic_state_is_nested(vcpu) evaluates to true, it successfully updates the
virtual state via vgic_v3_fold_lr() but unconditionally skips calling
vgic_v3_deactivate_phys().

Could this leave hardware-backed interrupts, such as the physical timer,
permanently active in the physical GIC distributor and block future timer
interrupts?

>  		vgic_v3_deactivate_phys(FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));
>  
>  	vgic_v3_fold_lr(vcpu, lr);

[Severity: High]
This isn't a bug introduced by this patch, but does dropping irq->irq_lock
between computing the LR snapshot and folding it create a race condition that
loses concurrent virtual interrupts?

vgic_v3_deactivate() takes the lock, computes the snapshot, and then the
scoped_guard ends:

scoped_guard(raw_spinlock, &irq->irq_lock) {
    ...
    lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
}

If a concurrent device injects an interrupt here via vgic_inject_irq() and
sets irq->pending_latch = true, won't the subsequent call to
vgic_v3_fold_lr(vcpu, lr) re-acquire the lock and evaluate the stale snapshot?

vgic_v3_fold_lr() would see !(val & ICH_LR_STATE) is true and execute:

if (irq->config == VGIC_CONFIG_LEVEL && !(val & ICH_LR_STATE))
    irq->pending_latch = false;

Could this wipe out the newly arrived interrupt and cause guest devices to
stall?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710222128.416581-1-scott@os.amperecomputing.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29
  2026-07-10 22:21 [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29 D Scott Phillips
  2026-07-10 22:37 ` sashiko-bot
@ 2026-07-11  7:37 ` Marc Zyngier
  1 sibling, 0 replies; 5+ messages in thread
From: Marc Zyngier @ 2026-07-11  7:37 UTC (permalink / raw)
  To: D Scott Phillips
  Cc: Oliver Upton, Catalin Marinas, Will Deacon, Jonathan Corbet,
	Shuah Khan, Joey Gouly, Steffen Eiden, Suzuki K Poulose,
	Zenghui Yu, Mark Rutland, Zeng Heng, Wei Xu, Vladimir Murzin,
	Lucas Wei, Kuninori Morimoto, Sascha Bischoff, Yicong Yang,
	Yeoreum Yun, linux-arm-kernel, linux-doc, linux-kernel, kvmarm

Hi Scott,

On Fri, 10 Jul 2026 23:21:28 +0100,
D Scott Phillips <scott@os.amperecomputing.com> wrote:
> 
> On AmpereOne, deactivating a physical interrupt through ICC_DIR_EL1 or
> ICC_EOIRx_EL1 (depending on EOImode) which is not active, but is the
> highest priority pending interrupt causes the cpu to lose the interrupt
> pending state and also prevents the delivery of future interrupts.
>
> Work around this in the vgic, avoiding the cpu issue.

Thanks for getting to the bottom of this.

> 
> Signed-off-by: D Scott Phillips <scott@os.amperecomputing.com>
> ---
> 
> Hi Marc, we've tracked down the nested virt hang reported
> previously[1] to a cpu erratum in AmpereOne[2].
> 
> Here I'm just sort of parroting the change you had posted for
> debugging. I'm not familiar with the vgic logic well enough to know if
> this change is sufficient and doesn't have some unintended
> consequences. I guess read this more are as "I've tested this and I'm
> not seeing it hang now."
>
> Sorry for sending this half-baked, I didn't want to further delay the
> errata details on my ongoing vgic education. I'm happy to take any
> advice you can give, otherwise I'll continue familiarizing myself and
> will hopefully later have a patch which I can actually claim I think is
> correct.

No worries.

To be perfectly clear, what I posted at [1] *is* a bug-fix. A very
minor one. Nothing wrong should come as a result, except when it does,
such as in your case.

The core reason why this happens is that the L2 will have EOI'd its
timer, and that the HW bit set in the LR will have propagated the
deactivation all the way to the HW redistributor. Then L1 takes over,
and needs to reconcile the LR state with its own, namely its view of
the active state.

The issue here is that when dealing with a nested vgic (the state
contained in the LRs is for L2, not L1), the deactivation process
doesn't need to involve the HW again -- this has already be dealt
with, and results in the double deactivation I mentioned in my email.

> 
> [1]: https://lore.kernel.org/linux-arm-kernel/87ecjybz30.wl-maz@kernel.org/
> 
> [2]: https://amperecomputing.com/products/developer-errata
> 
> The updates with AC03_CPU_57 and AC04_CPU_29 have not yet been
> published at the time I'm writing this. They should be coming
> soon. I've reproduced the full entries from those two coming documents
> collapsed together below:
> 
> | {AC03_CPU_57, AC04_CPU_29}: Deactivation of the non-active, highest
> | priority pending interrupt prevents further interrupt delivery.
> |
> | Functional Unit: CPU
> |
> | Category: 4
> |
> | Affected Version(s): AmpereOne AC03 A0, AmpereOne AC03 B0
> | Affected Version(s): AmpereOne AC04 A0, AmpereOne AC04_1 A0
> |
> | Fixed Version(s): Open
> |
> | Overview:
> |
> | If software directly deactivates a physical interrupt which is not
> | in the active state, and the interrupt is also currently the highest
> | priority pending interrupt, then interrupt delivery will cease on
> | that PE. Deactivation can happen either through ICC_EOIRx_EL1 if
> | ICC_CTLR_EL1.EOIMode==0, or through ICC_DIR_EL1 if
> | ICC_CTLR_EL1.EOIMode==1. Deactivation of virtual interrupts that are
> | redirected through ICV_ registers will not cause this issue, even
> | when the virtual interrupt deactivation triggers a physical
> | interrupt deactivation through ICH_LR<n>_EL2.HW=1.

OK, that's pretty good news. Can I safely assume that your HW doesn't
support VLPIs/VSGIs in any form (no GICv4+)?

> |
> | This has been observed with Nested Virtualization starting with
> | Linux-KVM v6.19.
> |
> | Impact:
> |
> | Physical interrupts will not be delivered after the deactivation of
> | the non-active, highest priority pending interrupt. A core may
> | appear to be hung.
> |
> | Workaround:
> |
> | Software must only deactivate interrupts which are currently active
> 
> 
>  Documentation/arch/arm64/silicon-errata.rst |  4 ++++
>  arch/arm64/Kconfig                          | 17 +++++++++++++++++
>  arch/arm64/kernel/cpu_errata.c              | 15 +++++++++++++++
>  arch/arm64/kvm/vgic/vgic-v3.c               |  4 +++-
>  arch/arm64/tools/cpucaps                    |  1 +
>  5 files changed, 40 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
> index 014aa1c215a16..89130404ce572 100644
> --- a/Documentation/arch/arm64/silicon-errata.rst
> +++ b/Documentation/arch/arm64/silicon-errata.rst
> @@ -55,10 +55,14 @@ stable kernels.
>  +----------------+-----------------+-----------------+-----------------------------+
>  | Ampere         | AmpereOne       | AC03_CPU_38     | AMPERE_ERRATUM_AC03_CPU_38  |
>  +----------------+-----------------+-----------------+-----------------------------+
> +| Ampere         | AmpereOne       | AC03_CPU_57     | AMPERE_ERRATUM_AC03_CPU_57  |
> ++----------------+-----------------+-----------------+-----------------------------+
>  | Ampere         | AmpereOne AC04  | AC04_CPU_10     | AMPERE_ERRATUM_AC03_CPU_38  |
>  +----------------+-----------------+-----------------+-----------------------------+
>  | Ampere         | AmpereOne AC04  | AC04_CPU_23     | AMPERE_ERRATUM_AC04_CPU_23  |
>  +----------------+-----------------+-----------------+-----------------------------+
> +| Ampere         | AmpereOne AC04  | AC04_CPU_29     | AMPERE_ERRATUM_AC03_CPU_57  |
> ++----------------+-----------------+-----------------+-----------------------------+
>  +----------------+-----------------+-----------------+-----------------------------+
>  | ARM            | Cortex-A510     | #2457168        | ARM64_ERRATUM_2457168       |
>  +----------------+-----------------+-----------------+-----------------------------+
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index b3afe0688919b..ee5421283d8df 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -436,6 +436,23 @@ config AMPERE_ERRATUM_AC03_CPU_38
>  
>  	  If unsure, say Y.
>  
> +config AMPERE_ERRATUM_AC03_CPU_57
> +	bool "AmpereOne: AC03_CPU_57: Deactivation of the non-active, highest priority pending interrupt prevents further interrupt delivery."
> +	default y
> +	help
> +	  This option adds an alternative code sequence to work around Ampere
> +	  errata AC03_CPU_57 and AC04_CPU_29 on AmpereOne.
> +
> +	  Deactivating a physical interrupt through ICC_DIR_EL1 or
> +	  ICC_EOIR1_EL1 (depending on EOImode) which is not active, but is the
> +	  highest priority pending interrupt causes the cpu to lose the
> +	  interrupt pending state and also prevents the delivery of future
> +	  interrupts.
> +
> +	  The workaround is for KVM to not deactivate interrupts for nested vgics.
> +
> +	  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
> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index 1995e1198648e..9b03dccd55e09 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -631,6 +631,14 @@ static const struct midr_range erratum_ac03_cpu_38_list[] = {
>  };
>  #endif
>  
> +#ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_57
> +static const struct midr_range erratum_ac03_cpu_57_list[] = {
> +	MIDR_ALL_VERSIONS(MIDR_AMPERE1),
> +	MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
> +	{},
> +};
> +#endif
> +
>  #ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
>  static const struct midr_range erratum_ac04_cpu_23_list[] = {
>  	MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
> @@ -987,6 +995,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
>  		ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_38_list),
>  	},
>  #endif
> +#ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_57
> +	{
> +		.desc = "AmpereOne erratum AC03_CPU_57",
> +		.capability = ARM64_WORKAROUND_AMPERE_AC03_CPU_57,
> +		ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_57_list),
> +	},
> +#endif
>  #ifdef CONFIG_AMPERE_ERRATUM_AC04_CPU_23
>  	{
>  		.desc = "AmpereOne erratum AC04_CPU_23",
> diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
> index 9e841e7afd4a7..8f1d10872360c 100644
> --- a/arch/arm64/kvm/vgic/vgic-v3.c
> +++ b/arch/arm64/kvm/vgic/vgic-v3.c
> @@ -275,7 +275,9 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
>  		lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
>  	}
>  
> -	if (lr & ICH_LR_HW)
> +	if ((lr & ICH_LR_HW) &&
> +	    !(cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_57) &&
> +	      vgic_state_is_nested(vcpu)))
>  		vgic_v3_deactivate_phys(FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));

I think this is slightly overkill. The hack I posted should be enough,
and we can replace all the capability business with a simple comment
referencing the errata numbers and the entries in silicon-errata.rst.

Use the information provided above to beef up the commit message and
stick:

Cc: stable@vger.kernel.org
Fixes: 6dd333c8942b2 ("KVM: arm64: GICv3: nv: Plug L1 LR sync into deactivation primitive")

so that we know how far this needs to be backported.

Thanks,

	M.

-- 
Jazz isn't dead. It just smells funny.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29
  2026-07-10 22:37 ` sashiko-bot
@ 2026-07-11  7:53   ` Marc Zyngier
  2026-07-11 22:27   ` Marc Zyngier
  1 sibling, 0 replies; 5+ messages in thread
From: Marc Zyngier @ 2026-07-11  7:53 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: D Scott Phillips, Oliver Upton, kvmarm

On Fri, 10 Jul 2026 23:37:17 +0100,
sashiko-bot@kernel.org wrote:
> 
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> 
> New issues:
> - [High] The AmpereOne erratum workaround unconditionally skips deactivating physical interrupts for all nested VMs, causing a physical interrupt state leak.
> 
> Pre-existing issues:
> - [Critical] The AmpereOne erratum workaround fails to mitigate a Guest-to-Host Denial of Service vector for non-nested (L1) guests.
> - [High] Dropping `irq->irq_lock` between computing the LR snapshot and folding it creates a race condition that loses concurrent virtual interrupts.
> --
> 
> --- Patch [1]: [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29 ---
> commit d1d195cfc998f3f14be1b81eaa8484fcb7eb08f8
> Author: D Scott Phillips <scott@os.amperecomputing.com>
> 
> arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29
> 
> This commit introduces a workaround for an AmpereOne CPU erratum where
> deactivating a non-active physical interrupt that is the highest priority
> pending interrupt hangs the CPU. The mitigation avoids physical deactivations
> when KVM handles a nested VM context.
> 
> Link: https://lore.kernel.org/linux-arm-kernel/87ecjybz30.wl-maz@kernel.org/
> Link: https://amperecomputing.com/products/developer-errata
> 
> [ ... ]
> 
> > diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
> > index 9e841e7afd4a7..8f1d10872360c 100644
> > --- a/arch/arm64/kvm/vgic/vgic-v3.c
> > +++ b/arch/arm64/kvm/vgic/vgic-v3.c
> > @@ -275,7 +275,9 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
> >  		lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
> >  	}
> >  
> > -	if (lr & ICH_LR_HW)
> > +	if ((lr & ICH_LR_HW) &&
> > +	    !(cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_57) &&
> > +	      vgic_state_is_nested(vcpu)))
> 
> [Severity: Critical]
> This is a pre-existing issue, but does the system remain vulnerable to the
> erratum for L1 guests?
> 
> Because vgic_state_is_nested(vcpu) evaluates to false for an L1 guest, KVM
> bypasses the workaround and still calls vgic_v3_deactivate_phys(). If an
> unprivileged guest operating in GICv2 mode on a GICv3 host writes the INTID of

There is no such thing with NV, as we only support GICv3 in guests.

> a hardware-backed interrupt to the GICC_DIR MMIO register while it is inactive,
> can this directly trigger the host CPU hang?
>
> [Severity: High]
> Does unconditionally bypassing the physical deactivation for nested VMs cause
> a physical interrupt state leak?
> 
> When an L2 guest legitimately deactivates an active hardware-backed
> interrupt and it traps to KVM, vgic_v3_deactivate() is called. Since
> vgic_state_is_nested(vcpu) evaluates to true, it successfully updates the
> virtual state via vgic_v3_fold_lr() but unconditionally skips calling
> vgic_v3_deactivate_phys().
> 
> Could this leave hardware-backed interrupts, such as the physical timer,
> permanently active in the physical GIC distributor and block future timer
> interrupts?

Go read the spec and the effects of the HW bit. This is actively
advocating for the reintroduction of the bug... :-/

> 
> >  		vgic_v3_deactivate_phys(FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));
> >  
> >  	vgic_v3_fold_lr(vcpu, lr);
> 
> [Severity: High]
> This isn't a bug introduced by this patch, but does dropping irq->irq_lock
> between computing the LR snapshot and folding it create a race condition that
> loses concurrent virtual interrupts?
> 
> vgic_v3_deactivate() takes the lock, computes the snapshot, and then the
> scoped_guard ends:
> 
> scoped_guard(raw_spinlock, &irq->irq_lock) {
>     ...
>     lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
> }
> 
> If a concurrent device injects an interrupt here via vgic_inject_irq() and
> sets irq->pending_latch = true, won't the subsequent call to
> vgic_v3_fold_lr(vcpu, lr) re-acquire the lock and evaluate the stale snapshot?
> 
> vgic_v3_fold_lr() would see !(val & ICH_LR_STATE) is true and execute:
> 
> if (irq->config == VGIC_CONFIG_LEVEL && !(val & ICH_LR_STATE))
>     irq->pending_latch = false;
> 
> Could this wipe out the newly arrived interrupt and cause guest devices to
> stall?

This one is a potential problem. I'll have a think...

	M.

-- 
Jazz isn't dead. It just smells funny.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29
  2026-07-10 22:37 ` sashiko-bot
  2026-07-11  7:53   ` Marc Zyngier
@ 2026-07-11 22:27   ` Marc Zyngier
  1 sibling, 0 replies; 5+ messages in thread
From: Marc Zyngier @ 2026-07-11 22:27 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: D Scott Phillips, Oliver Upton, kvmarm

On Fri, 10 Jul 2026 23:37:17 +0100,
sashiko-bot@kernel.org wrote:

[...]

> [Severity: High]
> This isn't a bug introduced by this patch, but does dropping irq->irq_lock
> between computing the LR snapshot and folding it create a race condition that
> loses concurrent virtual interrupts?
> 
> vgic_v3_deactivate() takes the lock, computes the snapshot, and then the
> scoped_guard ends:
> 
> scoped_guard(raw_spinlock, &irq->irq_lock) {
>     ...
>     lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
> }
> 
> If a concurrent device injects an interrupt here via vgic_inject_irq() and
> sets irq->pending_latch = true, won't the subsequent call to
> vgic_v3_fold_lr(vcpu, lr) re-acquire the lock and evaluate the stale snapshot?
> 
> vgic_v3_fold_lr() would see !(val & ICH_LR_STATE) is true and execute:
> 
> if (irq->config == VGIC_CONFIG_LEVEL && !(val & ICH_LR_STATE))
>     irq->pending_latch = false;
> 
> Could this wipe out the newly arrived interrupt and cause guest devices to
> stall?

Having thought about it (yes, this is what the NSJ is for), my
conclusion is that this report is utter bollocks.

The clearing of the latch obviously only applies to level interrupts,
which can only be set by SW. The convention is that the Ack of a level
interrupt consumes the latched signal (SW can't distinguish it from a
device interrupt anyway).

A *device* interrupt sets irq->line_level, and can only be dropped by
the device itself, not by anything happening in the LR.

My conclusion is that Sashiko doesn't understand the GIC interrupt
life cycle, and is deeply confused by it. I'm shocked.

	M.

-- 
Jazz isn't dead. It just smells funny.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-11 22:25 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 22:21 [PATCH] arm64: errata: Mitigate AmpereOne erratum AC03_CPU_57 and AC04_CPU_29 D Scott Phillips
2026-07-10 22:37 ` sashiko-bot
2026-07-11  7:53   ` Marc Zyngier
2026-07-11 22:27   ` Marc Zyngier
2026-07-11  7:37 ` Marc Zyngier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.