@@ -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;
@@ -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) {
@@ -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;
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.auger@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(+)