[libvirt] [PATCH v2 00/24] Support multiple PHBs for pSeries guests

Changes from [v1]: * address review comments; * implement a much better isolation algorithm that doesn't require parsing and formatting the isolation group and can handle more dynamic scenarios, such as empty PHBs changing their isolation groups to accomodate hotplugged hostdevs; * add more test cases. Reviewed-by tags have been collected, so figuring out which patches are still in need of reviewing is pretty easy. As an exception, patches 12 and 13 are unchanged but don't carry the tag due to the required documentation being still missing. Known limitations: * hot(un)plug is still not handled - shouldn't be too much work to fix this, but I though it would be better to send out the code now rather than holding it up further, as most of it shouldn't change anyway; * hostdevs in IOMMU group 0 are not handled properly - the default isolation group is currently 0, which means hostdevs in IOMMU group 0 will be assigned addresses as if they were emulated devices and will not be isolated properly. Fixing this will be a lot of work because it requires cleaning up the the code that instantiates pretty much anything embedding a virDomainDeviceInfo, which is... A lot of things. Luckily, IOMMU group 0 will probably not contain any devices that are actually usable as hostdevs, so it should be okay to fix this in a follow-up series rather than upfront; * documentation is still missing - I'll take care of that once the code is feature-complete, eg. the first item has been solved; * no epic cover letter this time around - apologies to all my fans :( [v1] https://www.redhat.com/archives/libvir-list/2017-June/msg00110.html Andrea Bolognani (24): conf: Remove obsolete comment conf: Make virDomainPCIAddressSetGrow() private conf: Make virDomainPCIAddressFlagsCompatible() private conf: Tweak virDomainPCIAddressGetNextAddr() signature tests: Update qemumemlock data tests: Mock IOMMU groups conf: Simplify slot allocation qemu: Allow qemuBuildControllerDevStr() to return NULL qemu: Tweak index number checking conf: Move index number checking to drivers qemu: Relax pci-root index requirement for pSeries guests conf: Parse and format <target index='...'/> conf: Add 'spapr-pci-host-bridge' controller model qemu: Automatically pick target index and model for pci-root controllers qemu: Introduce QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE qemu: Deal with PHB naming convention qemu: Use multiple PHBs for pSeries guests tests: Add tests for pSeries guests with multiple PHBs tests: Add baseline tests for automatic PHB usage qemu: Use PHBs to fill holes in PCI bus numbering qemu: Use PHBs when extending the guest PCI topology conf: Introduce isolation groups conf: Implement isolation rules qemu: Isolate hostdevs on pSeries guests docs/schemas/domaincommon.rng | 7 + src/bhyve/bhyve_device.c | 4 +- src/bhyve/bhyve_domain.c | 15 ++ src/conf/device_conf.h | 14 +- src/conf/domain_addr.c | 199 +++++++++++------ src/conf/domain_addr.h | 38 ++-- src/conf/domain_conf.c | 31 ++- src/conf/domain_conf.h | 2 + src/libvirt_private.syms | 2 - src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 148 ++++++++++-- src/qemu/qemu_command.h | 9 +- src/qemu/qemu_domain.c | 14 ++ src/qemu/qemu_domain_address.c | 248 +++++++++++++++++++-- src/qemu/qemu_hotplug.c | 5 +- .../qemuargv2xmldata/qemuargv2xml-pseries-disk.xml | 5 +- .../qemuargv2xml-pseries-nvram.xml | 5 +- tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + .../qemumemlock-pc-hardlimit+hostdev.xml | 2 +- .../qemumemlock-pc-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hostdev.xml | 2 +- .../qemumemlock-pc-locked+hostdev.xml | 2 +- .../qemumemlock-pseries-hardlimit+hostdev.xml | 2 +- ...emumemlock-pseries-hardlimit+locked+hostdev.xml | 2 +- .../qemumemlock-pseries-hostdev.xml | 2 +- .../qemumemlock-pseries-locked+hostdev.xml | 2 +- tests/qemumemlocktest.c | 21 +- .../qemuxml2argv-pseries-hostdevs-1.args | 25 +++ .../qemuxml2argv-pseries-hostdevs-1.xml | 38 ++++ .../qemuxml2argv-pseries-hostdevs-2.args | 25 +++ .../qemuxml2argv-pseries-hostdevs-2.xml | 37 +++ .../qemuxml2argv-pseries-hostdevs-3.args | 24 ++ .../qemuxml2argv-pseries-hostdevs-3.xml | 31 +++ .../qemuxml2argv-pseries-many-buses-1.args | 22 ++ .../qemuxml2argv-pseries-many-buses-1.xml | 19 ++ .../qemuxml2argv-pseries-many-buses-2.args | 22 ++ .../qemuxml2argv-pseries-many-buses-2.xml | 18 ++ .../qemuxml2argv-pseries-many-devices.args | 53 +++++ .../qemuxml2argv-pseries-many-devices.xml | 48 ++++ .../qemuxml2argv-pseries-phb-default-missing.args | 22 ++ .../qemuxml2argv-pseries-phb-default-missing.xml | 16 ++ .../qemuxml2argv-pseries-phb-simple.args | 22 ++ .../qemuxml2argv-pseries-phb-simple.xml | 17 ++ tests/qemuxml2argvtest.c | 64 +++++- .../qemuxml2xmlout-panic-pseries.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller-legacy.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller.xml | 5 +- .../qemuxml2xmlout-pseries-hostdevs-1.xml | 54 +++++ .../qemuxml2xmlout-pseries-hostdevs-2.xml | 50 +++++ .../qemuxml2xmlout-pseries-hostdevs-3.xml | 47 ++++ ...xml => qemuxml2xmlout-pseries-many-buses-1.xml} | 19 +- ...xml => qemuxml2xmlout-pseries-many-buses-2.xml} | 20 +- .../qemuxml2xmlout-pseries-many-devices.xml | 125 +++++++++++ .../qemuxml2xmlout-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-pseries-panic-missing.xml | 5 +- .../qemuxml2xmlout-pseries-panic-no-address.xml | 5 +- ...qemuxml2xmlout-pseries-phb-default-missing.xml} | 18 +- ...m.xml => qemuxml2xmlout-pseries-phb-simple.xml} | 18 +- tests/qemuxml2xmltest.c | 59 ++++- tests/virpcimock.c | 43 +++- 61 files changed, 1562 insertions(+), 211 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-many-buses-1.xml} (55%) copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-many-buses-2.xml} (54%) create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-phb-default-missing.xml} (56%) copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-phb-simple.xml} (56%) -- 2.7.5

The virDomainDeviceInfoIsSet() function no longer exists. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/conf/device_conf.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index a20de85..58b2c9c 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -134,10 +134,6 @@ struct _virDomainDeviceDimmAddress { typedef struct _virDomainDeviceInfo virDomainDeviceInfo; typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; struct _virDomainDeviceInfo { - /* If adding to this struct, ensure that - * virDomainDeviceInfoIsSet() is updated - * to consider the new fields - */ char *alias; int type; /* virDomainDeviceAddressType */ union { -- 2.7.5

There are no external users. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/conf/domain_addr.c | 2 +- src/conf/domain_addr.h | 5 ----- src/libvirt_private.syms | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 639168e..9c809e8 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -362,7 +362,7 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus, * 0 = no action performed * >0 = number of buses added */ -int +static int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index f884b8a..efa97ca 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -145,11 +145,6 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, - virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 044510f..996a88b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -115,7 +115,6 @@ virDomainPCIAddressReserveNextAddr; virDomainPCIAddressSetAllMulti; virDomainPCIAddressSetAlloc; virDomainPCIAddressSetFree; -virDomainPCIAddressSetGrow; virDomainPCIAddressSlotInUse; virDomainPCIAddressValidate; virDomainPCIControllerModelToConnectType; -- 2.7.5

There are no external users. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/conf/domain_addr.c | 2 +- src/conf/domain_addr.h | 8 -------- src/libvirt_private.syms | 1 - 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 9c809e8..0a7cb00 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -103,7 +103,7 @@ virDomainPCIControllerConnectTypeToModel(virDomainPCIConnectFlags flags) } -bool +static bool virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr, const char *addrStr, virDomainPCIConnectFlags busFlags, diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index efa97ca..0c7905b 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -121,14 +121,6 @@ virDomainPCIAddressSetPtr virDomainPCIAddressSetAlloc(unsigned int nbuses); void virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs); -bool virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr, - const char *addrStr, - virDomainPCIConnectFlags busFlags, - virDomainPCIConnectFlags devFlags, - bool reportError, - bool fromConfig) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - bool virDomainPCIAddressValidate(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, const char *addrStr, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 996a88b..65998d7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -108,7 +108,6 @@ virDomainGetBlkioParametersAssignFromDef; virDomainPCIAddressAsString; virDomainPCIAddressBusSetModel; virDomainPCIAddressEnsureAddr; -virDomainPCIAddressFlagsCompatible; virDomainPCIAddressReleaseAddr; virDomainPCIAddressReserveAddr; virDomainPCIAddressReserveNextAddr; -- 2.7.5

Move @function after @flags to match other functions in the same module like virDomainPCIAddressReserveNextAddr(). Also move virDomainPCIAddressReserveNextAddr() closer to virDomainPCIAddressReserveAddr() in the header file. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/conf/domain_addr.c | 6 +++--- src/conf/domain_addr.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 0a7cb00..b588b36 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -738,8 +738,8 @@ virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus, static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, - int function, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int function) { /* default to starting the search for a free slot from * the first slot of domain 0 bus 0... @@ -845,7 +845,7 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, { virPCIDeviceAddress addr; - if (virDomainPCIAddressGetNextAddr(addrs, &addr, function, flags) < 0) + if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0) return -1; if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 0c7905b..dbef4b1 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -142,6 +142,12 @@ int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags, + int function) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, virDomainPCIConnectFlags flags) @@ -151,12 +157,6 @@ int virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, - virDomainDeviceInfoPtr dev, - virDomainPCIConnectFlags flags, - int function) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - void virDomainPCIAddressSetAllMulti(virDomainDefPtr def) ATTRIBUTE_NONNULL(1); -- 2.7.5

Use 0001:01:00.0 instead of 0000:04:02.0 as the source address for the host device. This doesn't change anything at the moment, but it will make a difference later on. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml index 5443145..e03f5a5 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml index 8184eef..7070e5a 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml @@ -16,7 +16,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml index 6c058a9..cd517ee 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml @@ -10,7 +10,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml index fbc1dc3..da79cb5 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml index ddd3b47..baf0649 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml index 73c28c1..04ae4e9 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml @@ -16,7 +16,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml index daf70a4..a52768c 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml @@ -10,7 +10,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml index 74212f1..f5abef0 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> -- 2.7.5

Later on we're going to need access to information about IOMMU groups for host devices. Implement the support in virpcimock, and start using that mock library in a few QEMU test cases. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- tests/qemumemlocktest.c | 21 ++++++++++++++++++++- tests/qemuxml2argvtest.c | 25 ++++++++++++++++++++++--- tests/qemuxml2xmltest.c | 21 ++++++++++++++++++++- tests/virpcimock.c | 43 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 99 insertions(+), 11 deletions(-) diff --git a/tests/qemumemlocktest.c b/tests/qemumemlocktest.c index 6cf17a4..c0f1dc3 100644 --- a/tests/qemumemlocktest.c +++ b/tests/qemumemlocktest.c @@ -56,11 +56,25 @@ testCompareMemLock(const void *data) return ret; } +# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" static int mymain(void) { int ret = 0; + char *fakerootdir; + + if (VIR_STRDUP_QUIET(fakerootdir, FAKEROOTDIRTEMPLATE) < 0) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + if (!mkdtemp(fakerootdir)) { + fprintf(stderr, "Cannot create fakerootdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_ROOT_DIR", fakerootdir, 1); abs_top_srcdir = getenv("abs_top_srcdir"); if (!abs_top_srcdir) @@ -124,12 +138,17 @@ mymain(void) DO_TEST("pseries-hardlimit+locked+hostdev", 2147483648); DO_TEST("pseries-locked+hostdev", VIR_DOMAIN_MEMORY_PARAM_UNLIMITED); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -VIR_TEST_MAIN(mymain) +VIR_TEST_MAIN_PRELOAD(mymain, + abs_builddir "/.libs/virpcimock.so") #else diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 799aea9..31d137c 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -534,13 +534,27 @@ testCompareXMLToArgv(const void *data) return ret; } +# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" static int mymain(void) { int ret = 0; + char *fakerootdir; bool skipLegacyCPUs = false; + if (VIR_STRDUP_QUIET(fakerootdir, FAKEROOTDIRTEMPLATE) < 0) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + if (!mkdtemp(fakerootdir)) { + fprintf(stderr, "Cannot create fakerootdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_ROOT_DIR", fakerootdir, 1); + abs_top_srcdir = getenv("abs_top_srcdir"); if (!abs_top_srcdir) abs_top_srcdir = abs_srcdir "/.."; @@ -2599,15 +2613,20 @@ mymain(void) DO_TEST_PARSE_ERROR("cpu-cache-passthrough3", QEMU_CAPS_KVM); DO_TEST_PARSE_ERROR("cpu-cache-passthrough-l3", QEMU_CAPS_KVM); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } VIR_TEST_MAIN_PRELOAD(mymain, - abs_builddir "/.libs/qemuxml2argvmock.so", - abs_builddir "/.libs/virrandommock.so", - abs_builddir "/.libs/qemucpumock.so") + abs_builddir "/.libs/qemuxml2argvmock.so", + abs_builddir "/.libs/virrandommock.so", + abs_builddir "/.libs/qemucpumock.so", + abs_builddir "/.libs/virpcimock.so") #else diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 1bdd383..6c7d207 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -303,14 +303,28 @@ testInfoSet(struct testInfo *info, return -1; } +# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" static int mymain(void) { int ret = 0; + char *fakerootdir; struct testInfo info; virQEMUDriverConfigPtr cfg = NULL; + if (VIR_STRDUP_QUIET(fakerootdir, FAKEROOTDIRTEMPLATE) < 0) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + if (!mkdtemp(fakerootdir)) { + fprintf(stderr, "Cannot create fakerootdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_ROOT_DIR", fakerootdir, 1); + memset(&info, 0, sizeof(info)); if (qemuTestDriverInit(&driver) < 0) @@ -1144,12 +1158,17 @@ mymain(void) DO_TEST("cpu-check-default-partial", NONE); DO_TEST("cpu-check-default-partial2", NONE); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -VIR_TEST_MAIN(mymain) +VIR_TEST_MAIN_PRELOAD(mymain, + abs_builddir "/.libs/virpcimock.so") #else diff --git a/tests/virpcimock.c b/tests/virpcimock.c index e9408aa..19b10f4 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -127,6 +127,7 @@ struct pciDevice { int vendor; int device; int class; + int iommuGroup; struct pciDriver *driver; /* Driver attached. NULL if attached to no driver */ }; @@ -190,6 +191,22 @@ make_file(const char *path, VIR_FREE(filepath); } +static void +make_symlink(const char *path, + const char *name, + const char *target) +{ + char *filepath = NULL; + + if (virAsprintfQuiet(&filepath, "%s/%s", path, name) < 0) + ABORT_OOM(); + + if (symlink(target, filepath) < 0) + ABORT("Unable to create symlink filepath -> target"); + + VIR_FREE(filepath); +} + static int pci_read_file(const char *path, char *buf, @@ -322,7 +339,7 @@ pci_device_new_from_stub(const struct pciDevice *data) char *id; char *c; char *configSrc; - char tmp[32]; + char tmp[256]; struct stat sb; if (VIR_STRDUP_QUIET(id, data->id) < 0) @@ -386,6 +403,20 @@ pci_device_new_from_stub(const struct pciDevice *data) ABORT("@tmp overflow"); make_file(devpath, "class", tmp, -1); + if (snprintf(tmp, sizeof(tmp), + "%s/../../../kernel/iommu_groups/%d", + devpath, dev->iommuGroup) < 0) { + ABORT("@tmp overflow"); + } + if (virFileMakePath(tmp) < 0) + ABORT("Unable to create %s", tmp); + + if (snprintf(tmp, sizeof(tmp), + "../../../kernel/iommu_groups/%d", dev->iommuGroup) < 0) { + ABORT("@tmp overflow"); + } + make_symlink(devpath, "iommu_group", tmp); + if (pci_device_autobind(dev) < 0) ABORT("Unable to bind: %s", data->id); @@ -821,12 +852,12 @@ init_env(void) MAKE_PCI_DEVICE("0000:00:02.0", 0x8086, 0x0046); MAKE_PCI_DEVICE("0000:00:03.0", 0x8086, 0x0048); MAKE_PCI_DEVICE("0001:00:00.0", 0x1014, 0x03b9, .class = 0x060400); - MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e); - MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e); + MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e, .iommuGroup = 2); + MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e, .iommuGroup = 2); MAKE_PCI_DEVICE("0005:80:00.0", 0x10b5, 0x8112, .class = 0x060400); - MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035); - MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035); - MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0); + MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035, .iommuGroup = 3); + MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035, .iommuGroup = 3); + MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0, .iommuGroup = 3); MAKE_PCI_DEVICE("0000:0a:01.0", 0x8086, 0x0047); MAKE_PCI_DEVICE("0000:0a:02.0", 0x8286, 0x0048); MAKE_PCI_DEVICE("0000:0a:03.0", 0x8386, 0x0048); -- 2.7.5

The current algorithm for slot allocation tries to be clever and avoid looking at buses / slots more than once unless it's necessary. Unfortunately that makes the code more complex, and it will cause problem later on in some situations unless even more complex code is added. Since the performance gains are going to be pretty modest anyway, we can just get rid of the extra complexity and use a completely straighforward implementation instead. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/conf/domain_addr.c | 47 +++++++++-------------------------------------- src/conf/domain_addr.h | 2 -- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index b588b36..86b1367 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -741,46 +741,34 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags, int function) { - /* default to starting the search for a free slot from - * the first slot of domain 0 bus 0... - */ virPCIDeviceAddress a = { 0 }; - bool found = false; if (addrs->nbuses == 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available")); goto error; } - /* ...unless this search is for the exact same type of device as - * last time, then continue the search from the slot where we - * found the previous match (it's possible there will still be a - * function available on that slot). - */ - if (flags == addrs->lastFlags) - a = addrs->lastaddr; - else - a.slot = addrs->buses[0].minSlot; - /* if the caller asks for "any function", give them function 0 */ if (function == -1) a.function = 0; else a.function = function; - while (a.bus < addrs->nbuses) { - if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus], - &a, function, + /* "Begin at the beginning," the King said, very gravely, "and go on + * till you come to the end: then stop." */ + for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) { + virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus]; + bool found = false; + + a.slot = bus->minSlot; + + if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function, flags, &found) < 0) { goto error; } if (found) goto success; - - /* nothing on this bus, go to the next bus */ - if (++a.bus < addrs->nbuses) - a.slot = addrs->buses[a.bus].minSlot; } /* There were no free slots after the last used one */ @@ -791,20 +779,6 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, /* this device will use the first slot of the new bus */ a.slot = addrs->buses[a.bus].minSlot; goto success; - } else if (flags == addrs->lastFlags) { - /* Check the buses from 0 up to the last used one */ - for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) { - a.slot = addrs->buses[a.bus].minSlot; - - if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus], - &a, function, - flags, &found) < 0) { - goto error; - } - - if (found) - goto success; - } } virReportError(VIR_ERR_INTERNAL_ERROR, @@ -851,9 +825,6 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) return -1; - addrs->lastaddr = addr; - addrs->lastFlags = flags; - if (!addrs->dryRun) { dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; dev->addr.pci = addr; diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index dbef4b1..c98a228 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -106,8 +106,6 @@ typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr; struct _virDomainPCIAddressSet { virDomainPCIAddressBus *buses; size_t nbuses; - virPCIDeviceAddress lastaddr; - virDomainPCIConnectFlags lastFlags; bool dryRun; /* on a dry run, new buses are auto-added and addresses aren't saved in device infos */ }; -- 2.7.5

We will soon need to be able to return a NULL pointer without the caller considering that an error: to make it possible, change the return type to int and use an out parameter for the string instead. Add some documentation for the function as well. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_command.c | 55 ++++++++++++++++++++++++++++++++++++------------- src/qemu/qemu_command.h | 9 ++++---- src/qemu/qemu_hotplug.c | 5 ++++- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8c12b2b..836bb25 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2703,23 +2703,46 @@ qemuCheckSCSIControllerIOThreads(const virDomainDef *domainDef, } -char * +/** + * qemuBuildControllerDevStr: + * @domainDef: domain definition + * @def: controller definition + * @qemuCaps: QEMU binary capabilities + * @devstr: device string + * @nusbcontroller: number of USB controllers + * + * Turn @def into a description of the controller that QEMU will understand, + * to be used either on the command line or through the monitor. + * + * The description will be returned in @devstr and can be NULL, eg. when + * passing in one of the built-in controllers. The returned string must be + * freed by the caller. + * + * The number pointed to by @nusbcontroller will be increased by one every + * time the description for a USB controller has been generated successfully. + * + * Returns: 0 on success, <0 on failure + */ +int qemuBuildControllerDevStr(const virDomainDef *domainDef, virDomainControllerDefPtr def, virQEMUCapsPtr qemuCaps, + char **devstr, int *nusbcontroller) { virBuffer buf = VIR_BUFFER_INITIALIZER; int model = def->model; const char *modelName = NULL; + *devstr = NULL; + if (!qemuCheckCCWS390AddressSupport(domainDef, def->info, qemuCaps, "controller")) - return NULL; + return -1; if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { if ((qemuDomainSetSCSIControllerModel(domainDef, qemuCaps, &model)) < 0) - return NULL; + return -1; } if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI && @@ -2727,22 +2750,22 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (def->queues) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'queues' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->cmd_per_lun) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'cmd_per_lun' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->max_sectors) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'max_sectors' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->ioeventfd) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'ioeventfd' is only supported by virtio-scsi controller")); - return NULL; + return -1; } } @@ -3157,11 +3180,12 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (virBufferCheckError(&buf) < 0) goto error; - return virBufferContentAndReset(&buf); + *devstr = virBufferContentAndReset(&buf); + return 0; error: virBufferFreeAndReset(&buf); - return NULL; + return -1; } @@ -3256,12 +3280,15 @@ qemuBuildControllerDevCommandLine(virCommandPtr cmd, continue; } - virCommandAddArg(cmd, "-device"); - if (!(devstr = qemuBuildControllerDevStr(def, cont, qemuCaps, - &usbcontroller))) + if (qemuBuildControllerDevStr(def, cont, qemuCaps, + &devstr, &usbcontroller) < 0) return -1; - virCommandAddArg(cmd, devstr); - VIR_FREE(devstr); + + if (devstr) { + virCommandAddArg(cmd, "-device"); + virCommandAddArg(cmd, devstr); + VIR_FREE(devstr); + } } } diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 09cb00e..9a2ab29 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -118,10 +118,11 @@ char *qemuBuildDriveDevStr(const virDomainDef *def, virQEMUCapsPtr qemuCaps); /* Current, best practice */ -char *qemuBuildControllerDevStr(const virDomainDef *domainDef, - virDomainControllerDefPtr def, - virQEMUCapsPtr qemuCaps, - int *nusbcontroller); +int qemuBuildControllerDevStr(const virDomainDef *domainDef, + virDomainControllerDefPtr def, + virQEMUCapsPtr qemuCaps, + char **devstr, + int *nusbcontroller); int qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps, const char **backendType, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 0b8d3d8..99fa1b8 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -523,7 +523,10 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0) goto cleanup; - if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, NULL))) + if (qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, &devstr, NULL) < 0) + goto cleanup; + + if (!devstr) goto cleanup; if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) -- 2.7.5

Moving the check and rewriting it this way doesn't alter the current behavior, but will allow us to special-case pci-root down the line. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_command.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 836bb25..8123276 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2873,6 +2873,26 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, case VIR_DOMAIN_CONTROLLER_TYPE_PCI: switch ((virDomainControllerModelPCI) def->model) { case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS: + if (def->idx == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("index for pci controllers of model '%s' must be > 0"), + virDomainControllerModelPCITypeToString(def->model)); + goto error; + } + break; + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: + break; + } + switch ((virDomainControllerModelPCI) def->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: if (def->opts.pciopts.modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE || def->opts.pciopts.chassisNr == -1) { @@ -3131,12 +3151,6 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, _("wrong function called")); goto error; } - if (def->idx == 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("index for pci controllers of model '%s' must be > 0"), - virDomainControllerModelPCITypeToString(def->model)); - goto error; - } break; case VIR_DOMAIN_CONTROLLER_TYPE_IDE: -- 2.7.5

pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), which of course means that all but one of them will have a non-zero index; hence, we'll need to relax the current check. However, right now the check is performed in the conf module, which is generic rather than tied to the QEMU driver, and where we don't have information such as the guest machine type available. To make this change of behavior possible down the line, we need to move the check from the XML parser to the drivers. Luckily, only QEMU and bhyve are using PCI controllers, so this doesn't result in much duplication. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/bhyve/bhyve_domain.c | 15 +++++++++++++++ src/conf/domain_conf.c | 6 ------ src/qemu/qemu_domain.c | 9 +++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 20c8293..7176455 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -122,6 +122,21 @@ bhyveDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, bhyveDomainDiskDefAssignAddress(driver, disk, def) < 0) return -1; } + + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 0507ec1..6ee7696 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -9184,12 +9184,6 @@ virDomainControllerDefParseXML(xmlNodePtr node, "have an address")); goto error; } - if (def->idx > 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("pci-root and pcie-root controllers " - "should have index 0")); - goto error; - } if ((rc = virDomainParseScaledValue("./pcihole64", NULL, ctxt, &bytes, 1024, 1024ULL * ULONG_MAX, false)) < 0) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 6838d2e..855bd08 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3419,6 +3419,15 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, break; case VIR_DOMAIN_CONTROLLER_TYPE_PCI: + if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS && !qemuDomainIsI440FX(def)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", -- 2.7.5

pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), meaning the current check on the controller index no longer applies to them. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_domain.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 855bd08..8072f8d 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3419,9 +3419,14 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, break; case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || - cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && - cont->idx != 0) { + + /* pSeries guests can have multiple pci-root controllers, + * but other machine types only support a single one */ + if (!qemuDomainIsPSeries(def) && + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("pci-root and pcie-root controllers " "should have index 0")); -- 2.7.5

Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 24 ++++++++++++++++++++++++ src/conf/domain_conf.h | 1 + 3 files changed, 30 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 4950ddc..7234b49 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1997,6 +1997,11 @@ </attribute> </optional> <optional> + <attribute name='index'> + <ref name='uint8'/> + </attribute> + </optional> + <optional> <element name='node'> <ref name='unsignedInt'/> </element> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6ee7696..107cdba 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1866,6 +1866,7 @@ virDomainControllerDefNew(virDomainControllerType type) def->opts.pciopts.chassis = -1; def->opts.pciopts.port = -1; def->opts.pciopts.busNr = -1; + def->opts.pciopts.idx = -1; def->opts.pciopts.numaNode = -1; break; case VIR_DOMAIN_CONTROLLER_TYPE_IDE: @@ -9031,6 +9032,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } def->idx = idxVal; + VIR_FREE(idx); } cur = node->children; @@ -9062,6 +9064,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, chassis = virXMLPropString(cur, "chassis"); port = virXMLPropString(cur, "port"); busNr = virXMLPropString(cur, "busNr"); + idx = virXMLPropString(cur, "index"); processedTarget = true; } } @@ -9280,6 +9283,23 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } } + if (idx) { + if (virStrToLong_i(idx, NULL, 0, + &def->opts.pciopts.idx) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid target index '%s' in PCI controller"), + idx); + goto error; + } + if (def->opts.pciopts.idx < 0 || + def->opts.pciopts.idx > 31) { + virReportError(VIR_ERR_XML_ERROR, + _("PCI controller target index '%s' out of " + "range - must be 0-31"), + idx); + goto error; + } + } if (numaNode >= 0) def->opts.pciopts.numaNode = numaNode; break; @@ -21680,6 +21700,7 @@ virDomainControllerDefFormat(virBufferPtr buf, def->opts.pciopts.chassis != -1 || def->opts.pciopts.port != -1 || def->opts.pciopts.busNr != -1 || + def->opts.pciopts.idx != -1 || def->opts.pciopts.numaNode != -1) { virBufferAddLit(&childBuf, "<target"); if (def->opts.pciopts.chassisNr != -1) @@ -21694,6 +21715,9 @@ virDomainControllerDefFormat(virBufferPtr buf, if (def->opts.pciopts.busNr != -1) virBufferAsprintf(&childBuf, " busNr='%d'", def->opts.pciopts.busNr); + if (def->opts.pciopts.idx != -1) + virBufferAsprintf(&childBuf, " index='%d'", + def->opts.pciopts.idx); if (def->opts.pciopts.numaNode == -1) { virBufferAddLit(&childBuf, "/>\n"); } else { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e67b6fd..3713b7f 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -785,6 +785,7 @@ struct _virDomainPCIControllerOpts { int chassis; int port; int busNr; /* used by pci-expander-bus, -1 == unspecified */ + int idx; /* used by spapr-pci-host-bridge, -1 == unspecified */ /* numaNode is a *subelement* of target (to match existing * item in memory target config) -1 == unspecified */ -- 2.7.5

Adding it to the virDomainControllerPCIModelName enumeration is enough for existing code to handle it, so parsing and formatting will work without further tweaking. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- docs/schemas/domaincommon.rng | 2 ++ src/conf/domain_conf.c | 1 + src/conf/domain_conf.h | 1 + 3 files changed, 4 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 7234b49..2d19f23 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1954,6 +1954,8 @@ <element name="model"> <attribute name="name"> <choice> + <!-- implementations of 'pci-root' --> + <value>spapr-pci-host-bridge</value> <!-- implementations of 'pci-bridge' --> <value>pci-bridge</value> <!-- implementations of 'dmi-to-pci-bridge' --> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 107cdba..84110a7 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -349,6 +349,7 @@ VIR_ENUM_IMPL(virDomainControllerPCIModelName, "pxb", "pxb-pcie", "pcie-root-port", + "spapr-pci-host-bridge", ); VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3713b7f..5631ad1 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -710,6 +710,7 @@ typedef enum { VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB, VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE, VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT, + VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE, VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST } virDomainControllerPCIModelName; -- 2.7.5

pSeries guests will soon need the new information; luckily, we can figure it out automatically most of the time, so users won't have to worry about it. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_domain_address.c | 88 +++++++++++++++++++++- .../qemuargv2xmldata/qemuargv2xml-pseries-disk.xml | 5 +- .../qemuargv2xml-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-panic-pseries.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller-legacy.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller.xml | 5 +- .../qemuxml2xmlout-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-pseries-panic-missing.xml | 5 +- .../qemuxml2xmlout-pseries-panic-no-address.xml | 5 +- 9 files changed, 118 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index b5b863f..960ea04 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1861,6 +1861,7 @@ qemuDomainSupportsPCI(virDomainDefPtr def, static void qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, + virDomainDefPtr def, virQEMUCapsPtr qemuCaps) { int *modelName = &cont->opts.pciopts.modelName; @@ -1897,6 +1898,9 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE; break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (qemuDomainIsPSeries(def)) + *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE; + break; case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: break; @@ -1904,6 +1908,63 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, } +/** + * qemuDomainAddressFindNewTargetIndex: + * @def: domain definition + * + * Find a target index that can be used for a PCI controller. + * + * Returns: an unused target index, or -1 if all available target + * indexes are already taken. + */ +static int +qemuDomainAddressFindNewTargetIndex(virDomainDefPtr def) +{ + int idx; + int ret = -1; + + /* Try all indexes between 1 and 31 - QEMU only supports 32 + * PHBs, and 0 is reserved for the default, implicit one */ + for (idx = 1; idx <= 31; idx++) { + bool found = false; + size_t i; + + for (i = 0; i < def->ncontrollers; i++) { + virDomainControllerDefPtr cont = def->controllers[i]; + virDomainPCIControllerOptsPtr opts; + + /* We only care about pci-root controllers */ + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI || + cont->model != VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) { + continue; + } + + opts = &cont->opts.pciopts; + + /* More specifically, we only care about PHBs */ + if (opts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) + continue; + + /* Stop looking as soon as we find a PHB that's + * already using this specific target index */ + if (opts->idx == idx) { + found = true; + break; + } + } + + /* If no existing PCI controller uses this index, great, + * it means it's free and we can return it to the caller */ + if (!found) { + ret = idx; + break; + } + } + + return ret; +} + + static int qemuDomainAddressFindNewBusNr(virDomainDefPtr def) { @@ -2164,7 +2225,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, * device in qemu) for any controller that doesn't yet * have it set. */ - qemuDomainPCIControllerSetDefaultModelName(cont, qemuCaps); + qemuDomainPCIControllerSetDefaultModelName(cont, def, qemuCaps); /* set defaults for any other auto-generated config * options for this controller that haven't been @@ -2201,9 +2262,32 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, goto cleanup; } break; + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (!qemuDomainIsPSeries(def)) + break; + if (options->idx == -1) { + if (cont->idx == 0) { + /* The pci-root controller with controller index 0 + * must always be assigned target index 0, because + * it represents the implicit PHB which is treated + * differently than all other PHBs */ + options->idx = 0; + } else { + /* For all other PHBs the target index doesn't need + * to match the controller index or have any + * particular value, really */ + options->idx = qemuDomainAddressFindNewTargetIndex(def); + } + } + if (options->idx == -1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("No usable target index found for %d"), + addr->bus); + goto cleanup; + } + break; case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT: - case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: break; diff --git a/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml b/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml index 1bad8ee..601d0f7 100644 --- a/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml +++ b/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml @@ -30,7 +30,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <controller type='scsi' index='0'> <address type='spapr-vio' reg='0x2000'/> </controller> diff --git a/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml b/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml index 7e9f864..7787847 100644 --- a/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml +++ b/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='none'/> <nvram> <address type='spapr-vio' reg='0x4000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml index b7bde24..673b81d 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml @@ -22,7 +22,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml index 82aaaca..68995a9 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml @@ -22,7 +22,10 @@ <controller type='usb' index='0' model='pci-ohci'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml index 713f31c..f89b23b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='none'/> <nvram> <address type='spapr-vio' reg='0x4000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> -- 2.7.5

This new capability can be used to detect whether a QEMU binary supports the spapr-pci-host-bridge controller. Reviewed-by: Laine Stump <laine@laine.org> Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + 3 files changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c0c39bd..6d75998 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -376,6 +376,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "intel-iommu.device-iotlb", /* 260 */ "virtio.iommu_platform", "virtio.ats", + "spapr-pci-host-bridge", ); @@ -1625,6 +1626,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "nvdimm", QEMU_CAPS_DEVICE_NVDIMM }, { "pcie-root-port", QEMU_CAPS_DEVICE_PCIE_ROOT_PORT }, { "qemu-xhci", QEMU_CAPS_DEVICE_QEMU_XHCI }, + { "spapr-pci-host-bridge", QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE }, }; static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBalloon[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index e57cae9..c0464a1 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -415,6 +415,7 @@ typedef enum { QEMU_CAPS_INTEL_IOMMU_DEVICE_IOTLB, /* intel-iommu.device-iotlb */ QEMU_CAPS_VIRTIO_PCI_IOMMU_PLATFORM, /* virtio-*-pci.iommu_platform */ QEMU_CAPS_VIRTIO_PCI_ATS, /* virtio-*-pci.ats */ + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, /* -device spapr-pci-host-bridge */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml index 425992f..7fa652a 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml @@ -164,6 +164,7 @@ <flag name='query-named-block-nodes'/> <flag name='kernel-irqchip'/> <flag name='kernel-irqchip.split'/> + <flag name='spapr-pci-host-bridge'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> -- 2.7.5

Usually, a controller with alias 'x' will create a bus with the same name; however, the bus created by a PHBs with alias 'x' will be named 'x.0' instead, so we need to account for that. As an exception to the exception, the implicit PHB that's added automatically to every pSeries guest creates the 'pci.0' bus. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_command.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8123276..372f5ca 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -302,6 +302,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, int ret = -1; char *devStr = NULL; const char *contAlias = NULL; + virDomainControllerModelPCI contModel; + virDomainControllerPCIModelName contModelName; + int contIndex; if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { size_t i; @@ -314,6 +317,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && cont->idx == info->addr.pci.bus) { contAlias = cont->info.alias; + contModel = cont->model; + contModelName = cont->opts.pciopts.modelName; + contIndex = cont->opts.pciopts.idx; if (!contAlias) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Device alias was not set for PCI " @@ -349,7 +355,19 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, } } - virBufferAsprintf(buf, ",bus=%s", contAlias); + if (contModel == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT && + contModelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE && + contIndex > 0) { + /* The PCI bus created by a spapr-pci-host-bridge device with + * alias 'x' will be called 'x.0' rather than 'x'; however, + * this does not apply to the implicit PHB in a pSeries guest, + * which always has the hardcoded name 'pci.0' */ + virBufferAsprintf(buf, ",bus=%s.0", contAlias); + } else { + /* For all other controllers, the bus name matches the alias + * of the corresponding controller */ + virBufferAsprintf(buf, ",bus=%s", contAlias); + } if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) virBufferAddLit(buf, ",multifunction=on"); -- 2.7.5

Additional PHBs (pci-root controllers) will be created for the guest using the spapr-pci-host-bridge QEMU device, if available; the implicit default PHB, while present in the guest configuration, will be skipped. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1431193 Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_command.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 372f5ca..6640e4d 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3163,6 +3163,40 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, def->opts.pciopts.numaNode); break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (def->opts.pciopts.modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE || + def->opts.pciopts.idx == -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("autogenerated pci-root options not set")); + goto error; + } + + /* Skip the implicit one */ + if (def->opts.pciopts.idx == 0) + goto done; + + modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName); + if (!modelName) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown pci-root model name value %d"), + def->opts.pciopts.modelName); + goto error; + } + if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("PCI controller model name '%s' is not valid for a pci-root"), + modelName); + goto error; + } + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("the spapr-pci-host-bridge controller " + "is not supported in this QEMU binary")); + goto error; + } + virBufferAsprintf(&buf, "%s,index=%d,id=%s", + modelName, def->opts.pciopts.idx, + def->info.alias); + break; case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -3212,6 +3246,7 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (virBufferCheckError(&buf) < 0) goto error; + done: *devstr = virBufferContentAndReset(&buf); return 0; @@ -3269,10 +3304,16 @@ qemuBuildControllerDevCommandLine(virCommandPtr cmd, continue; } - /* skip pci-root/pcie-root */ + /* skip pcie-root */ if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && - (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || - cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)) + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) + continue; + + /* Skip pci-root, except for pSeries guests (which actually + * support more than one PCI Host Bridge per guest) */ + if (!qemuDomainIsPSeries(def) && + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) continue; /* first SATA controller on Q35 machines is implicit */ -- 2.7.5

Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- .../qemuxml2argv-pseries-phb-default-missing.args | 22 +++++++++++++++ .../qemuxml2argv-pseries-phb-default-missing.xml | 16 +++++++++++ .../qemuxml2argv-pseries-phb-simple.args | 22 +++++++++++++++ .../qemuxml2argv-pseries-phb-simple.xml | 17 +++++++++++ tests/qemuxml2argvtest.c | 8 ++++++ .../qemuxml2xmlout-pseries-phb-default-missing.xml | 33 ++++++++++++++++++++++ .../qemuxml2xmlout-pseries-phb-simple.xml | 33 ++++++++++++++++++++++ tests/qemuxml2xmltest.c | 7 +++++ 8 files changed, 158 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args new file mode 100644 index 0000000..009f5a8 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name QEMUGuest1 \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device spapr-pci-host-bridge,index=2,id=pci.2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml new file mode 100644 index 0000000..d0b45bf --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml @@ -0,0 +1,16 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' index='1' model='pci-root'/> + <controller type='pci' index='2' model='pci-root'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args new file mode 100644 index 0000000..009f5a8 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name QEMUGuest1 \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device spapr-pci-host-bridge,index=2,id=pci.2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml new file mode 100644 index 0000000..b1c6ff3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml @@ -0,0 +1,17 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' model='pci-root'/> + <controller type='pci' model='pci-root'/> + <controller type='pci' model='pci-root'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 31d137c..2b75647 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1709,6 +1709,14 @@ mymain(void) QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST_FAILURE("pseries-panic-address", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); + + DO_TEST("pseries-phb-simple", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-phb-default-missing", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("disk-ide-drive-split", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_IDE_CD); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml new file mode 100644 index 0000000..62708b4 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml new file mode 100644 index 0000000..2c1e64e --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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'/> + </controller> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> + </controller> + <controller type='usb' index='0' model='none'/> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 6c7d207..603a797 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -675,6 +675,13 @@ mymain(void) DO_TEST("pseries-panic-missing", NONE); DO_TEST("pseries-panic-no-address", NONE); + DO_TEST("pseries-phb-simple", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-phb-default-missing", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("balloon-device-auto", NONE); DO_TEST("balloon-device-period", NONE); DO_TEST("channel-virtio-auto", NONE); -- 2.7.5

These tests demonstrate that, while it's now possible for the user to create PHB explicitly and manually assign devices to them, libvirt still defaults to extending the guest PCI topology using PCI bridges and making suboptimal device placement choices. The next few commits will improve on these behaviors and the tests outputs will automatically be updated to reflect this. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- .../qemuxml2argv-pseries-hostdevs-1.args | 23 ++++ .../qemuxml2argv-pseries-hostdevs-1.xml | 38 +++++++ .../qemuxml2argv-pseries-hostdevs-2.args | 24 ++++ .../qemuxml2argv-pseries-hostdevs-2.xml | 37 ++++++ .../qemuxml2argv-pseries-hostdevs-3.args | 24 ++++ .../qemuxml2argv-pseries-hostdevs-3.xml | 31 +++++ .../qemuxml2argv-pseries-many-buses-1.args | 22 ++++ .../qemuxml2argv-pseries-many-buses-1.xml | 19 ++++ .../qemuxml2argv-pseries-many-buses-2.args | 22 ++++ .../qemuxml2argv-pseries-many-buses-2.xml | 18 +++ .../qemuxml2argv-pseries-many-devices.args | 53 +++++++++ .../qemuxml2argv-pseries-many-devices.xml | 48 ++++++++ tests/qemuxml2argvtest.c | 36 ++++++ .../qemuxml2xmlout-pseries-hostdevs-1.xml | 46 ++++++++ .../qemuxml2xmlout-pseries-hostdevs-2.xml | 47 ++++++++ .../qemuxml2xmlout-pseries-hostdevs-3.xml | 49 ++++++++ .../qemuxml2xmlout-pseries-many-buses-1.xml | 33 ++++++ .../qemuxml2xmlout-pseries-many-buses-2.xml | 34 ++++++ .../qemuxml2xmlout-pseries-many-devices.xml | 126 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 36 ++++++ 20 files changed, 766 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.args new file mode 100644 index 0000000..88eb081 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.args @@ -0,0 +1,23 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +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.0,id=hostdev1,bus=pci.0,addr=0x2 \ +-device vfio-pci,host=0001:01:00.1,id=hostdev2,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.xml new file mode 100644 index 0000000..87fe145 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.xml @@ -0,0 +1,38 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <!-- This hostdev will cause a new PHB to be created because its + isolation group is 2 --> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> + </source> + </hostdev> + <!-- This hostdev can't share the PHB that was just created, because + its isolation group is 3 --> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> + </source> + </hostdev> + <!-- This hostdev will be placed on the first PHB, since its isolation + group is 2 just like the first hostdev --> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> + </source> + </hostdev> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args new file mode 100644 index 0000000..c43e15d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args @@ -0,0 +1,24 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 \ +-device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.1,addr=0x2 \ +-device vfio-pci,host=0005:90:01.0,id=hostdev1,bus=pci.0,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.xml new file mode 100644 index 0000000..551b588 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.xml @@ -0,0 +1,37 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <!-- This device will cause a new PHB to be created because of its + address --> + <controller type='scsi' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + </controller> + <!-- This hostdev will share the same PHB as the SCSI controller + despite being in a separate isolation group, because the + address has been requested explicitly by the user --> + <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='0x01' slot='0x02' function='0x0'/> + </hostdev> + <!-- This hostdev can use neither the PHB that was just created, nor + the default one, because its isolation group is 3 --> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> + </source> + </hostdev> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args new file mode 100644 index 0000000..99df2e7 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args @@ -0,0 +1,24 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.0,addr=0x2 \ +-device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.2,addr=0x1 \ +-device vfio-pci,host=0001:01:00.1,id=hostdev1,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.xml new file mode 100644 index 0000000..0e61a17 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.xml @@ -0,0 +1,31 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <!-- This hostdev will cause a new PHB to be created because its + isolation group is 2. It will be PHB 2 due to the address --> + <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='0x02' slot='0x01' function='0x0'/> + </hostdev> + <!-- This hostdev will be placed on the same PHB, since its isolation + group is also 2 --> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> + </source> + </hostdev> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args new file mode 100644 index 0000000..bf78fc1 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml new file mode 100644 index 0000000..c52349d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml @@ -0,0 +1,19 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <!-- The SCSI controller is plugged into PCI bus 1, but since said bus + is not present in the configuration libvirt will have to add it --> + <controller type='scsi' model='virtio-scsi'> + <address type='pci' bus='1' slot='1'/> + </controller> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args new file mode 100644 index 0000000..1cb5831 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device spapr-pci-host-bridge,index=1,id=pci.2 \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml new file mode 100644 index 0000000..7065626 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml @@ -0,0 +1,18 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <!-- PCI buses 0 and 2 are present in the configuration, libvirt will + have to fill in the blanks and add bus 1 --> + <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='2' model='pci-root'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args new file mode 100644 index 0000000..1db4533 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args @@ -0,0 +1,53 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 \ +-device virtio-scsi-pci,id=scsi1,bus=pci.0,addr=0x3 \ +-device virtio-scsi-pci,id=scsi2,bus=pci.0,addr=0x4 \ +-device virtio-scsi-pci,id=scsi3,bus=pci.0,addr=0x5 \ +-device virtio-scsi-pci,id=scsi4,bus=pci.0,addr=0x6 \ +-device virtio-scsi-pci,id=scsi5,bus=pci.0,addr=0x7 \ +-device virtio-scsi-pci,id=scsi6,bus=pci.0,addr=0x8 \ +-device virtio-scsi-pci,id=scsi7,bus=pci.0,addr=0x9 \ +-device virtio-scsi-pci,id=scsi8,bus=pci.0,addr=0xa \ +-device virtio-scsi-pci,id=scsi9,bus=pci.0,addr=0xb \ +-device virtio-scsi-pci,id=scsi10,bus=pci.0,addr=0xc \ +-device virtio-scsi-pci,id=scsi11,bus=pci.0,addr=0xd \ +-device virtio-scsi-pci,id=scsi12,bus=pci.0,addr=0xe \ +-device virtio-scsi-pci,id=scsi13,bus=pci.0,addr=0xf \ +-device virtio-scsi-pci,id=scsi14,bus=pci.0,addr=0x10 \ +-device virtio-scsi-pci,id=scsi15,bus=pci.0,addr=0x11 \ +-device virtio-scsi-pci,id=scsi16,bus=pci.0,addr=0x12 \ +-device virtio-scsi-pci,id=scsi17,bus=pci.0,addr=0x13 \ +-device virtio-scsi-pci,id=scsi18,bus=pci.0,addr=0x14 \ +-device virtio-scsi-pci,id=scsi19,bus=pci.0,addr=0x15 \ +-device virtio-scsi-pci,id=scsi20,bus=pci.0,addr=0x16 \ +-device virtio-scsi-pci,id=scsi21,bus=pci.0,addr=0x17 \ +-device virtio-scsi-pci,id=scsi22,bus=pci.0,addr=0x18 \ +-device virtio-scsi-pci,id=scsi23,bus=pci.0,addr=0x19 \ +-device virtio-scsi-pci,id=scsi24,bus=pci.0,addr=0x1a \ +-device virtio-scsi-pci,id=scsi25,bus=pci.0,addr=0x1b \ +-device virtio-scsi-pci,id=scsi26,bus=pci.0,addr=0x1c \ +-device virtio-scsi-pci,id=scsi27,bus=pci.0,addr=0x1d \ +-device virtio-scsi-pci,id=scsi28,bus=pci.0,addr=0x1e \ +-device virtio-scsi-pci,id=scsi29,bus=pci.0,addr=0x1f \ +-device virtio-scsi-pci,id=scsi30,bus=pci.1,addr=0x1 \ +-device virtio-scsi-pci,id=scsi31,bus=pci.1,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml new file mode 100644 index 0000000..f3daba4 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml @@ -0,0 +1,48 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <!-- pci-root has 31 slots and there are 32 SCSI controllers here, so + libvirt will automatically add at least one more PCI controller --> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 2b75647..03290c1 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1717,6 +1717,42 @@ mymain(void) QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-many-devices", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-1", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-2", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-hostdevs-1", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("pseries-hostdevs-2", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("pseries-hostdevs-3", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("disk-ide-drive-split", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_IDE_CD); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml new file mode 100644 index 0000000..34defea --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml @@ -0,0 +1,46 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </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'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' 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'/> + </hostdev> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml new file mode 100644 index 0000000..62bead5 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml @@ -0,0 +1,47 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </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='0x01' slot='0x02' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </hostdev> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml new file mode 100644 index 0000000..77c0909 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml @@ -0,0 +1,49 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </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='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'/> + </hostdev> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml new file mode 100644 index 0000000..9044936 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml new file mode 100644 index 0000000..75dfabf --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml @@ -0,0 +1,34 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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'/> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml new file mode 100644 index 0000000..b596fe6 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml @@ -0,0 +1,126 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='scsi' index='1' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='scsi' index='2' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='scsi' index='3' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='scsi' index='4' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='scsi' index='5' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='scsi' index='6' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='scsi' index='7' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='scsi' index='8' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='scsi' index='9' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='scsi' index='10' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='scsi' index='11' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + </controller> + <controller type='scsi' index='12' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + </controller> + <controller type='scsi' index='13' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> + </controller> + <controller type='scsi' index='14' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> + </controller> + <controller type='scsi' index='15' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> + </controller> + <controller type='scsi' index='16' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> + </controller> + <controller type='scsi' index='17' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x13' function='0x0'/> + </controller> + <controller type='scsi' index='18' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x14' function='0x0'/> + </controller> + <controller type='scsi' index='19' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x15' function='0x0'/> + </controller> + <controller type='scsi' index='20' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x16' function='0x0'/> + </controller> + <controller type='scsi' index='21' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x17' function='0x0'/> + </controller> + <controller type='scsi' index='22' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x18' function='0x0'/> + </controller> + <controller type='scsi' index='23' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x19' function='0x0'/> + </controller> + <controller type='scsi' index='24' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x0'/> + </controller> + <controller type='scsi' index='25' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> + </controller> + <controller type='scsi' index='26' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1c' function='0x0'/> + </controller> + <controller type='scsi' index='27' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0'/> + </controller> + <controller type='scsi' index='28' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='scsi' index='29' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x0'/> + </controller> + <controller type='scsi' index='30' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + </controller> + <controller type='scsi' index='31' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x02' function='0x0'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 603a797..a122464 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -682,6 +682,42 @@ mymain(void) QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-many-devices", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-1", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-2", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-hostdevs-1", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("pseries-hostdevs-2", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("pseries-hostdevs-3", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("balloon-device-auto", NONE); DO_TEST("balloon-device-period", NONE); DO_TEST("channel-virtio-auto", NONE); -- 2.7.5

PCI bus has to be numbered sequentially, and no index can be missing, so libvirt will fill in the blanks automatically for the user. Up until now, it has done so using either pci-bridge, for machine types based on legacy PCI, or pcie-root-port, for machine types based on PCI Express. Neither choice is good for pSeries guests, where PHBs (pci-root) should be used instead. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_domain_address.c | 16 +++++++++++++--- .../qemuxml2argv-pseries-many-buses-2.args | 2 +- tests/qemuxml2argvtest.c | 1 - .../qemuxml2xmlout-pseries-many-buses-2.xml | 7 +++---- tests/qemuxml2xmltest.c | 1 - 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 960ea04..082cb72 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1097,10 +1097,14 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, * that don't yet have a corresponding controller in the domain * config. */ - if (hasPCIeRoot) + if (qemuDomainIsPSeries(def)) { + /* pSeries guests should use PHBs (pci-root controllers) */ + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT; + } else if (hasPCIeRoot) { defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; - else + } else { defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + } for (i = 1; i < addrs->nbuses; i++) { @@ -2182,7 +2186,13 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, dev.data.controller = def->controllers[contIndex]; /* set connect flags so it will be properly addressed */ qemuDomainFillDevicePCIConnectFlags(def, &dev, qemuCaps, driver); - if (qemuDomainPCIAddressReserveNextAddr(addrs, + + /* Reserve an address for the controller. pci-root and pcie-root + * controllers don't plug into any other PCI controller, hence + * they should skip this step */ + if (bus->model != VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT && + bus->model != VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT && + qemuDomainPCIAddressReserveNextAddr(addrs, &dev.data.controller->info) < 0) { goto cleanup; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args index 1cb5831..13fed02 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args @@ -19,4 +19,4 @@ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ -device spapr-pci-host-bridge,index=1,id=pci.2 \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 +-device spapr-pci-host-bridge,index=2,id=pci.1 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 03290c1..34aab4a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1730,7 +1730,6 @@ mymain(void) DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-hostdevs-1", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml index 75dfabf..14f3e36 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml @@ -23,10 +23,9 @@ <target index='1'/> </controller> <controller type='usb' index='0' model='none'/> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> </controller> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index a122464..ce8e60f 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -695,7 +695,6 @@ mymain(void) DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-hostdevs-1", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, -- 2.7.5

When looking for slots suitable for a PCI device, libvirt might need to add an extra PCI controller: for pSeries guests, we want that extra controller to be a PHB (pci-root) rather than a PCI bridge. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/conf/domain_addr.c | 56 +++++++++-------- src/conf/domain_addr.h | 2 + src/qemu/qemu_domain_address.c | 4 ++ .../qemuxml2argv-pseries-hostdevs-2.args | 8 +-- .../qemuxml2argv-pseries-hostdevs-3.args | 8 +-- .../qemuxml2argv-pseries-many-buses-1.args | 4 +- .../qemuxml2argv-pseries-many-devices.args | 66 ++++++++++---------- tests/qemuxml2argvtest.c | 4 -- .../qemuxml2xmlout-pseries-hostdevs-2.xml | 9 ++- .../qemuxml2xmlout-pseries-hostdevs-3.xml | 16 +++-- .../qemuxml2xmlout-pseries-many-buses-1.xml | 7 +-- .../qemuxml2xmlout-pseries-many-devices.xml | 71 +++++++++++----------- tests/qemuxml2xmltest.c | 4 -- 13 files changed, 129 insertions(+), 130 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 86b1367..b9e9145 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -383,33 +383,39 @@ virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, */ if (flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) { - model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + if (addrs->multipleRootsSupported) { + /* Use a pci-root controller to expand the guest's PCI + * topology if it supports having more than one */ + model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT; + } else { + model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; - /* if there aren't yet any buses that will accept a - * pci-bridge, and the caller is asking for one, we'll need to - * add a dmi-to-pci-bridge first. - */ - needDMIToPCIBridge = true; - for (i = 0; i < addrs->nbuses; i++) { - if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { - needDMIToPCIBridge = false; - break; - } - } - if (needDMIToPCIBridge && add == 1) { - /* We need to add a single pci-bridge to provide the bus - * our legacy PCI device will be plugged into; however, we - * have also determined that there isn't yet any proper - * place to connect that pci-bridge we're about to add (on - * a system with pcie-root, that "proper place" would be a - * dmi-to-pci-bridge". So, to give the pci-bridge a place - * to connect, we increase the count of buses to add, - * while also incrementing the bus number in the address - * for the device (since the pci-bridge will now be at an - * index 1 higher than the caller had anticipated). + /* if there aren't yet any buses that will accept a + * pci-bridge, and the caller is asking for one, we'll need to + * add a dmi-to-pci-bridge first. */ - add++; - addr->bus++; + needDMIToPCIBridge = true; + for (i = 0; i < addrs->nbuses; i++) { + if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { + needDMIToPCIBridge = false; + break; + } + } + if (needDMIToPCIBridge && add == 1) { + /* We need to add a single pci-bridge to provide the bus + * our legacy PCI device will be plugged into; however, we + * have also determined that there isn't yet any proper + * place to connect that pci-bridge we're about to add (on + * a system with pcie-root, that "proper place" would be a + * dmi-to-pci-bridge". So, to give the pci-bridge a place + * to connect, we increase the count of buses to add, + * while also incrementing the bus number in the address + * for the device (since the pci-bridge will now be at an + * index 1 higher than the caller had anticipated). + */ + add++; + addr->bus++; + } } } else if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE && addrs->buses[0].model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) { diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index c98a228..9cd1b29 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -108,6 +108,8 @@ struct _virDomainPCIAddressSet { size_t nbuses; bool dryRun; /* on a dry run, new buses are auto-added and addresses aren't saved in device infos */ + /* If true, the guest can have multiple pci-root controllers */ + bool multipleRootsSupported; }; typedef struct _virDomainPCIAddressSet virDomainPCIAddressSet; typedef virDomainPCIAddressSet *virDomainPCIAddressSetPtr; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 082cb72..50e41a4 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1061,6 +1061,10 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, addrs->dryRun = dryRun; + /* pSeries domains support multiple pci-root controllers */ + if (qemuDomainIsPSeries(def)) + addrs->multipleRootsSupported = true; + for (i = 0; i < def->ncontrollers; i++) { virDomainControllerDefPtr cont = def->controllers[i]; size_t idx = cont->idx; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args index c43e15d..83d4306 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args @@ -18,7 +18,7 @@ QEMU_AUDIO_DRV=none \ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ --device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 \ --device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.1,addr=0x2 \ --device vfio-pci,host=0005:90:01.0,id=hostdev1,bus=pci.0,addr=0x2 +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.1.0,addr=0x1 \ +-device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.1.0,addr=0x2 \ +-device vfio-pci,host=0005:90:01.0,id=hostdev1,bus=pci.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args index 99df2e7..eda6cc7 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args @@ -18,7 +18,7 @@ QEMU_AUDIO_DRV=none \ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ --device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.0,addr=0x2 \ --device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.2,addr=0x1 \ --device vfio-pci,host=0001:01:00.1,id=hostdev1,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.2.0,addr=0x1 \ +-device vfio-pci,host=0001:01:00.1,id=hostdev1,bus=pci.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args index bf78fc1..eb5ccbd 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args @@ -18,5 +18,5 @@ QEMU_AUDIO_DRV=none \ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ --device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.1.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args index 1db4533..f20bc52 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args @@ -18,36 +18,36 @@ QEMU_AUDIO_DRV=none \ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ --device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 \ --device virtio-scsi-pci,id=scsi1,bus=pci.0,addr=0x3 \ --device virtio-scsi-pci,id=scsi2,bus=pci.0,addr=0x4 \ --device virtio-scsi-pci,id=scsi3,bus=pci.0,addr=0x5 \ --device virtio-scsi-pci,id=scsi4,bus=pci.0,addr=0x6 \ --device virtio-scsi-pci,id=scsi5,bus=pci.0,addr=0x7 \ --device virtio-scsi-pci,id=scsi6,bus=pci.0,addr=0x8 \ --device virtio-scsi-pci,id=scsi7,bus=pci.0,addr=0x9 \ --device virtio-scsi-pci,id=scsi8,bus=pci.0,addr=0xa \ --device virtio-scsi-pci,id=scsi9,bus=pci.0,addr=0xb \ --device virtio-scsi-pci,id=scsi10,bus=pci.0,addr=0xc \ --device virtio-scsi-pci,id=scsi11,bus=pci.0,addr=0xd \ --device virtio-scsi-pci,id=scsi12,bus=pci.0,addr=0xe \ --device virtio-scsi-pci,id=scsi13,bus=pci.0,addr=0xf \ --device virtio-scsi-pci,id=scsi14,bus=pci.0,addr=0x10 \ --device virtio-scsi-pci,id=scsi15,bus=pci.0,addr=0x11 \ --device virtio-scsi-pci,id=scsi16,bus=pci.0,addr=0x12 \ --device virtio-scsi-pci,id=scsi17,bus=pci.0,addr=0x13 \ --device virtio-scsi-pci,id=scsi18,bus=pci.0,addr=0x14 \ --device virtio-scsi-pci,id=scsi19,bus=pci.0,addr=0x15 \ --device virtio-scsi-pci,id=scsi20,bus=pci.0,addr=0x16 \ --device virtio-scsi-pci,id=scsi21,bus=pci.0,addr=0x17 \ --device virtio-scsi-pci,id=scsi22,bus=pci.0,addr=0x18 \ --device virtio-scsi-pci,id=scsi23,bus=pci.0,addr=0x19 \ --device virtio-scsi-pci,id=scsi24,bus=pci.0,addr=0x1a \ --device virtio-scsi-pci,id=scsi25,bus=pci.0,addr=0x1b \ --device virtio-scsi-pci,id=scsi26,bus=pci.0,addr=0x1c \ --device virtio-scsi-pci,id=scsi27,bus=pci.0,addr=0x1d \ --device virtio-scsi-pci,id=scsi28,bus=pci.0,addr=0x1e \ --device virtio-scsi-pci,id=scsi29,bus=pci.0,addr=0x1f \ --device virtio-scsi-pci,id=scsi30,bus=pci.1,addr=0x1 \ --device virtio-scsi-pci,id=scsi31,bus=pci.1,addr=0x2 +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x1 \ +-device virtio-scsi-pci,id=scsi1,bus=pci.0,addr=0x2 \ +-device virtio-scsi-pci,id=scsi2,bus=pci.0,addr=0x3 \ +-device virtio-scsi-pci,id=scsi3,bus=pci.0,addr=0x4 \ +-device virtio-scsi-pci,id=scsi4,bus=pci.0,addr=0x5 \ +-device virtio-scsi-pci,id=scsi5,bus=pci.0,addr=0x6 \ +-device virtio-scsi-pci,id=scsi6,bus=pci.0,addr=0x7 \ +-device virtio-scsi-pci,id=scsi7,bus=pci.0,addr=0x8 \ +-device virtio-scsi-pci,id=scsi8,bus=pci.0,addr=0x9 \ +-device virtio-scsi-pci,id=scsi9,bus=pci.0,addr=0xa \ +-device virtio-scsi-pci,id=scsi10,bus=pci.0,addr=0xb \ +-device virtio-scsi-pci,id=scsi11,bus=pci.0,addr=0xc \ +-device virtio-scsi-pci,id=scsi12,bus=pci.0,addr=0xd \ +-device virtio-scsi-pci,id=scsi13,bus=pci.0,addr=0xe \ +-device virtio-scsi-pci,id=scsi14,bus=pci.0,addr=0xf \ +-device virtio-scsi-pci,id=scsi15,bus=pci.0,addr=0x10 \ +-device virtio-scsi-pci,id=scsi16,bus=pci.0,addr=0x11 \ +-device virtio-scsi-pci,id=scsi17,bus=pci.0,addr=0x12 \ +-device virtio-scsi-pci,id=scsi18,bus=pci.0,addr=0x13 \ +-device virtio-scsi-pci,id=scsi19,bus=pci.0,addr=0x14 \ +-device virtio-scsi-pci,id=scsi20,bus=pci.0,addr=0x15 \ +-device virtio-scsi-pci,id=scsi21,bus=pci.0,addr=0x16 \ +-device virtio-scsi-pci,id=scsi22,bus=pci.0,addr=0x17 \ +-device virtio-scsi-pci,id=scsi23,bus=pci.0,addr=0x18 \ +-device virtio-scsi-pci,id=scsi24,bus=pci.0,addr=0x19 \ +-device virtio-scsi-pci,id=scsi25,bus=pci.0,addr=0x1a \ +-device virtio-scsi-pci,id=scsi26,bus=pci.0,addr=0x1b \ +-device virtio-scsi-pci,id=scsi27,bus=pci.0,addr=0x1c \ +-device virtio-scsi-pci,id=scsi28,bus=pci.0,addr=0x1d \ +-device virtio-scsi-pci,id=scsi29,bus=pci.0,addr=0x1e \ +-device virtio-scsi-pci,id=scsi30,bus=pci.0,addr=0x1f \ +-device virtio-scsi-pci,id=scsi31,bus=pci.1.0,addr=0x1 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 34aab4a..5908992 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1720,12 +1720,10 @@ mymain(void) DO_TEST("pseries-many-devices", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-1", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, @@ -1741,14 +1739,12 @@ mymain(void) QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, QEMU_CAPS_HOST_PCI_MULTIDOMAIN, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST("pseries-hostdevs-3", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, QEMU_CAPS_HOST_PCI_MULTIDOMAIN, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DEVICE_VFIO_PCI); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml index 62bead5..17ff4c8 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml @@ -22,10 +22,9 @@ <model name='spapr-pci-host-bridge'/> <target index='0'/> </controller> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> </controller> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> @@ -39,7 +38,7 @@ <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> - <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </hostdev> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml index 77c0909..58023ec 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml @@ -19,15 +19,13 @@ <model name='spapr-pci-host-bridge'/> <target index='0'/> </controller> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> </controller> - <controller type='pci' index='2' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='2'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> </controller> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> @@ -41,7 +39,7 @@ <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='0x00' slot='0x01' function='0x0'/> </hostdev> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml index 9044936..eb7bb80 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml @@ -22,10 +22,9 @@ <model name='spapr-pci-host-bridge'/> <target index='0'/> </controller> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> </controller> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml index b596fe6..ff7a08f 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml @@ -15,110 +15,109 @@ <devices> <emulator>/usr/bin/qemu-system-ppc64</emulator> <controller type='scsi' index='0' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> <controller type='scsi' index='1' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </controller> <controller type='scsi' index='2' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </controller> <controller type='scsi' index='3' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </controller> <controller type='scsi' index='4' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </controller> <controller type='scsi' index='5' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </controller> <controller type='scsi' index='6' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </controller> <controller type='scsi' index='7' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> </controller> <controller type='scsi' index='8' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> </controller> <controller type='scsi' index='9' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </controller> <controller type='scsi' index='10' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> </controller> <controller type='scsi' index='11' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> </controller> <controller type='scsi' index='12' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> </controller> <controller type='scsi' index='13' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> </controller> <controller type='scsi' index='14' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> </controller> <controller type='scsi' index='15' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> </controller> <controller type='scsi' index='16' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> </controller> <controller type='scsi' index='17' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x13' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> </controller> <controller type='scsi' index='18' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x14' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x13' function='0x0'/> </controller> <controller type='scsi' index='19' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x15' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x14' function='0x0'/> </controller> <controller type='scsi' index='20' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x16' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x15' function='0x0'/> </controller> <controller type='scsi' index='21' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x17' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x16' function='0x0'/> </controller> <controller type='scsi' index='22' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x18' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x17' function='0x0'/> </controller> <controller type='scsi' index='23' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x19' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x18' function='0x0'/> </controller> <controller type='scsi' index='24' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x19' function='0x0'/> </controller> <controller type='scsi' index='25' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x0'/> </controller> <controller type='scsi' index='26' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1c' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> </controller> <controller type='scsi' index='27' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1c' function='0x0'/> </controller> <controller type='scsi' index='28' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0'/> </controller> <controller type='scsi' index='29' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> </controller> <controller type='scsi' index='30' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x0'/> </controller> <controller type='scsi' index='31' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x01' slot='0x02' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> </controller> <controller type='usb' index='0' model='none'/> <controller type='pci' index='0' model='pci-root'> <model name='spapr-pci-host-bridge'/> <target index='0'/> </controller> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> </controller> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index ce8e60f..36e1821 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -685,12 +685,10 @@ mymain(void) DO_TEST("pseries-many-devices", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-1", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, @@ -706,14 +704,12 @@ mymain(void) QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, QEMU_CAPS_HOST_PCI_MULTIDOMAIN, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST("pseries-hostdevs-3", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, QEMU_CAPS_HOST_PCI_MULTIDOMAIN, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DEVICE_VFIO_PCI); -- 2.7.5

Isolation groups will eventually allow us to make sure certain devices, eg. PCI hostdevs, are assigned to guest PCI buses in a way that guarantees improved isolation, error detection and recovery for machine types and hypervisors that support it, eg. pSeries guest on QEMU. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/bhyve/bhyve_device.c | 4 ++-- src/conf/device_conf.h | 10 ++++++++++ src/conf/domain_addr.c | 17 ++++++++++++----- src/conf/domain_addr.h | 9 ++++++++- src/qemu/qemu_domain_address.c | 35 ++++++++++++++++++----------------- 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c index fdfd512..03aa6c9 100644 --- a/src/bhyve/bhyve_device.c +++ b/src/bhyve/bhyve_device.c @@ -57,7 +57,7 @@ bhyveCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, } if (virDomainPCIAddressReserveAddr(addrs, addr, - VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) { + VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) { goto cleanup; } @@ -100,7 +100,7 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def, lpc_addr.slot = 0x1; if (virDomainPCIAddressReserveAddr(addrs, &lpc_addr, - VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) { + VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) { goto error; } diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 58b2c9c..18542c2 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -163,6 +163,16 @@ struct _virDomainDeviceInfo { * assignment, never saved and never reported. */ int pciConnectFlags; /* enum virDomainPCIConnectFlags */ + + /* PCI devices will only be automatically placed on a PCI bus + * that shares the same isolation group */ + int isolationGroup; + + /* Usually, PCI buses will take on the same isolation group + * as the first device that is plugged into them, but in some + * cases we might want to prevent that from happening by + * locking the isolation group */ + bool isolationGroupLocked; }; diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index b9e9145..48af1f5 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -534,6 +534,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags, + int isolationGroup ATTRIBUTE_UNUSED, bool fromConfig) { int ret = -1; @@ -586,9 +587,11 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int isolationGroup) { - return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags, true); + return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags, + isolationGroup, true); } int @@ -624,7 +627,8 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, goto cleanup; ret = virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci, - flags, true); + flags, dev->isolationGroup, + true); } else { ret = virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1); } @@ -745,6 +749,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, virDomainPCIConnectFlags flags, + int isolationGroup ATTRIBUTE_UNUSED, int function) { virPCIDeviceAddress a = { 0 }; @@ -825,10 +830,12 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, { virPCIDeviceAddress addr; - if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0) + if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, + dev->isolationGroup, function) < 0) return -1; - if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) + if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, + dev->isolationGroup, false) < 0) return -1; if (!addrs->dryRun) { diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 9cd1b29..f8d63df 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -100,6 +100,12 @@ typedef struct { * bit is set, that function is in use by a device. */ virDomainPCIAddressSlot slot[VIR_PCI_ADDRESS_SLOT_LAST + 1]; + + /* See virDomainDeviceInfo::isolationGroup */ + int isolationGroup; + + /* See virDomainDeviceInfo::isolationGroupLocked */ + bool isolationGroupLocked; } virDomainPCIAddressBus; typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr; @@ -139,7 +145,8 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs, int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int isolationGroup) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 50e41a4..3d56900 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1037,7 +1037,8 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, } if (virDomainPCIAddressReserveAddr(addrs, addr, - info->pciConnectFlags) < 0) { + info->pciConnectFlags, + info->isolationGroup) < 0) { goto cleanup; } @@ -1082,6 +1083,10 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; + /* Forward the information about whether or not this bus should + * be allowed to change isolation groups */ + addrs->buses[idx].isolationGroupLocked = cont->info.isolationGroupLocked; + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) hasPCIeRoot = true; } @@ -1198,7 +1203,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, if (addrs->nbuses) { memset(&tmp_addr, 0, sizeof(tmp_addr)); tmp_addr.slot = 1; - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; } @@ -1233,7 +1238,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, goto cleanup; } } else { - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; primaryVideo->info.addr.pci = tmp_addr; primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; @@ -1258,7 +1263,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video" " device will not be possible without manual" " intervention"); - } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) { + } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) { goto cleanup; } } @@ -1334,10 +1339,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, assign = true; } if (assign) { - if (virDomainPCIAddressReserveAddr(addrs, - &tmp_addr, flags) < 0) { + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; - } cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; cont->info.addr.pci.domain = 0; @@ -1359,10 +1362,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, memset(&tmp_addr, 0, sizeof(tmp_addr)); tmp_addr.slot = 0x1E; if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { - if (virDomainPCIAddressReserveAddr(addrs, - &tmp_addr, flags) < 0) { + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; - } cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; cont->info.addr.pci.domain = 0; @@ -1385,12 +1386,12 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, tmp_addr.slot = 0x1F; tmp_addr.function = 0; tmp_addr.multi = VIR_TRISTATE_SWITCH_ON; - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; tmp_addr.function = 3; tmp_addr.multi = VIR_TRISTATE_SWITCH_ABSENT; - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; } @@ -1424,7 +1425,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, goto cleanup; } } else { - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; primaryVideo->info.addr.pci = tmp_addr; @@ -1450,8 +1451,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, " device will not be possible without manual" " intervention"); virResetLastError(); - } else if (virDomainPCIAddressReserveAddr(addrs, - &tmp_addr, flags) < 0) { + } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) { goto cleanup; } } @@ -1472,7 +1472,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&sound->info)) { continue; } - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; @@ -1689,7 +1689,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (foundAddr) { /* Reserve this function on the slot we found */ if (virDomainPCIAddressReserveAddr(addrs, &addr, - cont->info.pciConnectFlags) < 0) { + cont->info.pciConnectFlags, + cont->info.isolationGroup) < 0) { goto error; } -- 2.7.5

These rules will make it possible for libvirt to automatically assign PCI addresses in a way that respects any isolation constraints devices might have. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/conf/domain_addr.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 48af1f5..ae1f0e0 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -534,7 +534,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags, - int isolationGroup ATTRIBUTE_UNUSED, + int isolationGroup, bool fromConfig) { int ret = -1; @@ -542,6 +542,8 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, virDomainPCIAddressBusPtr bus; virErrorNumber errType = (fromConfig ? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR); + bool firstDevice; + size_t slot; if (!(addrStr = virDomainPCIAddressAsString(addr))) goto cleanup; @@ -572,6 +574,36 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, bus->slot[addr->slot].aggregate = true; } + /* Figure out whether this is the first device we're plugging + * into the bus by looking at all the slots */ + firstDevice = true; + for (slot = bus->minSlot; slot <= bus->maxSlot; slot++) { + if (bus->slot[slot].functions) { + firstDevice = false; + break; + } + } + + if (firstDevice && !bus->isolationGroupLocked) { + /* The first device decides the isolation group for the + * entire bus */ + bus->isolationGroup = isolationGroup; + VIR_DEBUG("PCI bus %.4x:%.2x assigned isolation group %d because of " + "first device %s", + addr->domain, addr->bus, isolationGroup, addrStr); + } else if (bus->isolationGroup != isolationGroup && fromConfig) { + /* If this is not the first function and its isolation group + * doesn't match the bus', then it should not be using this + * address. However, if the address comes from the user then + * we comply with the request and change the isolation group + * back to the default (because at that point isolation can't + * be guaranteed anymore) */ + bus->isolationGroup = 0; + VIR_DEBUG("PCI bus %.4x:%.2x assigned isolation group %d because of " + "user assigned address %s", + addr->domain, addr->bus, isolationGroup, addrStr); + } + /* mark the requested function as reserved */ bus->slot[addr->slot].functions |= (1 << addr->function); VIR_DEBUG("Reserving PCI address %s (aggregate='%s')", addrStr, @@ -749,7 +781,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, virDomainPCIConnectFlags flags, - int isolationGroup ATTRIBUTE_UNUSED, + int isolationGroup, int function) { virPCIDeviceAddress a = { 0 }; @@ -765,12 +797,51 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, else a.function = function; - /* "Begin at the beginning," the King said, very gravely, "and go on - * till you come to the end: then stop." */ + /* When looking for a suitable bus for the device, start by being + * very strict and ignoring all those where the isolation groups + * don't match. This ensures all devices sharing the same isolation + * group will end up on the same group */ for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) { virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus]; bool found = false; + if (bus->isolationGroup != isolationGroup) + continue; + + a.slot = bus->minSlot; + + if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function, + flags, &found) < 0) { + goto error; + } + + if (found) + goto success; + } + + /* We haven't been able to find a perfectly matching bus, but we + * might still be able to make this work by altering the isolation + * group for a bus that's currently empty. So let's try that */ + for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) { + virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus]; + bool found = false; + bool firstDevice = true; + size_t slot; + + /* Go through all the slots and see whether they are empty */ + for (slot = bus->minSlot; slot <= bus->maxSlot; slot++) { + if (bus->slot[slot].functions) { + firstDevice = false; + break; + } + } + + /* We can only change the isolation group for a bus when + * plugging in the first device; moreover, some buses are + * prevented from ever changing it */ + if (!firstDevice || bus->isolationGroupLocked) + continue; + a.slot = bus->minSlot; if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function, @@ -778,6 +849,8 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, goto error; } + /* The isolation group for the bus will actually be changed + * later, in virDomainPCIAddressReserveAddrInternal() */ if (found) goto success; } -- 2.7.5

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 Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- src/qemu/qemu_domain_address.c | 105 +++++++++++++++++++++ .../qemuxml2argv-pseries-hostdevs-1.args | 8 +- .../qemuxml2argv-pseries-hostdevs-2.args | 3 +- .../qemuxml2argv-pseries-hostdevs-3.args | 2 +- .../qemuxml2xmlout-pseries-hostdevs-1.xml | 14 ++- .../qemuxml2xmlout-pseries-hostdevs-2.xml | 6 +- .../qemuxml2xmlout-pseries-hostdevs-3.xml | 2 +- 7 files changed, 130 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 3d56900..395e0b9 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -906,6 +906,108 @@ 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 ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque ATTRIBUTE_UNUSED) +{ + virDomainHostdevDefPtr hostdev; + virPCIDeviceAddressPtr hostAddr; + + /* 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); +} + + +static int +qemuDomainSetupIsolationGroups(virDomainDefPtr def) +{ + virDomainControllerDefPtr defaultPHB; + int idx; + int ret = -1; + + /* Only pSeries guests care about isolation groups at the moment */ + if (!qemuDomainIsPSeries(def)) + return 0; + + if (qemuDomainFillAllIsolationGroups(def) < 0) + goto out; + + idx = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0); + if (idx < 0) + goto out; + + defaultPHB = def->controllers[idx]; + + /* We want to prevent hostdevs from being plugged into the default + * PHB, so we lock its isolation group */ + defaultPHB->info.isolationGroupLocked = true; + + ret = 0; + + out: + return ret; +} + +/** * qemuDomainFillDevicePCIConnectFlags: * * @def: the entire DomainDef @@ -2076,6 +2178,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, if (qemuDomainFillAllPCIConnectFlags(def, qemuCaps, driver) < 0) goto cleanup; + if (qemuDomainSetupIsolationGroups(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-hostdevs-1.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.args index 88eb081..36f2def 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-1.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.0,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.0,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/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args index 83d4306..cd5b664 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-2.args @@ -19,6 +19,7 @@ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ -device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device spapr-pci-host-bridge,index=2,id=pci.2 \ -device virtio-scsi-pci,id=scsi0,bus=pci.1.0,addr=0x1 \ -device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.1.0,addr=0x2 \ --device vfio-pci,host=0005:90:01.0,id=hostdev1,bus=pci.0,addr=0x1 +-device vfio-pci,host=0005:90:01.0,id=hostdev1,bus=pci.2.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args index eda6cc7..66a31ba 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdevs-3.args @@ -21,4 +21,4 @@ server,nowait \ -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.2.0,addr=0x1 \ --device vfio-pci,host=0001:01:00.1,id=hostdev1,bus=pci.0,addr=0x1 +-device vfio-pci,host=0001:01:00.1,id=hostdev1,bus=pci.2.0,addr=0x2 diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml index 34defea..494c414 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-1.xml @@ -19,26 +19,34 @@ <model name='spapr-pci-host-bridge'/> <target index='0'/> </controller> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> + </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='0x0'/> </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'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml index 17ff4c8..cfa395b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-2.xml @@ -26,6 +26,10 @@ <model name='spapr-pci-host-bridge'/> <target index='1'/> </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> + </controller> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> @@ -38,7 +42,7 @@ <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> </hostdev> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml index 58023ec..f91959b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdevs-3.xml @@ -39,7 +39,7 @@ <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> </hostdev> <memballoon model='none'/> <panic model='pseries'/> -- 2.7.5
participants (1)
-
Andrea Bolognani