Skip to content

Commit b156e48

Browse files
rchatreawilliam
authored andcommitted
vfio/pci: Use xarray for interrupt context storage
Interrupt context is statically allocated at the time interrupts are allocated. Following allocation, the context is managed by directly accessing the elements of the array using the vector as index. The storage is released when interrupts are disabled. It is possible to dynamically allocate a single MSI-X interrupt after MSI-X is enabled. A dynamic storage for interrupt context is needed to support this. Replace the interrupt context array with an xarray (similar to what the core uses as store for MSI descriptors) that can support the dynamic expansion while maintaining the custom that uses the vector as index. With a dynamic storage it is no longer required to pre-allocate interrupt contexts at the time the interrupts are allocated. MSI and MSI-X interrupt contexts are only used when interrupts are enabled. Their allocation can thus be delayed until interrupt enabling. Only enabled interrupts will have associated interrupt contexts. Whether an interrupt has been allocated (a Linux irq number exists for it) becomes the criteria for whether an interrupt can be enabled. Signed-off-by: Reinette Chatre <[email protected]> Link: https://lore.kernel.org/lkml/[email protected]/ Reviewed-by: Kevin Tian <[email protected]> Acked-by: Thomas Gleixner <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/40e235f38d427aff79ae35eda0ced42502aa0937.1683740667.git.reinette.chatre@intel.com Signed-off-by: Alex Williamson <[email protected]>
1 parent 8850336 commit b156e48

File tree

3 files changed

+48
-46
lines changed

3 files changed

+48
-46
lines changed

drivers/vfio/pci/vfio_pci_core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,6 +2102,7 @@ int vfio_pci_core_init_dev(struct vfio_device *core_vdev)
21022102
INIT_LIST_HEAD(&vdev->vma_list);
21032103
INIT_LIST_HEAD(&vdev->sriov_pfs_item);
21042104
init_rwsem(&vdev->memory_lock);
2105+
xa_init(&vdev->ctx);
21052106

21062107
return 0;
21072108
}

drivers/vfio/pci/vfio_pci_intrs.c

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -52,25 +52,33 @@ static
5252
struct vfio_pci_irq_ctx *vfio_irq_ctx_get(struct vfio_pci_core_device *vdev,
5353
unsigned long index)
5454
{
55-
if (index >= vdev->num_ctx)
56-
return NULL;
57-
return &vdev->ctx[index];
55+
return xa_load(&vdev->ctx, index);
5856
}
5957

60-
static void vfio_irq_ctx_free_all(struct vfio_pci_core_device *vdev)
58+
static void vfio_irq_ctx_free(struct vfio_pci_core_device *vdev,
59+
struct vfio_pci_irq_ctx *ctx, unsigned long index)
6160
{
62-
kfree(vdev->ctx);
61+
xa_erase(&vdev->ctx, index);
62+
kfree(ctx);
6363
}
6464

65-
static int vfio_irq_ctx_alloc_num(struct vfio_pci_core_device *vdev,
66-
unsigned long num)
65+
static struct vfio_pci_irq_ctx *
66+
vfio_irq_ctx_alloc(struct vfio_pci_core_device *vdev, unsigned long index)
6767
{
68-
vdev->ctx = kcalloc(num, sizeof(struct vfio_pci_irq_ctx),
69-
GFP_KERNEL_ACCOUNT);
70-
if (!vdev->ctx)
71-
return -ENOMEM;
68+
struct vfio_pci_irq_ctx *ctx;
69+
int ret;
7270

73-
return 0;
71+
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
72+
if (!ctx)
73+
return NULL;
74+
75+
ret = xa_insert(&vdev->ctx, index, ctx, GFP_KERNEL_ACCOUNT);
76+
if (ret) {
77+
kfree(ctx);
78+
return NULL;
79+
}
80+
81+
return ctx;
7482
}
7583

7684
/*
@@ -226,23 +234,16 @@ static irqreturn_t vfio_intx_handler(int irq, void *dev_id)
226234
static int vfio_intx_enable(struct vfio_pci_core_device *vdev)
227235
{
228236
struct vfio_pci_irq_ctx *ctx;
229-
int ret;
230237

231238
if (!is_irq_none(vdev))
232239
return -EINVAL;
233240

234241
if (!vdev->pdev->irq)
235242
return -ENODEV;
236243

237-
ret = vfio_irq_ctx_alloc_num(vdev, 1);
238-
if (ret)
239-
return ret;
240-
241-
ctx = vfio_irq_ctx_get(vdev, 0);
242-
if (!ctx) {
243-
vfio_irq_ctx_free_all(vdev);
244-
return -EINVAL;
245-
}
244+
ctx = vfio_irq_ctx_alloc(vdev, 0);
245+
if (!ctx)
246+
return -ENOMEM;
246247

247248
vdev->num_ctx = 1;
248249

@@ -334,7 +335,7 @@ static void vfio_intx_disable(struct vfio_pci_core_device *vdev)
334335
vfio_intx_set_signal(vdev, -1);
335336
vdev->irq_type = VFIO_PCI_NUM_IRQS;
336337
vdev->num_ctx = 0;
337-
vfio_irq_ctx_free_all(vdev);
338+
vfio_irq_ctx_free(vdev, ctx, 0);
338339
}
339340

340341
/*
@@ -358,18 +359,13 @@ static int vfio_msi_enable(struct vfio_pci_core_device *vdev, int nvec, bool msi
358359
if (!is_irq_none(vdev))
359360
return -EINVAL;
360361

361-
ret = vfio_irq_ctx_alloc_num(vdev, nvec);
362-
if (ret)
363-
return ret;
364-
365362
/* return the number of supported vectors if we can't get all: */
366363
cmd = vfio_pci_memory_lock_and_enable(vdev);
367364
ret = pci_alloc_irq_vectors(pdev, 1, nvec, flag);
368365
if (ret < nvec) {
369366
if (ret > 0)
370367
pci_free_irq_vectors(pdev);
371368
vfio_pci_memory_unlock_and_restore(vdev, cmd);
372-
vfio_irq_ctx_free_all(vdev);
373369
return ret;
374370
}
375371
vfio_pci_memory_unlock_and_restore(vdev, cmd);
@@ -401,29 +397,36 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_core_device *vdev,
401397
if (vector >= vdev->num_ctx)
402398
return -EINVAL;
403399

404-
ctx = vfio_irq_ctx_get(vdev, vector);
405-
if (!ctx)
406-
return -EINVAL;
407400
irq = pci_irq_vector(pdev, vector);
401+
if (irq < 0)
402+
return -EINVAL;
408403

409-
if (ctx->trigger) {
404+
ctx = vfio_irq_ctx_get(vdev, vector);
405+
406+
if (ctx) {
410407
irq_bypass_unregister_producer(&ctx->producer);
411408

412409
cmd = vfio_pci_memory_lock_and_enable(vdev);
413410
free_irq(irq, ctx->trigger);
414411
vfio_pci_memory_unlock_and_restore(vdev, cmd);
415412
kfree(ctx->name);
416413
eventfd_ctx_put(ctx->trigger);
417-
ctx->trigger = NULL;
414+
vfio_irq_ctx_free(vdev, ctx, vector);
418415
}
419416

420417
if (fd < 0)
421418
return 0;
422419

420+
ctx = vfio_irq_ctx_alloc(vdev, vector);
421+
if (!ctx)
422+
return -ENOMEM;
423+
423424
ctx->name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-msi%s[%d](%s)",
424425
msix ? "x" : "", vector, pci_name(pdev));
425-
if (!ctx->name)
426-
return -ENOMEM;
426+
if (!ctx->name) {
427+
ret = -ENOMEM;
428+
goto out_free_ctx;
429+
}
427430

428431
trigger = eventfd_ctx_fdget(fd);
429432
if (IS_ERR(trigger)) {
@@ -469,6 +472,8 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_core_device *vdev,
469472
eventfd_ctx_put(trigger);
470473
out_free_name:
471474
kfree(ctx->name);
475+
out_free_ctx:
476+
vfio_irq_ctx_free(vdev, ctx, vector);
472477
return ret;
473478
}
474479

@@ -498,16 +503,13 @@ static void vfio_msi_disable(struct vfio_pci_core_device *vdev, bool msix)
498503
{
499504
struct pci_dev *pdev = vdev->pdev;
500505
struct vfio_pci_irq_ctx *ctx;
501-
unsigned int i;
506+
unsigned long i;
502507
u16 cmd;
503508

504-
for (i = 0; i < vdev->num_ctx; i++) {
505-
ctx = vfio_irq_ctx_get(vdev, i);
506-
if (ctx) {
507-
vfio_virqfd_disable(&ctx->unmask);
508-
vfio_virqfd_disable(&ctx->mask);
509-
vfio_msi_set_vector_signal(vdev, i, -1, msix);
510-
}
509+
xa_for_each(&vdev->ctx, i, ctx) {
510+
vfio_virqfd_disable(&ctx->unmask);
511+
vfio_virqfd_disable(&ctx->mask);
512+
vfio_msi_set_vector_signal(vdev, i, -1, msix);
511513
}
512514

513515
cmd = vfio_pci_memory_lock_and_enable(vdev);
@@ -523,7 +525,6 @@ static void vfio_msi_disable(struct vfio_pci_core_device *vdev, bool msix)
523525

524526
vdev->irq_type = VFIO_PCI_NUM_IRQS;
525527
vdev->num_ctx = 0;
526-
vfio_irq_ctx_free_all(vdev);
527528
}
528529

529530
/*
@@ -663,7 +664,7 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_core_device *vdev,
663664

664665
for (i = start; i < start + count; i++) {
665666
ctx = vfio_irq_ctx_get(vdev, i);
666-
if (!ctx || !ctx->trigger)
667+
if (!ctx)
667668
continue;
668669
if (flags & VFIO_IRQ_SET_DATA_NONE) {
669670
eventfd_signal(ctx->trigger, 1);

include/linux/vfio_pci_core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct vfio_pci_core_device {
5959
struct perm_bits *msi_perm;
6060
spinlock_t irqlock;
6161
struct mutex igate;
62-
struct vfio_pci_irq_ctx *ctx;
62+
struct xarray ctx;
6363
int num_ctx;
6464
int irq_type;
6565
int num_regions;

0 commit comments

Comments
 (0)