summaryrefslogtreecommitdiff
path: root/hw/misc
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2013-12-06 11:16:13 -0700
committerAlex Williamson <alex.williamson@redhat.com>2013-12-06 11:16:13 -0700
commit5b49ab188ff0339aa3097ce7f5309f1306092f9e (patch)
tree08fb0cea7a891bdc7e0deecabc39ae3936aaede6 /hw/misc
parentbf63839ffa2d0eebb1eb1706022f46e93b6fec08 (diff)
downloadqemu-5b49ab188ff0339aa3097ce7f5309f1306092f9e.tar.gz
vfio-pci: Make use of new KVM-VFIO device
Add and remove groups from the KVM virtual VFIO device as we make use of them. This allows KVM to optimize for performance and correctness based on properties of the group. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'hw/misc')
-rw-r--r--hw/misc/vfio.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index f7f8a19ee8..f1aa4a7209 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -208,6 +208,17 @@ static QLIST_HEAD(, VFIOContainer)
static QLIST_HEAD(, VFIOGroup)
group_list = QLIST_HEAD_INITIALIZER(group_list);
+#ifdef CONFIG_KVM
+/*
+ * We have a single VFIO pseudo device per KVM VM. Once created it lives
+ * for the life of the VM. Closing the file descriptor only drops our
+ * reference to it and the device's reference to kvm. Therefore once
+ * initialized, this file descriptor is only released on QEMU exit and
+ * we'll re-use it should another vfio device be attached before then.
+ */
+static int vfio_kvm_device_fd = -1;
+#endif
+
static void vfio_disable_interrupts(VFIODevice *vdev);
static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
@@ -3041,6 +3052,59 @@ static void vfio_pci_reset_handler(void *opaque)
}
}
+static void vfio_kvm_device_add_group(VFIOGroup *group)
+{
+#ifdef CONFIG_KVM
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_GROUP,
+ .attr = KVM_DEV_VFIO_GROUP_ADD,
+ .addr = (uint64_t)(unsigned long)&group->fd,
+ };
+
+ if (!kvm_enabled()) {
+ return;
+ }
+
+ if (vfio_kvm_device_fd < 0) {
+ struct kvm_create_device cd = {
+ .type = KVM_DEV_TYPE_VFIO,
+ };
+
+ if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
+ DPRINTF("KVM_CREATE_DEVICE: %m\n");
+ return;
+ }
+
+ vfio_kvm_device_fd = cd.fd;
+ }
+
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_report("Failed to add group %d to KVM VFIO device: %m",
+ group->groupid);
+ }
+#endif
+}
+
+static void vfio_kvm_device_del_group(VFIOGroup *group)
+{
+#ifdef CONFIG_KVM
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_GROUP,
+ .attr = KVM_DEV_VFIO_GROUP_DEL,
+ .addr = (uint64_t)(unsigned long)&group->fd,
+ };
+
+ if (vfio_kvm_device_fd < 0) {
+ return;
+ }
+
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_report("Failed to remove group %d to KVM VFIO device: %m",
+ group->groupid);
+ }
+#endif
+}
+
static int vfio_connect_container(VFIOGroup *group)
{
VFIOContainer *container;
@@ -3189,6 +3253,8 @@ static VFIOGroup *vfio_get_group(int groupid)
QLIST_INSERT_HEAD(&group_list, group, next);
+ vfio_kvm_device_add_group(group);
+
return group;
}
@@ -3198,6 +3264,7 @@ static void vfio_put_group(VFIOGroup *group)
return;
}
+ vfio_kvm_device_del_group(group);
vfio_disconnect_container(group);
QLIST_REMOVE(group, next);
DPRINTF("vfio_put_group: close group->fd\n");