]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: GICv2: Handle LR overflow when EOImode==0
authorMarc Zyngier <maz@kernel.org>
Thu, 20 Nov 2025 17:25:27 +0000 (17:25 +0000)
committerOliver Upton <oupton@kernel.org>
Mon, 24 Nov 2025 22:29:14 +0000 (14:29 -0800)
Similarly to the GICv3 version, handle the EOIcount-driven deactivation
by walking the overflow list.

Tested-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://msgid.link/20251120172540.2267180-38-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>
arch/arm64/kvm/vgic/vgic-v2.c

index 9a2de03f74c3003359ccf69ba028b39c8731e1cb..bbd4d003fde86cec3ca5f22a02a02371321a94a8 100644 (file)
@@ -100,6 +100,8 @@ static void vgic_v2_fold_lr(struct kvm_vcpu *vcpu, u32 val)
        vgic_put_irq(vcpu->kvm, irq);
 }
 
+static u32 vgic_v2_compute_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq);
+
 /*
  * transfer the content of the LRs back into the corresponding ap_list:
  * - active bit is transferred as is
@@ -111,12 +113,37 @@ 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;
 
        DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
        for (int lr = 0; lr < vgic_cpu->vgic_v2.used_lrs; lr++)
                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) {
+               u32 lr;
+
+               if (!eoicount) {
+                       break;
+               } else {
+                       guard(raw_spinlock)(&irq->irq_lock);
+
+                       if (!(likely(vgic_target_oracle(irq) == vcpu) &&
+                             irq->active))
+                               continue;
+
+                       lr = vgic_v2_compute_lr(vcpu, irq) & ~GICH_LR_ACTIVE_BIT;
+               }
+
+               if (lr & GICH_LR_HW)
+                       writel_relaxed(FIELD_GET(GICH_LR_PHYSID_CPUID, lr),
+                                      kvm_vgic_global_state.gicc_base + GIC_CPU_DEACTIVATE);
+               vgic_v2_fold_lr(vcpu, lr);
+               eoicount--;
+       }
+
        cpuif->used_lrs = 0;
 }