Commit 3a08a6ca authored by Oliver Upton's avatar Oliver Upton
Browse files

KVM: arm64: vgic-v3: Use bare refcount for VGIC LPIs



KVM's use of krefs to manage LPIs isn't adding much, especially
considering vgic_irq_release() is a noop due to the lack of sufficient
context.

Switch to using a regular refcount in anticipation of adding a
meaningful release concept for LPIs.

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


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent 7d6ca84a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ static int iter_mark_lpis(struct kvm *kvm)
	int nr_lpis = 0;

	xa_for_each(&dist->lpi_xa, intid, irq) {
		if (!vgic_try_get_irq_kref(irq))
		if (!vgic_try_get_irq_ref(irq))
			continue;

		xa_set_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER);
+2 −2
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
		raw_spin_lock_init(&irq->irq_lock);
		irq->vcpu = NULL;
		irq->target_vcpu = vcpu0;
		kref_init(&irq->refcount);
		refcount_set(&irq->refcount, 0);
		switch (dist->vgic_model) {
		case KVM_DEV_TYPE_ARM_VGIC_V2:
			irq->targets = 0;
@@ -277,7 +277,7 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
		irq->intid = i;
		irq->vcpu = NULL;
		irq->target_vcpu = vcpu;
		kref_init(&irq->refcount);
		refcount_set(&irq->refcount, 0);
		if (vgic_irq_is_sgi(i)) {
			/* SGIs */
			irq->enabled = 1;
+4 −4
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
	raw_spin_lock_init(&irq->irq_lock);

	irq->config = VGIC_CONFIG_EDGE;
	kref_init(&irq->refcount);
	refcount_set(&irq->refcount, 1);
	irq->intid = intid;
	irq->target_vcpu = vcpu;
	irq->group = 1;
@@ -111,7 +111,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
	 * check that we don't add a second list entry with the same LPI.
	 */
	oldirq = xa_load(&dist->lpi_xa, intid);
	if (vgic_try_get_irq_kref(oldirq)) {
	if (vgic_try_get_irq_ref(oldirq)) {
		/* Someone was faster with adding this LPI, lets use that. */
		kfree(irq);
		irq = oldirq;
@@ -547,7 +547,7 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db,
	rcu_read_lock();

	irq = xa_load(&its->translation_cache, cache_key);
	if (!vgic_try_get_irq_kref(irq))
	if (!vgic_try_get_irq_ref(irq))
		irq = NULL;

	rcu_read_unlock();
@@ -571,7 +571,7 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its,
	 * its_lock, as the ITE (and the reference it holds) cannot be freed.
	 */
	lockdep_assert_held(&its->its_lock);
	vgic_get_irq_kref(irq);
	vgic_get_irq_ref(irq);

	old = xa_store(&its->translation_cache, cache_key, irq, GFP_KERNEL_ACCOUNT);

+1 −1
Original line number Diff line number Diff line
@@ -518,7 +518,7 @@ static struct vgic_irq *__vgic_host_irq_get_vlpi(struct kvm *kvm, int host_irq)
		if (!irq->hw || irq->host_irq != host_irq)
			continue;

		if (!vgic_try_get_irq_kref(irq))
		if (!vgic_try_get_irq_ref(irq))
			return NULL;

		return irq;
+4 −13
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid)
	rcu_read_lock();

	irq = xa_load(&dist->lpi_xa, intid);
	if (!vgic_try_get_irq_kref(irq))
	if (!vgic_try_get_irq_ref(irq))
		irq = NULL;

	rcu_read_unlock();
@@ -114,15 +114,6 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
	return vgic_get_irq(vcpu->kvm, intid);
}

/*
 * We can't do anything in here, because we lack the kvm pointer to
 * lock and remove the item from the lpi_list. So we keep this function
 * empty and use the return value of kref_put() to trigger the freeing.
 */
static void vgic_irq_release(struct kref *ref)
{
}

void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
{
	struct vgic_dist *dist = &kvm->arch.vgic;
@@ -131,7 +122,7 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
	if (irq->intid < VGIC_MIN_LPI)
		return;

	if (!kref_put(&irq->refcount, vgic_irq_release))
	if (!refcount_dec_and_test(&irq->refcount))
		return;

	xa_lock_irqsave(&dist->lpi_xa, flags);
@@ -399,7 +390,7 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,
	 * now in the ap_list. This is safe as the caller must already hold a
	 * reference on the irq.
	 */
	vgic_get_irq_kref(irq);
	vgic_get_irq_ref(irq);
	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
	irq->vcpu = vcpu;

@@ -657,7 +648,7 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)

			/*
			 * This vgic_put_irq call matches the
			 * vgic_get_irq_kref in vgic_queue_irq_unlock,
			 * vgic_get_irq_ref in vgic_queue_irq_unlock,
			 * where we added the LPI to the ap_list. As
			 * we remove the irq from the list, we drop
			 * also drop the refcount.
Loading