yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
05bba0
From 3e7a0ab48e4cd233caf8ab9e2593d1d2978bad9d Mon Sep 17 00:00:00 2001
05bba0
From: Alex Williamson <alex.williamson@redhat.com>
05bba0
Date: Fri, 10 Apr 2015 16:34:19 +0200
05bba0
Subject: [PATCH 08/14] vfio-pci: Enable device request notification support
05bba0
05bba0
Message-id: <20150410163419.15324.17072.stgit@gimli.home>
05bba0
Patchwork-id: 64788
05bba0
O-Subject: [RHEL7.2 qemu-kvm PATCH 8/8] vfio-pci: Enable device request notification support
05bba0
Bugzilla: 1210509
05bba0
RH-Acked-by: Thomas Huth <thuth@redhat.com>
05bba0
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
05bba0
RH-Acked-by: Bandan Das <bsd@redhat.com>
05bba0
05bba0
Upstream: 47cbe50cc8d8e59129311bcdb827e1116e935bde
05bba0
05bba0
Linux v4.0-rc1 vfio-pci introduced a new virtual interrupt to allow
05bba0
the kernel to request a device from the user.  When signaled, QEMU
05bba0
will by default attmempt to hot-unplug the device.  This is a one-
05bba0
shot attempt with the expectation that the kernel will continue to
05bba0
poll for the device if it is not returned.  Returning the device when
05bba0
requested is the expected standard model of cooperative usage, but we
05bba0
also add an option option to disable this feature.  Initially this
05bba0
opt-out is set as an experimental option because we really should
05bba0
honor kernel requests for the device.
05bba0
05bba0
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
05bba0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
05bba0
---
05bba0
 hw/misc/vfio.c             | 100 +++++++++++++++++++++++++++++++++++++++++++++
05bba0
 linux-headers/linux/vfio.h |   1 +
05bba0
 2 files changed, 101 insertions(+)
05bba0
05bba0
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
05bba0
index d06b485..cbc9d8a 100644
05bba0
--- a/hw/misc/vfio.c
05bba0
+++ b/hw/misc/vfio.c
05bba0
@@ -195,14 +195,18 @@ typedef struct VFIODevice {
05bba0
     QLIST_ENTRY(VFIODevice) next;
05bba0
     struct VFIOGroup *group;
05bba0
     EventNotifier err_notifier;
05bba0
+    EventNotifier req_notifier;
05bba0
     uint32_t features;
05bba0
 #define VFIO_FEATURE_ENABLE_VGA_BIT 0
05bba0
 #define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
05bba0
+#define VFIO_FEATURE_ENABLE_REQ_BIT 1
05bba0
+#define VFIO_FEATURE_ENABLE_REQ (1 << VFIO_FEATURE_ENABLE_REQ_BIT)
05bba0
     int32_t bootindex;
05bba0
     uint8_t pm_cap;
05bba0
     bool reset_works;
05bba0
     bool has_vga;
05bba0
     bool pci_aer;
05bba0
+    bool req_enabled;
05bba0
     bool has_flr;
05bba0
     bool has_pm_reset;
05bba0
     bool needs_reset;
05bba0
@@ -3595,6 +3599,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
05bba0
 
05bba0
         vdev->has_vga = true;
05bba0
     }
05bba0
+
05bba0
     irq_info.index = VFIO_PCI_ERR_IRQ_INDEX;
05bba0
 
05bba0
     ret = ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
05bba0
@@ -3737,6 +3742,97 @@ static void vfio_unregister_err_notifier(VFIODevice *vdev)
05bba0
     event_notifier_cleanup(&vdev->err_notifier);
05bba0
 }
05bba0
 
05bba0
+static void vfio_req_notifier_handler(void *opaque)
05bba0
+{
05bba0
+    VFIODevice *vdev = opaque;
05bba0
+
05bba0
+    if (!event_notifier_test_and_clear(&vdev->req_notifier)) {
05bba0
+        return;
05bba0
+    }
05bba0
+
05bba0
+    qdev_unplug(&vdev->pdev.qdev, NULL);
05bba0
+}
05bba0
+
05bba0
+static void vfio_register_req_notifier(VFIODevice *vdev)
05bba0
+{
05bba0
+    struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info),
05bba0
+                                      .index = VFIO_PCI_REQ_IRQ_INDEX };
05bba0
+    int argsz;
05bba0
+    struct vfio_irq_set *irq_set;
05bba0
+    int32_t *pfd;
05bba0
+
05bba0
+    if (!(vdev->features & VFIO_FEATURE_ENABLE_REQ)) {
05bba0
+        return;
05bba0
+    }
05bba0
+
05bba0
+    if (ioctl(vdev->fd,
05bba0
+              VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0 || irq_info.count < 1) {
05bba0
+        return;
05bba0
+    }
05bba0
+
05bba0
+    if (event_notifier_init(&vdev->req_notifier, 0)) {
05bba0
+        error_report("vfio: Unable to init event notifier for device request");
05bba0
+        return;
05bba0
+    }
05bba0
+
05bba0
+    argsz = sizeof(*irq_set) + sizeof(*pfd);
05bba0
+
05bba0
+    irq_set = g_malloc0(argsz);
05bba0
+    irq_set->argsz = argsz;
05bba0
+    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
05bba0
+                     VFIO_IRQ_SET_ACTION_TRIGGER;
05bba0
+    irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
05bba0
+    irq_set->start = 0;
05bba0
+    irq_set->count = 1;
05bba0
+    pfd = (int32_t *)&irq_set->data;
05bba0
+
05bba0
+    *pfd = event_notifier_get_fd(&vdev->req_notifier);
05bba0
+    qemu_set_fd_handler(*pfd, vfio_req_notifier_handler, NULL, vdev);
05bba0
+
05bba0
+    if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
05bba0
+        error_report("vfio: Failed to set up device request notification");
05bba0
+        qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
05bba0
+        event_notifier_cleanup(&vdev->req_notifier);
05bba0
+    } else {
05bba0
+        vdev->req_enabled = true;
05bba0
+    }
05bba0
+
05bba0
+    g_free(irq_set);
05bba0
+}
05bba0
+
05bba0
+static void vfio_unregister_req_notifier(VFIODevice *vdev)
05bba0
+{
05bba0
+    int argsz;
05bba0
+    struct vfio_irq_set *irq_set;
05bba0
+    int32_t *pfd;
05bba0
+
05bba0
+    if (!vdev->req_enabled) {
05bba0
+        return;
05bba0
+    }
05bba0
+
05bba0
+    argsz = sizeof(*irq_set) + sizeof(*pfd);
05bba0
+
05bba0
+    irq_set = g_malloc0(argsz);
05bba0
+    irq_set->argsz = argsz;
05bba0
+    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
05bba0
+                     VFIO_IRQ_SET_ACTION_TRIGGER;
05bba0
+    irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
05bba0
+    irq_set->start = 0;
05bba0
+    irq_set->count = 1;
05bba0
+    pfd = (int32_t *)&irq_set->data;
05bba0
+    *pfd = -1;
05bba0
+
05bba0
+    if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
05bba0
+        error_report("vfio: Failed to de-assign device request fd: %m");
05bba0
+    }
05bba0
+    g_free(irq_set);
05bba0
+    qemu_set_fd_handler(event_notifier_get_fd(&vdev->req_notifier),
05bba0
+                        NULL, NULL, vdev);
05bba0
+    event_notifier_cleanup(&vdev->req_notifier);
05bba0
+
05bba0
+    vdev->req_enabled = false;
05bba0
+}
05bba0
+
05bba0
 static int vfio_initfn(PCIDevice *pdev)
05bba0
 {
05bba0
     VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
05bba0
@@ -3889,6 +3985,7 @@ static int vfio_initfn(PCIDevice *pdev)
05bba0
 
05bba0
     add_boot_device_path(vdev->bootindex, &pdev->qdev, NULL);
05bba0
     vfio_register_err_notifier(vdev);
05bba0
+    vfio_register_req_notifier(vdev);
05bba0
 
05bba0
     return 0;
05bba0
 
05bba0
@@ -3908,6 +4005,7 @@ static void vfio_exitfn(PCIDevice *pdev)
05bba0
     VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
05bba0
     VFIOGroup *group = vdev->group;
05bba0
 
05bba0
+    vfio_unregister_req_notifier(vdev);
05bba0
     vfio_unregister_err_notifier(vdev);
05bba0
     pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
05bba0
     vfio_disable_interrupts(vdev);
05bba0
@@ -3962,6 +4060,8 @@ static Property vfio_pci_dev_properties[] = {
05bba0
                        intx.mmap_timeout, 1100),
05bba0
     DEFINE_PROP_BIT("x-vga", VFIODevice, features,
05bba0
                     VFIO_FEATURE_ENABLE_VGA_BIT, false),
05bba0
+    DEFINE_PROP_BIT("x-req", VFIODevice, features,
05bba0
+                    VFIO_FEATURE_ENABLE_REQ_BIT, true),
05bba0
     DEFINE_PROP_INT32("bootindex", VFIODevice, bootindex, -1),
05bba0
     /*
05bba0
      * TODO - support passed fds... is this necessary?
05bba0
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
05bba0
index 7919c76..d197fd4 100644
05bba0
--- a/linux-headers/linux/vfio.h
05bba0
+++ b/linux-headers/linux/vfio.h
05bba0
@@ -321,6 +321,7 @@ enum {
05bba0
 	VFIO_PCI_MSI_IRQ_INDEX,
05bba0
 	VFIO_PCI_MSIX_IRQ_INDEX,
05bba0
 	VFIO_PCI_ERR_IRQ_INDEX,
05bba0
+	VFIO_PCI_REQ_IRQ_INDEX,
05bba0
 	VFIO_PCI_NUM_IRQS
05bba0
 };
05bba0
 
05bba0
-- 
05bba0
1.8.3.1
05bba0