[libvirt] [PATCH 3/4] qemu: assign addresses for spapr vfio hostdevices and generate cli

Shivaprasad G Bhat shivaprasadbhat at gmail.com
Fri Oct 17 16:57:04 UTC 2014


On pseries, the vfio host devices attach to the spapr-pci-vfio domain
instead of the default emulated domain.
So,  for a host device belonging to iommu group(say) 3, would need below
host bridge.
     -device spapr-pci-vfio-host-bridge,iommu=3,id=vfiohostbridge3,index=1

The vfio device then needs to assign itself to the bus "vfiohostbridge3"
as below :
     -device vfio-pci,host=0003:05:00.1,id=hostdev0,bus=vfiohostbridge3.0,addr=0x1

Since each host bridge controller adds a new domain, all the devices addressing
would need to start from bus0:slot1:function0 in the new domain.

The controller tag for spapr-pci-vfio-host-bridge in the xml has the
domain and iommu number allocated during the parsing based of the hostdevs in
the xml. Assign the pci addressses for the hostdevs from their respective
domains. The domain id "vfiohostbridge<iommu>" is used for uniqueness in the
controller alias.

For Example, 
The live xml and the lspci output of a running guest can be seen at
http://fpaste.org/142911/

Signed-off-by: Shivaprasad G Bhat <sbhat at linux.vnet.ibm.com>
Signed-off-by: Pradipta Kumar Banerjee <bpradip at in.ibm.com>
---
 src/conf/domain_addr.c   |    8 +
 src/conf/domain_addr.h   |    1 
 src/libvirt_private.syms |    1 
 src/qemu/qemu_command.c  |  277 +++++++++++++++++++++++++++++++++++++++++++---
 src/qemu/qemu_command.h  |   17 ++-
 tests/qemuhotplugtest.c  |    2 
 6 files changed, 283 insertions(+), 23 deletions(-)

diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index fb4a76f..db448f2 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -110,11 +110,11 @@ virDomainPCIAddressValidate(virDomainPCIAddressSetPtr addrs,
         virReportError(errType, "%s", _("No PCI buses available"));
         return false;
     }
-    if (addr->domain != 0) {
+    if (addr->domain != addrs->domainId) {
         virReportError(errType,
                        _("Invalid PCI address %s. "
-                         "Only PCI domain 0 is available"),
-                       addrStr);
+                         "Only PCI domain %d is available"),
+                       addrStr, addrs->domainId);
         return false;
     }
     if (addr->bus >= addrs->nbuses) {
@@ -463,7 +463,7 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs,
     /* default to starting the search for a free slot from
      * 0000:00:00.0
      */
-    virDevicePCIAddress a = { 0, 0, 0, 0, false };
+    virDevicePCIAddress a = { addrs->domainId, 0, 0, 0, false };
     char *addrStr = NULL;
 
     /* except if this search is for the exact same type of device as
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 2c3468e..2510bfd 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -64,6 +64,7 @@ struct _virDomainPCIAddressSet {
     size_t nbuses;
     virDevicePCIAddress lastaddr;
     virDomainPCIConnectFlags lastFlags;
+    int domainId;
     bool dryRun;          /* on a dry run, new buses are auto-added
                              and addresses aren't saved in device infos */
 };
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f61fccd..dfebcee 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -213,6 +213,7 @@ virDomainDeviceDefFree;
 virDomainDeviceDefParse;
 virDomainDeviceFindControllerModel;
 virDomainDeviceGetInfo;
+virDomainDeviceInfoClear;
 virDomainDeviceInfoCopy;
 virDomainDeviceInfoIterate;
 virDomainDeviceTypeToString;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3cec764..e0727b7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -69,6 +69,8 @@ VIR_LOG_INIT("qemu.qemu_command");
 #define VIO_ADDR_SERIAL 0x30000000ul
 #define VIO_ADDR_NVRAM 0x3000ul
 
+#define DEFAULT_PCI 0
+
 VIR_ENUM_DECL(virDomainDiskQEMUBus)
 VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
               "ide",
@@ -561,6 +563,12 @@ qemuNetworkPrepareDevices(virDomainDefPtr def)
                 goto cleanup;
             if (virDomainDefMaybeAddHostdevSpaprPCIVfiocontrollers(def) < 0)
                 goto cleanup;
+            /* The net device is originally assigned address in generic domain.
+             * Clear the original address for the new address to take effect.
+             */
+            if ((def->os.arch == VIR_ARCH_PPC64) && def->os.machine &&
+                STRPREFIX(def->os.machine, "pseries"))
+                virDomainDeviceInfoClear(&net->info);
         }
     }
     ret = 0;
@@ -885,6 +893,9 @@ qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
             return virAsprintf(&controller->info.alias, "pcie.%d", controller->idx);
         else
             return virAsprintf(&controller->info.alias, "pci.%d", controller->idx);
+    } else if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) {
+        return virAsprintf(&controller->info.alias, "vfiohostbridge%d.%d",
+                           controller->opts.spaprvfio.iommuGroupNum, controller->idx);
     }
 
     return virAsprintf(&controller->info.alias, "%s%d", prefix, controller->idx);
@@ -1291,6 +1302,49 @@ int qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def,
     return ret;
 }
 
+static int
+qemuIsValidCurrentDomainDevice(virDomainDefPtr def,
+                               virDomainDeviceDefPtr device,
+                               int domain)
+{
+    size_t j;
+    int currentDomainHostdev = 0;
+    int actualType = -1;
+    virDomainHostdevDefPtr hostdev = NULL;
+
+    if (device->type == VIR_DOMAIN_DEVICE_CONTROLLER &&
+        domain != device->data.controller->domain)
+        return -1; /* Dont reserve controllers not belonging to the current domain */
+
+    if (device->type == VIR_DOMAIN_DEVICE_NET) {
+        actualType = virDomainNetGetActualType(device->data.net);
+        if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV)
+            hostdev = virDomainNetGetActualHostdev(device->data.net);
+    } else if (device->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+        hostdev = device->data.hostdev;
+    }
+
+    if (domain == 0 && hostdev && (IS_PCI_VFIO_HOSTDEV(hostdev)))
+        return -1; /* Don't reserve vfio devices in emulated domain. */
+
+    if (domain != 0) {
+        if (device->type != VIR_DOMAIN_DEVICE_CONTROLLER && !hostdev)
+                return -1; /* Don't reserve non vfio devices and controllers in spapr-vfio domain */
+
+        if (hostdev && IS_PCI_VFIO_HOSTDEV(hostdev)) {
+            for (j = 0; j < def->ncontrollers; j++) {
+                if ((def->controllers[j]->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) &&
+                    (domain == def->controllers[j]->domain) &&
+                    (def->controllers[j]->opts.spaprvfio.iommuGroupNum == hostdev->source.subsys.u.pci.iommu))
+                    currentDomainHostdev = 1;
+            }
+            /* Dont reserve hostdevs which dont belong to current domain */
+            if (!currentDomainHostdev)
+                return -1;
+        }
+    }
+    return 0;
+}
 
 static int
 qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
@@ -1316,6 +1370,16 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
         return 0;
     }
 
+    /* For PPC64 the passthrough devices are assigned to non-emulated
+     * pci domain and wont be part of domain zero.
+     */
+    if (def->os.arch == VIR_ARCH_PPC64 && def->os.machine &&
+        STRPREFIX(def->os.machine, "pseries"))
+    {
+        if (qemuIsValidCurrentDomainDevice(def, device, addrs->domainId) < 0)
+            return 0;
+    }
+
     /* Change flags according to differing requirements of different
      * devices.
      */
@@ -1323,6 +1387,7 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
     case VIR_DOMAIN_DEVICE_CONTROLLER:
         switch (device->data.controller->type) {
         case  VIR_DOMAIN_CONTROLLER_TYPE_PCI:
+        case  VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO:
             switch (device->data.controller->model) {
             case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
                 /* pci-bridge needs a PCI slot, but it isn't
@@ -1460,27 +1525,40 @@ qemuDomainSupportsPCI(virDomainDefPtr def)
 
 int
 qemuDomainAssignPCIAddresses(virDomainDefPtr def,
-                             virQEMUCapsPtr qemuCaps,
-                             virDomainObjPtr obj)
+                                   virQEMUCapsPtr qemuCaps,
+                                   virDomainObjPtr obj,
+                                   int domain)
 {
     int ret = -1;
+    int iommu = -1;
     virDomainPCIAddressSetPtr addrs = NULL;
     qemuDomainObjPrivatePtr priv = NULL;
+    int controllerType = -1;
 
     if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
         int max_idx = -1;
         int nbuses = 0;
+        int ncontrollers = def->ncontrollers;
         size_t i;
         int rv;
         virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCI;
 
         for (i = 0; i < def->ncontrollers; i++) {
-            if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
-                if ((int) def->controllers[i]->idx > max_idx)
-                    max_idx = def->controllers[i]->idx;
-            }
+            virDomainControllerDefPtr cont = def->controllers[i];
+            if ((cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) &&
+                (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO))
+                continue;
+            if (cont->domain != domain)
+                continue;
+            if ((int) cont->idx > max_idx)
+                max_idx = cont->idx;
+            if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO)
+                iommu = cont->opts.spaprvfio.iommuGroupNum;
         }
 
+        controllerType = (domain == DEFAULT_PCI)?VIR_DOMAIN_CONTROLLER_TYPE_PCI:
+                    VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO;
+
         nbuses = max_idx + 1;
 
         if (nbuses > 0 &&
@@ -1488,7 +1566,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
             virDomainDeviceInfo info;
 
             /* 1st pass to figure out how many PCI bridges we need */
-            if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true)))
+            if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, domain, true)))
                 goto cleanup;
             if (qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
                 goto cleanup;
@@ -1500,9 +1578,18 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
                 virDomainPCIAddressBusPtr bus = &addrs->buses[i];
 
                 if ((rv = virDomainDefMaybeAddController(
-                         def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
+                         def, controllerType, domain,
                          i, bus->model)) < 0)
                     goto cleanup;
+
+                if (controllerType == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) {
+                    if (ncontrollers < def->ncontrollers) {
+                        /* If a bridge was actually added, set the IOMMU */
+                        def->controllers[def->ncontrollers-1]->opts.spaprvfio.iommuGroupNum = iommu;
+                        ncontrollers = def->ncontrollers;
+                    }
+                }
+
                 /* If we added a new bridge, we will need one more address */
                 if (rv > 0 && virDomainPCIAddressReserveNextSlot(addrs, &info,
                                                                  flags) < 0)
@@ -1519,7 +1606,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
             goto cleanup;
         }
 
-        if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, false)))
+        if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, domain, false)))
             goto cleanup;
 
         if (qemuDomainSupportsPCI(def)) {
@@ -1528,7 +1615,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
         }
     }
 
-    if (obj && obj->privateData) {
+    if (obj && obj->privateData && domain == DEFAULT_PCI) {
         priv = obj->privateData;
         if (addrs) {
             /* if this is the live domain object, we persist the PCI addresses*/
@@ -1549,6 +1636,32 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
     return ret;
 }
 
+int
+qemuDomainAssignSpaprVFIOHostdevPCIAddresses(virDomainDefPtr def,
+                                             virQEMUCapsPtr qemuCaps,
+                                             virDomainObjPtr obj)
+{
+    int ret = -1;
+    if ((def->os.arch != VIR_ARCH_PPC64) ||
+                    !STRPREFIX(def->os.machine, "pseries"))
+        return 0;
+
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
+        size_t i;
+        for (i = 0; i < def->ncontrollers; i++) {
+            if (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
+                def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) {
+                ret = qemuDomainAssignPCIAddresses(def, qemuCaps, obj,
+                                                   def->controllers[i]->domain);
+                if (ret)
+                    return ret;
+            }
+        }
+    }
+
+    return 0;
+}
+
 int qemuDomainAssignAddresses(virDomainDefPtr def,
                               virQEMUCapsPtr qemuCaps,
                               virDomainObjPtr obj)
@@ -1567,13 +1680,19 @@ int qemuDomainAssignAddresses(virDomainDefPtr def,
     if (rc)
         return rc;
 
-    return qemuDomainAssignPCIAddresses(def, qemuCaps, obj);
+    rc = qemuDomainAssignSpaprVFIOHostdevPCIAddresses(def, qemuCaps, obj);
+    if (rc)
+        return rc;
+
+    return qemuDomainAssignPCIAddresses(def, qemuCaps, obj, DEFAULT_PCI);
+
 }
 
 
 virDomainPCIAddressSetPtr
 qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
                               unsigned int nbuses,
+                              int domainId,
                               bool dryRun)
 {
     virDomainPCIAddressSetPtr addrs;
@@ -1584,6 +1703,7 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
 
     addrs->nbuses = nbuses;
     addrs->dryRun = dryRun;
+    addrs->domainId = domainId;
 
     /* As a safety measure, set default model='pci-root' for first pci
      * controller and 'pci-bridge' for all subsequent. After setting
@@ -1603,7 +1723,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
     for (i = 0; i < def->ncontrollers; i++) {
         size_t idx = def->controllers[i]->idx;
 
-        if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
+        if ((def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) &&
+            (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO))
+            continue;
+
+        if (def->controllers[i]->domain != domainId)
             continue;
 
         if (idx >= addrs->nbuses) {
@@ -1964,6 +2088,85 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
     return ret;
 }
 
+static int
+qemuAssignSPAPRHostDevAddresses(virDomainDefPtr def,
+                                virDomainPCIAddressSetPtr addrs)
+{
+    size_t i;
+    int iommu = -1;
+    int actualType = -1;
+    virDomainHostdevDefPtr hostdev = NULL;
+    virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_HOTPLUGGABLE | VIR_PCI_CONNECT_TYPE_PCI;
+    /* PCI controllers */
+    for (i = 0; i < def->ncontrollers; i++) {
+        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) {
+            if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+                continue;
+            if (def->controllers[i]->domain != addrs->domainId)
+                continue;
+            switch (def->controllers[i]->model) {
+            case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+                /* pci-root is implicit in the machine,
+                 * and needs no address */
+                iommu = def->controllers[i]->opts.spaprvfio.iommuGroupNum;
+                continue;
+            case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+                /* pci-bridge doesn't require hot-plug
+                 * (although it does provide hot-plug in its slots)
+                 */
+                flags = VIR_PCI_CONNECT_TYPE_PCI;
+                break;
+            default:
+                flags = VIR_PCI_CONNECT_HOTPLUGGABLE | VIR_PCI_CONNECT_TYPE_PCI;
+                break;
+            }
+            iommu = def->controllers[i]->opts.spaprvfio.iommuGroupNum;
+            if (virDomainPCIAddressReserveNextSlot(addrs,
+                                                   &def->controllers[i]->info,
+                                                   flags) < 0)
+                goto error;
+        }
+    }
+
+    flags = VIR_PCI_CONNECT_HOTPLUGGABLE | VIR_PCI_CONNECT_TYPE_PCI;
+
+    for (i = 0; i < def->nhostdevs; i++) {
+        if (def->hostdevs[i]->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+
+        if (!IS_PCI_VFIO_HOSTDEV(def->hostdevs[i]) ||
+            def->hostdevs[i]->source.subsys.u.pci.iommu != iommu)
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs, def->hostdevs[i]->info, flags) < 0)
+            goto error;
+    }
+    /* Network interfaces */
+    for (i = 0; i < def->nnets; i++) {
+        /* type='network' network devices that are SR-IOV VFs use VFIO.
+         * handle them here.
+         */
+        if ((def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK) ||
+            (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) {
+            continue;
+        }
+
+        actualType = virDomainNetGetActualType(def->nets[i]);
+        if (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)
+           continue;
+
+        hostdev = virDomainNetGetActualHostdev(def->nets[i]);
+        if (!hostdev || hostdev->source.subsys.u.pci.iommu != iommu)
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info,
+                                               flags) < 0)
+            goto error;
+    }
+    return 0;
+ error:
+    return -1;
+}
 
 /*
  * This assigns static PCI slots to all configured devices.
@@ -2020,6 +2223,12 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
         goto error;
     }
 
+    if (STRPREFIX(def->os.machine, "pseries") && (addrs->domainId > 0)) {
+        if (qemuAssignSPAPRHostDevAddresses(def, addrs))
+            goto error;
+        return 0;
+    }
+
     /* PCI controllers */
     for (i = 0; i < def->ncontrollers; i++) {
         if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
@@ -2077,6 +2286,13 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
             (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) {
             continue;
         }
+
+        if (addrs->domainId == 0 && (STRPREFIX(def->os.machine, "pseries"))) {
+           int actualType = virDomainNetGetActualType(def->nets[i]);
+           if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV)
+              continue;
+        }
+
         if (virDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info,
                                                flags) < 0)
             goto error;
@@ -2124,6 +2340,10 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
         if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
             continue;
 
+        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) {
+            continue;
+        }
+
         /* USB2 needs special handling to put all companions in the same slot */
         if (IS_USB2_CONTROLLER(def->controllers[i])) {
             virDevicePCIAddress addr = { 0, 0, 0, 0, false };
@@ -2213,6 +2433,10 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
             def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
             continue;
 
+        if (addrs->domainId == 0 && (STRPREFIX(def->os.machine, "pseries")) &&
+            IS_PCI_VFIO_HOSTDEV(def->hostdevs[i]))
+            continue;
+
         if (virDomainPCIAddressReserveNextSlot(addrs,
                                                def->hostdevs[i]->info,
                                                flags) < 0)
@@ -2318,9 +2542,12 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
             goto cleanup;
         for (i = 0; i < domainDef->ncontrollers; i++) {
             virDomainControllerDefPtr cont = domainDef->controllers[i];
+            if (info->addr.pci.domain != cont->domain)
+                continue;
 
-            if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
-                cont->idx == info->addr.pci.bus) {
+            if ((cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI ||
+                cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) &&
+                 cont->idx == info->addr.pci.bus) {
                 contAlias = cont->info.alias;
                 if (!contAlias) {
                     virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4335,6 +4562,7 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef,
         break;
 
     case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
+    case VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO:
         switch (def->model) {
         case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
             if (def->idx == 0) {
@@ -4342,8 +4570,12 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef,
                                _("PCI bridge index should be > 0"));
                 goto error;
             }
-            virBufferAsprintf(&buf, "pci-bridge,chassis_nr=%d,id=pci.%d",
-                              def->idx, def->idx);
+            if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
+                virBufferAsprintf(&buf, "pci-bridge,chassis_nr=%d,id=pci.%d",
+                                  def->idx, def->idx);
+            else
+                virBufferAsprintf(&buf, "pci-bridge,chassis_nr=%d,id=vfiohostbridge%d.%d",
+                                  def->opts.spaprvfio.iommuGroupNum, def->opts.spaprvfio.iommuGroupNum, def->idx);
             break;
         case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
             if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE)) {
@@ -4360,6 +4592,18 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef,
             virBufferAsprintf(&buf, "i82801b11-bridge,id=pci.%d", def->idx);
             break;
         case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+            if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO) {
+                if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPAPR_VFIO_HOST_BRIDGE)) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                   _("The spapr-pci-vfio-host-bridge "
+                                     "controller is not supported in this QEMU binary"));
+                    goto error;
+                }
+                virBufferAsprintf(&buf,
+                                  "spapr-pci-vfio-host-bridge,iommu=%d,id=vfiohostbridge%d,index=%d",
+                                  def->opts.spaprvfio.iommuGroupNum, def->opts.spaprvfio.iommuGroupNum, def->domain);
+                break;
+            }
         case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("wrong function called for pci-root/pcie-root"));
@@ -7799,6 +8043,7 @@ qemuBuildCommandLine(virConnectPtr conn,
         VIR_DOMAIN_CONTROLLER_TYPE_SATA,
         VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
         VIR_DOMAIN_CONTROLLER_TYPE_CCID,
+        VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO,
     };
     virArch hostarch = virArchFromHost();
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index aa40c9e..6f997f3 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -161,6 +161,13 @@ char *qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
                                 virDomainHostdevDefPtr dev,
                                 const char *configfd,
                                 virQEMUCapsPtr qemuCaps);
+char *
+qemuGetSPAPRVFIOHostDevContAliasString(virDomainDefPtr def,
+                                       virDomainDeviceInfoPtr info);
+
+int qemuBuildSPAPRVFIODeviceCommandLine(virCommandPtr cmd,
+                                        virDomainDefPtr def,
+                                        virQEMUCapsPtr qemuCaps);
 
 int qemuOpenPCIConfig(virDomainHostdevDefPtr dev);
 
@@ -232,22 +239,28 @@ int qemuDomainAssignAddresses(virDomainDefPtr def,
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 int qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def,
                                       virQEMUCapsPtr qemuCaps);
+int
+qemuDomainAssignSpaprVFIOHostdevPCIAddresses(virDomainDefPtr def,
+                                             virQEMUCapsPtr qemuCaps,
+                                             virDomainObjPtr obj);
 
 void qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
                                     virDomainDeviceInfoPtr info,
                                     const char *devstr);
 
-
 int qemuDomainAssignPCIAddresses(virDomainDefPtr def,
                                  virQEMUCapsPtr qemuCaps,
-                                 virDomainObjPtr obj);
+                                 virDomainObjPtr obj, int domain);
 virDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
                                                         unsigned int nbuses,
+                                                        int domainId,
                                                         bool dryRun);
 
 int qemuAssignDevicePCISlots(virDomainDefPtr def,
                              virQEMUCapsPtr qemuCaps,
                              virDomainPCIAddressSetPtr addrs);
+int qemuAssignHostDevAddresses(virDomainDefPtr def,
+                               virDomainPCIAddressSetPtr addrs);
 
 int qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps);
 int qemuDomainNetVLAN(virDomainNetDefPtr def);
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
index 9d39968..dea2d77 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -84,7 +84,7 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
     if (event)
         virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT);
 
-    if (qemuDomainAssignPCIAddresses((*vm)->def, priv->qemuCaps, *vm) < 0)
+    if (qemuDomainAssignPCIAddresses((*vm)->def, priv->qemuCaps, *vm, 0) < 0)
         goto cleanup;
 
     if (qemuAssignDeviceAliases((*vm)->def, priv->qemuCaps) < 0)




More information about the libvir-list mailing list