Skip to content

Commit e416343

Browse files
rchatreawilliam
authored andcommitted
vfio/pci: Support dynamic MSI-X
pci_msix_alloc_irq_at() enables an individual MSI-X interrupt to be allocated after MSI-X enabling. Use dynamic MSI-X (if supported by the device) to allocate an interrupt after MSI-X is enabled. An MSI-X interrupt is dynamically allocated at the time a valid eventfd is assigned. This is different behavior from a range provided during MSI-X enabling where interrupts are allocated for the entire range whether a valid eventfd is provided for each interrupt or not. The PCI-MSIX API requires that some number of irqs are allocated for an initial set of vectors when enabling MSI-X on the device. When dynamic MSIX allocation is not supported, the vector table, and thus the allocated irq set can only be resized by disabling and re-enabling MSI-X with a different range. In that case the irq allocation is essentially a cache for configuring vectors within the previously allocated vector range. When dynamic MSI-X allocation is supported, the API still requires some initial set of irqs to be allocated, but also supports allocating and freeing specific irq vectors both within and beyond the initially allocated range. For consistency between modes, as well as to reduce latency and improve reliability of allocations, and also simplicity, this implementation only releases irqs via pci_free_irq_vectors() when either the interrupt mode changes or the device is released. Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Link: https://lore.kernel.org/lkml/20230403211841.0e206b67.alex.williamson@redhat.com/ Reviewed-by: Kevin Tian <kevin.tian@intel.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/956c47057ae9fd45591feaa82e9ae20929889249.1683740667.git.reinette.chatre@intel.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent dd27a70 commit e416343

File tree

1 file changed

+41
-6
lines changed

1 file changed

+41
-6
lines changed

drivers/vfio/pci/vfio_pci_intrs.c

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,27 +381,55 @@ static int vfio_msi_enable(struct vfio_pci_core_device *vdev, int nvec, bool msi
381381
return 0;
382382
}
383383

384+
/*
385+
* vfio_msi_alloc_irq() returns the Linux IRQ number of an MSI or MSI-X device
386+
* interrupt vector. If a Linux IRQ number is not available then a new
387+
* interrupt is allocated if dynamic MSI-X is supported.
388+
*
389+
* Where is vfio_msi_free_irq()? Allocated interrupts are maintained,
390+
* essentially forming a cache that subsequent allocations can draw from.
391+
* Interrupts are freed using pci_free_irq_vectors() when MSI/MSI-X is
392+
* disabled.
393+
*/
394+
static int vfio_msi_alloc_irq(struct vfio_pci_core_device *vdev,
395+
unsigned int vector, bool msix)
396+
{
397+
struct pci_dev *pdev = vdev->pdev;
398+
struct msi_map map;
399+
int irq;
400+
u16 cmd;
401+
402+
irq = pci_irq_vector(pdev, vector);
403+
if (WARN_ON_ONCE(irq == 0))
404+
return -EINVAL;
405+
if (irq > 0 || !msix || !vdev->has_dyn_msix)
406+
return irq;
407+
408+
cmd = vfio_pci_memory_lock_and_enable(vdev);
409+
map = pci_msix_alloc_irq_at(pdev, vector, NULL);
410+
vfio_pci_memory_unlock_and_restore(vdev, cmd);
411+
412+
return map.index < 0 ? map.index : map.virq;
413+
}
414+
384415
static int vfio_msi_set_vector_signal(struct vfio_pci_core_device *vdev,
385416
unsigned int vector, int fd, bool msix)
386417
{
387418
struct pci_dev *pdev = vdev->pdev;
388419
struct vfio_pci_irq_ctx *ctx;
389420
struct eventfd_ctx *trigger;
390-
int irq, ret;
421+
int irq = -EINVAL, ret;
391422
u16 cmd;
392423

393-
irq = pci_irq_vector(pdev, vector);
394-
if (irq < 0)
395-
return -EINVAL;
396-
397424
ctx = vfio_irq_ctx_get(vdev, vector);
398425

399426
if (ctx) {
400427
irq_bypass_unregister_producer(&ctx->producer);
401-
428+
irq = pci_irq_vector(pdev, vector);
402429
cmd = vfio_pci_memory_lock_and_enable(vdev);
403430
free_irq(irq, ctx->trigger);
404431
vfio_pci_memory_unlock_and_restore(vdev, cmd);
432+
/* Interrupt stays allocated, will be freed at MSI-X disable. */
405433
kfree(ctx->name);
406434
eventfd_ctx_put(ctx->trigger);
407435
vfio_irq_ctx_free(vdev, ctx, vector);
@@ -410,6 +438,13 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_core_device *vdev,
410438
if (fd < 0)
411439
return 0;
412440

441+
if (irq == -EINVAL) {
442+
/* Interrupt stays allocated, will be freed at MSI-X disable. */
443+
irq = vfio_msi_alloc_irq(vdev, vector, msix);
444+
if (irq < 0)
445+
return irq;
446+
}
447+
413448
ctx = vfio_irq_ctx_alloc(vdev, vector);
414449
if (!ctx)
415450
return -ENOMEM;

0 commit comments

Comments
 (0)