@@ -16,6 +16,7 @@
#include "qemu/range.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
+#include <sys/ioctl.h>
#include "hw/nvram/fw_cfg.h"
#include "pci.h"
#include "trace.h"
@@ -287,13 +288,31 @@ static VFIOQuirk *vfio_quirk_alloc(int nr_mem)
return quirk;
}
-static void vfio_ioeventfd_exit(VFIOIOEventFD *ioeventfd)
+static void vfio_ioeventfd_exit(VFIOPCIDevice *vdev, VFIOIOEventFD *ioeventfd)
{
QLIST_REMOVE(ioeventfd, next);
+
memory_region_del_eventfd(ioeventfd->mr, ioeventfd->addr, ioeventfd->size,
ioeventfd->match_data, ioeventfd->data,
&ioeventfd->e);
- qemu_set_fd_handler(event_notifier_get_fd(&ioeventfd->e), NULL, NULL, NULL);
+
+ if (ioeventfd->vfio) {
+ struct vfio_device_ioeventfd vfio_ioeventfd;
+
+ vfio_ioeventfd.argsz = sizeof(vfio_ioeventfd);
+ vfio_ioeventfd.flags = ioeventfd->size;
+ vfio_ioeventfd.data = ioeventfd->data;
+ vfio_ioeventfd.offset = ioeventfd->region->fd_offset +
+ ioeventfd->region_addr;
+ vfio_ioeventfd.fd = -1;
+
+ ioctl(vdev->vbasedev.fd, VFIO_DEVICE_IOEVENTFD, &vfio_ioeventfd);
+
+ } else {
+ qemu_set_fd_handler(event_notifier_get_fd(&ioeventfd->e),
+ NULL, NULL, NULL);
+ }
+
event_notifier_cleanup(&ioeventfd->e);
g_free(ioeventfd);
}
@@ -304,7 +323,7 @@ static void vfio_drop_dynamic_eventfds(VFIOPCIDevice *vdev, VFIOQuirk *quirk)
QLIST_FOREACH_SAFE(ioeventfd, &quirk->ioeventfds, next, tmp) {
if (ioeventfd->dynamic) {
- vfio_ioeventfd_exit(ioeventfd);
+ vfio_ioeventfd_exit(vdev, ioeventfd);
}
}
}
@@ -326,6 +345,7 @@ static VFIOIOEventFD *vfio_ioeventfd_init(VFIOPCIDevice *vdev,
hwaddr region_addr, bool dynamic)
{
VFIOIOEventFD *ioeventfd = g_malloc0(sizeof(*ioeventfd));
+ struct vfio_device_ioeventfd vfio_ioeventfd;
if (event_notifier_init(&ioeventfd->e, 0)) {
g_free(ioeventfd);
@@ -349,8 +369,21 @@ static VFIOIOEventFD *vfio_ioeventfd_init(VFIOPCIDevice *vdev,
ioeventfd->region = region;
ioeventfd->region_addr = region_addr;
- qemu_set_fd_handler(event_notifier_get_fd(&ioeventfd->e),
- vfio_ioeventfd_handler, NULL, ioeventfd);
+ vfio_ioeventfd.argsz = sizeof(vfio_ioeventfd);
+ vfio_ioeventfd.flags = ioeventfd->size;
+ vfio_ioeventfd.data = ioeventfd->data;
+ vfio_ioeventfd.offset = ioeventfd->region->fd_offset +
+ ioeventfd->region_addr;
+ vfio_ioeventfd.fd = event_notifier_get_fd(&ioeventfd->e);
+
+ ioeventfd->vfio = !ioctl(vdev->vbasedev.fd,
+ VFIO_DEVICE_IOEVENTFD, &vfio_ioeventfd);
+
+ if (!ioeventfd->vfio) {
+ qemu_set_fd_handler(event_notifier_get_fd(&ioeventfd->e),
+ vfio_ioeventfd_handler, NULL, ioeventfd);
+ }
+
memory_region_add_eventfd(ioeventfd->mr, ioeventfd->addr,
ioeventfd->size, ioeventfd->match_data,
ioeventfd->data, &ioeventfd->e);
@@ -1820,7 +1853,7 @@ void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr)
QLIST_FOREACH(quirk, &bar->quirks, next) {
while (!QLIST_EMPTY(&quirk->ioeventfds)) {
- vfio_ioeventfd_exit(QLIST_FIRST(&quirk->ioeventfds));
+ vfio_ioeventfd_exit(vdev, QLIST_FIRST(&quirk->ioeventfds));
}
for (i = 0; i < quirk->nr_mem; i++) {
@@ -35,6 +35,7 @@ typedef struct VFIOIOEventFD {
hwaddr region_addr;
bool match_data;
bool dynamic;
+ bool vfio;
} VFIOIOEventFD;
typedef struct VFIOQuirk {
With vfio ioeventfd support, we can program vfio-pci to perform a specified BAR write when an eventfd is triggered. This allows the KVM ioeventfd to be wired directly to vfio-pci, entirely avoiding userspace handling for these events. On the same micro-benchmark where the ioeventfd got us to almost 90% of performance versus disabling the GeForce quirks, this gets us to within 95%. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> --- hw/vfio/pci-quirks.c | 45 +++++++++++++++++++++++++++++++++++++++------ hw/vfio/pci.h | 1 + 2 files changed, 40 insertions(+), 6 deletions(-)