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

Shivaprasad G Bhat shivaprasadbhat at gmail.com
Mon Nov 17 10:05:05 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 has the domain and iommu
number allocated during the parsing based on 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.

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

diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index fb4a76f..e6c96f8 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->pciDomainId) {
         virReportError(errType,
                        _("Invalid PCI address %s. "
-                         "Only PCI domain 0 is available"),
-                       addrStr);
+                         "Only PCI domain %d is available"),
+                       addrStr, addrs->pciDomainId);
         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->pciDomainId, 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..df4d4e0 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -64,6 +64,8 @@ struct _virDomainPCIAddressSet {
     size_t nbuses;
     virDevicePCIAddress lastaddr;
     virDomainPCIConnectFlags lastFlags;
+    int pciDomainId;      /* The PCI domain to which the devices should belong
+                             to in the guest */
     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 e6ff977..797fa77 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 6f10e6d..5813332 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -70,6 +70,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",
@@ -562,6 +564,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 (ARCH_IS_PPC64(def->os.arch) && def->os.machine &&
+                STRPREFIX(def->os.machine, "pseries"))
+                virDomainDeviceInfoClear(&net->info);
         }
     }
     ret = 0;
@@ -886,6 +894,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);
@@ -1292,6 +1303,51 @@ 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 pci
+                    * 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 pci 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 pci domain */
+            if (!currentDomainHostdev)
+                return -1;
+        }
+    }
+    return 0;
+}
 
 static int
 qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
@@ -1317,6 +1373,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 (ARCH_IS_PPC64(def->os.arch) && def->os.machine &&
+        STRPREFIX(def->os.machine, "pseries"))
+    {
+        if (qemuIsValidCurrentDomainDevice(def, device, addrs->pciDomainId) < 0)
+            return 0;
+    }
+
     /* Change flags according to differing requirements of different
      * devices.
      */
@@ -1324,6 +1390,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
@@ -1461,24 +1528,35 @@ 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->domain != domain)
+                continue;
+            switch (cont->type) {
+              case VIR_DOMAIN_CONTROLLER_TYPE_SPAPR_PCI_VFIO:
+                   iommu = cont->opts.spaprvfio.iommuGroupNum;
+              case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
+                   controllerType = cont->type;
+                   if ((int) cont->idx > max_idx)
+                      max_idx = cont->idx;
             }
         }
 
@@ -1489,7 +1567,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;
@@ -1501,9 +1579,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)
@@ -1520,7 +1607,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
             goto cleanup;
         }
 
-        if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, false)))
+        if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, domain, false)))
             goto cleanup;
 
         if (qemuDomainSupportsPCI(def)) {
@@ -1529,7 +1616,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*/
@@ -1550,6 +1637,32 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
     return ret;
 }
 
+int
+qemuDomainAssignSpaprVFIOHostdevPCIAddresses(virDomainDefPtr def,
+                                             virQEMUCapsPtr qemuCaps,
+                                             virDomainObjPtr obj)
+{
+    int ret = -1;
+    if (!ARCH_IS_PPC64(def->os.arch) ||
+                    !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)
@@ -1568,13 +1681,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 pciDomainId,
                               bool dryRun)
 {
     virDomainPCIAddressSetPtr addrs;
@@ -1585,6 +1704,7 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
 
     addrs->nbuses = nbuses;
     addrs->dryRun = dryRun;
+    addrs->pciDomainId = pciDomainId;
 
     /* As a safety measure, set default model='pci-root' for first pci
      * controller and 'pci-bridge' for all subsequent. After setting
@@ -1604,7 +1724,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 != pciDomainId)
             continue;
 
         if (idx >= addrs->nbuses) {
@@ -1965,6 +2089,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;
+    /* SPAPR-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->pciDomainId)
+                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:
+                /* no other types */
+                continue;
+            }
+            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;
+        /* consider only those devices which belong to current
+         * pci domain iommu group */
+        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.
@@ -2021,6 +2224,12 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
         goto error;
     }
 
+    if (STRPREFIX(def->os.machine, "pseries") && (addrs->pciDomainId > 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) {
@@ -2078,6 +2287,13 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
             (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) {
             continue;
         }
+
+        if (addrs->pciDomainId == 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;
@@ -2125,6 +2341,9 @@ 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 };
@@ -2214,6 +2433,10 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
             def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
             continue;
 
+        if (addrs->pciDomainId == 0 && (STRPREFIX(def->os.machine, "pseries")) &&
+            IS_PCI_VFIO_HOSTDEV(def->hostdevs[i]))
+            continue;
+
         if (virDomainPCIAddressReserveNextSlot(addrs,
                                                def->hostdevs[i]->info,
                                                flags) < 0)
@@ -2319,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,
@@ -4397,6 +4623,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) {
@@ -4404,8 +4631,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)) {
@@ -4422,6 +4653,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"));
@@ -7874,6 +8117,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 f7d3c2d..2164bb4 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -162,6 +162,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);
 
@@ -233,22 +240,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 pciDomainId,
                                                         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