Commit 982f31bb authored by Oliver Upton's avatar Oliver Upton
Browse files

KVM: arm64: vgic-v3: Don't require IRQs be disabled for LPI xarray lock



Now that releases of LPIs have been unnested from the ap_list_lock there
are no xarray writers that exist in a context where IRQs are already
disabled. As such we can relax the locking to the non-IRQ disabling
spinlock to guard the LPI xarray.

Note that there are still readers of the LPI xarray where IRQs are
disabled however the readers rely on RCU protection instead of the lock.

Reviewed-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250905100531.282980-6-oliver.upton@linux.dev


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent d54594ac
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ void kvm_vgic_early_init(struct kvm *kvm)
{
	struct vgic_dist *dist = &kvm->arch.vgic;

	xa_init_flags(&dist->lpi_xa, XA_FLAGS_LOCK_IRQ);
	xa_init(&dist->lpi_xa);
}

/* CREATION */
+3 −4
Original line number Diff line number Diff line
@@ -78,7 +78,6 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
{
	struct vgic_dist *dist = &kvm->arch.vgic;
	struct vgic_irq *irq = vgic_get_irq(kvm, intid), *oldirq;
	unsigned long flags;
	int ret;

	/* In this case there is no put, since we keep the reference. */
@@ -89,7 +88,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
	if (!irq)
		return ERR_PTR(-ENOMEM);

	ret = xa_reserve_irq(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT);
	ret = xa_reserve(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT);
	if (ret) {
		kfree(irq);
		return ERR_PTR(ret);
@@ -104,7 +103,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
	irq->target_vcpu = vcpu;
	irq->group = 1;

	xa_lock_irqsave(&dist->lpi_xa, flags);
	xa_lock(&dist->lpi_xa);

	/*
	 * There could be a race with another vgic_add_lpi(), so we need to
@@ -126,7 +125,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
	}

out_unlock:
	xa_unlock_irqrestore(&dist->lpi_xa, flags);
	xa_unlock(&dist->lpi_xa);

	if (ret)
		return ERR_PTR(ret);
+6 −7
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = {
 *     kvm->arch.config_lock (mutex)
 *       its->cmd_lock (mutex)
 *         its->its_lock (mutex)
 *           vgic_dist->lpi_xa.xa_lock		must be taken with IRQs disabled
 *           vgic_dist->lpi_xa.xa_lock
 *             vgic_cpu->ap_list_lock		must be taken with IRQs disabled
 *               vgic_irq->irq_lock		must be taken with IRQs disabled
 *
@@ -141,30 +141,29 @@ static __must_check bool vgic_put_irq_norelease(struct kvm *kvm, struct vgic_irq
void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
{
	struct vgic_dist *dist = &kvm->arch.vgic;
	unsigned long flags;

	if (!__vgic_put_irq(kvm, irq))
		return;

	xa_lock_irqsave(&dist->lpi_xa, flags);
	xa_lock(&dist->lpi_xa);
	vgic_release_lpi_locked(dist, irq);
	xa_unlock_irqrestore(&dist->lpi_xa, flags);
	xa_unlock(&dist->lpi_xa);
}

static void vgic_release_deleted_lpis(struct kvm *kvm)
{
	struct vgic_dist *dist = &kvm->arch.vgic;
	unsigned long flags, intid;
	unsigned long intid;
	struct vgic_irq *irq;

	xa_lock_irqsave(&dist->lpi_xa, flags);
	xa_lock(&dist->lpi_xa);

	xa_for_each(&dist->lpi_xa, intid, irq) {
		if (irq->pending_release)
			vgic_release_lpi_locked(dist, irq);
	}

	xa_unlock_irqrestore(&dist->lpi_xa, flags);
	xa_unlock(&dist->lpi_xa);
}

void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)