Skip to content

Commit 05b9405

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: Resolve vLPI by host IRQ in vgic_v4_unset_forwarding()
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]>
1 parent fc4dafe commit 05b9405

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
@@ -2800,8 +2800,7 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
28002800
if (irq_entry->type != KVM_IRQ_ROUTING_MSI)
28012801
return;
28022802

2803-
kvm_vgic_v4_unset_forwarding(irqfd->kvm, prod->irq,
2804-
&irqfd->irq_entry);
2803+
kvm_vgic_v4_unset_forwarding(irqfd->kvm, prod->irq);
28052804
}
28062805

28072806
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
@@ -508,42 +508,47 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq,
508508
return ret;
509509
}
510510

511-
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int virq,
512-
struct kvm_kernel_irq_routing_entry *irq_entry)
511+
static struct vgic_irq *__vgic_host_irq_get_vlpi(struct kvm *kvm, int host_irq)
512+
{
513+
struct vgic_irq *irq;
514+
unsigned long idx;
515+
516+
guard(rcu)();
517+
xa_for_each(&kvm->arch.vgic.lpi_xa, idx, irq) {
518+
if (!irq->hw || irq->host_irq != host_irq)
519+
continue;
520+
521+
if (!vgic_try_get_irq_kref(irq))
522+
return NULL;
523+
524+
return irq;
525+
}
526+
527+
return NULL;
528+
}
529+
530+
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int host_irq)
513531
{
514-
struct vgic_its *its;
515532
struct vgic_irq *irq;
516533
unsigned long flags;
517534
int ret = 0;
518535

519536
if (!vgic_supports_direct_msis(kvm))
520537
return 0;
521538

522-
/*
523-
* Get the ITS, and escape early on error (not a valid
524-
* doorbell for any of our vITSs).
525-
*/
526-
its = vgic_get_its(kvm, irq_entry);
527-
if (IS_ERR(its))
539+
irq = __vgic_host_irq_get_vlpi(kvm, host_irq);
540+
if (!irq)
528541
return 0;
529542

530-
mutex_lock(&its->its_lock);
531-
532-
ret = vgic_its_resolve_lpi(kvm, its, irq_entry->msi.devid,
533-
irq_entry->msi.data, &irq);
534-
if (ret)
535-
goto out;
536-
537543
raw_spin_lock_irqsave(&irq->irq_lock, flags);
538-
WARN_ON(irq->hw && irq->host_irq != virq);
544+
WARN_ON(irq->hw && irq->host_irq != host_irq);
539545
if (irq->hw) {
540546
atomic_dec(&irq->target_vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count);
541547
irq->hw = false;
542-
ret = its_unmap_vlpi(virq);
548+
ret = its_unmap_vlpi(host_irq);
543549
}
544550

545551
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
546-
out:
547-
mutex_unlock(&its->its_lock);
552+
vgic_put_irq(kvm, irq);
548553
return ret;
549554
}

include/kvm/arm_vgic.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,7 @@ struct kvm_kernel_irq_routing_entry;
434434
int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int irq,
435435
struct kvm_kernel_irq_routing_entry *irq_entry);
436436

437-
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int irq,
438-
struct kvm_kernel_irq_routing_entry *irq_entry);
437+
int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int host_irq);
439438

440439
int vgic_v4_load(struct kvm_vcpu *vcpu);
441440
void vgic_v4_commit(struct kvm_vcpu *vcpu);

0 commit comments

Comments
 (0)