All the pieces are now in place, so we can finally start
using isolation groups to achieve our initial goal, which is
separating hostdevs from emulated PCI devices while keeping
hostdevs that belong to the same host IOMMU group together.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1280542
---
src/qemu/qemu_domain_address.c | 79 ++++++++++++++++++++++
.../qemuxml2argv-pseries-hostdev.args | 8 ++-
.../qemuxml2xmlout-pseries-hostdev.xml | 16 ++++-
3 files changed, 97 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 384d6fd..877ff90 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -901,6 +901,82 @@ qemuDomainFillAllPCIConnectFlags(virDomainDefPtr def,
/**
+ * qemuDomainFillDeviceIsolationGroupIter:
+ * @def: domain definition
+ * @dev: device definition
+ * @info: device information
+ * @opaque: user data
+ *
+ * Fill isolation group information for a single device.
+ *
+ * You're not meant to call this directly, use
+ * qemuDomainFillAllIsolationGroups() instead.
+ *
+ * Return: 0 on success, <0 on failure
+ * */
+static int
+qemuDomainFillDeviceIsolationGroupIter(virDomainDefPtr def,
+ virDomainDeviceDefPtr dev,
+ virDomainDeviceInfoPtr info,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ virDomainHostdevDefPtr hostdev;
+ virPCIDeviceAddressPtr hostAddr;
+
+ /* Only pSeries guests care about isolation groups at the moment */
+ if (!qemuDomainIsPSeries(def))
+ return 0;
+
+ /* Only hostdev... */
+ if (dev->type != VIR_DOMAIN_DEVICE_HOSTDEV)
+ return 0;
+
+ hostdev = dev->data.hostdev;
+
+ /* ... of the PCI kind need this extra information */
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+ hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+ return 0;
+ }
+
+ hostAddr = &hostdev->source.subsys.u.pci.addr;
+
+ /* The isolation group is simply the IOMMU group assigned by the host */
+ info->isolationGroup = virPCIDeviceAddressGetIOMMUGroupNum(hostAddr);
+
+ if (info->isolationGroup < 0) {
+ VIR_WARN("Can't look up isolation group for device
%04x:%02x:%02x.%x",
+ hostAddr->domain, hostAddr->bus,
+ hostAddr->slot, hostAddr->function);
+ } else {
+ VIR_DEBUG("Isolation group for device %04x:%02x:%02x.%x is %d",
+ hostAddr->domain, hostAddr->bus,
+ hostAddr->slot, hostAddr->function,
+ info->isolationGroup);
+ }
+
+ return info->isolationGroup;
+}
+
+
+/**
+ * qemuDomainFillAllIsolationGroups:
+ * @def: domain definition
+ *
+ * Fill isolation group information for all devices in @def.
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static int
+qemuDomainFillAllIsolationGroups(virDomainDefPtr def)
+{
+ return virDomainDeviceInfoIterate(def,
+ qemuDomainFillDeviceIsolationGroupIter,
+ NULL);
+}
+
+
+/**
* qemuDomainFillDevicePCIConnectFlags:
*
* @def: the entire DomainDef
@@ -2036,6 +2112,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
if (qemuDomainFillAllPCIConnectFlags(def, qemuCaps, driver) < 0)
goto cleanup;
+ if (qemuDomainFillAllIsolationGroups(def) < 0)
+ goto cleanup;
+
if (nbuses > 0) {
/* 1st pass to figure out how many PCI bridges we need */
if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true)))
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args
b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args
index dbd2964..9630a83 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args
@@ -18,6 +18,8 @@ QEMU_AUDIO_DRV=none \
server,nowait \
-mon chardev=charmonitor,id=monitor,mode=readline \
-boot c \
--device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.0,addr=0x1 \
--device vfio-pci,host=0005:90:01.2,id=hostdev1,bus=pci.0,addr=0x2 \
--device vfio-pci,host=0001:01:00.1,id=hostdev2,bus=pci.0,addr=0x3
+-device spapr-pci-host-bridge,index=1,id=pci.1 \
+-device spapr-pci-host-bridge,index=2,id=pci.2 \
+-device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.1.0,addr=0x1 \
+-device vfio-pci,host=0005:90:01.2,id=hostdev1,bus=pci.2.0,addr=0x1 \
+-device vfio-pci,host=0001:01:00.1,id=hostdev2,bus=pci.1.0,addr=0x2
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml
b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml
index a00c09c..7560661 100644
--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml
@@ -19,26 +19,36 @@
<target index='0'/>
</controller>
<controller type='usb' index='0' model='none'/>
+ <controller type='pci' index='1' model='pci-root'>
+ <model name='spapr-pci-host-bridge'/>
+ <target index='1'/>
+ <isolationGroup>2</isolationGroup>
+ </controller>
+ <controller type='pci' index='2' model='pci-root'>
+ <model name='spapr-pci-host-bridge'/>
+ <target index='2'/>
+ <isolationGroup>3</isolationGroup>
+ </controller>
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0001' bus='0x01' slot='0x00'
function='0x0'/>
</source>
- <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x0'/>
+ <address type='pci' domain='0x0000' bus='0x01'
slot='0x01' function='0x0'/>
</hostdev>
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0005' bus='0x90' slot='0x01'
function='0x2'/>
</source>
- <address type='pci' domain='0x0000' bus='0x00'
slot='0x02' function='0x0'/>
+ <address type='pci' domain='0x0000' bus='0x02'
slot='0x01' function='0x0'/>
</hostdev>
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0001' bus='0x01' slot='0x00'
function='0x1'/>
</source>
- <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ <address type='pci' domain='0x0000' bus='0x01'
slot='0x02' function='0x0'/>
</hostdev>
<memballoon model='none'/>
<panic model='pseries'/>
--
2.7.5