[libvirt] [RFC PATCH 25/28] qemu: hotplug: Implement multifunction device hotplug

Shivaprasad G Bhat posted 28 patches 6 years, 8 months ago
[libvirt] [RFC PATCH 25/28] qemu: hotplug: Implement multifunction device hotplug
Posted by Shivaprasad G Bhat 6 years, 8 months ago
Signed-off-by: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com>
---
 src/qemu/qemu_domain.c                             |    2 
 src/qemu/qemu_domain_address.c                     |   68 +++++++++++++++++
 src/qemu/qemu_domain_address.h                     |    5 +
 src/qemu/qemu_driver.c                             |   66 ++++++++++------
 src/qemu/qemu_hotplug.c                            |   82 ++++++++++++++++++++
 src/qemu/qemu_hotplug.h                            |    4 +
 tests/qemuhotplugtest.c                            |   39 ++++++++--
 .../qemuhotplug-multifunction-hostdev-pci-2.xml    |   14 +++
 .../qemuhotplug-multifunction-hostdev-pci.xml      |   20 +++++
 ...hotplug-base-live+multifunction-hostdev-pci.xml |   76 +++++++++++++++++++
 ...eries-base-live+multifunction-hostdev-pci-2.xml |   61 +++++++++++++++
 ...pseries-base-live+multifunction-hostdev-pci.xml |   69 +++++++++++++++++
 12 files changed, 475 insertions(+), 31 deletions(-)
 create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci-2.xml
 create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci.xml
 create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+multifunction-hostdev-pci.xml
 create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci-2.xml
 create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci.xml

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index c0a0af525f..1cfaf01540 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -33,6 +33,8 @@
 #include "qemu_capabilities.h"
 #include "qemu_migration.h"
 #include "qemu_security.h"
+#include "qemu_hotplug.h"
+#include "qemu_hostdev.h"
 #include "viralloc.h"
 #include "virlog.h"
 #include "virerror.h"
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 7bee4fb937..ee743321dd 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -25,6 +25,7 @@
 
 #include "qemu_domain_address.h"
 #include "qemu_domain.h"
+#include "domain_conf.h"
 #include "viralloc.h"
 #include "virhostdev.h"
 #include "virerror.h"
@@ -3206,6 +3207,73 @@ qemuDomainEnsurePCIAddress(virDomainObjPtr obj,
                                          info->pciConnectFlags);
 }
 
+
+int
+qemuDomainPCIMultifunctionHostdevEnsurePCIAddresses(virDomainObjPtr vm,
+                                                    virDomainDeviceDefListPtr devlist,
+                                                    virQEMUDriverPtr driver)
+{
+    int ret = -1, aggrslotidx = 0;
+    virBitmapPtr slotmap = NULL;
+    size_t i;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainPCIMultifunctionAddressInfoPtr devinfos = NULL;
+
+    if (devlist->count > VIR_PCI_MAX_FUNCTIONS) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("More devices per slot found"));
+        return -1;
+    }
+
+    for (i = 0; i < devlist->count; i++)
+        qemuDomainFillDevicePCIConnectFlags(vm->def, devlist->devs[i], priv->qemuCaps, driver);
+
+    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + devlist->count) < 0)
+        return -1;
+
+    /* Temporarily add the devices to the domain def to get the
+     * next aggregateIdx */
+    for (i = 0; i < devlist->count; i++)
+        vm->def->hostdevs[vm->def->nhostdevs++] = devlist->devs[i]->data.hostdev;
+
+    for (i = 0; i < devlist->count; i++) {
+        if (qemuDomainIsPSeries(vm->def)) {
+            /* Isolation groups are only relevant for pSeries guests */
+            if (qemuDomainFillDeviceIsolationGroup(vm->def, devlist->devs[i]) < 0)
+                return -1;
+        }
+        qemuDomainSetDeviceSlotAggregateIdx(vm->def, devlist->devs[i]);
+        aggrslotidx = aggrslotidx ? aggrslotidx : devlist->devs[i]->data.hostdev->info->aggregateSlotIdx;
+        if (aggrslotidx != devlist->devs[i]->data.hostdev->info->aggregateSlotIdx) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Devices belong to different PCI slots"));
+            return -1;
+        }
+    }
+
+    for (i = 0; i < devlist->count; i++)
+        vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;
+
+    slotmap = virDomainDefHostdevGetPCIOnlineFunctionMap(vm->def, aggrslotidx);
+    if (!virBitmapIsAllClear(slotmap)) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("Device already assigned to guest"));
+        return -1;
+    }
+
+    if (VIR_ALLOC(devinfos) < 0)
+        return -1;
+
+    for (i = 0; i < devlist->count; i++) {
+         virPCIDeviceAddress addr = devlist->devs[i]->data.hostdev->source.subsys.u.pci.addr;
+         devinfos->infos[addr.function] =  devlist->devs[i]->data.hostdev->info;
+    }
+
+    ret = virDomainPCIAddressEnsureMultifunctionAddress(priv->pciaddrs, devinfos);
+    VIR_FREE(devinfos);
+    return ret;
+}
+
 void
 qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
                                virDomainDeviceInfoPtr info,
diff --git a/src/qemu/qemu_domain_address.h b/src/qemu/qemu_domain_address.h
index e1cc467714..43d1de889e 100644
--- a/src/qemu/qemu_domain_address.h
+++ b/src/qemu/qemu_domain_address.h
@@ -51,6 +51,11 @@ int qemuDomainEnsurePCIAddress(virDomainObjPtr obj,
                                virQEMUDriverPtr driver)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
 
+int
+qemuDomainPCIMultifunctionHostdevEnsurePCIAddresses(virDomainObjPtr obj,
+                                                    virDomainDeviceDefListPtr devlist,
+                                                    virQEMUDriverPtr driver);
+
 int qemuDomainFillDeviceIsolationGroup(virDomainDefPtr def,
                                        virDomainDeviceDefPtr dev)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d2e10082ea..fb14475d8c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7744,15 +7744,26 @@ qemuDomainAttachDeviceLiveInternal(virDomainObjPtr vm,
 
 static int
 qemuDomainAttachDeviceLive(virDomainObjPtr vm,
-                           virDomainDeviceDefPtr dev,
+                           virDomainDeviceDefListPtr devlist,
                            virQEMUDriverPtr driver)
 {
     int ret = -1;
+    size_t i;
 
-    if (virDomainDefCompatibleDevice(vm->def, dev, NULL) < 0)
-        return -1;
+    for (i = 0; i < devlist->count; i++)
+        if (virDomainDefCompatibleDevice(vm->def, devlist->devs[i], NULL) < 0)
+            return ret;
+
+    if (devlist->count > 1) {
+        ret = qemuDomainAttachMultifunctionDevice(vm, devlist, driver);
+        if (ret == 0) {
+            for (i = 0; i < devlist->count; i++)
+                devlist->devs[i]->data.hostdev = NULL;
+        }
+    } else if (devlist->count == 1) {
+        ret = qemuDomainAttachDeviceLiveInternal(vm, devlist->devs[0], driver);
+    }
 
-    ret = qemuDomainAttachDeviceLiveInternal(vm, dev, driver);
     if (ret == 0)
         ret = qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE);
 
@@ -8178,16 +8189,22 @@ qemuDomainAttachDeviceConfigInternal(virDomainDefPtr vmdef,
 
 static int
 qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
-                             virDomainDeviceDefPtr dev,
+                             virDomainDeviceDefListPtr devlist,
                              virCapsPtr caps,
                              unsigned int parse_flags,
                              virDomainXMLOptionPtr xmlopt)
 {
-    if (virDomainDefCompatibleDevice(vmdef, dev, NULL) < 0)
-        return -1;
+    size_t i;
 
-    if (qemuDomainAttachDeviceConfigInternal(vmdef, dev))
-        return -1;
+    for (i = 0; i < devlist->count; i++) {
+       if (virDomainDefCompatibleDevice(vmdef, devlist->devs[i], NULL) < 0)
+           return -1;
+    }
+
+    for (i = 0; i < devlist->count; i++) {
+        if (qemuDomainAttachDeviceConfigInternal(vmdef, devlist->devs[i]))
+            return -1;
+    }
 
     if (virDomainDefPostParse(vmdef, caps, parse_flags, xmlopt, NULL) < 0)
         return -1;
@@ -8493,9 +8510,11 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr vm,
                                     const char *xml,
                                     unsigned int flags)
 {
+    size_t i;
     virDomainDefPtr vmdef = NULL;
     virQEMUDriverConfigPtr cfg = NULL;
-    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
+    virDomainDeviceDefListPtr devlist = NULL, devcopylist = NULL;
+    virDomainDeviceDefListData data = {.def = vm->def, .xmlopt = driver->xmlopt, .caps = NULL};
     int ret = -1;
     virCapsPtr caps = NULL;
     unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE |
@@ -8508,15 +8527,16 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr vm,
 
     if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
         goto cleanup;
+    data.caps = caps;
 
-    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
-                                             caps, driver->xmlopt,
-                                             parse_flags);
-    if (dev == NULL)
+    devlist = qemuDomainDeviceParseXMLMany(xml, &data, parse_flags);
+    if (!devlist)
         goto cleanup;
+    devcopylist = devlist;
 
-    if (virDomainDeviceValidateAliasForHotplug(vm, dev, flags) < 0)
-        goto cleanup;
+    for (i = 0; i < devlist->count; i++)
+        if (virDomainDeviceValidateAliasForHotplug(vm, devlist->devs[i], flags) < 0)
+            goto cleanup;
 
     if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
         flags & VIR_DOMAIN_AFFECT_LIVE) {
@@ -8524,8 +8544,8 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr vm,
          * create a deep copy of device as adding
          * to CONFIG takes one instance.
          */
-        dev_copy = virDomainDeviceDefCopy(dev, vm->def, caps, driver->xmlopt);
-        if (!dev_copy)
+        devcopylist =  virDomainDeviceDefListCopy(devlist, &data);
+        if (!devcopylist)
             goto cleanup;
     }
 
@@ -8535,14 +8555,14 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr vm,
         if (!vmdef)
             goto cleanup;
 
-        if ((ret = qemuDomainAttachDeviceConfig(vmdef, dev, caps,
+        if ((ret = qemuDomainAttachDeviceConfig(vmdef, devlist, caps,
                                                 parse_flags,
                                                 driver->xmlopt)) < 0)
             goto cleanup;
     }
 
     if (flags & VIR_DOMAIN_AFFECT_LIVE) {
-        if ((ret = qemuDomainAttachDeviceLive(vm, dev_copy, driver)) < 0)
+        if ((ret = qemuDomainAttachDeviceLive(vm, devcopylist, driver)) < 0)
             goto cleanup;
         /*
          * update domain status forcibly because the domain status may be
@@ -8566,9 +8586,9 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr vm,
 
  cleanup:
     virDomainDefFree(vmdef);
-    if (dev != dev_copy)
-        virDomainDeviceDefFree(dev_copy);
-    virDomainDeviceDefFree(dev);
+    if (devlist != devcopylist)
+        virDomainDeviceDefListFree(devcopylist);
+    virDomainDeviceDefListFree(devlist);
     virObjectUnref(cfg);
     virObjectUnref(caps);
 
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 7dffaf9502..a339e92bfa 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1402,6 +1402,88 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
 }
 
 
+static int
+qemuiHostdevPCIMultifunctionDevicesListSort(const void *p1,
+                                            const void *p2)
+{
+    virDomainDeviceDefPtr a = *(virDomainDeviceDefPtr *) p1;
+    virDomainDeviceDefPtr b = *(virDomainDeviceDefPtr *) p2;
+    virPCIDeviceAddressPtr addr1 = &a->data.hostdev->source.subsys.u.pci.addr;
+    virPCIDeviceAddressPtr addr2 = &b->data.hostdev->source.subsys.u.pci.addr;
+
+    return addr1->function - addr2->function;
+}
+
+
+int
+qemuDomainAttachMultifunctionDevice(virDomainObjPtr vm,
+                                    virDomainDeviceDefListPtr devlist,
+                                    virQEMUDriverPtr driver)
+{
+    size_t i, d, h = devlist->count;
+    int ret = -1;
+    char *alias;
+    virObjectEventPtr event;
+    virQEMUCapsPtr qemuCaps = NULL;
+    virDomainHostdevDefPtr hostdev = NULL;
+
+    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache,
+                                            vm->def->emulator)))
+        return -1;
+
+    qsort(devlist->devs, devlist->count, sizeof(*devlist->devs), qemuiHostdevPCIMultifunctionDevicesListSort);
+
+    if (qemuDomainPCIMultifunctionHostdevEnsurePCIAddresses(vm, devlist, driver) < 0)
+        return -1;
+
+    for (d = 0; d < devlist->count; d++)
+        if (qemuDomainAttachPCIHostDevicePrepare(driver, vm->def, devlist->devs[d]->data.hostdev, qemuCaps) < 0)
+            goto cleanup;
+
+    /* Hotplug all functions, and Primary at last */
+    for (h = devlist->count; h > 0; h--) {
+        /* The functions need not be contiguous, as a card may be sold with
+         * minimal functionality and then install the additional functions on
+         * purchase into any of the daughter-card connectors.
+         */
+        hostdev = devlist->devs[h-1]->data.hostdev;
+        ret = qemuDomainAttachHostPCIDevice(driver, vm, hostdev);
+        if (ret)
+            goto release;
+
+        alias = hostdev->info->alias;
+        hostdev = NULL;
+
+        event = virDomainEventDeviceAddedNewFromObj(vm, alias);
+        qemuDomainEventQueue(driver, event);
+    }
+
+ release:
+    /* Release addresses for the device which are not hotplugged.
+     */
+    for (i = 0; i < h; i++)
+        qemuDomainReleaseDeviceAddress(vm, devlist->devs[i]->data.hostdev->info, NULL);
+
+ cleanup:
+    /* If none are actually hotplugged and just detached from the
+     * host driver reattach the devices to host driver.
+     *
+     * If one of the hotplug failed, those which are already hotplugged cannot
+     * be unplugged as they are released by qemu only on guest reboot even
+     * if we issue device_del on them.
+     * So, dont attempt to reattach any of them.
+     * NB: Let them be in the guest as they are not used anyway without
+     *     function-zero?
+     */
+    if (d > 0 && h == devlist->count) {
+        for (i = 0; i < d; i++)
+            qemuHostdevReAttachPCIDevices(driver, vm->def->name, &devlist->devs[i]->data.hostdev, 1);
+    }
+
+    return ret;
+}
+
+
 void
 qemuDomainDelTLSObjects(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index db0e1df79a..7a6e2dfb60 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -158,6 +158,10 @@ int qemuDomainAttachPCIHostDevicePrepare(virQEMUDriverPtr driver,
                                          virDomainDefPtr def,
                                          virDomainHostdevDefPtr dev,
                                          virQEMUCapsPtr qemuCaps);
+int
+qemuDomainAttachMultifunctionDevice(virDomainObjPtr vm,
+                                    virDomainDeviceDefListPtr devlist,
+                                    virQEMUDriverPtr driver);
 
 int
 qemuDomainChrInsert(virDomainDefPtr vmdef,
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
index b5dca5e5c9..39f122e083 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -82,6 +82,8 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
     virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI);
     virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE);
     virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY);
+    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_HOST_PCI_MULTIDOMAIN);
+    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_PCI_MULTIFUNCTION);
     if (event)
         virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT);
 
@@ -115,9 +117,14 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
 
 static int
 testQemuHotplugAttach(virDomainObjPtr vm,
-                      virDomainDeviceDefPtr dev)
+                      virDomainDeviceDefListPtr devlist)
 {
     int ret = -1;
+    virDomainDeviceDefPtr dev;
+
+    if (devlist->count > 1)
+        return qemuDomainAttachMultifunctionDevice(vm, devlist, &driver);
+    dev = devlist->devs[0];
 
     switch (dev->type) {
     case VIR_DOMAIN_DEVICE_DISK:
@@ -249,7 +256,9 @@ testQemuHotplug(const void *data)
     bool keep = test->keep;
     unsigned int device_parse_flags = 0;
     virDomainObjPtr vm = NULL;
-    virDomainDeviceDefPtr dev = NULL;
+    virDomainDeviceDefPtr dev = NULL; /*temperory */
+    virDomainDeviceDefListPtr devlist = NULL;
+    virDomainDeviceDefListData listdata;
     virCapsPtr caps = NULL;
     qemuMonitorTestPtr test_mon = NULL;
     qemuDomainObjPrivatePtr priv = NULL;
@@ -286,10 +295,13 @@ testQemuHotplug(const void *data)
     if (test->action == ATTACH)
         device_parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
 
-    if (!(dev = virDomainDeviceDefParse(device_xml, vm->def,
-                                        caps, driver.xmlopt,
-                                        device_parse_flags)))
+    listdata.def = vm->def;
+    listdata.xmlopt = driver.xmlopt;
+    listdata.caps = caps;
+    devlist = qemuDomainDeviceParseXMLMany(device_xml, &listdata, device_parse_flags);
+    if (!devlist)
         goto cleanup;
+    dev = devlist->devs[0]; /* temporary */
 
     /* Now is the best time to feed the spoofed monitor with predefined
      * replies. */
@@ -319,11 +331,11 @@ testQemuHotplug(const void *data)
 
     switch (test->action) {
     case ATTACH:
-        ret = testQemuHotplugAttach(vm, dev);
+        ret = testQemuHotplugAttach(vm, devlist);
         if (ret == 0) {
             /* vm->def stolen dev->data.* so we just need to free the dev
              * envelope */
-            VIR_FREE(dev);
+            virDomainDeviceDefListFreeShallow(devlist);
         }
         if (ret == 0 || fail)
             ret = testQemuHotplugCheckResult(vm, result_xml,
@@ -357,7 +369,7 @@ testQemuHotplug(const void *data)
         virObjectUnref(vm);
         test->vm = NULL;
     }
-    virDomainDeviceDefFree(dev);
+    virDomainDeviceDefListFree(devlist);
     virObjectUnref(caps);
     qemuMonitorTestFree(test_mon);
     return ((ret < 0 && fail) || (!ret && !fail)) ? 0 : -1;
@@ -856,6 +868,17 @@ mymain(void)
                    "device_add", QMP_OK);
     DO_TEST_DETACH("pseries-base-live", "hostdev-pci", false, false,
                    "device_del", QMP_DEVICE_DELETED("hostdev0") QMP_OK);
+    DO_TEST_ATTACH("base-live", "multifunction-hostdev-pci", false, false,
+                   "device_add", QMP_OK,
+                   "device_add", QMP_OK,
+                   "device_add", QMP_OK);
+
+    qemuTestSetHostArch(driver.caps, VIR_ARCH_PPC64);
+    DO_TEST_ATTACH("pseries-base-live", "multifunction-hostdev-pci-2", false, false,
+                   "device_add", QMP_OK,
+                   "device_add", QMP_OK,
+                   "device_add", QMP_OK);
+    qemuTestSetHostArch(driver.caps, VIR_ARCH_X86_64);
 
     DO_TEST_ATTACH("base-live", "watchdog", false, true,
                    "watchdog-set-action", QMP_OK,
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci-2.xml b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci-2.xml
new file mode 100644
index 0000000000..02e2236e5d
--- /dev/null
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci-2.xml
@@ -0,0 +1,14 @@
+<devices>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/>
+      </source>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/>
+      </source>
+    </hostdev>
+</devices>
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci.xml b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci.xml
new file mode 100644
index 0000000000..54bb627e30
--- /dev/null
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci.xml
@@ -0,0 +1,20 @@
+<devices>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x1'/>
+      </source>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/>
+      </source>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/>
+      </source>
+    </hostdev>
+</devices>
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+multifunction-hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+multifunction-hostdev-pci.xml
new file mode 100644
index 0000000000..f53fe7601b
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+multifunction-hostdev-pci.xml
@@ -0,0 +1,76 @@
+<domain type='kvm' id='7'>
+  <name>hotplug</name>
+  <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
+  <memory unit='KiB'>4194304</memory>
+  <currentMemory unit='KiB'>4194304</currentMemory>
+  <vcpu placement='static'>4</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <acpi/>
+    <apic/>
+    <pae/>
+  </features>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <controller type='usb' index='0'>
+      <alias name='usb'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='ide' index='0'>
+      <alias name='ide'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <alias name='scsi0'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'>
+      <alias name='pci'/>
+    </controller>
+    <controller type='virtio-serial' index='0'>
+      <alias name='virtio-serial0'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </controller>
+    <input type='mouse' bus='ps2'>
+      <alias name='input0'/>
+    </input>
+    <input type='keyboard' bus='ps2'>
+      <alias name='input1'/>
+    </input>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/>
+      </source>
+      <alias name='hostdev0'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x2'/>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x1'/>
+      </source>
+      <alias name='hostdev1'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x1'/>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/>
+      </source>
+      <alias name='hostdev2'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0' multifunction='on'/>
+    </hostdev>
+    <memballoon model='none'>
+      <alias name='balloon0'/>
+    </memballoon>
+  </devices>
+  <seclabel type='none' model='none'/>
+</domain>
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci-2.xml b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci-2.xml
new file mode 100644
index 0000000000..85dc48fdb8
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci-2.xml
@@ -0,0 +1,61 @@
+<domain type='kvm' id='7'>
+  <name>hotplug</name>
+  <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
+  <memory unit='KiB'>4194304</memory>
+  <currentMemory unit='KiB'>4194304</currentMemory>
+  <vcpu placement='static'>4</vcpu>
+  <os>
+    <type arch='ppc64' machine='pseries'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-ppc64</emulator>
+    <controller type='pci' index='0' model='pci-root'>
+      <model name='spapr-pci-host-bridge'/>
+      <target index='0'/>
+      <alias name='pci.0'/>
+    </controller>
+    <controller type='pci' index='1' model='pci-root'>
+      <model name='spapr-pci-host-bridge'/>
+      <target index='1'/>
+      <alias name='pci.1'/>
+    </controller>
+    <controller type='usb' index='0'>
+      <alias name='usb'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+    </controller>
+    <input type='keyboard' bus='usb'>
+      <alias name='input0'/>
+      <address type='usb' bus='0' port='1'/>
+    </input>
+    <input type='mouse' bus='usb'>
+      <alias name='input1'/>
+      <address type='usb' bus='0' port='2'/>
+    </input>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/>
+      </source>
+      <alias name='hostdev0'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x1'/>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/>
+      </source>
+      <alias name='hostdev1'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0' multifunction='on'/>
+    </hostdev>
+    <memballoon model='none'>
+      <alias name='balloon0'/>
+    </memballoon>
+    <panic model='pseries'/>
+  </devices>
+  <seclabel type='none' model='none'/>
+</domain>
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci.xml
new file mode 100644
index 0000000000..9338d42e2e
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunction-hostdev-pci.xml
@@ -0,0 +1,69 @@
+<domain type='kvm' id='7'>
+  <name>hotplug</name>
+  <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
+  <memory unit='KiB'>4194304</memory>
+  <currentMemory unit='KiB'>4194304</currentMemory>
+  <vcpu placement='static'>4</vcpu>
+  <os>
+    <type arch='ppc64' machine='pseries'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-ppc64</emulator>
+    <controller type='pci' index='0' model='pci-root'>
+      <model name='spapr-pci-host-bridge'/>
+      <target index='0'/>
+      <alias name='pci.0'/>
+    </controller>
+    <controller type='pci' index='1' model='pci-root'>
+      <model name='spapr-pci-host-bridge'/>
+      <target index='1'/>
+      <alias name='pci.1'/>
+    </controller>
+    <controller type='usb' index='0'>
+      <alias name='usb'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+    </controller>
+    <input type='keyboard' bus='usb'>
+      <alias name='input0'/>
+      <address type='usb' bus='0' port='1'/>
+    </input>
+    <input type='mouse' bus='usb'>
+      <alias name='input1'/>
+      <address type='usb' bus='0' port='2'/>
+    </input>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/>
+      </source>
+      <alias name='hostdev0'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x2'/>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x1'/>
+      </source>
+      <alias name='hostdev1'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x1'/>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/>
+      </source>
+      <alias name='hostdev2'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0' multifunction='on'/>
+    </hostdev>
+    <memballoon model='none'>
+      <alias name='balloon0'/>
+    </memballoon>
+    <panic model='pseries'/>
+  </devices>
+  <seclabel type='none' model='none'/>
+</domain>

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list