43fe83
From be42017f858b8227a7a2569eb80adbcb79342145 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <be42017f858b8227a7a2569eb80adbcb79342145.1382534060.git.jdenemar@redhat.com>
43fe83
From: Peter Krempa <pkrempa@redhat.com>
43fe83
Date: Thu, 10 Oct 2013 13:56:37 +0200
43fe83
Subject: [PATCH] qemu: Prefer VFIO for PCI device passthrough
43fe83
43fe83
https://bugzilla.redhat.com/show_bug.cgi?id=1001738
43fe83
43fe83
Prefer using VFIO (if available) to the legacy KVM device passthrough.
43fe83
43fe83
With this patch a PCI passthrough device without the driver configured
43fe83
will be started with VFIO if it's available on the host. If not legacy
43fe83
KVM passthrough is checked and error is reported if it's not available.
43fe83
43fe83
(cherry picked from commit f094aaac48a6bbeef87a4df0345dfe2964297298)
43fe83
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
---
43fe83
 docs/formatdomain.html.in |  9 ++++-----
43fe83
 src/conf/domain_conf.h    |  2 +-
43fe83
 src/libvirt_private.syms  |  1 +
43fe83
 src/qemu/qemu_command.c   | 12 +++++++-----
43fe83
 src/qemu/qemu_hostdev.c   | 30 +++++++++++++++++++++++++-----
43fe83
 src/qemu/qemu_hostdev.h   |  4 +++-
43fe83
 src/qemu/qemu_hotplug.c   |  2 +-
43fe83
 src/qemu/qemu_process.c   | 15 ++++++++-------
43fe83
 tests/qemuxml2argvtest.c  | 11 +++++++++++
43fe83
 9 files changed, 61 insertions(+), 25 deletions(-)
43fe83
43fe83
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
43fe83
index 4fecdee..512e0df 100644
43fe83
--- a/docs/formatdomain.html.in
43fe83
+++ b/docs/formatdomain.html.in
43fe83
@@ -2704,11 +2704,10 @@
43fe83
         backend, which is compatible with UEFI SecureBoot) or "kvm"
43fe83
         (for the legacy device assignment handled directly by the KVM
43fe83
         kernel module)Since 1.0.5 (QEMU and KVM
43fe83
-        only, requires kernel 3.6 or newer). Currently, "kvm"
43fe83
-        is the default used by libvirt when not explicitly provided,
43fe83
-        but since the two are functionally equivalent, this default
43fe83
-        could be changed in the future with no impact to domains that
43fe83
-        don't specify anything.
43fe83
+        only, requires kernel 3.6 or newer). The default, when
43fe83
+        the driver name is not explicitly specified, is to check wether
43fe83
+        VFIO is available and use it if it's the case. If VFIO is not
43fe83
+        available, the legacy "kvm" assignment is attempted.
43fe83
       
43fe83
       
readonly
43fe83
       
Indicates that the device is readonly, only supported by SCSI host
43fe83
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
43fe83
index 5a21576..5ad0318 100644
43fe83
--- a/src/conf/domain_conf.h
43fe83
+++ b/src/conf/domain_conf.h
43fe83
@@ -398,7 +398,7 @@ enum virDomainHostdevSubsysType {
43fe83
 
43fe83
 /* the backend driver used for PCI hostdev devices */
43fe83
 typedef enum {
43fe83
-    VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* currently kvm, could change */
43fe83
+    VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* detect automaticaly, prefer VFIO */
43fe83
     VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM,    /* force legacy kvm style */
43fe83
     VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO,   /* force vfio */
43fe83
 
43fe83
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
43fe83
index 5e4de67..9a00dfe 100644
43fe83
--- a/src/libvirt_private.syms
43fe83
+++ b/src/libvirt_private.syms
43fe83
@@ -261,6 +261,7 @@ virDomainHostdevFind;
43fe83
 virDomainHostdevInsert;
43fe83
 virDomainHostdevModeTypeToString;
43fe83
 virDomainHostdevRemove;
43fe83
+virDomainHostdevSubsysPciBackendTypeToString;
43fe83
 virDomainHostdevSubsysTypeToString;
43fe83
 virDomainHubTypeFromString;
43fe83
 virDomainHubTypeToString;
43fe83
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
43fe83
index 9c9b956..78f07c8 100644
43fe83
--- a/src/qemu/qemu_command.c
43fe83
+++ b/src/qemu/qemu_command.c
43fe83
@@ -5347,10 +5347,10 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
43fe83
                           virQEMUCapsPtr qemuCaps)
43fe83
 {
43fe83
     virBuffer buf = VIR_BUFFER_INITIALIZER;
43fe83
+    int backend = dev->source.subsys.u.pci.backend;
43fe83
 
43fe83
-    switch ((virDomainHostdevSubsysPciBackendType)
43fe83
-            dev->source.subsys.u.pci.backend) {
43fe83
-    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
43fe83
+    /* caller has to assign proper passthrough backend type */
43fe83
+    switch ((virDomainHostdevSubsysPciBackendType) backend) {
43fe83
     case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
43fe83
         virBufferAddLit(&buf, "pci-assign");
43fe83
         if (configfd && *configfd)
43fe83
@@ -5361,9 +5361,11 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
43fe83
         virBufferAddLit(&buf, "vfio-pci");
43fe83
         break;
43fe83
 
43fe83
+    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
43fe83
     case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
43fe83
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
43fe83
-                       _("PCI passhthrough type needs to be specified"));
43fe83
+        virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
+                       _("invalid PCI passthrough type '%s'"),
43fe83
+                       virDomainHostdevSubsysPciBackendTypeToString(backend));
43fe83
         break;
43fe83
     }
43fe83
 
43fe83
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
43fe83
index 7f3170d..81e0e88 100644
43fe83
--- a/src/qemu/qemu_hostdev.c
43fe83
+++ b/src/qemu/qemu_hostdev.c
43fe83
@@ -564,7 +564,8 @@ qemuHostdevHostSupportsPassthroughLegacy(void)
43fe83
 
43fe83
 static bool
43fe83
 qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
43fe83
-                                  size_t nhostdevs)
43fe83
+                                  size_t nhostdevs,
43fe83
+                                  virQEMUCapsPtr qemuCaps)
43fe83
 {
43fe83
     bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
43fe83
     bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
43fe83
@@ -581,6 +582,23 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
43fe83
             continue;
43fe83
 
43fe83
         switch ((virDomainHostdevSubsysPciBackendType) *backend) {
43fe83
+        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
43fe83
+            if (supportsPassthroughVFIO &&
43fe83
+                virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
43fe83
+                *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
43fe83
+            } else if (supportsPassthroughKVM &&
43fe83
+                       (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) ||
43fe83
+                        virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
43fe83
+                *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
43fe83
+            } else {
43fe83
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
43fe83
+                               _("host doesn't support passthrough of "
43fe83
+                                 "host PCI devices"));
43fe83
+                return false;
43fe83
+            }
43fe83
+
43fe83
+            break;
43fe83
+
43fe83
         case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
43fe83
             if (!supportsPassthroughVFIO) {
43fe83
                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
43fe83
@@ -589,7 +607,6 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
43fe83
             }
43fe83
             break;
43fe83
 
43fe83
-        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
43fe83
         case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
43fe83
             if (!supportsPassthroughKVM) {
43fe83
                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
43fe83
@@ -613,7 +630,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
43fe83
                              const char *name,
43fe83
                              const unsigned char *uuid,
43fe83
                              virDomainHostdevDefPtr *hostdevs,
43fe83
-                             int nhostdevs)
43fe83
+                             int nhostdevs,
43fe83
+                             virQEMUCapsPtr qemuCaps)
43fe83
 {
43fe83
     virPCIDeviceListPtr pcidevs;
43fe83
     int last_processed_hostdev_vf = -1;
43fe83
@@ -621,7 +639,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
43fe83
     int ret = -1;
43fe83
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
43fe83
 
43fe83
-    if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs))
43fe83
+    if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps))
43fe83
         goto cleanup;
43fe83
 
43fe83
     virObjectLock(driver->activePciHostdevs);
43fe83
@@ -1142,13 +1160,15 @@ cleanup:
43fe83
 int
43fe83
 qemuPrepareHostDevices(virQEMUDriverPtr driver,
43fe83
                        virDomainDefPtr def,
43fe83
+                       virQEMUCapsPtr qemuCaps,
43fe83
                        bool coldBoot)
43fe83
 {
43fe83
     if (!def->nhostdevs)
43fe83
         return 0;
43fe83
 
43fe83
     if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
43fe83
-                                     def->hostdevs, def->nhostdevs) < 0)
43fe83
+                                     def->hostdevs, def->nhostdevs,
43fe83
+                                     qemuCaps) < 0)
43fe83
         return -1;
43fe83
 
43fe83
     if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
43fe83
diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h
43fe83
index 327d4d5..272086e 100644
43fe83
--- a/src/qemu/qemu_hostdev.h
43fe83
+++ b/src/qemu/qemu_hostdev.h
43fe83
@@ -37,7 +37,8 @@ int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
43fe83
                                  const char *name,
43fe83
                                  const unsigned char *uuid,
43fe83
                                  virDomainHostdevDefPtr *hostdevs,
43fe83
-                                 int nhostdevs);
43fe83
+                                 int nhostdevs,
43fe83
+                                 virQEMUCapsPtr qemuCaps);
43fe83
 int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
43fe83
                              bool mandatory,
43fe83
                              virUSBDevicePtr *usb);
43fe83
@@ -50,6 +51,7 @@ int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
43fe83
                                   int nhostdevs);
43fe83
 int qemuPrepareHostDevices(virQEMUDriverPtr driver,
43fe83
                            virDomainDefPtr def,
43fe83
+                           virQEMUCapsPtr qemuCaps,
43fe83
                            bool coldBoot);
43fe83
 void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
43fe83
                                        const char *name,
43fe83
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
43fe83
index 0c42b0a..cdbafa7 100644
43fe83
--- a/src/qemu/qemu_hotplug.c
43fe83
+++ b/src/qemu/qemu_hotplug.c
43fe83
@@ -1018,7 +1018,7 @@ int qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver,
43fe83
         return -1;
43fe83
 
43fe83
     if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
43fe83
-                                     &hostdev, 1) < 0)
43fe83
+                                     &hostdev, 1, priv->qemuCaps) < 0)
43fe83
         return -1;
43fe83
 
43fe83
     switch ((virDomainHostdevSubsysPciBackendType) backend) {
43fe83
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
43fe83
index f979877..b9f291d 100644
43fe83
--- a/src/qemu/qemu_process.c
43fe83
+++ b/src/qemu/qemu_process.c
43fe83
@@ -3540,6 +3540,12 @@ int qemuProcessStart(virConnectPtr conn,
43fe83
             goto cleanup;
43fe83
     }
43fe83
 
43fe83
+    VIR_DEBUG("Determining emulator version");
43fe83
+    virObjectUnref(priv->qemuCaps);
43fe83
+    if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
43fe83
+                                                      vm->def->emulator)))
43fe83
+        goto cleanup;
43fe83
+
43fe83
     /* network devices must be "prepared" before hostdevs, because
43fe83
      * setting up a network device might create a new hostdev that
43fe83
      * will need to be setup.
43fe83
@@ -3550,7 +3556,8 @@ int qemuProcessStart(virConnectPtr conn,
43fe83
 
43fe83
     /* Must be run before security labelling */
43fe83
     VIR_DEBUG("Preparing host devices");
43fe83
-    if (qemuPrepareHostDevices(driver, vm->def, !migrateFrom) < 0)
43fe83
+    if (qemuPrepareHostDevices(driver, vm->def, priv->qemuCaps,
43fe83
+                               !migrateFrom) < 0)
43fe83
         goto cleanup;
43fe83
 
43fe83
     VIR_DEBUG("Preparing chr devices");
43fe83
@@ -3632,12 +3639,6 @@ int qemuProcessStart(virConnectPtr conn,
43fe83
         }
43fe83
     }
43fe83
 
43fe83
-    VIR_DEBUG("Determining emulator version");
43fe83
-    virObjectUnref(priv->qemuCaps);
43fe83
-    if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
43fe83
-                                                      vm->def->emulator)))
43fe83
-        goto cleanup;
43fe83
-
43fe83
     if (!qemuValidateCpuMax(vm->def, priv->qemuCaps))
43fe83
         goto cleanup;
43fe83
 
43fe83
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
43fe83
index 23ea2ee..1d964ce 100644
43fe83
--- a/tests/qemuxml2argvtest.c
43fe83
+++ b/tests/qemuxml2argvtest.c
43fe83
@@ -98,6 +98,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
43fe83
     virConnectPtr conn;
43fe83
     char *log = NULL;
43fe83
     virCommandPtr cmd = NULL;
43fe83
+    size_t i;
43fe83
 
43fe83
     if (!(conn = virGetConnect()))
43fe83
         goto out;
43fe83
@@ -154,6 +155,16 @@ static int testCompareXMLToArgvFiles(const char *xml,
43fe83
     if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
43fe83
         goto out;
43fe83
 
43fe83
+    for (i = 0; i < vmdef->nhostdevs; i++) {
43fe83
+        virDomainHostdevDefPtr hostdev = vmdef->hostdevs[i];
43fe83
+
43fe83
+        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
43fe83
+            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
43fe83
+            hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) {
43fe83
+            hostdev->source.subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
43fe83
+        }
43fe83
+    }
43fe83
+
43fe83
     if (!(cmd = qemuBuildCommandLine(conn, &driver, vmdef, &monitor_chr,
43fe83
                                      (flags & FLAG_JSON), extraFlags,
43fe83
                                      migrateFrom, migrateFd, NULL,
43fe83
-- 
43fe83
1.8.4
43fe83