Skip to content

Commit 8b9f128

Browse files
madscientist159Alex Williamson
authored andcommitted
vfio/pci: Fix INTx handling on legacy non-PCI 2.3 devices
PCI devices prior to PCI 2.3 both use level interrupts and do not support interrupt masking, leading to a failure when passed through to a KVM guest on at least the ppc64 platform. This failure manifests as receiving and acknowledging a single interrupt in the guest, while the device continues to assert the level interrupt indicating a need for further servicing. When lazy IRQ masking is used on DisINTx- (non-PCI 2.3) hardware, the following sequence occurs: * Level IRQ assertion on device * IRQ marked disabled in kernel * Host interrupt handler exits without clearing the interrupt on the device * Eventfd is delivered to userspace * Guest processes IRQ and clears device interrupt * Device de-asserts INTx, then re-asserts INTx while the interrupt is masked * Newly asserted interrupt acknowledged by kernel VMM without being handled * Software mask removed by VFIO driver * Device INTx still asserted, host controller does not see new edge after EOI The behavior is now platform-dependent. Some platforms (amd64) will continue to spew IRQs for as long as the INTX line remains asserted, therefore the IRQ will be handled by the host as soon as the mask is dropped. Others (ppc64) will only send the one request, and if it is not handled no further interrupts will be sent. The former behavior theoretically leaves the system vulnerable to interrupt storm, and the latter will result in the device stalling after receiving exactly one interrupt in the guest. Work around this by disabling lazy IRQ masking for DisINTx- INTx devices. Signed-off-by: Timothy Pearson <tpearson@raptorengineering.com> Link: https://lore.kernel.org/r/333803015.1744464.1758647073336.JavaMail.zimbra@raptorengineeringinc.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent acb59a4 commit 8b9f128

1 file changed

Lines changed: 7 additions & 0 deletions

File tree

drivers/vfio/pci/vfio_pci_intrs.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,14 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev,
304304

305305
vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX;
306306

307+
if (!vdev->pci_2_3)
308+
irq_set_status_flags(pdev->irq, IRQ_DISABLE_UNLAZY);
309+
307310
ret = request_irq(pdev->irq, vfio_intx_handler,
308311
irqflags, ctx->name, ctx);
309312
if (ret) {
313+
if (!vdev->pci_2_3)
314+
irq_clear_status_flags(pdev->irq, IRQ_DISABLE_UNLAZY);
310315
vdev->irq_type = VFIO_PCI_NUM_IRQS;
311316
kfree(name);
312317
vfio_irq_ctx_free(vdev, ctx, 0);
@@ -352,6 +357,8 @@ static void vfio_intx_disable(struct vfio_pci_core_device *vdev)
352357
vfio_virqfd_disable(&ctx->unmask);
353358
vfio_virqfd_disable(&ctx->mask);
354359
free_irq(pdev->irq, ctx);
360+
if (!vdev->pci_2_3)
361+
irq_clear_status_flags(pdev->irq, IRQ_DISABLE_UNLAZY);
355362
if (ctx->trigger)
356363
eventfd_ctx_put(ctx->trigger);
357364
kfree(ctx->name);

0 commit comments

Comments
 (0)