public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] KVM: arm64: vgic: Pick EOIcount deactivations from AP-list tail
@ 2026-03-07 19:11 Marc Zyngier
  2026-03-07 20:56 ` Valentine Burley
  2026-03-07 21:49 ` [PATCH] " Marc Zyngier
  0 siblings, 2 replies; 3+ messages in thread
From: Marc Zyngier @ 2026-03-07 19:11 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Valentine Burley, stable

Valentine reports that their guests fail to boot correctly, losing
interrupts, and indicates that the wrong interrupt gets deactivated.

What happens here is that if the maintenance interrupt is slow enough
to kick us out of the guest, extra interrupts can be activated from
the LRs. We then exit and proceed to handle EOIcount deactivations,
picking active interrupts from the AP list. But we start from the
top of the list, potentially deactivating interrupts that were in
the LRs, while EOIcount only denotes deactivation of interrupts that
are not present in an LR.

Solve this by tracking the last interrupt that made it in the LRs,
and start the EOIcount deactivation walk *after* that interrupt.
Since this only makes sense while the vcpu is loaded, stash this
in the per-CPU host state.

Huge thanks to Valentine for doing all the detective work and
providing an initial patch.

Fixes: 3cfd59f81e0f3 ("KVM: arm64: GICv3: Handle LR overflow when EOImode==0")
Fixes: 281c6c06e2a7b ("KVM: arm64: GICv2: Handle LR overflow when EOImode==0")
Reported-by: Valentine Burley <valentine.burley@collabora.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20260307115955.369455-1-valentine.burley@collabora.com
Cc: stable@vger.kernel.org
---
 arch/arm64/include/asm/kvm_host.h |  3 +++
 arch/arm64/kvm/vgic/vgic-v2.c     |  4 ++--
 arch/arm64/kvm/vgic/vgic-v3.c     | 12 ++++++------
 arch/arm64/kvm/vgic/vgic.c        |  6 ++++++
 4 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 2ca264b3db5fa..70cb9cfd760a3 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -784,6 +784,9 @@ struct kvm_host_data {
 	/* Number of debug breakpoints/watchpoints for this CPU (minus 1) */
 	unsigned int debug_brps;
 	unsigned int debug_wrps;
+
+	/* Last vgic_irq part of the AP list recorded in an LR */
+	struct vgic_irq *last_lr_irq;
 };
 
 struct kvm_host_psci_config {
diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c
index 585491fbda807..cafa3cb32bda6 100644
--- a/arch/arm64/kvm/vgic/vgic-v2.c
+++ b/arch/arm64/kvm/vgic/vgic-v2.c
@@ -115,7 +115,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2;
 	u32 eoicount = FIELD_GET(GICH_HCR_EOICOUNT, cpuif->vgic_hcr);
-	struct vgic_irq *irq;
+	struct vgic_irq *irq = *host_data_ptr(last_lr_irq);
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
@@ -123,7 +123,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
 		vgic_v2_fold_lr(vcpu, cpuif->vgic_lr[lr]);
 
 	/* See the GICv3 equivalent for the EOIcount handling rationale */
-	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+	list_for_each_entry_continue(irq, &vgic_cpu->ap_list_head, ap_list) {
 		u32 lr;
 
 		if (!eoicount) {
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index 386ddf69a9c51..6a355eca19348 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -148,7 +148,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3;
 	u32 eoicount = FIELD_GET(ICH_HCR_EL2_EOIcount, cpuif->vgic_hcr);
-	struct vgic_irq *irq;
+	struct vgic_irq *irq = *host_data_ptr(last_lr_irq);
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
@@ -158,12 +158,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 	/*
 	 * EOIMode=0: use EOIcount to emulate deactivation. We are
 	 * guaranteed to deactivate in reverse order of the activation, so
-	 * just pick one active interrupt after the other in the ap_list,
-	 * and replay the deactivation as if the CPU was doing it. We also
-	 * rely on priority drop to have taken place, and the list to be
-	 * sorted by priority.
+	 * just pick one active interrupt after the other in the tail part
+	 * of the ap_list, past the LRs, and replay the deactivation as if
+	 * the CPU was doing it. We also rely on priority drop to have taken
+	 * place, and the list to be sorted by priority.
 	 */
-	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+	list_for_each_entry_continue(irq, &vgic_cpu->ap_list_head, ap_list) {
 		u64 lr;
 
 		/*
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 430aa98888fda..e22b79cfff965 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -814,6 +814,9 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
 {
+	if (!*host_data_ptr(last_lr_irq))
+		return;
+
 	if (kvm_vgic_global_state.type == VGIC_V2)
 		vgic_v2_fold_lr_state(vcpu);
 	else
@@ -960,10 +963,13 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 	if (irqs_outside_lrs(&als))
 		vgic_sort_ap_list(vcpu);
 
+	*host_data_ptr(last_lr_irq) = NULL;
+
 	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
 		scoped_guard(raw_spinlock,  &irq->irq_lock) {
 			if (likely(vgic_target_oracle(irq) == vcpu)) {
 				vgic_populate_lr(vcpu, irq, count++);
+				*host_data_ptr(last_lr_irq) = irq;
 			}
 		}
 
-- 
2.47.3


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

* Re:[PATCH] KVM: arm64: vgic: Pick EOIcount deactivations from AP-list tail
  2026-03-07 19:11 [PATCH] KVM: arm64: vgic: Pick EOIcount deactivations from AP-list tail Marc Zyngier
@ 2026-03-07 20:56 ` Valentine Burley
  2026-03-07 21:49 ` [PATCH] " Marc Zyngier
  1 sibling, 0 replies; 3+ messages in thread
From: Valentine Burley @ 2026-03-07 20:56 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, Joey Gouly, Suzuki K Poulose,
	Oliver Upton, Zenghui Yu, stable

On Sat, 07 Mar 2026 20:11:51 +0100  Marc Zyngier <maz@kernel.org> wrote
 > Valentine reports that their guests fail to boot correctly, losing
 > interrupts, and indicates that the wrong interrupt gets deactivated.
 > 
 > What happens here is that if the maintenance interrupt is slow enough
 > to kick us out of the guest, extra interrupts can be activated from
 > the LRs. We then exit and proceed to handle EOIcount deactivations,
 > picking active interrupts from the AP list. But we start from the
 > top of the list, potentially deactivating interrupts that were in
 > the LRs, while EOIcount only denotes deactivation of interrupts that
 > are not present in an LR.
 > 
 > Solve this by tracking the last interrupt that made it in the LRs,
 > and start the EOIcount deactivation walk *after* that interrupt.
 > Since this only makes sense while the vcpu is loaded, stash this
 > in the per-CPU host state.
 > 
 > Huge thanks to Valentine for doing all the detective work and
 > providing an initial patch.
 > 
 > Fixes: 3cfd59f81e0f3 ("KVM: arm64: GICv3: Handle LR overflow when EOImode==0")
 > Fixes: 281c6c06e2a7b ("KVM: arm64: GICv2: Handle LR overflow when EOImode==0")
 > Reported-by: Valentine Burley <valentine.burley@collabora.com>
 > Signed-off-by: Marc Zyngier <maz@kernel.org>
 > Link: https://lore.kernel.org/r/20260307115955.369455-1-valentine.burley@collabora.com
 > Cc: stable@vger.kernel.org

Tested-by: Valentine Burley <valentine.burley@collabora.com>

Thanks a lot again for the quick fix!

Cheers,
Valentine

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

* Re: [PATCH] KVM: arm64: vgic: Pick EOIcount deactivations from AP-list tail
  2026-03-07 19:11 [PATCH] KVM: arm64: vgic: Pick EOIcount deactivations from AP-list tail Marc Zyngier
  2026-03-07 20:56 ` Valentine Burley
@ 2026-03-07 21:49 ` Marc Zyngier
  1 sibling, 0 replies; 3+ messages in thread
From: Marc Zyngier @ 2026-03-07 21:49 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, Marc Zyngier
  Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Valentine Burley, stable

On Sat, 07 Mar 2026 19:11:51 +0000, Marc Zyngier wrote:
> Valentine reports that their guests fail to boot correctly, losing
> interrupts, and indicates that the wrong interrupt gets deactivated.
> 
> What happens here is that if the maintenance interrupt is slow enough
> to kick us out of the guest, extra interrupts can be activated from
> the LRs. We then exit and proceed to handle EOIcount deactivations,
> picking active interrupts from the AP list. But we start from the
> top of the list, potentially deactivating interrupts that were in
> the LRs, while EOIcount only denotes deactivation of interrupts that
> are not present in an LR.
> 
> [...]

Applied to fixes, thanks!

[1/1] KVM: arm64: vgic: Pick EOIcount deactivations from AP-list tail
      commit: 6da5e537f5afe091658e846da1949d7e557d2ade

Cheers,

	M.
-- 
Without deviation from the norm, progress is not possible.



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

end of thread, other threads:[~2026-03-07 21:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-07 19:11 [PATCH] KVM: arm64: vgic: Pick EOIcount deactivations from AP-list tail Marc Zyngier
2026-03-07 20:56 ` Valentine Burley
2026-03-07 21:49 ` [PATCH] " Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox