We use the VFIO_PCI_DMA_FAULT_IRQ_INDEX "irq" index to set/unset a notifier for physical DMA faults. The associated eventfd is triggered, in nested mode, whenever a fault is detected at IOMMU physical level.
As this is the first use of this new IRQ index, also handle it in irq_to_str() in case the signaling setup fails. The actual handler will be implemented in subsequent patches. Signed-off-by: Eric Auger <eric.au...@redhat.com> --- v3 -> v4: - check VFIO_PCI_DMA_FAULT_IRQ_INDEX is supported at kernel level before attempting to set signaling for it. --- hw/vfio/common.c | 3 +++ hw/vfio/pci.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/vfio/pci.h | 1 + 3 files changed, 56 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 532ede0e70..cf0087321e 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -130,6 +130,9 @@ static char *irq_to_str(int index, int subindex) case VFIO_PCI_REQ_IRQ_INDEX: str = g_strdup_printf("REQ-%d", subindex); break; + case VFIO_PCI_DMA_FAULT_IRQ_INDEX: + str = g_strdup_printf("DMA-FAULT-%d", subindex); + break; default: str = g_strdup_printf("index %d (unknown)", index); break; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index b613b20501..29d4f633b0 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2736,6 +2736,56 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) vdev->req_enabled = false; } +static void vfio_dma_fault_notifier_handler(void *opaque) +{ + VFIOPCIDevice *vdev = opaque; + + if (!event_notifier_test_and_clear(&vdev->dma_fault_notifier)) { + return; + } +} + +static void vfio_register_dma_fault_notifier(VFIOPCIDevice *vdev) +{ + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info), + .index = VFIO_PCI_DMA_FAULT_IRQ_INDEX }; + Error *err = NULL; + int32_t fd; + + if (ioctl(vdev->vbasedev.fd, + VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0 || irq_info.count < 1) { + return; + } + + if (event_notifier_init(&vdev->dma_fault_notifier, 0)) { + error_report("vfio: Unable to init event notifier for dma fault"); + return; + } + + fd = event_notifier_get_fd(&vdev->dma_fault_notifier); + qemu_set_fd_handler(fd, vfio_dma_fault_notifier_handler, NULL, vdev); + + if (vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_DMA_FAULT_IRQ_INDEX, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + qemu_set_fd_handler(fd, NULL, NULL, vdev); + event_notifier_cleanup(&vdev->dma_fault_notifier); + } +} + +static void vfio_unregister_dma_fault_notifier(VFIOPCIDevice *vdev) +{ + Error *err = NULL; + + if (vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_DMA_FAULT_IRQ_INDEX, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); + } + qemu_set_fd_handler(event_notifier_get_fd(&vdev->dma_fault_notifier), + NULL, NULL, vdev); + event_notifier_cleanup(&vdev->dma_fault_notifier); +} + static void vfio_realize(PCIDevice *pdev, Error **errp) { VFIOPCIDevice *vdev = PCI_VFIO(pdev); @@ -3035,6 +3085,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_register_err_notifier(vdev); vfio_register_req_notifier(vdev); + vfio_register_dma_fault_notifier(vdev); vfio_setup_resetfn_quirk(vdev); return; @@ -3073,6 +3124,7 @@ static void vfio_exitfn(PCIDevice *pdev) vfio_unregister_req_notifier(vdev); vfio_unregister_err_notifier(vdev); + vfio_unregister_dma_fault_notifier(vdev); pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); vfio_disable_interrupts(vdev); if (vdev->intx.mmap_timer) { diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index cfcd1a81b8..96d29d667b 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -135,6 +135,7 @@ typedef struct VFIOPCIDevice { PCIHostDeviceAddress host; EventNotifier err_notifier; EventNotifier req_notifier; + EventNotifier dma_fault_notifier; int (*resetfn)(struct VFIOPCIDevice *); uint32_t vendor_id; uint32_t device_id; -- 2.20.1