Skip to content

Commit 1d6f83f

Browse files
committed
KVM: arm64: vgic: Store LPIs in an xarray
Using a linked-list for LPIs is less than ideal as it of course requires iterative searches to find a particular entry. An xarray is a better data structure for this use case, as it provides faster searches and can still handle a potentially sparse range of INTID allocations. Start by storing LPIs in an xarray, punting usage of the xarray to a subsequent change. The observant among you will notice that we added yet another lock to the chain of locking order rules; document the ordering of the xa_lock. Don't worry, we'll get rid of the lpi_list_lock one day... Reviewed-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 6613476 commit 1d6f83f

File tree

4 files changed

+24
-1
lines changed

4 files changed

+24
-1
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ void kvm_vgic_early_init(struct kvm *kvm)
5656
INIT_LIST_HEAD(&dist->lpi_list_head);
5757
INIT_LIST_HEAD(&dist->lpi_translation_cache);
5858
raw_spin_lock_init(&dist->lpi_list_lock);
59+
xa_init_flags(&dist->lpi_xa, XA_FLAGS_LOCK_IRQ);
5960
}
6061

6162
/* CREATION */
@@ -366,6 +367,8 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
366367

367368
if (vgic_supports_direct_msis(kvm))
368369
vgic_v4_teardown(kvm);
370+
371+
xa_destroy(&dist->lpi_xa);
369372
}
370373

371374
static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
5252
if (!irq)
5353
return ERR_PTR(-ENOMEM);
5454

55+
ret = xa_reserve_irq(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT);
56+
if (ret) {
57+
kfree(irq);
58+
return ERR_PTR(ret);
59+
}
60+
5561
INIT_LIST_HEAD(&irq->lpi_list);
5662
INIT_LIST_HEAD(&irq->ap_list);
5763
raw_spin_lock_init(&irq->irq_lock);
@@ -86,12 +92,22 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
8692
goto out_unlock;
8793
}
8894

95+
ret = xa_err(xa_store(&dist->lpi_xa, intid, irq, 0));
96+
if (ret) {
97+
xa_release(&dist->lpi_xa, intid);
98+
kfree(irq);
99+
goto out_unlock;
100+
}
101+
89102
list_add_tail(&irq->lpi_list, &dist->lpi_list_head);
90103
dist->lpi_list_count++;
91104

92105
out_unlock:
93106
raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
94107

108+
if (ret)
109+
return ERR_PTR(ret);
110+
95111
/*
96112
* We "cache" the configuration table entries in our struct vgic_irq's.
97113
* However we only have those structs for mapped IRQs, so we read in

arch/arm64/kvm/vgic/vgic.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = {
3030
* its->its_lock (mutex)
3131
* vgic_cpu->ap_list_lock must be taken with IRQs disabled
3232
* kvm->lpi_list_lock must be taken with IRQs disabled
33-
* vgic_irq->irq_lock must be taken with IRQs disabled
33+
* vgic_dist->lpi_xa.xa_lock must be taken with IRQs disabled
34+
* vgic_irq->irq_lock must be taken with IRQs disabled
3435
*
3536
* As the ap_list_lock might be taken from the timer interrupt handler,
3637
* we have to disable IRQs before taking this lock and everything lower
@@ -131,6 +132,7 @@ void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq)
131132
return;
132133

133134
list_del(&irq->lpi_list);
135+
xa_erase(&dist->lpi_xa, irq->intid);
134136
dist->lpi_list_count--;
135137

136138
kfree(irq);

include/kvm/arm_vgic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/spinlock.h>
1414
#include <linux/static_key.h>
1515
#include <linux/types.h>
16+
#include <linux/xarray.h>
1617
#include <kvm/iodev.h>
1718
#include <linux/list.h>
1819
#include <linux/jump_label.h>
@@ -275,6 +276,7 @@ struct vgic_dist {
275276

276277
/* Protects the lpi_list and the count value below. */
277278
raw_spinlock_t lpi_list_lock;
279+
struct xarray lpi_xa;
278280
struct list_head lpi_list_head;
279281
int lpi_list_count;
280282

0 commit comments

Comments
 (0)