]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: Move undeliverable interrupts to the end of ap_list
authorMarc Zyngier <maz@kernel.org>
Thu, 20 Nov 2025 17:25:15 +0000 (17:25 +0000)
committerOliver Upton <oupton@kernel.org>
Mon, 24 Nov 2025 22:29:13 +0000 (14:29 -0800)
Interrupts in the ap_list that cannot be acted upon because they
are not enabled, or that their group is not enabled, shouldn't
make it into the LRs if we are space-constrained.

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-26-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>
arch/arm64/kvm/vgic/vgic.c

index c7a5454ac4c9f0cd4bb952e2b20b29ccaf5fb19d..abe01c9c6b364dc83bbd54d82c79f8673718fd79 100644 (file)
@@ -265,6 +265,11 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
        return NULL;
 }
 
+struct vgic_sort_info {
+       struct kvm_vcpu *vcpu;
+       struct vgic_vmcr vmcr;
+};
+
 /*
  * The order of items in the ap_lists defines how we'll pack things in LRs as
  * well, the first items in the list being the first things populated in the
@@ -273,6 +278,7 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
  * Pending, non-active interrupts must be placed at the head of the list.
  * Otherwise things should be sorted by the priority field and the GIC
  * hardware support will take care of preemption of priority groups etc.
+ * Interrupts that are not deliverable should be at the end of the list.
  *
  * Return negative if "a" sorts before "b", 0 to preserve order, and positive
  * to sort "b" before "a".
@@ -282,6 +288,8 @@ static int vgic_irq_cmp(void *priv, const struct list_head *a,
 {
        struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
        struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
+       struct vgic_sort_info *info = priv;
+       struct kvm_vcpu *vcpu = info->vcpu;
        bool penda, pendb;
        int ret;
 
@@ -295,6 +303,17 @@ static int vgic_irq_cmp(void *priv, const struct list_head *a,
        raw_spin_lock(&irqa->irq_lock);
        raw_spin_lock_nested(&irqb->irq_lock, SINGLE_DEPTH_NESTING);
 
+       /* Undeliverable interrupts should be last */
+       ret = (int)(vgic_target_oracle(irqb) == vcpu) - (int)(vgic_target_oracle(irqa) == vcpu);
+       if (ret)
+               goto out;
+
+       /* Same thing for interrupts targeting a disabled group */
+       ret =  (int)(irqb->group ? info->vmcr.grpen1 : info->vmcr.grpen0);
+       ret -= (int)(irqa->group ? info->vmcr.grpen1 : info->vmcr.grpen0);
+       if (ret)
+               goto out;
+
        penda = irqa->enabled && irq_is_pending(irqa) && !irqa->active;
        pendb = irqb->enabled && irq_is_pending(irqb) && !irqb->active;
 
@@ -320,10 +339,12 @@ out:
 static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
 {
        struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+       struct vgic_sort_info info = { .vcpu = vcpu, };
 
        lockdep_assert_held(&vgic_cpu->ap_list_lock);
 
-       list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
+       vgic_get_vmcr(vcpu, &info.vmcr);
+       list_sort(&info, &vgic_cpu->ap_list_head, vgic_irq_cmp);
 }
 
 /*