Skip to content

Commit 5c929e4

Browse files
author
Gavin Shan
committed
KVM: arm64: Resolve vLPI by host IRQ in vgic_v4_unset_forwarding()
JIRA: https://issues.redhat.com/browse/RHEL-93666 The virtual mapping and "GSI" routing of a particular vLPI is subject to change in response to the guest / userspace. This can be pretty annoying to deal with when KVM needs to track the physical state that's managed for vLPI direct injection. Make vgic_v4_unset_forwarding() resilient by using the host IRQ to resolve the vgic IRQ. Since this uses the LPI xarray directly, finding the ITS by doorbell address + grabbing it's its_lock is no longer necessary. Note that matching the right ITS / ITE is already handled in vgic_v4_set_forwarding(), and unless there's a bug in KVM's VGIC ITS emulation the virtual mapping that should remain stable for the lifetime of the vLPI mapping. Tested-by: Sweet Tea Dorminy <[email protected]> Signed-off-by: Oliver Upton <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]> (cherry picked from commit 05b9405) Signed-off-by: Gavin Shan <[email protected]>
1 parent 084f8b0 commit 5c929e4

File tree

3 files changed

+27
-24
lines changed

3 files changed

+27
-24
lines changed

arch/arm64/kvm/arm.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2751,8 +2751,7 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
27512751
if (irq_entry->type != KVM_IRQ_ROUTING_MSI)
27522752
return;
27532753

2754-
kvm_vgic_v4_unset_forwarding(irqfd->kvm, prod->irq,
2755-
&irqfd->irq_entry);
2754+
kvm_vgic_v4_unset_forwarding(irqfd->kvm, prod->irq);
27562755
}
27572756

27582757
void kvm_arch_irq_bypass_stop(struct irq_bypass_consumer *cons)

arch/arm64/kvm/vgic/vgic-v4.c

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -492,42 +492,47 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq,
492492
return ret;
493493
}
494494

495-
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int virq,
496-
struct kvm_kernel_irq_routing_entry *irq_entry)
495+
static struct vgic_irq *__vgic_host_irq_get_vlpi(struct kvm *kvm, int host_irq)
496+
{
497+
struct vgic_irq *irq;
498+
unsigned long idx;
499+
500+
guard(rcu)();
501+
xa_for_each(&kvm->arch.vgic.lpi_xa, idx, irq) {
502+
if (!irq->hw || irq->host_irq != host_irq)
503+
continue;
504+
505+
if (!vgic_try_get_irq_kref(irq))
506+
return NULL;
507+
508+
return irq;
509+
}
510+
511+
return NULL;
512+
}
513+
514+
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int host_irq)
497515
{
498-
struct vgic_its *its;
499516
struct vgic_irq *irq;
500517
unsigned long flags;
501518
int ret = 0;
502519

503520
if (!vgic_supports_direct_msis(kvm))
504521
return 0;
505522

506-
/*
507-
* Get the ITS, and escape early on error (not a valid
508-
* doorbell for any of our vITSs).
509-
*/
510-
its = vgic_get_its(kvm, irq_entry);
511-
if (IS_ERR(its))
523+
irq = __vgic_host_irq_get_vlpi(kvm, host_irq);
524+
if (!irq)
512525
return 0;
513526

514-
mutex_lock(&its->its_lock);
515-
516-
ret = vgic_its_resolve_lpi(kvm, its, irq_entry->msi.devid,
517-
irq_entry->msi.data, &irq);
518-
if (ret)
519-
goto out;
520-
521527
raw_spin_lock_irqsave(&irq->irq_lock, flags);
522-
WARN_ON(irq->hw && irq->host_irq != virq);
528+
WARN_ON(irq->hw && irq->host_irq != host_irq);
523529
if (irq->hw) {
524530
atomic_dec(&irq->target_vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count);
525531
irq->hw = false;
526-
ret = its_unmap_vlpi(virq);
532+
ret = its_unmap_vlpi(host_irq);
527533
}
528534

529535
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
530-
out:
531-
mutex_unlock(&its->its_lock);
536+
vgic_put_irq(kvm, irq);
532537
return ret;
533538
}

include/kvm/arm_vgic.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,8 +426,7 @@ struct kvm_kernel_irq_routing_entry;
426426
int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int irq,
427427
struct kvm_kernel_irq_routing_entry *irq_entry);
428428

429-
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int irq,
430-
struct kvm_kernel_irq_routing_entry *irq_entry);
429+
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int host_irq);
431430

432431
int vgic_v4_load(struct kvm_vcpu *vcpu);
433432
void vgic_v4_commit(struct kvm_vcpu *vcpu);

0 commit comments

Comments
 (0)