|
|
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 |
|