[libvirt] [PATCH v3 00/18] Use mode PCIe less legacy PCI

(this time with auto-root-port-add goodness!) Last month I posted a short patch series that attempted to auto-assign addresses on PCI Express controllers to devices that were PCI Express devices. https://www.redhat.com/archives/libvir-list/2016-August/msg00732.html In particular, it would assign PCI virtio-1.0 devices, e1000e network devices, and nec-usb-xhci devices to hotpluggable PCIe express ports *if any were available*. However, a basic PCIe machine doesn't have any hotpluggable PCIe ports, and the patchset I sent had no provision for automatically adding any. This new patchset takes care of that limitation by automatically adding pci-root-ports as they are needed, and also automatically adds a dmi-to-pci-bridge device (to create a legacy PCI bus hierarchy) when needed so that we can do away with the code that *always* adds one (and there is a patch that *does* do away with that code :-). Once all of that was done, it turned out that virt-manager could create an *almost* legacy-PCI-free Q35 domain config - the only legacy PCI device was the sound device. Since the ich9 sound device is integrated into the Intel ich9 chip (which is part of real Q35 hardware), as a curiousity I made an RFC patch that attempts to place any ich9 audio device at 00:1B.0, which is the address where real Q35 hardware puts this device. With that patch in place, all you have to do to get a legacy-free Q35 config out of virt-manager is switch the sound device model from ich6 to ich9. (I don't expect that patch will be pushed, but it's nice to see this result). Although Andrea had ACKed most of the patches in the last patchset, I hadn't wanted to push them without accompanying patches to auto-add the pcie-root-ports (since doing so would render virt-manager + new libvirt unusable for Q35 domains). Since then I've decided on a cleaner manner for setting device connectFlags, so all but Patch 1 of the last set was discarded and re-written from scratch. Although there are still a couple more things I'd like to do, these patches can be pushed without a serious regression in functionality for Q35 domains: 1) currently I put each new pcie-root-port on its own slot, rather than putting 8 of them on the different functions of a single slot. This means you can only get ~30 devices before you have to start manually adding pcie controllers. That will be remedied soon. 2) I don't have a patch yet to read a PCI device's capabilities to see whether or not it is an Express device and change the connectFlags accordingly. In the meantime if you want to plug in a vfio assigned device, you'll either need to manually address it to a PCIe port, or you'll need to manually add a pci-bridge device to the config. 3) I don't do anything to assure there are any unused pcie-root-ports available for hotplug. We need to fix that, but I'm not sure how many to "reserve". Suggestions I've heard have been "1", "2", "4", and "just add pcie-root-ports 8 at a time and you'll have 'something between 1 and 8' available". Laine Stump (18): conf: restrict what type of buses will accept a pci-bridge qemu: replace a lot of "def->controllers[i]" with equivalent "cont" qemu: new functions qemuDomainMachineHasPCI[e]Root() qemu: new functions qemuDomainDeviceConnectFlags*() conf: new function virDomainPCIAddressReserveNextAddr() qemu: use virDomainPCIAddressReserveNextAddr in qemuDomainAssignDevicePCISlots conf: make virDomainPCIAddressGetNextSlot() a local static function qemu: replace calls to virDomainPCIAddressReserveNext*() with static function qemu: set/use info->pciConnectFlags during qemuDomainAssignDevicePCISlots qemu: set/use proper pciConnectFlags during hotplug qemu: assign virtio devices to PCIe slot when appropriate qemu: assign e1000e network devices to PCIe slots when appropriate qemu: assign nec-xhci (USB3) controller to a PCIe address when appropriate qemu: only force an available legacy-PCI slot on domains with pci-root qemu: auto-add pcie-root-port/dmi-to-pci-bridge controllers as needed qemu: don't force-add a dmi-to-pci-bridge just on principle qemu: add a USB3 controller to Q35 domains by default [RFC] qemu: try to put ich9 sound device at 00:1B.0 src/conf/device_conf.h | 5 + src/conf/domain_addr.c | 180 ++++- src/conf/domain_addr.h | 15 +- src/libvirt_private.syms | 2 +- src/qemu/qemu_domain.c | 50 +- src/qemu/qemu_domain.h | 2 + src/qemu/qemu_domain_address.c | 802 +++++++++++++++------ src/qemu/qemu_domain_address.h | 4 + src/qemu/qemu_hotplug.c | 25 +- tests/qemuxml2argvdata/qemuxml2argv-autoindex.args | 10 +- tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args | 3 +- .../qemuxml2argv-q35-default-devices-only.args | 22 + .../qemuxml2argv-q35-default-devices-only.xml | 18 + .../qemuxml2argv-q35-pcie-autoadd.args | 56 ++ .../qemuxml2argv-q35-pcie-autoadd.xml | 51 ++ tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 58 ++ tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 67 ++ .../qemuxml2argv-q35-virt-manager-basic.args | 56 ++ .../qemuxml2argv-q35-virt-manager-basic.xml | 76 ++ .../qemuxml2argv-q35-virtio-pci.args | 58 ++ .../qemuxml2argv-q35-virtio-pci.xml | 1 + tests/qemuxml2argvtest.c | 123 ++++ .../qemuxml2xmlout-autoindex.xml | 10 +- .../qemuxml2xmlout-pcie-root.xml | 4 - .../qemuxml2xmlout-q35-default-devices-only.xml | 40 + .../qemuxml2xmlout-q35-pcie-autoadd.xml | 143 ++++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 152 ++++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 116 +++ .../qemuxml2xmlout-q35-virtio-pci.xml | 152 ++++ tests/qemuxml2xmltest.c | 108 +++ 30 files changed, 2117 insertions(+), 292 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args create mode 120000 tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml -- 2.7.4

A pci-bridge has *almost* the same rules as a legacy PCI endpoint device for where it can be automatically connected, and until now both had been considered identical. There is one pairing that is okay when specifically requested by the user (i.e. manual assignment), but we want to avoid it when auto-assigning addresses - plugging a pci-bridge directly into pcie-root (it is cleaner to plug in a dmi-to-pci-bridge, then plug the pci-bridge into that). In order to allow that difference, this patch makes a separate CONNECT_TYPE for pci-bridge, and uses it to restrict auto-assigned addresses for pci-bridges to be only on pci-root, pci-expander-bus, dmi-to-pci-bridge, or on another pci-bridge. NB: As with other discouraged-but-seem-to-work configurations (e.g. plugging a legacy PCI device into a pcie-root-port) if someone *really* wants to, they can still force a pci-bridge to be plugged into pcie-root (by manually specifying its PCI address.) --- src/conf/domain_addr.c | 24 ++++++++++++++++-------- src/conf/domain_addr.h | 4 +++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 93026c2..cff2c3b 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -51,11 +51,7 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model) return 0; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: - /* pci-bridge is treated like a standard - * PCI endpoint device, because it can plug into any - * standard PCI slot (it just can't be hotplugged). - */ - return VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + return VIR_PCI_CONNECT_TYPE_PCI_BRIDGE; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS: return VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS; @@ -110,6 +106,12 @@ virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr, */ if (devFlags & VIR_PCI_CONNECT_HOTPLUGGABLE) busFlags |= VIR_PCI_CONNECT_HOTPLUGGABLE; + /* if the device is a pci-bridge, allow manually + * assigning to any bus that would also accept a + * standard PCI device. + */ + if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) + devFlags |= VIR_PCI_CONNECT_TYPE_PCI_DEVICE; } /* If this bus doesn't allow the type of connection (PCI @@ -138,6 +140,8 @@ virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr, connectStr = "pci-expander-bus"; } else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS) { connectStr = "pcie-expander-bus"; + } else if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { + connectStr = "pci-bridge"; } else { /* this should never happen. If it does, there is a * bug in the code that sets the flag bits for devices. @@ -247,19 +251,22 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus, case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE | VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS); bus->minSlot = 1; bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST; break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE); + VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE); bus->minSlot = 1; bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST; break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS: bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE); + VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE); bus->minSlot = 0; bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST; break; @@ -280,7 +287,8 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus, case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: /* slots 0 - 31, standard PCI slots, * but *not* hot-pluggable */ - bus->flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + bus->flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE); bus->minSlot = 0; bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST; break; diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 596cd4c..0072a08 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -43,6 +43,7 @@ typedef enum { VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE = 1 << 6, VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS = 1 << 7, VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS = 1 << 8, + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE = 1 << 9, } virDomainPCIConnectFlags; /* a combination of all bits that describe the type of connections @@ -55,7 +56,8 @@ typedef enum { VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT | \ VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE | \ VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS | \ - VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS) + VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS | \ + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) /* combination of all bits that could be used to connect a normal * endpoint device (i.e. excluding the connection possible between an -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
A pci-bridge has *almost* the same rules as a legacy PCI endpoint device for where it can be automatically connected, and until now both had been considered identical. There is one pairing that is okay when specifically requested by the user (i.e. manual assignment), but we want to avoid it when auto-assigning addresses - plugging a pci-bridge directly into pcie-root (it is cleaner to plug in a dmi-to-pci-bridge, then plug the pci-bridge into that).
In order to allow that difference, this patch makes a separate CONNECT_TYPE for pci-bridge, and uses it to restrict auto-assigned addresses for pci-bridges to be only on pci-root, pci-expander-bus, dmi-to-pci-bridge, or on another pci-bridge.
NB: As with other discouraged-but-seem-to-work configurations (e.g. plugging a legacy PCI device into a pcie-root-port) if someone *really* wants to, they can still force a pci-bridge to be plugged into pcie-root (by manually specifying its PCI address.) --- src/conf/domain_addr.c | 24 ++++++++++++++++-------- src/conf/domain_addr.h | 4 +++- 2 files changed, 19 insertions(+), 9 deletions(-)
ACK -- Andrea Bolognani / Red Hat / Virtualization

There's no functional change here. This pointer was just used so many times that the extra long lines became annoying. --- src/qemu/qemu_domain_address.c | 100 +++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index bb16738..dc4e4ee 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -743,36 +743,38 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCIE_DEVICE; for (i = 0; i < def->ncontrollers; i++) { - switch (def->controllers[i]->type) { + virDomainControllerDefPtr cont = def->controllers[i]; + + switch (cont->type) { case VIR_DOMAIN_CONTROLLER_TYPE_SATA: /* Verify that the first SATA controller is at 00:1F.2 the * q35 machine type *always* has a SATA controller at this * address. */ - if (def->controllers[i]->idx == 0) { - if (virDeviceInfoPCIAddressPresent(&def->controllers[i]->info)) { - if (def->controllers[i]->info.addr.pci.domain != 0 || - def->controllers[i]->info.addr.pci.bus != 0 || - def->controllers[i]->info.addr.pci.slot != 0x1F || - def->controllers[i]->info.addr.pci.function != 2) { + if (cont->idx == 0) { + if (virDeviceInfoPCIAddressPresent(&cont->info)) { + if (cont->info.addr.pci.domain != 0 || + cont->info.addr.pci.bus != 0 || + cont->info.addr.pci.slot != 0x1F || + cont->info.addr.pci.function != 2) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Primary SATA controller must have PCI address 0:0:1f.2")); goto cleanup; } } else { - def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; - def->controllers[i]->info.addr.pci.domain = 0; - def->controllers[i]->info.addr.pci.bus = 0; - def->controllers[i]->info.addr.pci.slot = 0x1F; - def->controllers[i]->info.addr.pci.function = 2; + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + cont->info.addr.pci.domain = 0; + cont->info.addr.pci.bus = 0; + cont->info.addr.pci.slot = 0x1F; + cont->info.addr.pci.function = 2; } } break; case VIR_DOMAIN_CONTROLLER_TYPE_USB: - if ((def->controllers[i]->model + if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1) && - (def->controllers[i]->info.type + (cont->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) { /* Try to assign the first found USB2 controller to * 00:1D.0 and 2nd to 00:1A.0 (because that is their @@ -798,21 +800,21 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, false, true) < 0) goto cleanup; - def->controllers[i]->info.type + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; - def->controllers[i]->info.addr.pci.domain = 0; - def->controllers[i]->info.addr.pci.bus = 0; - def->controllers[i]->info.addr.pci.slot = tmp_addr.slot; - def->controllers[i]->info.addr.pci.function = 0; - def->controllers[i]->info.addr.pci.multi + cont->info.addr.pci.domain = 0; + cont->info.addr.pci.bus = 0; + cont->info.addr.pci.slot = tmp_addr.slot; + cont->info.addr.pci.function = 0; + cont->info.addr.pci.multi = VIR_TRISTATE_SWITCH_ON; } } break; case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - if (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE && - def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE && + cont->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { /* Try to assign this bridge to 00:1E.0 (because that * is its standard location on real hardware) unless * it's already taken, but don't insist on it. @@ -823,11 +825,11 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, true, false) < 0) goto cleanup; - def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; - def->controllers[i]->info.addr.pci.domain = 0; - def->controllers[i]->info.addr.pci.bus = 0; - def->controllers[i]->info.addr.pci.slot = 0x1E; - def->controllers[i]->info.addr.pci.function = 0; + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + cont->info.addr.pci.domain = 0; + cont->info.addr.pci.bus = 0; + cont->info.addr.pci.slot = 0x1E; + cont->info.addr.pci.function = 0; } } break; @@ -1001,12 +1003,14 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, /* PCI controllers */ for (i = 0; i < def->ncontrollers; i++) { - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { - virDomainControllerModelPCI model = def->controllers[i]->model; + virDomainControllerDefPtr cont = def->controllers[i]; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { + virDomainControllerModelPCI model = cont->model; if (model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT || - !virDeviceInfoPCIAddressWanted(&def->controllers[i]->info)) + !virDeviceInfoPCIAddressWanted(&cont->info)) continue; /* convert the type of controller into a "CONNECT_TYPE" @@ -1014,9 +1018,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * controller/bus to connect it to on the upstream side. */ flags = virDomainPCIControllerModelToConnectType(model); - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->controllers[i]->info, - flags) < 0) + if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0) goto error; } } @@ -1071,38 +1073,40 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, /* Device controllers (SCSI, USB, but not IDE, FDC or CCID) */ for (i = 0; i < def->ncontrollers; i++) { + virDomainControllerDefPtr cont = def->controllers[i]; + /* PCI controllers have been dealt with earlier */ - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) continue; /* USB controller model 'none' doesn't need a PCI address */ - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && - def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE) + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE) continue; /* FDC lives behind the ISA bridge; CCID is a usb device */ - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || - def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID) + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID) continue; /* First IDE controller lives on the PIIX3 at slot=1, function=1, dealt with earlier on*/ - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && - def->controllers[i]->idx == 0) + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && + cont->idx == 0) continue; - if (!virDeviceInfoPCIAddressWanted(&def->controllers[i]->info)) + if (!virDeviceInfoPCIAddressWanted(&cont->info)) continue; /* USB2 needs special handling to put all companions in the same slot */ - if (IS_USB2_CONTROLLER(def->controllers[i])) { + if (IS_USB2_CONTROLLER(cont)) { virPCIDeviceAddress addr = {0}; bool foundAddr = false; memset(&tmp_addr, 0, sizeof(tmp_addr)); for (j = 0; j < def->ncontrollers; j++) { if (IS_USB2_CONTROLLER(def->controllers[j]) && - def->controllers[j]->idx == def->controllers[i]->idx && + def->controllers[j]->idx == cont->idx && virDeviceInfoPCIAddressPresent(&def->controllers[j]->info)) { addr = def->controllers[j]->info.addr.pci; foundAddr = true; @@ -1110,7 +1114,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, } } - switch (def->controllers[i]->model) { + switch (cont->model) { case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: addr.function = 7; addr.multi = VIR_TRISTATE_SWITCH_ABSENT; @@ -1147,12 +1151,10 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, false, foundAddr) < 0) goto error; - def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; - def->controllers[i]->info.addr.pci = addr; + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + cont->info.addr.pci = addr; } else { - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->controllers[i]->info, - flags) < 0) + if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0) goto error; } } -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
There's no functional change here. This pointer was just used so many times that the extra long lines became annoying. --- src/qemu/qemu_domain_address.c | 100 +++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 49 deletions(-) [...] @@ -798,21 +800,21 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, false, true) < 0) goto cleanup; - def->controllers[i]->info.type + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
You can now join this line with the one above it :)
- def->controllers[i]->info.addr.pci.domain = 0; - def->controllers[i]->info.addr.pci.bus = 0; - def->controllers[i]->info.addr.pci.slot = tmp_addr.slot; - def->controllers[i]->info.addr.pci.function = 0; - def->controllers[i]->info.addr.pci.multi + cont->info.addr.pci.domain = 0; + cont->info.addr.pci.bus = 0; + cont->info.addr.pci.slot = tmp_addr.slot; + cont->info.addr.pci.function = 0; + cont->info.addr.pci.multi = VIR_TRISTATE_SWITCH_ON;
Same here. [...]
@@ -1014,9 +1018,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * controller/bus to connect it to on the upstream side. */ flags = virDomainPCIControllerModelToConnectType(model); - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->controllers[i]->info, - flags) < 0) + if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0)
This is >80 columns, so "flags) < 0)" will have to remain on its own line. [...]
@@ -1147,12 +1151,10 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, false, foundAddr) < 0) goto error; - def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; - def->controllers[i]->info.addr.pci = addr; + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + cont->info.addr.pci = addr; } else { - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->controllers[i]->info, - flags) < 0) + if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0)
Same here. ACK once you address the comments above. -- Andrea Bolognani / Red Hat / Virtualization

These functions provide a simple one line method of learning if the current domain has a pci-root or pcie-root bus. --- src/qemu/qemu_domain.c | 28 ++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3f16dbe..227134e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5263,6 +5263,34 @@ qemuDomainMachineIsI440FX(const virDomainDef *def) bool +qemuDomainMachineHasPCIRoot(const virDomainDef *def) +{ + int root = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0); + + if (root < 0) + return false; + + if (def->controllers[root]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) + return true; + return false; +} + + +bool +qemuDomainMachineHasPCIeRoot(const virDomainDef *def) +{ + int root = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0); + + if (root < 0) + return false; + + if (def->controllers[root]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) + return true; + return false; +} + + +bool qemuDomainMachineNeedsFDC(const virDomainDef *def) { char *p = STRSKIP(def->os.machine, "pc-q35-"); diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index a1404d0..5b97c8c 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -637,6 +637,8 @@ virDomainChrDefPtr qemuFindAgentConfig(virDomainDefPtr def); bool qemuDomainMachineIsQ35(const virDomainDef *def); bool qemuDomainMachineIsI440FX(const virDomainDef *def); +bool qemuDomainMachineHasPCIRoot(const virDomainDef *def); +bool qemuDomainMachineHasPCIeRoot(const virDomainDef *def); bool qemuDomainMachineNeedsFDC(const virDomainDef *def); bool qemuDomainMachineIsS390CCW(const virDomainDef *def); bool qemuDomainMachineIsVirt(const virDomainDef *def); -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
These functions provide a simple one line method of learning if the current domain has a pci-root or pcie-root bus. --- src/qemu/qemu_domain.c | 28 ++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3f16dbe..227134e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5263,6 +5263,34 @@ qemuDomainMachineIsI440FX(const virDomainDef *def) bool +qemuDomainMachineHasPCIRoot(const virDomainDef *def) +{ + int root = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0); + + if (root < 0) + return false; + + if (def->controllers[root]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) + return true;
Please leave an empty line here...
+ return false; +} + + +bool +qemuDomainMachineHasPCIeRoot(const virDomainDef *def) +{ + int root = virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0); + + if (root < 0) + return false; + + if (def->controllers[root]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) + return true;
... and here. You might want to consider reversing the polarity of the neutron flow^W^W^W^W^Wmodel check, so that the function looks like if (...) return false; if (...) return false; return true; ACK, with the empty lines added, whether or not you decide to go for this change. -- Andrea Bolognani / Red Hat / Virtualization

The lowest level function of this trio aims to be the ultimate authority for the virDomainPCIConnectFlags to use for any given device using a particular arch/machinetype/qemu-binary. qemuDomainDeviceConnectFlagsInternal() returns the flags qemuDomainDeviceConnectFlags() sets info->pciConnectFlags in a single device (unless it has no virDomainDeviceInfo, in which case it's a NOP). qemuDomainDeviceSetAllConnectFlags() sets info->pciConnectFlags in all devices that have a virDomainDeviceInfo (using virDomainDeviceInfoIterate()) The latter two functions aren't called anywhere yet. This commit is just making them available. --- src/conf/device_conf.h | 5 + src/qemu/qemu_domain_address.c | 257 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 8443de6..f435fb5 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -142,6 +142,11 @@ typedef struct _virDomainDeviceInfo { /* bootIndex is only used for disk, network interface, hostdev * and redirdev devices */ unsigned int bootIndex; + + /* pciConnectFlags is only used internally during address + * assignment, never saved and never reported. + */ + int pciConnectFlags; /* enum virDomainPCIConnectFlags */ } virDomainDeviceInfo, *virDomainDeviceInfoPtr; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index dc4e4ee..7f86c32 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -398,6 +398,263 @@ qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def, } +/** + * qemuDomainDeviceConnectFlagsInternal: + * + * Lowest level function to determine PCI connectFlags for a + * device. Assume HOTPLUGGABLE | PCI_ENDPOINT, then modify + * appropriately for exceptions. This function relies on the next + * higher-level function determining the value for pcieFlags and + * virtioFlags in advance - this is to make it more efficient to call + * multiple times. + * + * @dev: The device to be checked + * + * @pcieFlags: flags to use for a known PCI Express device + * + * @virtioFlags: flags to use for a virtio device (properly vetted + * for the current qemu binary and arch/machinetype) + * + * returns appropriate virDomainPCIConnectFlags for this device in + * this domain, or 0 if the device doesn't connect using PCI. There + * is no failure. + * + */ +static virDomainPCIConnectFlags +qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, + virDomainPCIConnectFlags pcieFlags + ATTRIBUTE_UNUSED, + virDomainPCIConnectFlags virtioFlags + ATTRIBUTE_UNUSED) +{ + virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + + /* Get these out of the way to simplify the rest */ + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER && + dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) + return virDomainPCIControllerModelToConnectType(dev->data.controller->model); + + /* remember - default flags is PCI_DEVICE, so only set if it's different. */ + switch (dev->type) { + case VIR_DOMAIN_DEVICE_CONTROLLER: { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID || + (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE)) + flags = 0; + break; + } + + case VIR_DOMAIN_DEVICE_FS: + /* the only type of filesystem so far is virtio-9p-pci */ + break; + + case VIR_DOMAIN_DEVICE_NET: { + virDomainNetDefPtr net = dev->data.net; + + /* NB: a type='hostdev' will use PCI, but its + * address is assigned when we're assigning the + * addresses for other hostdev devices. + */ + if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + STREQ(net->model, "usb-net")) + flags = 0; + break; + } + + case VIR_DOMAIN_DEVICE_SOUND: + switch (dev->data.sound->model) { + case VIR_DOMAIN_SOUND_MODEL_SB16: + case VIR_DOMAIN_SOUND_MODEL_PCSPK: + case VIR_DOMAIN_SOUND_MODEL_USB: + flags = 0; + break; + } + break; + + case VIR_DOMAIN_DEVICE_DISK: + if (dev->data.disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) + flags = 0; /* only virtio disks use PCI */ + break; + + case VIR_DOMAIN_DEVICE_HOSTDEV: + break; + + case VIR_DOMAIN_DEVICE_MEMBALLOON: + if (dev->data.memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_RNG: + if (dev->data.rng->model != VIR_DOMAIN_RNG_MODEL_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_WATCHDOG: + /* only one model connects using PCI */ + if (dev->data.watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_VIDEO: + break; + + case VIR_DOMAIN_DEVICE_SHMEM: + break; + + case VIR_DOMAIN_DEVICE_INPUT: + if (dev->data.input->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_CHR: + if (dev->data.chr->targetType != VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) + flags = 0; + break; + + /* These devices don't ever connect with PCI */ + case VIR_DOMAIN_DEVICE_NVRAM: + case VIR_DOMAIN_DEVICE_TPM: + case VIR_DOMAIN_DEVICE_PANIC: + case VIR_DOMAIN_DEVICE_MEMORY: + case VIR_DOMAIN_DEVICE_HUB: + case VIR_DOMAIN_DEVICE_REDIRDEV: + case VIR_DOMAIN_DEVICE_SMARTCARD: + /* These devices don't even have a DeviceInfo */ + case VIR_DOMAIN_DEVICE_LEASE: + case VIR_DOMAIN_DEVICE_GRAPHICS: + case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_LAST: + case VIR_DOMAIN_DEVICE_NONE: + flags = 0; + break; + } + + if (flags) + flags |= VIR_PCI_CONNECT_HOTPLUGGABLE; + + return flags; +} + + +/** + * qemuDomainDeviceConnectFlags: + * + * The version of the function to call if it will be called just + * once. + * + * @def: the entire DomainDef + * + * @dev: The device to be checked + * + * @qemuCaps: as you'd expect + * + * sets device's info->pciConnectFlags when appropriate. + * There is no failure, so there is no return value. + * + */ +static void ATTRIBUTE_UNUSED +qemuDomainDeviceConnectFlags(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virQEMUCapsPtr qemuCaps) +{ + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + + if (info) { + /* These flags are passed to qemuDomainDeviceConnectFlagsInternal + * after setting according to the machinetype and qemu + * capabilities. That may seem like pointless posturing, but + * it's done this way to eliminate duplicated code while + * allowing more efficient operation when it's being done + * repeatedly with the device iterator. + */ + virDomainPCIConnectFlags virtioFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + virDomainPCIConnectFlags pcieFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + + if (qemuDomainMachineHasPCIeRoot(def)) + pcieFlags = VIR_PCI_CONNECT_TYPE_PCIE_DEVICE; + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) + virtioFlags = pcieFlags; + + info->pciConnectFlags + = qemuDomainDeviceConnectFlagsInternal(dev, pcieFlags, virtioFlags); + } +} + + +typedef struct { + virDomainPCIConnectFlags virtioFlags; + virDomainPCIConnectFlags pcieFlags; +} qemuDomainDeviceConnectFlagsIteratorData; + +/** + * qemuDomainDeviceConnectFlagsIterator: + * + * The version of the function to call with + * virDomainDeviceInfoIterate() + * + * @def: the entire DomainDef + * + * @dev: The device to be checked + * + * @info: virDomainDeviceInfo within the device + * + * @opaque: points to iterator data setup beforehand. + * + * Sets @info->pciConnectFlags. Always returns 0 - there + * is no failure. + * + */ +static int +qemuDomainDeviceConnectFlagsIterator(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque) +{ + qemuDomainDeviceConnectFlagsIteratorData *data = opaque; + + info->pciConnectFlags + = qemuDomainDeviceConnectFlagsInternal(dev, data->pcieFlags, + data->virtioFlags); + return 0; +} + + +/** + * qemuDomainDeviceSetAllConnectFlags: + * + * Set the info->pciConnectFlags for all devices in the domain. + * + * @def: the entire DomainDef + * + * @qemuCaps: as you'd expect + * + * sets info->pciConnectFlags for all devices as appropriate. returns + * 0 on success or -1 on failure (the only possibility of failure would + * be some internal problem with virDomainDeviceInfoIterate()) + */ +static int ATTRIBUTE_UNUSED +qemuDomainDeviceSetAllConnectFlags(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps) +{ + qemuDomainDeviceConnectFlagsIteratorData data + = { .virtioFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE, + .pcieFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE }; + + if (qemuDomainMachineHasPCIeRoot(def)) + data.pcieFlags = VIR_PCI_CONNECT_TYPE_PCIE_DEVICE; + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) + data.virtioFlags = data.pcieFlags; + + return virDomainDeviceInfoIterate(def, qemuDomainDeviceConnectFlagsIterator, + &data); +} + + static int qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, virDomainDeviceDefPtr device, -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
The lowest level function of this trio aims to be the ultimate authority for the virDomainPCIConnectFlags to use for any given device using a particular arch/machinetype/qemu-binary. qemuDomainDeviceConnectFlagsInternal() returns the flags qemuDomainDeviceConnectFlags() sets info->pciConnectFlags in a single device (unless it has no virDomainDeviceInfo, in which case it's a NOP).
It should be called qemuDomainDeviceSetConnectFlags() then, both to convey its purpose better and to be more consistent with the one below.
qemuDomainDeviceSetAllConnectFlags() sets info->pciConnectFlags in all devices that have a virDomainDeviceInfo (usingW
s/usingW/using/
virDomainDeviceInfoIterate())
I would propose renaming these along the lines of qemuDomainDeviceCalculatePCIConnectFlags() qemuDomainFillDevicePCIConnectFlags() qemuDomainFill[AllDevices]PCIConnectFlags() based on what they do, the kind of object they work on, and whether they treat the input as read-only or update it. I know they're not great names, but at least their purpose should be quite clear when you run into them. In any case, the subject will have to be updated because it's not correct even with the current naming.
The latter two functions aren't called anywhere yet. This commit is just making them available.
This was already mentioned on IRC, and I think we both agreed this patch should have appeared later in the series, ideally right before patch 9 which actually uses the functions it introduces.
--- src/conf/device_conf.h | 5 + src/qemu/qemu_domain_address.c | 257 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 8443de6..f435fb5 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -142,6 +142,11 @@ typedef struct _virDomainDeviceInfo { /* bootIndex is only used for disk, network interface, hostdev * and redirdev devices */ unsigned int bootIndex; + + /* pciConnectFlags is only used internally during address + * assignment, never saved and never reported. + */ + int pciConnectFlags; /* enum virDomainPCIConnectFlags */ } virDomainDeviceInfo, *virDomainDeviceInfoPtr; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index dc4e4ee..7f86c32 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -398,6 +398,263 @@ qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def, } +/** + * qemuDomainDeviceConnectFlagsInternal: + * + * Lowest level function to determine PCI connectFlags for a + * device.
The entire comment leaves two spaces after the asterisk, it should be a single space instead. Same applies to all such comments below.
Assume HOTPLUGGABLE | PCI_ENDPOINT, then modify + * appropriately for exceptions.
This is an implementation detail that shouldn't leak into the function's documentation.
This function relies on the next + * higher-level function determining the value for pcieFlags and + * virtioFlags in advance - this is to make it more efficient to call + * multiple times. + * + * @dev: The device to be checked + * + * @pcieFlags: flags to use for a known PCI Express device + * + * @virtioFlags: flags to use for a virtio device (properly vetted + * for the current qemu binary and arch/machinetype) + * + * returns appropriate virDomainPCIConnectFlags for this device in + * this domain, or 0 if the device doesn't connect using PCI. There + * is no failure. + *
Remove the empty line.
+ */ +static virDomainPCIConnectFlags +qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, + virDomainPCIConnectFlags pcieFlags + ATTRIBUTE_UNUSED, + virDomainPCIConnectFlags virtioFlags + ATTRIBUTE_UNUSED) +{ + virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + + /* Get these out of the way to simplify the rest */ + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER && + dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) + return virDomainPCIControllerModelToConnectType(dev->data.controller->model);
Please add curly braces here, as per the style guidelines. The last line is also >80 columns.
+ + /* remember - default flags is PCI_DEVICE, so only set if it's different. */ + switch (dev->type) { + case VIR_DOMAIN_DEVICE_CONTROLLER: { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID || + (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE)) + flags = 0;
Curly braces here as well.
+ break; + } + + case VIR_DOMAIN_DEVICE_FS: + /* the only type of filesystem so far is virtio-9p-pci */ + break; + + case VIR_DOMAIN_DEVICE_NET: { + virDomainNetDefPtr net = dev->data.net; + + /* NB: a type='hostdev' will use PCI, but its + * address is assigned when we're assigning the + * addresses for other hostdev devices. + */ + if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + STREQ(net->model, "usb-net")) + flags = 0;
Curly braces.
+ break; + } + + case VIR_DOMAIN_DEVICE_SOUND: + switch (dev->data.sound->model) { + case VIR_DOMAIN_SOUND_MODEL_SB16: + case VIR_DOMAIN_SOUND_MODEL_PCSPK: + case VIR_DOMAIN_SOUND_MODEL_USB: + flags = 0; + break; + } + break; + + case VIR_DOMAIN_DEVICE_DISK: + if (dev->data.disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) + flags = 0; /* only virtio disks use PCI */ + break; + + case VIR_DOMAIN_DEVICE_HOSTDEV: + break; + + case VIR_DOMAIN_DEVICE_MEMBALLOON: + if (dev->data.memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_RNG: + if (dev->data.rng->model != VIR_DOMAIN_RNG_MODEL_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_WATCHDOG: + /* only one model connects using PCI */ + if (dev->data.watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_VIDEO: + break; + + case VIR_DOMAIN_DEVICE_SHMEM: + break; + + case VIR_DOMAIN_DEVICE_INPUT: + if (dev->data.input->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_CHR: + if (dev->data.chr->targetType != VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) + flags = 0; + break; + + /* These devices don't ever connect with PCI */ + case VIR_DOMAIN_DEVICE_NVRAM: + case VIR_DOMAIN_DEVICE_TPM: + case VIR_DOMAIN_DEVICE_PANIC: + case VIR_DOMAIN_DEVICE_MEMORY: + case VIR_DOMAIN_DEVICE_HUB: + case VIR_DOMAIN_DEVICE_REDIRDEV: + case VIR_DOMAIN_DEVICE_SMARTCARD: + /* These devices don't even have a DeviceInfo */ + case VIR_DOMAIN_DEVICE_LEASE: + case VIR_DOMAIN_DEVICE_GRAPHICS: + case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_LAST: + case VIR_DOMAIN_DEVICE_NONE: + flags = 0; + break; + } + + if (flags) + flags |= VIR_PCI_CONNECT_HOTPLUGGABLE;
Wouldn't it be better to start with flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE | \ VIR_PCI_CONNECT_HOTPLUGGABLE; and skip these two lines? That way the default is clearly stated at the beginning of the function, and the behavior would be the same.
+ return flags; +} + + +/** + * qemuDomainDeviceConnectFlags: + * + * The version of the function to call if it will be called just + * once.
This description won't do. How about Set PCI connection flags for @dev based on the guest configuration and the capabilities of the QEMU binary. or something along those lines?
+ * @def: the entire DomainDef + * + * @dev: The device to be checked + * + * @qemuCaps: as you'd expect + * + * sets device's info->pciConnectFlags when appropriate. + * There is no failure, so there is no return value.
Once this is covered by the description, you can leave the bit about the return value out entirely.
+ * + */ +static void ATTRIBUTE_UNUSED +qemuDomainDeviceConnectFlags(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virQEMUCapsPtr qemuCaps) +{ + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + + if (info) { + /* These flags are passed to qemuDomainDeviceConnectFlagsInternal + * after setting according to the machinetype and qemu + * capabilities. That may seem like pointless posturing, but + * it's done this way to eliminate duplicated code while + * allowing more efficient operation when it's being done + * repeatedly with the device iterator. + */ + virDomainPCIConnectFlags virtioFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + virDomainPCIConnectFlags pcieFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + + if (qemuDomainMachineHasPCIeRoot(def)) + pcieFlags = VIR_PCI_CONNECT_TYPE_PCIE_DEVICE; + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) + virtioFlags = pcieFlags;
Of course, if the suggestion above about HOTPLUGGABLE is followed, pcieFlags and virtioFlags should have HOTPLUGGABLE set here as well. Are all endpoint devices hotpluggable? It looks like it.
+ info->pciConnectFlags + = qemuDomainDeviceConnectFlagsInternal(dev, pcieFlags, virtioFlags); + } +} + + +typedef struct { + virDomainPCIConnectFlags virtioFlags; + virDomainPCIConnectFlags pcieFlags; +} qemuDomainDeviceConnectFlagsIteratorData; + +/** + * qemuDomainDeviceConnectFlagsIterator: + * + * The version of the function to call with + * virDomainDeviceInfoIterate()
See above, although in this case the function is a simple implementation detail and the documentation is less crucial.
+ * @def: the entire DomainDef + * + * @dev: The device to be checked + * + * @info: virDomainDeviceInfo within the device + * + * @opaque: points to iterator data setup beforehand. + * + * Sets @info->pciConnectFlags. Always returns 0 - there + * is no failure. + * + */ +static int +qemuDomainDeviceConnectFlagsIterator(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque) +{ + qemuDomainDeviceConnectFlagsIteratorData *data = opaque; + + info->pciConnectFlags + = qemuDomainDeviceConnectFlagsInternal(dev, data->pcieFlags, + data->virtioFlags); + return 0; +} + + +/** + * qemuDomainDeviceSetAllConnectFlags: + * + * Set the info->pciConnectFlags for all devices in the domain. + * + * @def: the entire DomainDef + * + * @qemuCaps: as you'd expect + * + * sets info->pciConnectFlags for all devices as appropriate. returns + * 0 on success or -1 on failure (the only possibility of failure would + * be some internal problem with virDomainDeviceInfoIterate())
The purpose has already been described above, and why the function would fail is an implementation detail. It's safe to stick to the usual "returns 0 on success or <0 on failure" blurb here.
+ */ +static int ATTRIBUTE_UNUSED +qemuDomainDeviceSetAllConnectFlags(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps) +{ + qemuDomainDeviceConnectFlagsIteratorData data + = { .virtioFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE,
Double space here; however...
+ .pcieFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE }; + + if (qemuDomainMachineHasPCIeRoot(def)) + data.pcieFlags = VIR_PCI_CONNECT_TYPE_PCIE_DEVICE; + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) + data.virtioFlags = data.pcieFlags;
... this is the same exact logic already present in qemuDomainDeviceConnectFlags() above. We should really try to avoid duplication - it's the whole point of this exercise after all ;) How about a tiny helper that initializes a IteratorData structure based on def and qemuCaps? Then this function can just use the IteratorData directly, and the one above simply has to pass the two members separately.
+ return virDomainDeviceInfoIterate(def, qemuDomainDeviceConnectFlagsIterator, + &data); +} + + static int qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, virDomainDeviceDefPtr device, -- Andrea Bolognani / Red Hat / Virtualization

There is an existing virDomainPCIAddressReserveNextSlot() which will reserve all functions of the next available PCI slot. One place in the qemu PCI address assignment code requires reserving a *single* function of the next available PCI slot. This patch modifies and renames virDomainPCIAddressReserveNextSlot() so that it can fulfill both the original purpose and the need to reserve a single function. (This is being done so that the abovementioned code in qemu can have its "kind of open coded" solution replaced with a call to this new function). --- src/conf/domain_addr.c | 50 +++++++++++++++++++++++++++++++++++++++++++----- src/conf/domain_addr.h | 7 +++++++ src/libvirt_private.syms | 1 + 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index cff2c3b..f735fb4 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -691,29 +691,69 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, return 0; } +/** + * virDomainPCIAddressReserveNextAddr: + * + * find the next *completely unreserved* slot with compatible + * connection @flags, and mark either one function or the entire + * slot (according to @function and @reserveEntireSlot). + * + * @addrs: a set of addresses - one bit for each function on each + * slot on each bus, set if in use, clear if not in use. + * + * @dev: virDomainDeviceInfo that should get the new address set. + * + * @flags: CONNECT_TYPE flags for the port we're looking for + * + * @function: which function on the slot to mark as reserved + * (if @reserveEntireSlot is false) + * + * @reserveEntireSlot: true to reserve all functions on the new slot, + * false to reserve just @function + * + * + * returns 0 (and dev->addr.pci set) on success, or -1 on failure. + */ int -virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, +virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + unsigned int function, + bool reserveEntireSlot) { virPCIDeviceAddress addr; + if (virDomainPCIAddressGetNextSlot(addrs, &addr, flags) < 0) return -1; - if (virDomainPCIAddressReserveSlot(addrs, &addr, flags) < 0) + addr.function = reserveEntireSlot ? 0 : function; + + if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, reserveEntireSlot, false) < 0) return -1; + addrs->lastaddr = addr; + addrs->lastaddr.function = 0; + addrs->lastaddr.multi = VIR_TRISTATE_SWITCH_ABSENT; + addrs->lastFlags = flags; + if (!addrs->dryRun) { dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; dev->addr.pci = addr; } - addrs->lastaddr = addr; - addrs->lastFlags = flags; return 0; } +int +virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags) +{ + return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, 0, true); +} + + static char* virDomainCCWAddressAsString(virDomainDeviceCCWAddressPtr addr) { diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 0072a08..904d060 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -160,6 +160,13 @@ int virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags, + unsigned int function, + bool reserveEntireSlot) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, virDomainPCIConnectFlags flags) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9610e0c..34ea3c6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -99,6 +99,7 @@ virDomainPCIAddressFlagsCompatible; virDomainPCIAddressGetNextSlot; virDomainPCIAddressReleaseSlot; virDomainPCIAddressReserveAddr; +virDomainPCIAddressReserveNextAddr; virDomainPCIAddressReserveNextSlot; virDomainPCIAddressReserveSlot; virDomainPCIAddressSetAlloc; -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
There is an existing virDomainPCIAddressReserveNextSlot() which will reserve all functions of the next available PCI slot. One place in the qemu PCI address assignment code requires reserving a *single* function of the next available PCI slot. This patch modifies and renames virDomainPCIAddressReserveNextSlot() so that it can fulfill both the original purpose and the need to reserve a single function. (This is being done so that the abovementioned code in qemu can have its "kind of open coded" solution replaced with a call to this new function). --- src/conf/domain_addr.c | 50 +++++++++++++++++++++++++++++++++++++++++++----- src/conf/domain_addr.h | 7 +++++++ src/libvirt_private.syms | 1 + 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index cff2c3b..f735fb4 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -691,29 +691,69 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, return 0; } +/** + * virDomainPCIAddressReserveNextAddr: + * + * find the next *completely unreserved* slot with compatible + * connection @flags, and mark either one function or the entire + * slot (according to @function and @reserveEntireSlot).
Indentation is weird, here and below. We don't seem to be parsing and formatting the documentation for internal functions such as this one, still...
+ * @addrs: a set of addresses - one bit for each function on each + * slot on each bus, set if in use, clear if not in use.
I don't think you need to explain virDomainPCIAddressSetPtr here, especially not down to how it's implemented :)
+ * @dev: virDomainDeviceInfo that should get the new address set. + * + * @flags: CONNECT_TYPE flags for the port we're looking for + * + * @function: which function on the slot to mark as reserved + * (if @reserveEntireSlot is false) + * + * @reserveEntireSlot: true to reserve all functions on the new slot, + * false to reserve just @function + * + * + * returns 0 (and dev->addr.pci set) on success, or -1 on failure.
Side effects such as setting the PCI address for @dev should be part of the description, not here.
+ */ int -virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, +virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + unsigned int function, + bool reserveEntireSlot) { virPCIDeviceAddress addr; + if (virDomainPCIAddressGetNextSlot(addrs, &addr, flags) < 0) return -1; - if (virDomainPCIAddressReserveSlot(addrs, &addr, flags) < 0) + addr.function = reserveEntireSlot ? 0 : function; + + if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, reserveEntireSlot, false) < 0) return -1; + addrs->lastaddr = addr; + addrs->lastaddr.function = 0; + addrs->lastaddr.multi = VIR_TRISTATE_SWITCH_ABSENT;
Do we need to explicitly set function = 0 and multi = ABSENT? AFAICT only domain, bus and slot are used in the context of virDomainPCIAddressSet. And if that wasn't the case, they should be set according to the last address that was reserved, including function. Everything else looks good :) -- Andrea Bolognani / Red Hat / Virtualization

instead of calling virDomainPCIAddressGetNextSlot() (which I want to turn into a local static in domain_addr.c). --- src/qemu/qemu_domain_address.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 7f86c32..5a19f0b 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1256,7 +1256,6 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, { size_t i, j; virDomainPCIConnectFlags flags = 0; /* initialize to quiet gcc warning */ - virPCIDeviceAddress tmp_addr; /* PCI controllers */ for (i = 0; i < def->ncontrollers; i++) { @@ -1360,7 +1359,6 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, virPCIDeviceAddress addr = {0}; bool foundAddr = false; - memset(&tmp_addr, 0, sizeof(tmp_addr)); for (j = 0; j < def->ncontrollers; j++) { if (IS_USB2_CONTROLLER(def->controllers[j]) && def->controllers[j]->idx == cont->idx && @@ -1390,26 +1388,23 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, break; } - if (!foundAddr) { - /* This is the first part of the controller, so need - * to find a free slot & then reserve a function */ - if (virDomainPCIAddressGetNextSlot(addrs, &tmp_addr, flags) < 0) + if (foundAddr) { + /* Reserve this function on the slot we found */ + if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, + false, true) < 0) goto error; - addr.bus = tmp_addr.bus; - addr.slot = tmp_addr.slot; + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + cont->info.addr.pci = addr; + } else { + /* This is the first part of the controller, so need + * to find a free slot & then reserve this function */ + if (virDomainPCIAddressReserveNextAddr(addrs, &cont->info, flags, + addr.function, false) < 0) + goto error; - addrs->lastaddr = addr; - addrs->lastaddr.function = 0; - addrs->lastaddr.multi = VIR_TRISTATE_SWITCH_ABSENT; + cont->info.addr.pci.multi = addr.multi; } - /* Finally we can reserve the slot+function */ - if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, - false, foundAddr) < 0) - goto error; - - cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; - cont->info.addr.pci = addr; } else { if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0) goto error; -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
instead of calling virDomainPCIAddressGetNextSlot() (which I want to turn into a local static in domain_addr.c). --- src/qemu/qemu_domain_address.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 7f86c32..5a19f0b 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1256,7 +1256,6 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, { size_t i, j; virDomainPCIConnectFlags flags = 0; /* initialize to quiet gcc warning */ - virPCIDeviceAddress tmp_addr; /* PCI controllers */ for (i = 0; i < def->ncontrollers; i++) { @@ -1360,7 +1359,6 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, virPCIDeviceAddress addr = {0}; bool foundAddr = false; - memset(&tmp_addr, 0, sizeof(tmp_addr)); for (j = 0; j < def->ncontrollers; j++) { if (IS_USB2_CONTROLLER(def->controllers[j]) && def->controllers[j]->idx == cont->idx && @@ -1390,26 +1388,23 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, break; } - if (!foundAddr) { - /* This is the first part of the controller, so need - * to find a free slot & then reserve a function */ - if (virDomainPCIAddressGetNextSlot(addrs, &tmp_addr, flags) < 0) + if (foundAddr) { + /* Reserve this function on the slot we found */ + if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, + false, true) < 0) goto error; - addr.bus = tmp_addr.bus; - addr.slot = tmp_addr.slot; + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + cont->info.addr.pci = addr; + } else { + /* This is the first part of the controller, so need + * to find a free slot & then reserve this function */ + if (virDomainPCIAddressReserveNextAddr(addrs, &cont->info, flags, + addr.function, false) < 0)
This line is >80 columns.
+ goto error; - addrs->lastaddr = addr; - addrs->lastaddr.function = 0; - addrs->lastaddr.multi = VIR_TRISTATE_SWITCH_ABSENT; + cont->info.addr.pci.multi = addr.multi; } - /* Finally we can reserve the slot+function */ - if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, - false, foundAddr) < 0) - goto error; - - cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; - cont->info.addr.pci = addr; } else { if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0) goto error;
ACK -- Andrea Bolognani / Red Hat / Virtualization

This function is no longer needed outside of domain_addr.c. --- 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 f735fb4..be42f15 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -591,7 +591,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs) } -int +static int virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, virDomainPCIConnectFlags flags) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 904d060..4d6d12a 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -155,11 +155,6 @@ int virDomainPCIAddressReleaseSlot(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, - virPCIDeviceAddressPtr next_addr, - virDomainPCIConnectFlags flags) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, virDomainPCIConnectFlags flags, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 34ea3c6..8ac2e79 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -96,7 +96,6 @@ virDomainPCIAddressAsString; virDomainPCIAddressBusSetModel; virDomainPCIAddressEnsureAddr; virDomainPCIAddressFlagsCompatible; -virDomainPCIAddressGetNextSlot; virDomainPCIAddressReleaseSlot; virDomainPCIAddressReserveAddr; virDomainPCIAddressReserveNextAddr; -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
This function is no longer needed outside of domain_addr.c. --- 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 f735fb4..be42f15 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -591,7 +591,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs) } -int +static int virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, virDomainPCIConnectFlags flags) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 904d060..4d6d12a 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -155,11 +155,6 @@ int virDomainPCIAddressReleaseSlot(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, - virPCIDeviceAddressPtr next_addr, - virDomainPCIConnectFlags flags) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
These attributes are lost when you make the function static. ACK -- Andrea Bolognani / Red Hat / Virtualization

An upcoming commit will remove the "flag" argument from all the calls to reserve the next available address|slot, but I don't want to change the arguments in the hypervisor-agnostic virDomainPCIAddressReserveNext*() functions, so this patch places a simple qemu-specific wrapper around those functions - the new functions don't take a flags arg, but grab it from the device's info->pciConnectFlags. --- src/qemu/qemu_domain_address.c | 92 ++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 5a19f0b..7de081b 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -656,6 +656,27 @@ qemuDomainDeviceSetAllConnectFlags(virDomainDefPtr def, static int +qemuDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags, + unsigned int function, + bool reserveEntireSlot) +{ + return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, + function, reserveEntireSlot); +} + + +static int +qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags) +{ + return qemuDomainPCIAddressReserveNextAddr(addrs, dev, flags, 0, true); +} + + +static int qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, virDomainDeviceDefPtr device, virDomainDeviceInfoPtr info, @@ -940,7 +961,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { - if (virDomainPCIAddressReserveNextSlot(addrs, + if (qemuDomainPCIAddressReserveNextSlot(addrs, &primaryVideo->info, flags) < 0) goto cleanup; @@ -1133,7 +1154,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { - if (virDomainPCIAddressReserveNextSlot(addrs, + if (qemuDomainPCIAddressReserveNextSlot(addrs, &primaryVideo->info, flags) < 0) goto cleanup; @@ -1274,7 +1295,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * controller/bus to connect it to on the upstream side. */ flags = virDomainPCIControllerModelToConnectType(model); - if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &cont->info, + flags) < 0) goto error; } } @@ -1292,8 +1314,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, /* Only support VirtIO-9p-pci so far. If that changes, * we might need to skip devices here */ - if (virDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info, + flags) < 0) goto error; } @@ -1307,8 +1329,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&def->nets[i]->info)) { continue; } - if (virDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info, + flags) < 0) goto error; } @@ -1322,8 +1344,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_USB) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info, + flags) < 0) goto error; } @@ -1399,14 +1421,15 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, } else { /* This is the first part of the controller, so need * to find a free slot & then reserve this function */ - if (virDomainPCIAddressReserveNextAddr(addrs, &cont->info, flags, - addr.function, false) < 0) + if (qemuDomainPCIAddressReserveNextAddr(addrs, &cont->info, flags, + addr.function, false) < 0) goto error; cont->info.addr.pci.multi = addr.multi; } } else { - if (virDomainPCIAddressReserveNextSlot(addrs, &cont->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &cont->info, + flags) < 0) goto error; } } @@ -1438,8 +1461,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, goto error; } - if (virDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info, + flags) < 0) goto error; } @@ -1451,9 +1474,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, - def->hostdevs[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, def->hostdevs[i]->info, + flags) < 0) goto error; } @@ -1461,9 +1483,9 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (def->memballoon && def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO && virDeviceInfoPCIAddressWanted(&def->memballoon->info)) { - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->memballoon->info, - flags) < 0) + + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->memballoon->info, + flags) < 0) goto error; } @@ -1473,8 +1495,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&def->rngs[i]->info)) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->rngs[i]->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->rngs[i]->info, + flags) < 0) goto error; } @@ -1482,8 +1504,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (def->watchdog && def->watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB && virDeviceInfoPCIAddressWanted(&def->watchdog->info)) { - if (virDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info, + flags) < 0) goto error; } @@ -1491,8 +1513,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * assigned address. */ if (def->nvideos > 0 && virDeviceInfoPCIAddressWanted(&def->videos[0]->info)) { - if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info, + flags) < 0) goto error; } @@ -1505,8 +1527,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, } if (!virDeviceInfoPCIAddressWanted(&def->videos[i]->info)) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info, + flags) < 0) goto error; } @@ -1515,8 +1537,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (!virDeviceInfoPCIAddressWanted(&def->shmems[i]->info)) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->shmems[i]->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->shmems[i]->info, + flags) < 0) goto error; } for (i = 0; i < def->ninputs; i++) { @@ -1524,8 +1546,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&def->inputs[i]->info)) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, - &def->inputs[i]->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->inputs[i]->info, + flags) < 0) goto error; } for (i = 0; i < def->nparallels; i++) { @@ -1538,7 +1560,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&chr->info)) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, &chr->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &chr->info, flags) < 0) goto error; } for (i = 0; i < def->nchannels; i++) { @@ -1731,7 +1753,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, */ if (!buses_reserved && !qemuDomainMachineIsVirt(def) && - virDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) + qemuDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) goto cleanup; if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0) @@ -1746,7 +1768,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, goto cleanup; /* If we added a new bridge, we will need one more address */ if (rv > 0 && - virDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) + qemuDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) goto cleanup; } nbuses = addrs->nbuses; -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
An upcoming commit will remove the "flag" argument from all the calls to reserve the next available address|slot, but I don't want to change the arguments in the hypervisor-agnostic virDomainPCIAddressReserveNext*() functions, so this patch places a simple qemu-specific wrapper around those functions - the new functions don't take a flags arg, but grab it from the device's info->pciConnectFlags. --- src/qemu/qemu_domain_address.c | 92 ++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 35 deletions(-) [...] @@ -940,7 +961,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { - if (virDomainPCIAddressReserveNextSlot(addrs, + if (qemuDomainPCIAddressReserveNextSlot(addrs, &primaryVideo->info, flags) < 0) goto cleanup; @@ -1133,7 +1154,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { - if (virDomainPCIAddressReserveNextSlot(addrs, + if (qemuDomainPCIAddressReserveNextSlot(addrs, &primaryVideo->info, flags) < 0)
Alignment is off after the change. [...]
@@ -1399,14 +1421,15 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, } else { /* This is the first part of the controller, so need * to find a free slot & then reserve this function */ - if (virDomainPCIAddressReserveNextAddr(addrs, &cont->info, flags, - addr.function, false) < 0) + if (qemuDomainPCIAddressReserveNextAddr(addrs, &cont->info, flags, + addr.function, false) < 0)
Please reformat this call to make all lines <80 columns while you're at it. ACK -- Andrea Bolognani / Red Hat / Virtualization

Set pciConnectFlags in each device's DeviceInfo prior to assigning PCI addresses, and then use those flags later when actually assigning the addresses with qemuDomainPCIAddressReserveNextAddr() (rather than scattering the logic about which devices need which type of slot all over the place). --- src/qemu/qemu_domain_address.c | 234 ++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 130 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 7de081b..ed728f5 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -555,7 +555,7 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, * There is no failure, so there is no return value. * */ -static void ATTRIBUTE_UNUSED +static void qemuDomainDeviceConnectFlags(virDomainDefPtr def, virDomainDeviceDefPtr dev, virQEMUCapsPtr qemuCaps) @@ -636,7 +636,7 @@ qemuDomainDeviceConnectFlagsIterator(virDomainDefPtr def ATTRIBUTE_UNUSED, * 0 on success or -1 on failure (the only possibility of failure would * be some internal problem with virDomainDeviceInfoIterate()) */ -static int ATTRIBUTE_UNUSED +static int qemuDomainDeviceSetAllConnectFlags(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) { @@ -658,21 +658,20 @@ qemuDomainDeviceSetAllConnectFlags(virDomainDefPtr def, static int qemuDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, - virDomainPCIConnectFlags flags, unsigned int function, bool reserveEntireSlot) { - return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, + return virDomainPCIAddressReserveNextAddr(addrs, dev, + dev->pciConnectFlags, function, reserveEntireSlot); } static int qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, - virDomainDeviceInfoPtr dev, - virDomainPCIConnectFlags flags) + virDomainDeviceInfoPtr dev) { - return qemuDomainPCIAddressReserveNextAddr(addrs, dev, flags, 0, true); + return qemuDomainPCIAddressReserveNextAddr(addrs, dev, 0, true); } @@ -686,9 +685,6 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, int ret = -1; virPCIDeviceAddressPtr addr = &info->addr.pci; bool entireSlot; - /* flags may be changed from default below */ - virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE); if (!virDeviceInfoPCIAddressPresent(info) || ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) && @@ -700,69 +696,25 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, return 0; } - /* Change flags according to differing requirements of different - * devices. + /* If we get to here, the device has a PCI address assigned in the + * config and we should mark it as in-use. But if the + * pciConnectFlags are 0, then this device shouldn't have a PCI + * address associated with it. *BUT* since there are cases in the + * past where we've apparently allowed that, we need to pretend + * for now that it's okay, otherwise an existing domain could + * "disappear" from the list of domains due to a parse failure. We + * can fix this by just forcing the pciConnectFlags to be + * PCI_DEVICE (and then relying on validation functions to report + * inappropriate address types. */ - switch (device->type) { - case VIR_DOMAIN_DEVICE_CONTROLLER: - switch (device->data.controller->type) { - case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - flags = virDomainPCIControllerModelToConnectType(device->data.controller->model); - break; - - case VIR_DOMAIN_CONTROLLER_TYPE_SATA: - /* SATA controllers aren't hot-plugged, and can be put in - * either a PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); - break; - - case VIR_DOMAIN_CONTROLLER_TYPE_USB: - /* allow UHCI and EHCI controllers to be manually placed on - * the PCIe bus (but don't put them there automatically) - */ - switch (device->data.controller->model) { - case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; - break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: - /* should this be PCIE-only? Or do we need to allow PCI - * for backward compatibility? - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); - break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: - /* Allow these for PCI only */ - break; - } - } - break; - - case VIR_DOMAIN_DEVICE_SOUND: - switch (device->data.sound->model) { - case VIR_DOMAIN_SOUND_MODEL_ICH6: - case VIR_DOMAIN_SOUND_MODEL_ICH9: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; - break; - } - break; - - case VIR_DOMAIN_DEVICE_VIDEO: - /* video cards aren't hot-plugged, and can be put in either a - * PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); - break; + if (info->pciConnectFlags == 0) { + char *addrStr = virDomainPCIAddressAsString(&info->addr.pci); + + VIR_WARN("qemuDomainDeviceConnectFlagsInternal() thinks that the " + "device with PCI address %s should not have a PCI address", + addrStr ? addrStr : "(unknown)"); + VIR_FREE(addrStr); + info->pciConnectFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; } /* Ignore implicit controllers on slot 0:0:1.0: @@ -807,7 +759,7 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, entireSlot = (addr->function == 0 && addr->multi != VIR_TRISTATE_SWITCH_ON); - if (virDomainPCIAddressReserveAddr(addrs, addr, flags, + if (virDomainPCIAddressReserveAddr(addrs, addr, info->pciConnectFlags, entireSlot, true) < 0) goto cleanup; @@ -962,8 +914,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { if (qemuDomainPCIAddressReserveNextSlot(addrs, - &primaryVideo->info, - flags) < 0) + &primaryVideo->info) < 0) goto cleanup; } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -1155,8 +1106,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { if (qemuDomainPCIAddressReserveNextSlot(addrs, - &primaryVideo->info, - flags) < 0) + &primaryVideo->info) < 0) goto cleanup; } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -1276,7 +1226,6 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, virDomainPCIAddressSetPtr addrs) { size_t i, j; - virDomainPCIConnectFlags flags = 0; /* initialize to quiet gcc warning */ /* PCI controllers */ for (i = 0; i < def->ncontrollers; i++) { @@ -1294,28 +1243,18 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * flag to use when searching for the proper * controller/bus to connect it to on the upstream side. */ - flags = virDomainPCIControllerModelToConnectType(model); - if (qemuDomainPCIAddressReserveNextSlot(addrs, &cont->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &cont->info) < 0) goto error; } } - /* all other devices that plug into a PCI slot are treated as a - * PCI endpoint devices that require a hotplug-capable slot - * (except for some special cases which have specific handling - * below) - */ - flags = VIR_PCI_CONNECT_HOTPLUGGABLE | VIR_PCI_CONNECT_TYPE_PCI_DEVICE; - for (i = 0; i < def->nfss; i++) { if (!virDeviceInfoPCIAddressWanted(&def->fss[i]->info)) continue; /* Only support VirtIO-9p-pci so far. If that changes, * we might need to skip devices here */ - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info) < 0) goto error; } @@ -1325,27 +1264,31 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * in hostdevs list anyway, so handle them with other hostdevs * instead of here. */ - if ((def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || - !virDeviceInfoPCIAddressWanted(&def->nets[i]->info)) { + virDomainNetDefPtr net = def->nets[i]; + + if ((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + !virDeviceInfoPCIAddressWanted(&net->info)) { continue; } - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info, - flags) < 0) + + if (qemuDomainPCIAddressReserveNextSlot(addrs, &net->info) < 0) goto error; } /* Sound cards */ for (i = 0; i < def->nsounds; i++) { - if (!virDeviceInfoPCIAddressWanted(&def->sounds[i]->info)) + virDomainSoundDefPtr sound = def->sounds[i]; + + if (!virDeviceInfoPCIAddressWanted(&sound->info)) continue; + /* Skip ISA sound card, PCSPK and usb-audio */ - if (def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_SB16 || - def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK || - def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_USB) + if (sound->model == VIR_DOMAIN_SOUND_MODEL_SB16 || + sound->model == VIR_DOMAIN_SOUND_MODEL_PCSPK || + sound->model == VIR_DOMAIN_SOUND_MODEL_USB) continue; - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &sound->info) < 0) goto error; } @@ -1412,7 +1355,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (foundAddr) { /* Reserve this function on the slot we found */ - if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, + if (virDomainPCIAddressReserveAddr(addrs, &addr, + def->controllers[i]->info.pciConnectFlags, false, true) < 0) goto error; @@ -1421,16 +1365,15 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, } else { /* This is the first part of the controller, so need * to find a free slot & then reserve this function */ - if (qemuDomainPCIAddressReserveNextAddr(addrs, &cont->info, flags, + if (qemuDomainPCIAddressReserveNextAddr(addrs, &cont->info, addr.function, false) < 0) goto error; cont->info.addr.pci.multi = addr.multi; } } else { - if (qemuDomainPCIAddressReserveNextSlot(addrs, &cont->info, - flags) < 0) - goto error; + if (qemuDomainPCIAddressReserveNextSlot(addrs, &cont->info) < 0) + goto error; } } @@ -1461,8 +1404,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, goto error; } - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info) < 0) goto error; } @@ -1474,8 +1416,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; - if (qemuDomainPCIAddressReserveNextSlot(addrs, def->hostdevs[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, + def->hostdevs[i]->info) < 0) goto error; } @@ -1484,8 +1426,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO && virDeviceInfoPCIAddressWanted(&def->memballoon->info)) { - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->memballoon->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, + &def->memballoon->info) < 0) goto error; } @@ -1495,8 +1437,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&def->rngs[i]->info)) continue; - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->rngs[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->rngs[i]->info) < 0) goto error; } @@ -1504,8 +1445,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (def->watchdog && def->watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB && virDeviceInfoPCIAddressWanted(&def->watchdog->info)) { - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info) < 0) goto error; } @@ -1513,8 +1453,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * assigned address. */ if (def->nvideos > 0 && virDeviceInfoPCIAddressWanted(&def->videos[0]->info)) { - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info) < 0) goto error; } @@ -1527,8 +1466,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, } if (!virDeviceInfoPCIAddressWanted(&def->videos[i]->info)) continue; - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info, - flags) < 0) + + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info) < 0) goto error; } @@ -1537,8 +1476,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (!virDeviceInfoPCIAddressWanted(&def->shmems[i]->info)) continue; - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->shmems[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->shmems[i]->info) < 0) goto error; } for (i = 0; i < def->ninputs; i++) { @@ -1546,8 +1484,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&def->inputs[i]->info)) continue; - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->inputs[i]->info, - flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->inputs[i]->info) < 0) goto error; } for (i = 0; i < def->nparallels; i++) { @@ -1560,7 +1497,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&chr->info)) continue; - if (qemuDomainPCIAddressReserveNextSlot(addrs, &chr->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &chr->info) < 0) goto error; } for (i = 0; i < def->nchannels; i++) { @@ -1715,8 +1652,6 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, int rv; bool buses_reserved = true; - virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; - for (i = 0; i < def->ncontrollers; i++) { if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { if ((int) def->controllers[i]->idx > max_idx) @@ -1726,10 +1661,23 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, nbuses = max_idx + 1; + /* set the connect type flags (pci vs. pcie) in the DeviceInfo + * of all devices. This will be used to pick an appropriate + * bus when assigning addresses. + */ + if (qemuDomainDeviceSetAllConnectFlags(def, qemuCaps) < 0) + goto cleanup; + if (nbuses > 0 && virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) { + /* This is a dummy info used to reserve a slot for a legacy + * PCI device that doesn't exist, but may in the future, e.g. + * if another device is hotplugged into the domain. + */ virDomainDeviceInfo info; + info.pciConnectFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + /* 1st pass to figure out how many PCI bridges we need */ if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true))) goto cleanup; @@ -1753,24 +1701,50 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, */ if (!buses_reserved && !qemuDomainMachineIsVirt(def) && - qemuDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) + qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) goto cleanup; if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0) goto cleanup; for (i = 1; i < addrs->nbuses; i++) { + virDomainDeviceDef dev; + int contIndex; virDomainPCIAddressBusPtr bus = &addrs->buses[i]; if ((rv = virDomainDefMaybeAddController( def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, i, bus->model)) < 0) goto cleanup; - /* If we added a new bridge, we will need one more address */ - if (rv > 0 && - qemuDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0) + + if (rv == 0) + continue; /* no new controller added */ + + /* We did add a new controller, so we will need one more + * address (and we need to set the new controller's + * pciConnectFlags) + */ + contIndex = virDomainControllerFind(def, + VIR_DOMAIN_CONTROLLER_TYPE_PCI, + i); + if (contIndex < 0) { + /* this should never happen - we just added it */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find auto-added %s controller " + "with index %zu"), + virDomainControllerModelPCITypeToString(bus->model), + i); + goto cleanup; + } + dev.type = VIR_DOMAIN_DEVICE_CONTROLLER; + dev.data.controller = def->controllers[contIndex]; + /* set connect flags so it will be properly addressed */ + qemuDomainDeviceConnectFlags(def, &dev, qemuCaps); + if (qemuDomainPCIAddressReserveNextSlot(addrs, + &dev.data.controller->info) < 0) goto cleanup; } + nbuses = addrs->nbuses; virDomainPCIAddressSetFree(addrs); addrs = NULL; -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Set pciConnectFlags in each device's DeviceInfo prior to assigning PCI addresses, and then use those flags later when actually assigning the addresses with qemuDomainPCIAddressReserveNextAddr() (rather than scattering the logic about which devices need which type of slot all over the place). --- src/qemu/qemu_domain_address.c | 234 ++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 130 deletions(-)
[...]
@@ -686,9 +685,6 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, int ret = -1; virPCIDeviceAddressPtr addr = &info->addr.pci; bool entireSlot; - /* flags may be changed from default below */ - virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE);
This hunk you're removing seems to support my comment in patch 4, the one arguing against adding HOTPLUGGABLE at the end of the function.
if (!virDeviceInfoPCIAddressPresent(info) || ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) && @@ -700,69 +696,25 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, return 0; } - /* Change flags according to differing requirements of different - * devices. + /* If we get to here, the device has a PCI address assigned in the + * config and we should mark it as in-use. But if the + * pciConnectFlags are 0, then this device shouldn't have a PCI + * address associated with it. *BUT* since there are cases in the + * past where we've apparently allowed that, we need to pretend + * for now that it's okay, otherwise an existing domain could + * "disappear" from the list of domains due to a parse failure. We + * can fix this by just forcing the pciConnectFlags to be + * PCI_DEVICE (and then relying on validation functions to report + * inappropriate address types. */ - switch (device->type) { - case VIR_DOMAIN_DEVICE_CONTROLLER: - switch (device->data.controller->type) { - case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - flags = virDomainPCIControllerModelToConnectType(device->data.controller->model); - break; - - case VIR_DOMAIN_CONTROLLER_TYPE_SATA: - /* SATA controllers aren't hot-plugged, and can be put in - * either a PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE);
The new code doesn't seem to have any special handling of CONTROLLER_TYPE_SATA, which means it will end up as PCI_DEVICE|HOTPLUGGABLE instead of PCI_DEVICE|PCIE_DEVICE.
- break; - - case VIR_DOMAIN_CONTROLLER_TYPE_USB: - /* allow UHCI and EHCI controllers to be manually placed on - * the PCIe bus (but don't put them there automatically) - */ - switch (device->data.controller->model) { - case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE;
All these will be HOTPLUGGABLE.
- break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: - /* should this be PCIE-only? Or do we need to allow PCI - * for backward compatibility? - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE);
This will be PCI_DEVICE|HOTPLUGGABLE instead of PCI_DEVICE|PCIE_DEVICE.
- break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: - /* Allow these for PCI only */ - break; - } - } - break; - - case VIR_DOMAIN_DEVICE_SOUND: - switch (device->data.sound->model) { - case VIR_DOMAIN_SOUND_MODEL_ICH6: - case VIR_DOMAIN_SOUND_MODEL_ICH9: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE;
All these will be HOTPLUGGABLE.
- break; - } - break; - - case VIR_DOMAIN_DEVICE_VIDEO: - /* video cards aren't hot-plugged, and can be put in either a - * PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE);
These will be hotpluggable and PCI only. All these differences between the code you're removing and the code that's supposed to replace it make me wonder whether I'm missing something. Feel free to point out my mistake right about... Now! :) On a related note, reviewing this would be *much* easier if you could start off qemuDomainDeviceConnectFlagsInternal() as (mostly) a straight copy of this chunk of code, and then stray from it after switching over, instead of starting with a completely different implementation. I also believe the original code is easier to follow, because it looks more like a direct mapping from model to flags. Ideally we would just list all devices and models, grouped by purpose, and explicitly assign flags to them, in a similar way we get flags for PCI controllers. And shouldn't the compiler give us at least a warning when we're not considering all the possible values of an enum as part of a switch()? That would be super-neat!
- break; + if (info->pciConnectFlags == 0) { + char *addrStr = virDomainPCIAddressAsString(&info->addr.pci);
Double space.
+ VIR_WARN("qemuDomainDeviceConnectFlagsInternal() thinks that the "
Adjust if you change the name of the function due to my comments on patch 4 :) [...]
@@ -1325,27 +1264,31 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * in hostdevs list anyway, so handle them with other hostdevs * instead of here. */ - if ((def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || - !virDeviceInfoPCIAddressWanted(&def->nets[i]->info)) { + virDomainNetDefPtr net = def->nets[i]; + + if ((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + !virDeviceInfoPCIAddressWanted(&net->info)) { continue; } - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info, - flags) < 0) + + if (qemuDomainPCIAddressReserveNextSlot(addrs, &net->info) < 0)
The change from def->nets[i] to net is a good one, but it should have been done in a separate commit earlier in the series. In fact, patch 2/18 is basically the same change in a different part of libvirt :) [...]
@@ -1412,7 +1355,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (foundAddr) { /* Reserve this function on the slot we found */ - if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, + if (virDomainPCIAddressReserveAddr(addrs, &addr, + def->controllers[i]->info.pciConnectFlags,
Long line is long. -- Andrea Bolognani / Red Hat / Virtualization

On 10/04/2016 10:11 AM, Andrea Bolognani wrote:
Set pciConnectFlags in each device's DeviceInfo prior to assigning PCI addresses, and then use those flags later when actually assigning the addresses with qemuDomainPCIAddressReserveNextAddr() (rather than scattering the logic about which devices need which type of slot all over the place). --- src/qemu/qemu_domain_address.c | 234 ++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 130 deletions(-) [...] @@ -686,9 +685,6 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, int ret = -1; virPCIDeviceAddressPtr addr = &info->addr.pci; bool entireSlot; - /* flags may be changed from default below */ - virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE); This hunk you're removing seems to support my comment in
On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote: patch 4, the one arguing against adding HOTPLUGGABLE at the end of the function.
Nah, just shows that I had done it that way in the past, and this time it seemed to take less typing to do it the other way :-) I'm fine with either though.
if (!virDeviceInfoPCIAddressPresent(info) || ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) && @@ -700,69 +696,25 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, return 0; }
- /* Change flags according to differing requirements of different - * devices. + /* If we get to here, the device has a PCI address assigned in the + * config and we should mark it as in-use. But if the + * pciConnectFlags are 0, then this device shouldn't have a PCI + * address associated with it. *BUT* since there are cases in the + * past where we've apparently allowed that, we need to pretend + * for now that it's okay, otherwise an existing domain could + * "disappear" from the list of domains due to a parse failure. We + * can fix this by just forcing the pciConnectFlags to be + * PCI_DEVICE (and then relying on validation functions to report + * inappropriate address types. */ - switch (device->type) { - case VIR_DOMAIN_DEVICE_CONTROLLER: - switch (device->data.controller->type) { - case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - flags = virDomainPCIControllerModelToConnectType(device->data.controller->model); - break; - - case VIR_DOMAIN_CONTROLLER_TYPE_SATA: - /* SATA controllers aren't hot-plugged, and can be put in - * either a PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE);
The new code doesn't seem to have any special handling of CONTROLLER_TYPE_SATA, which means it will end up as PCI_DEVICE|HOTPLUGGABLE instead of PCI_DEVICE|PCIE_DEVICE.
Which is correct (for all occasions, except the built-in SATA controller in Q35, and that is handled with an "override" in the Q35-specific function (I forget its name right now). In the past I had mistakenly assumed that the SATA controller could also be PCIe because it was one of the integrated devices in a Q35 machine, but that's not the case.
- break; - - case VIR_DOMAIN_CONTROLLER_TYPE_USB: - /* allow UHCI and EHCI controllers to be manually placed on - * the PCIe bus (but don't put them there automatically) - */ - switch (device->data.controller->model) { - case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; All these will be HOTPLUGGABLE.
Yep. Although libvirt doesn't support hotplugging them, qemu apparently does, and the recommendation I was given when I posted the "hotpluggable attribute" patchset was that we should in general consider *all* devices as potentially hotpluggable unless there was a good reason/precedent for not doing so.
- break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: - /* should this be PCIE-only? Or do we need to allow PCI - * for backward compatibility? - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); This will be PCI_DEVICE|HOTPLUGGABLE instead of PCI_DEVICE|PCIE_DEVICE.
That will be changed in an upcoming patch to add PCIE_DEVICE, and it will then be correct. I left it this way here so that behavior wouldn't change.
- break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: - /* Allow these for PCI only */ - break; - } - } - break; - - case VIR_DOMAIN_DEVICE_SOUND: - switch (device->data.sound->model) { - case VIR_DOMAIN_SOUND_MODEL_ICH6: - case VIR_DOMAIN_SOUND_MODEL_ICH9: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; All these will be HOTPLUGGABLE.
See above.
- break; - } - break; - - case VIR_DOMAIN_DEVICE_VIDEO: - /* video cards aren't hot-plugged, and can be put in either a - * PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); These will be hotpluggable and PCI only.
Also correct. I had previously made the same mistaken assumption with video devices as with the SATA controller. In reality, all of the emulated video devices supported by qemu are PCI-only except for the virtio video device (that will be set to PCIE_DEVICE in an upcoming patch.) (BTW, part of my confusion was caused by the fact that I didn't realize that a device plugged into pcie-root shows up as a PCI device, not PCIe - since I'd been told it was okay to plug the video devices into pcie-root, I thought that meant they were PCIe devices, but that conclusion *doesn't* follow from the former information).
All these differences between the code you're removing and the code that's supposed to replace it make me wonder whether I'm missing something. Feel free to point out my mistake right about... Now! :)
Yeah, you're missing the fact that these current flag settings are incorrect, decided on when I had less information/knowledge than I do now. Fixing them doesn't create any changes in behavior, but it does set us up to make behavior changes (in the right direction) in upcoming patches.
On a related note, reviewing this would be *much* easier if you could start off qemuDomainDeviceConnectFlagsInternal() as (mostly) a straight copy of this chunk of code, and then stray from it after switching over, instead of starting with a completely different implementation.
I might have to create an extra patch so that this function isn't called until it is "fixed", but I see your point.
I also believe the original code is easier to follow, because it looks more like a direct mapping from model to flags. Ideally we would just list all devices and models, grouped by purpose, and explicitly assign flags to them, in a similar way we get flags for PCI controllers.
But the PCI controllers each have a different flag (because they're all slightly different) so an entry for each one is needed anyhow. For the rest of the devices, most of them are plain "PCI + hotpluggable", with a relatively small number of exceptions. If we explicitly put in an entry for every model of every device, we could end up in a situation of losing the interesting "trees" (exceptions) in the "forest" (all the nearly identical settings to the default).
And shouldn't the compiler give us at least a warning when we're not considering all the possible values of an enum as part of a switch()? That would be super-neat!
It's because many of these variables aren't defined as enums in the device object, but as int. I suppose this could be taken care of by typecasting to the enum in the switches. Again, it seems like a lot of extra lines when the majority of emulated devices are still legacy PCI though. Let me think about it...
- break; + if (info->pciConnectFlags == 0) { + char *addrStr = virDomainPCIAddressAsString(&info->addr.pci); Double space.
+ VIR_WARN("qemuDomainDeviceConnectFlagsInternal() thinks that the " Adjust if you change the name of the function due to my comments on patch 4 :)
Or better yet, don't name the function, but describe it in another way that won't be affected by name changes.
[...]
@@ -1325,27 +1264,31 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * in hostdevs list anyway, so handle them with other hostdevs * instead of here. */ - if ((def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || - !virDeviceInfoPCIAddressWanted(&def->nets[i]->info)) { + virDomainNetDefPtr net = def->nets[i]; + + if ((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + !virDeviceInfoPCIAddressWanted(&net->info)) { continue; } - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info, - flags) < 0) + + if (qemuDomainPCIAddressReserveNextSlot(addrs, &net->info) < 0) The change from def->nets[i] to net is a good one, but it should have been done in a separate commit earlier in the series. In fact, patch 2/18 is basically the same change in a different part of libvirt :)
Well, that patch changed def->controllers[i] to cont, not def->nets[i] :-P There were a few places this happened (going over the usage threshold of def->blahs[i] so that it became cleaner to have a temp variable). The ones with controllers[i] were just so excessive that I went back and pulled them out into a separate patch. When a few more came along later, they didn't seem as significant, and I was more burned out on the whole "create more patches to make the set look more intimidating to a reviewer while simultaneously creating merge conflicts when I rebase to add the new patch" thing. If that makes it easier for you, I can pull out the rest of these on the next round though.
[...]
@@ -1412,7 +1355,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
if (foundAddr) { /* Reserve this function on the slot we found */ - if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, + if (virDomainPCIAddressReserveAddr(addrs, &addr, + def->controllers[i]->info.pciConnectFlags, Long line is long.
I'm no longer able to figure out when you seriously want me to fix these, and when you're just existentially complaining about the state of the universe :-P

On Tue, 2016-10-04 at 11:50 -0400, Laine Stump wrote:
All these differences between the code you're removing and the code that's supposed to replace it make me wonder whether I'm missing something. Feel free to point out my mistake right about... Now! :) Yeah, you're missing the fact that these current flag settings are incorrect, decided on when I had less information/knowledge than I do now. Fixing them doesn't create any changes in behavior, but it does set us up to make behavior changes (in the right direction) in upcoming patches. On a related note, reviewing this would be *much* easier if you could start off qemuDomainDeviceConnectFlagsInternal() as (mostly) a straight copy of this chunk of code, and then stray from it after switching over, instead of starting with a completely different implementation. I might have to create an extra patch so that this function isn't called until it is "fixed", but I see your point.
Let me elaborate a bit. After reading your explanation above for the specific cases I pointed out, I see why you did change the flags in the way you did. But, until you replied to my questions, the information was just not there. This series is basically doing two things at once: * refactoring the code so that connect flags for PCI devices is centralized * updating connect flags to either fix earlier mistakes or enable better device placement (more PCIe) We definitely want both, and the latter is of course much easier to achieve after the former has been completed. However, they really are two separate goals and mixing them makes the reviewer's life harder, which is why I'm strongly against it :) My recommendation would be to have either two separate series (it's okay for a series to depend on another one), or a single series with clearly defined "part one" and "part two". The refactoring should not change the behavior at all, just move around bits until all connect flags related decisions happen in a single place; after that's out of the way, changes in connect flags, even the ones that are fixing existing bugs, should go in separate commits that explain why the change is being performed. The last few comments in this series are great examples of the approach I'm describing. The result will be a much easier time for the reviewer and a much more useful Git history to refer to a few years down the line, when we will inevitably have to reassess some of the choices made today. It should also be noted that the commit messages for the series have been overall excellent - we just need more! ;)
I also believe the original code is easier to follow, because it looks more like a direct mapping from model to flags. Ideally we would just list all devices and models, grouped by purpose, and explicitly assign flags to them, in a similar way we get flags for PCI controllers. But the PCI controllers each have a different flag (because they're all slightly different) so an entry for each one is needed anyhow. For the rest of the devices, most of them are plain "PCI + hotpluggable", with a relatively small number of exceptions. If we explicitly put in an entry for every model of every device, we could end up in a situation of losing the interesting "trees" (exceptions) in the "forest" (all the nearly identical settings to the default). And shouldn't the compiler give us at least a warning when we're not considering all the possible values of an enum as part of a switch()? That would be super-neat! It's because many of these variables aren't defined as enums in the device object, but as int. I suppose this could be taken care of by typecasting to the enum in the switches. Again, it seems like a lot of extra lines when the majority of emulated devices are still legacy PCI though. Let me think about it...
I see what you mean, however by using the fallthrough property of the switch statement we should be able to group a whole bunch of devices and avoid excessive redundancy, like in the very code you're removing with this commit: case VIR_DOMAIN_CONTROLLER_TYPE_USB: /* allow UHCI and EHCI controllers to be manually placed on * the PCIe bus (but don't put them there automatically) */ switch (device->data.controller->model) { case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3: case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI: flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; break; case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: /* should this be PCIE-only? Or do we need to allow PCI * for backward compatibility? */ flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); break; case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: /* Allow these for PCI only */ break; } } break; Is this more verbose than the code you're replacing it with? Sure. But breaking down all the models this way allows us to clearly see what kind of device can go in which controller with a single glance, which I consider a big win. Especially if we can then use casting to convince the compiler to alert us if we ever add a new model and forget to update this function, which is prefereable to it silently getting the default connect flags. The more deliberate we have to be when making changes, the least likely it is that something will slip through the cracks.
@@ -1325,27 +1264,31 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, * in hostdevs list anyway, so handle them with other hostdevs * instead of here. */ - if ((def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || - !virDeviceInfoPCIAddressWanted(&def->nets[i]->info)) { + virDomainNetDefPtr net = def->nets[i]; + + if ((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + !virDeviceInfoPCIAddressWanted(&net->info)) { continue; } - if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info, - flags) < 0) + + if (qemuDomainPCIAddressReserveNextSlot(addrs, &net->info) < 0) The change from def->nets[i] to net is a good one, but it should have been done in a separate commit earlier in the series. In fact, patch 2/18 is basically the same change in a different part of libvirt :) Well, that patch changed def->controllers[i] to cont, not def->nets[i] :-P There were a few places this happened (going over the usage threshold of def->blahs[i] so that it became cleaner to have a temp variable). The ones with controllers[i] were just so excessive that I went back and
[...] pulled them out into a separate patch. When a few more came along later, they didn't seem as significant, and I was more burned out on the whole "create more patches to make the set look more intimidating to a reviewer while simultaneously creating merge conflicts when I rebase to add the new patch" thing. If that makes it easier for you, I can pull out the rest of these on the next round though.
Yes, I'd very much like to have these in a separate patch, early in the refactoring series / first part of the series. And at least as far as I'm concerned, a series consisting in a big number of small, self-contained patches is *less* rather than more intimidating :)
@@ -1412,7 +1355,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (foundAddr) { /* Reserve this function on the slot we found */ - if (virDomainPCIAddressReserveAddr(addrs, &addr, flags, + if (virDomainPCIAddressReserveAddr(addrs, &addr, + def->controllers[i]->info.pciConnectFlags, Long line is long. I'm no longer able to figure out when you seriously want me to fix
[...] these, and when you're just existentially complaining about the state of the universe :-P
Can't it be both? :) For a more serious answer, see [1]. [1] https://www.redhat.com/archives/libvir-list/2016-October/msg00157.html -- Andrea Bolognani / Red Hat / Virtualization

On 10/04/2016 10:11 AM, Andrea Bolognani wrote:
Set pciConnectFlags in each device's DeviceInfo prior to assigning PCI addresses, and then use those flags later when actually assigning the addresses with qemuDomainPCIAddressReserveNextAddr() (rather than scattering the logic about which devices need which type of slot all over the place). --- src/qemu/qemu_domain_address.c | 234 ++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 130 deletions(-) [...] @@ -686,9 +685,6 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, int ret = -1; virPCIDeviceAddressPtr addr = &info->addr.pci; bool entireSlot; - /* flags may be changed from default below */ - virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE); This hunk you're removing seems to support my comment in
On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote: patch 4, the one arguing against adding HOTPLUGGABLE at the end of the function.
if (!virDeviceInfoPCIAddressPresent(info) || ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) && @@ -700,69 +696,25 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, return 0; }
- /* Change flags according to differing requirements of different - * devices. + /* If we get to here, the device has a PCI address assigned in the + * config and we should mark it as in-use. But if the + * pciConnectFlags are 0, then this device shouldn't have a PCI + * address associated with it. *BUT* since there are cases in the + * past where we've apparently allowed that, we need to pretend + * for now that it's okay, otherwise an existing domain could + * "disappear" from the list of domains due to a parse failure. We + * can fix this by just forcing the pciConnectFlags to be + * PCI_DEVICE (and then relying on validation functions to report + * inappropriate address types. */ - switch (device->type) { - case VIR_DOMAIN_DEVICE_CONTROLLER: - switch (device->data.controller->type) { - case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - flags = virDomainPCIControllerModelToConnectType(device->data.controller->model); - break; - - case VIR_DOMAIN_CONTROLLER_TYPE_SATA: - /* SATA controllers aren't hot-plugged, and can be put in - * either a PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE);
The new code doesn't seem to have any special handling of CONTROLLER_TYPE_SATA, which means it will end up as PCI_DEVICE|HOTPLUGGABLE instead of PCI_DEVICE|PCIE_DEVICE.
All of the flag settings in this function are essentially pointless, and *not* what is used when actually assigning an address to a device (it took me a while to realize this). There is a fuller explanation below, but in short, when we are examining device addresses that were manually set (or auto-assigned at some earlier time), any combination of the following flags is considered equivalent: VIR_PCI_CONNECT_TYPE_PCI_DEVICE VIR_PCI_CONNECT_TYPE_PCIE_DEVICE VIR_PCI_CONNECT_HOTPLUGGABLE so all of the flags settings in this function are equivalent to PCI_DEVICE | HOTPLUGGABLE.
- break; - - case VIR_DOMAIN_CONTROLLER_TYPE_USB: - /* allow UHCI and EHCI controllers to be manually placed on - * the PCIe bus (but don't put them there automatically) - */ - switch (device->data.controller->model) { - case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; All these will be HOTPLUGGABLE.
^^ e.g. this
- break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: - /* should this be PCIE-only? Or do we need to allow PCI - * for backward compatibility? - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); This will be PCI_DEVICE|HOTPLUGGABLE instead of PCI_DEVICE|PCIE_DEVICE.
^^ and this. etc.
- break; - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: - case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: - /* Allow these for PCI only */ - break; - } - } - break; - - case VIR_DOMAIN_DEVICE_SOUND: - switch (device->data.sound->model) { - case VIR_DOMAIN_SOUND_MODEL_ICH6: - case VIR_DOMAIN_SOUND_MODEL_ICH9: - flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; All these will be HOTPLUGGABLE.
- break; - } - break; - - case VIR_DOMAIN_DEVICE_VIDEO: - /* video cards aren't hot-plugged, and can be put in either a - * PCI or PCIe slot - */ - flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE - | VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); These will be hotpluggable and PCI only.
All these differences between the code you're removing and the code that's supposed to replace it make me wonder whether I'm missing something. Feel free to point out my mistake right about... Now! :)
I believed you were onto something, so I modified the new function (qemuDomainDeviceCalculatePCIConnectFlags()) to exactly reflect the flags as they're set in this function (qemuDomainCollectPCIAddress()). But that caused some unit tests to fail. That's when I realized that the flag settings in qemuDomainCollectPCIAddress()) are only used when checking manually set addresses ("fromConfig") as we're setting in-use bits for all the addresses already used, and in this case the setting of HOTPLUGGABLE, or PCI vs. PCIE doesn't is ignored. What is actually important is how the flags are set in qemuDomainAssignDevicePCISlots(), which uses "PCI_DEVICE | HOTPLUGGABLE" for *everything* except PCI controllers. In the case of qemuDomainCollectPCIAddress(), since the addresses are coming "fromConfig", validation will succeed regardless of any mismatch in hotpluggable flag, or PCI vs PCIE (the address validation function allows you to break those rules when manually addressing, because qemu allows it). So the proper thing for the new qemuDomainDeviceCalculatePCIConnectFlags() function (I've renamed it, but haven't yet reposted) is to set PCI_DEVICE | HOTPLUGGABLE for everything (until the patches that make exceptions for specific device/type/model combinations). Note that one very nice side effect of this patch is that there is now only a single place where the PCI connect flags are calculated, rather than 2, so such confusion won't happen in the future.
On a related note, reviewing this would be *much* easier if you could start off qemuDomainDeviceConnectFlagsInternal() as (mostly) a straight copy of this chunk of code, and then stray from it after switching over, instead of starting with a completely different implementation.
Actually, not a copy of this chunk of code, because this chunk of code has settings that would break the other use of qemuDomainDeviceCalculatePCIConnectFlags() (see above). I have rewritten (and renamed) the function, but its initial version now always sets the flags to PCI_DEVICE | HOTPLUGGABLE.
I also believe the original code is easier to follow, because it looks more like a direct mapping from model to flags.
In all honesty, the original code is just plain pointless. It *tried* to be right, but got some things wrong, and then it ended up not mattering anyway because the hotpluggable flag, and PCI vs. PCIE, is ignored when validating already-assigned addresses anyway.
Ideally we would just list all devices and models, grouped by purpose, and explicitly assign flags to them, in a similar way we get flags for PCI controllers.
That's what I've done now. You'll see the results in a day or two.
And shouldn't the compiler give us at least a warning when we're not considering all the possible values of an enum as part of a switch()? That would be super-neat!
The jury is out.

Before now, all the qemu hotplug functions assumed that all devices to be hotplugged were legacy PCI endpoint devices (VIR_PCI_CONNECT_TYPE_PCI_DEVICE). This worked out "okay", because all devices *are* legacy PCI endpoint devices on x86/440fx machinetypes, and hotplug didn't work properly on machinetypes using PCIe anyway (hotplugging onto a legacy PCI slot doesn't work, and until commit b87703cf any attempt to manually specify a PCIe address for a hotplugged device would be erroneously rejected). This patch makes all qemu hotplug operations honor the pciConnectFlags set by the single all-knowing function qemuDomainDeviceConnectFlagsInternal(). This is done in 3 steps, but in a single commit since we would have to touch the other points at each step anyway: 1) add a flags argument to the hypervisor-agnostic virDomainPCIAddressEnsureAddr() (previously it hardcoded ..._PCI_DEVICE) 2) add a new qemu-specific function qemuDomainEnsurePCIAddress() which gets the correct pciConnectFlags for the device from qemuDomainDeviceConnectFlags(), then calls virDomainPCIAddressEnsureAddr(). 3) in qemu_hotplug.c replace all calls to virDomainPCIAddressEnsureAddr() with calls to qemuDomainEnsurePCIAddress() So in effect, we're putting a "shim" on top of all calls to virDomainPCIAddressEnsureAddr() that sets the right pciConnectFlags. --- src/conf/domain_addr.c | 16 ++++++++-------- src/conf/domain_addr.h | 3 ++- src/qemu/qemu_domain_address.c | 27 +++++++++++++++++++++++++++ src/qemu/qemu_domain_address.h | 4 ++++ src/qemu/qemu_hotplug.c | 25 +++++++++++++++++-------- 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index be42f15..12b5cb2 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -485,17 +485,17 @@ virDomainPCIAddressReserveSlot(virDomainPCIAddressSetPtr addrs, int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, - virDomainDeviceInfoPtr dev) + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags) { int ret = -1; char *addrStr = NULL; - /* Flags should be set according to the particular device, - * but only the caller knows the type of device. Currently this - * function is only used for hot-plug, though, and hot-plug is - * only supported for standard PCI devices, so we can safely use - * the setting below */ - virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE); + + /* if pciConnectFlags is 0, the particular model of this device + * on this machinetype doesn't need a PCI address, so we're done. + */ + if (!flags) + return 0; if (!(addrStr = virDomainPCIAddressAsString(&dev->addr.pci))) goto cleanup; diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 4d6d12a..92ee04c 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -144,7 +144,8 @@ int virDomainPCIAddressReserveSlot(virDomainPCIAddressSetPtr addrs, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, - virDomainDeviceInfoPtr dev) + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs, diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index ed728f5..d811540 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -2032,6 +2032,33 @@ qemuDomainAssignAddresses(virDomainDefPtr def, return 0; } +/** + * qemuDomainEnsurePCIAddress: + * + * if @dev should have a PCI address but doesn't, assign + * an address on a compatible PCI bus. Validate that any + * existing address is on a compatible bus. + * + * @obj: the virDomainObjPtr for the domain. This will include + * qemuCaps and address cache (if there is one) + * + * @dev: the device that we need to ensure has a PCI address + * + * returns 0 on success (and any new address set in dev->...info) -1 + * on failure. + */ +int +qemuDomainEnsurePCIAddress(virDomainObjPtr obj, + virDomainDeviceDefPtr dev) +{ + qemuDomainObjPrivatePtr priv = obj->privateData; + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + + qemuDomainDeviceConnectFlags(obj->def, dev, priv->qemuCaps); + + return virDomainPCIAddressEnsureAddr(priv->pciaddrs, info, + info->pciConnectFlags); +} void qemuDomainReleaseDeviceAddress(virDomainObjPtr vm, diff --git a/src/qemu/qemu_domain_address.h b/src/qemu/qemu_domain_address.h index 11d6e92..800859c 100644 --- a/src/qemu/qemu_domain_address.h +++ b/src/qemu/qemu_domain_address.h @@ -37,6 +37,10 @@ int qemuDomainAssignAddresses(virDomainDefPtr def, bool newDomain) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int qemuDomainEnsurePCIAddress(virDomainObjPtr obj, + virDomainDeviceDefPtr dev) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + void qemuDomainReleaseDeviceAddress(virDomainObjPtr vm, virDomainDeviceInfoPtr info, const char *devstr); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 72dd93b..cee6f5c 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -304,6 +304,7 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn, int ret = -1; int rv; qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_DISK, { .disk = disk } }; virErrorPtr orig_err; char *devstr = NULL; char *drivestr = NULL; @@ -344,7 +345,7 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn, goto error; } else if (!disk->info.type || disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { - if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0) + if (qemuDomainEnsurePCIAddress(vm, &dev) < 0) goto error; } releaseaddr = true; @@ -462,6 +463,8 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, const char* type = virDomainControllerTypeToString(controller->type); char *devstr = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CONTROLLER, + { .controller = controller } }; virDomainCCWAddressSetPtr ccwaddrs = NULL; bool releaseaddr = false; @@ -501,7 +504,7 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE || controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { - if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0) + if (qemuDomainEnsurePCIAddress(vm, &dev) < 0) goto cleanup; } else if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) { if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def))) @@ -914,6 +917,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, virDomainNetDefPtr net) { qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_NET, { .net = net } }; char **tapfdName = NULL; int *tapfd = NULL; size_t tapfdSize = 0; @@ -1077,7 +1081,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("virtio-s390 net device cannot be hotplugged.")); goto cleanup; - } else if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0) { + } else if (qemuDomainEnsurePCIAddress(vm, &dev) < 0) { goto cleanup; } @@ -1287,6 +1291,8 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver, virDomainHostdevDefPtr hostdev) { qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV, + { .hostdev = hostdev } }; int ret; char *devstr = NULL; int configfd = -1; @@ -1357,7 +1363,7 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver, if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0) goto error; - if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, hostdev->info) < 0) + if (qemuDomainEnsurePCIAddress(vm, &dev) < 0) goto error; releaseaddr = true; if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO && @@ -1584,10 +1590,12 @@ qemuDomainChrRemove(virDomainDefPtr vmdef, } static int -qemuDomainAttachChrDeviceAssignAddr(virDomainDefPtr def, +qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm, qemuDomainObjPrivatePtr priv, virDomainChrDefPtr chr) { + virDomainDefPtr def = vm->def; + virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CHR, { .chr = chr } }; int ret = -1; virDomainVirtioSerialAddrSetPtr vioaddrs = NULL; @@ -1603,7 +1611,7 @@ qemuDomainAttachChrDeviceAssignAddr(virDomainDefPtr def, } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL && chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) { - if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &chr->info) < 0) + if (qemuDomainEnsurePCIAddress(vm, &dev) < 0) goto cleanup; ret = 1; @@ -1663,7 +1671,7 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0) goto cleanup; - if ((rc = qemuDomainAttachChrDeviceAssignAddr(vm->def, priv, chr)) < 0) + if ((rc = qemuDomainAttachChrDeviceAssignAddr(vm, priv, chr)) < 0) goto cleanup; if (rc == 1) need_release = true; @@ -1749,6 +1757,7 @@ qemuDomainAttachRNGDevice(virQEMUDriverPtr driver, virDomainRNGDefPtr rng) { qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_RNG, { .rng = rng } }; virErrorPtr orig_err; char *devstr = NULL; char *charAlias = NULL; @@ -1785,7 +1794,7 @@ qemuDomainAttachRNGDevice(virQEMUDriverPtr driver, if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE || rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { - if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &rng->info) < 0) + if (qemuDomainEnsurePCIAddress(vm, &dev) < 0) return -1; } else if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) { if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def))) -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Before now, all the qemu hotplug functions assumed that all devices to be hotplugged were legacy PCI endpoint devices (VIR_PCI_CONNECT_TYPE_PCI_DEVICE). This worked out "okay", because all devices *are* legacy PCI endpoint devices on x86/440fx machinetypes, and hotplug didn't work properly on machinetypes using PCIe anyway (hotplugging onto a legacy PCI slot doesn't work, and until commit b87703cf any attempt to manually specify a PCIe address for a hotplugged device would be erroneously rejected). This patch makes all qemu hotplug operations honor the pciConnectFlags set by the single all-knowing function qemuDomainDeviceConnectFlagsInternal().
[...]
@@ -485,17 +485,17 @@ virDomainPCIAddressReserveSlot(virDomainPCIAddressSetPtr addrs, int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, - virDomainDeviceInfoPtr dev) + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags) { int ret = -1; char *addrStr = NULL; - /* Flags should be set according to the particular device, - * but only the caller knows the type of device. Currently this - * function is only used for hot-plug, though, and hot-plug is - * only supported for standard PCI devices, so we can safely use - * the setting below */ - virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE | - VIR_PCI_CONNECT_TYPE_PCI_DEVICE); + + /* if pciConnectFlags is 0, the particular model of this device
s/pciConnectFlags/flags/ [...]
@@ -2032,6 +2032,33 @@ qemuDomainAssignAddresses(virDomainDefPtr def, return 0; } +/** + * qemuDomainEnsurePCIAddress: + * + * if @dev should have a PCI address but doesn't, assign + * an address on a compatible PCI bus. Validate that any + * existing address is on a compatible bus. + * + * @obj: the virDomainObjPtr for the domain. This will include + * qemuCaps and address cache (if there is one) + * + * @dev: the device that we need to ensure has a PCI address + * + * returns 0 on success (and any new address set in dev->...info) -1 + * on failure.
The new address is set, not returned, so that information doesn't belong in this section. The description already mention the fact that an address will be assigned if needed anyway. [...]
@@ -1584,10 +1590,12 @@ qemuDomainChrRemove(virDomainDefPtr vmdef, } static int -qemuDomainAttachChrDeviceAssignAddr(virDomainDefPtr def, +qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm, qemuDomainObjPrivatePtr priv,
Please change the type of the first argument from virDomainDefPtr to virDomainObjPtr in a separate commit, and use that chance to remove the qemuDomainObjPrivatePtr argument altogether - you can retrieve it from @vm the same way you already retrieve the DomainDef. ACK -- Andrea Bolognani / Red Hat / Virtualization

libvirt previously assigned nearly all devices to a "hotpluggable" legacy PCI slot even on machines with a PCIe root bus (and even though most such machines don't even support hotplug on legacy PCI slots!) Forcing all devices onto legacy PCI slots means that the domain will need a dmi-to-pci-bridge (to convert from PCIe to legacy PCI) and a pci-bridge (to provide hotpluggable legacy PCI slots which, again, usually aren't hotpluggable anyway). To help reduce the need for these legacy controllers, this patch tries to assign virtio-1.0-capable devices to PCIe slots whenever possible, by setting appropriate connectFlags in virDomainDeviceConnectFlagsInternal(). Happily, when that function was written (just a few commits ago) it was created with a "virtioFlags" argument, set by both of its callers, which is the proper connectFlags to set for any virtio-*-pci device - depending on the arch/machinetype of the domain, and whether or not the qemu binary supports virtio-1.0, that flag will have either been set to PCI or PCIE. This patch merely enables the functionality by setting the flags for the device to whatever is in virtioFlags if the device is a virtio-*-pci device. NB: since the slot must be hotpluggable, and pcie-root (the PCIe root complex) does *not* support hotplug, this means that suitable controllers must also be in the config (i.e. either pcie-root-port, or pcie-downstream-port). For now, libvirt doesn't add those automatically, so if you put virtio devices in a config for a qemu that has PCIe-capable virtio devices, you'll need to add extra pcie-root-ports yourself. That requirement will be eliminated in a future patch, but for now, it's simple to do this: <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> ... Partially Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1330024 --- src/qemu/qemu_domain_address.c | 39 ++++-- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 57 ++++++++ tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 60 +++++++++ .../qemuxml2argv-q35-virtio-pci.args | 57 ++++++++ .../qemuxml2argv-q35-virtio-pci.xml | 1 + tests/qemuxml2argvtest.c | 45 +++++++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 149 +++++++++++++++++++++ .../qemuxml2xmlout-q35-virtio-pci.xml | 149 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 40 ++++++ 9 files changed, 586 insertions(+), 11 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args create mode 120000 tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index d811540..c8a8f6b 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -424,8 +424,7 @@ static virDomainPCIConnectFlags qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, virDomainPCIConnectFlags pcieFlags ATTRIBUTE_UNUSED, - virDomainPCIConnectFlags virtioFlags - ATTRIBUTE_UNUSED) + virDomainPCIConnectFlags virtioFlags) { virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; @@ -439,16 +438,22 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_CONTROLLER: { virDomainControllerDefPtr cont = dev->data.controller; - if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || - cont->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID || - (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && - cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE)) + if ((cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI) || + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) { + flags = virtioFlags; + } else if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID || + (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE)) { flags = 0; + } break; } case VIR_DOMAIN_DEVICE_FS: /* the only type of filesystem so far is virtio-9p-pci */ + flags = virtioFlags; break; case VIR_DOMAIN_DEVICE_NET: { @@ -461,6 +466,8 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || STREQ(net->model, "usb-net")) flags = 0; + else if (STREQ(net->model, "virtio")) + flags = virtioFlags; break; } @@ -475,20 +482,26 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, break; case VIR_DOMAIN_DEVICE_DISK: - if (dev->data.disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) - flags = 0; /* only virtio disks use PCI */ + if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) + flags = virtioFlags; + else + flags = 0; /* no other disk types use PCI */ break; case VIR_DOMAIN_DEVICE_HOSTDEV: break; case VIR_DOMAIN_DEVICE_MEMBALLOON: - if (dev->data.memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) + if (dev->data.memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) + flags = virtioFlags; + else flags = 0; break; case VIR_DOMAIN_DEVICE_RNG: - if (dev->data.rng->model != VIR_DOMAIN_RNG_MODEL_VIRTIO) + if (dev->data.rng->model == VIR_DOMAIN_RNG_MODEL_VIRTIO) + flags = virtioFlags; + else flags = 0; break; @@ -499,13 +512,17 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, break; case VIR_DOMAIN_DEVICE_VIDEO: + if (dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO) + flags = virtioFlags; break; case VIR_DOMAIN_DEVICE_SHMEM: break; case VIR_DOMAIN_DEVICE_INPUT: - if (dev->data.input->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO) + if (dev->data.input->bus == VIR_DOMAIN_INPUT_BUS_VIRTIO) + flags = virtioFlags; + else flags = 0; break; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args new file mode 100644 index 0000000..2ea0c08 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args @@ -0,0 +1,57 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/libexec/qemu-kvm \ +-name q35-test \ +-S \ +-M q35 \ +-m 2048 \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \ +-no-acpi \ +-boot c \ +-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=7,id=pci.7,bus=pcie.0,addr=0x6 \ +-device ioh3420,port=0x38,chassis=8,id=pci.8,bus=pcie.0,addr=0x7 \ +-device ioh3420,port=0x40,chassis=9,id=pci.9,bus=pcie.0,addr=0x8 \ +-device ioh3420,port=0x48,chassis=10,id=pci.10,bus=pcie.0,addr=0x9 \ +-device ioh3420,port=0x50,chassis=11,id=pci.11,bus=pcie.0,addr=0xa \ +-device ioh3420,port=0x58,chassis=12,id=pci.12,bus=pcie.0,addr=0xb \ +-device ioh3420,port=0x60,chassis=13,id=pci.13,bus=pcie.0,addr=0xc \ +-device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ +-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ +addr=0x1d \ +-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pcie.0,addr=0x1d.0x1 \ +-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pcie.0,addr=0x1d.0x2 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.6,addr=0x0 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.5,addr=0x0 \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk1 \ +-device virtio-blk-pci,bus=pci.7,addr=0x0,drive=drive-virtio-disk1,\ +id=virtio-disk1 \ +-fsdev local,security_model=passthrough,id=fsdev-fs0,path=/export/to/guest \ +-device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=/import/from/host,\ +bus=pci.3,addr=0x0 \ +-netdev user,id=hostnet0 \ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.4,\ +addr=0x0 \ +-device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.10,\ +addr=0x0 \ +-device virtio-mouse-pci,id=input1,bus=pci.11,addr=0x0 \ +-device virtio-keyboard-pci,id=input2,bus=pci.12,addr=0x0 \ +-device virtio-tablet-pci,id=input3,bus=pci.13,addr=0x0 \ +-device virtio-vga,id=video0,bus=pcie.0,addr=0x1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.8,addr=0x0 \ +-object rng-random,id=objrng0,filename=/dev/urandom \ +-device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,bus=pci.9,\ +addr=0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml new file mode 100644 index 0000000..7bed08c --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml @@ -0,0 +1,60 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <controller type='pci' model='pcie-root'/> + <controller type='pci' model='dmi-to-pci-bridge'/> + <controller type='pci' model='pci-bridge'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> + <controller type='virtio-serial'/> + <controller type='scsi' model='virtio-scsi'/> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + </disk> + <filesystem type='mount'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + </filesystem> + <video> + <model type='virtio'/> + </video> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + </interface> + <memballoon model='virtio'/> + <rng model='virtio'> + <rate bytes='123' period='1234'/> + <backend model='random'>/dev/urandom</backend> + </rng> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + </input> + <input type='mouse' bus='virtio'/> + <input type='keyboard' bus='virtio'/> + <input type='tablet' bus='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args new file mode 100644 index 0000000..7cedc82 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args @@ -0,0 +1,57 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/libexec/qemu-kvm \ +-name q35-test \ +-S \ +-M q35 \ +-m 2048 \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \ +-no-acpi \ +-boot c \ +-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=7,id=pci.7,bus=pcie.0,addr=0x6 \ +-device ioh3420,port=0x38,chassis=8,id=pci.8,bus=pcie.0,addr=0x7 \ +-device ioh3420,port=0x40,chassis=9,id=pci.9,bus=pcie.0,addr=0x8 \ +-device ioh3420,port=0x48,chassis=10,id=pci.10,bus=pcie.0,addr=0x9 \ +-device ioh3420,port=0x50,chassis=11,id=pci.11,bus=pcie.0,addr=0xa \ +-device ioh3420,port=0x58,chassis=12,id=pci.12,bus=pcie.0,addr=0xb \ +-device ioh3420,port=0x60,chassis=13,id=pci.13,bus=pcie.0,addr=0xc \ +-device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ +-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ +addr=0x1d \ +-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pcie.0,addr=0x1d.0x1 \ +-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pcie.0,addr=0x1d.0x2 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x4 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.2,addr=0x3 \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk1 \ +-device virtio-blk-pci,bus=pci.2,addr=0x5,drive=drive-virtio-disk1,\ +id=virtio-disk1 \ +-fsdev local,security_model=passthrough,id=fsdev-fs0,path=/export/to/guest \ +-device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=/import/from/host,\ +bus=pci.2,addr=0x1 \ +-netdev user,id=hostnet0 \ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.2,\ +addr=0x2 \ +-device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.2,\ +addr=0x8 \ +-device virtio-mouse-pci,id=input1,bus=pci.2,addr=0x9 \ +-device virtio-keyboard-pci,id=input2,bus=pci.2,addr=0xa \ +-device virtio-tablet-pci,id=input3,bus=pci.2,addr=0xb \ +-device virtio-vga,id=video0,bus=pcie.0,addr=0x1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x6 \ +-object rng-random,id=objrng0,filename=/dev/urandom \ +-device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,bus=pci.2,\ +addr=0x7 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.xml new file mode 120000 index 0000000..fc8c0ad --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.xml @@ -0,0 +1 @@ +qemuxml2argv-q35-pcie.xml \ No newline at end of file diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index e854077..582a02a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1692,6 +1692,51 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); + /* verify that devices with pcie capability are assigned to a pcie slot */ + DO_TEST("q35-pcie", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + /* same XML as q35-pcie, but don't set QEMU_CAPS_VIRTIO_PCI_LEGACY, + * so virtio devices should be assigned to legacy pci slots + */ + DO_TEST("q35-virtio-pci", + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root-port", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml new file mode 100644 index 0000000..60e29b5 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml @@ -0,0 +1,149 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + </disk> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='2'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x40'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='10' port='0x48'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='11' port='0x50'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='12' port='0x58'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='13' port='0x60'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + </controller> + <controller type='usb' index='0' model='ich9-ehci1'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </filesystem> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </interface> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + </input> + <input type='keyboard' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + </input> + <input type='tablet' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <rate bytes='123' period='1234'/> + <backend model='random'>/dev/urandom</backend> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + </rng> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml new file mode 100644 index 0000000..5c5acac --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml @@ -0,0 +1,149 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x05' function='0x0'/> + </disk> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='2'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x40'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='10' port='0x48'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='11' port='0x50'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='12' port='0x58'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='13' port='0x60'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x04' function='0x0'/> + </controller> + <controller type='usb' index='0' model='ich9-ehci1'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> + </filesystem> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> + </interface> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x08' function='0x0'/> + </input> + <input type='mouse' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x09' function='0x0'/> + </input> + <input type='keyboard' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x0a' function='0x0'/> + </input> + <input type='tablet' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x0b' function='0x0'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x06' function='0x0'/> + </memballoon> + <rng model='virtio'> + <rate bytes='123' period='1234'/> + <backend model='random'>/dev/urandom</backend> + <address type='pci' domain='0x0000' bus='0x02' slot='0x07' function='0x0'/> + </rng> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index fb05c85..93f465d 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -693,6 +693,46 @@ mymain(void) QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); + DO_TEST("q35-pcie", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + /* same XML as q35-pcie, but don't set QEMU_CAPS_VIRTIO_PCI_LEGACY */ + DO_TEST("q35-virtio-pci", + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
libvirt previously assigned nearly all devices to a "hotpluggable" legacy PCI slot even on machines with a PCIe root bus (and even though most such machines don't even support hotplug on legacy PCI slots!) Forcing all devices onto legacy PCI slots means that the domain will need a dmi-to-pci-bridge (to convert from PCIe to legacy PCI) and a pci-bridge (to provide hotpluggable legacy PCI slots which, again, usually aren't hotpluggable anyway). To help reduce the need for these legacy controllers, this patch tries to assign virtio-1.0-capable devices to PCIe slots whenever possible, by setting appropriate connectFlags in virDomainDeviceConnectFlagsInternal(). Happily, when that function was written (just a few commits ago) it was created with a "virtioFlags" argument, set by both of its callers, which is the proper connectFlags to set for any virtio-*-pci device - depending on the arch/machinetype of the domain, and whether or not the qemu binary supports virtio-1.0, that flag will have either been set to PCI or PCIE. This patch merely enables the functionality by setting the flags for the device to whatever is in virtioFlags if the device is a virtio-*-pci device. NB: since the slot must be hotpluggable, and pcie-root (the PCIe root complex) does *not* support hotplug, this means that suitable controllers must also be in the config (i.e. either pcie-root-port, or pcie-downstream-port). For now, libvirt doesn't add those automatically, so if you put virtio devices in a config for a qemu that has PCIe-capable virtio devices, you'll need to add extra pcie-root-ports yourself. That requirement will be eliminated in a future patch, but for now, it's simple to do this: <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> ... Partially Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1330024
[...]
@@ -475,20 +482,26 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, break; case VIR_DOMAIN_DEVICE_DISK: - if (dev->data.disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) - flags = 0; /* only virtio disks use PCI */ + if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) + flags = virtioFlags;
Double space. [...]
@@ -1692,6 +1692,51 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); + /* verify that devices with pcie capability are assigned to a pcie slot */ + DO_TEST("q35-pcie", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + /* same XML as q35-pcie, but don't set QEMU_CAPS_VIRTIO_PCI_LEGACY,
s/_PCI_LEGACY/_PCI_DISABLE_LEGACY/ Same in qemuxml2xmltest. [...]
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml new file mode 100644 index 0000000..60e29b5 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml @@ -0,0 +1,149 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + </disk> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='2'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x40'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='10' port='0x48'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='11' port='0x50'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='12' port='0x58'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='13' port='0x60'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + </controller> + <controller type='usb' index='0' model='ich9-ehci1'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci1'> + <master startport='0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci2'> + <master startport='2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci3'> + <master startport='4'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </filesystem> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </interface> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + </input> + <input type='keyboard' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + </input> + <input type='tablet' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
I was initially baffled by this, because I expected it to be assigned to one of the available pcie-root-ports just like all the other virtio devices. However, according to qemuDomainValidateDevicePCISlotsQ35() this is intentional, so I guess we're good :) One improvement I can recommend to this test case is to add one more pcie-root-port, so that it becomes quite clear that virtio-vga has been assigned to pcie-root on purpose and *not* due to a lack of pcie-root-ports. ACK -- Andrea Bolognani / Red Hat / Virtualization

On 10/06/2016 10:13 AM, Andrea Bolognani wrote:
On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
libvirt previously assigned nearly all devices to a "hotpluggable" legacy PCI slot even on machines with a PCIe root bus (and even though most such machines don't even support hotplug on legacy PCI slots!) Forcing all devices onto legacy PCI slots means that the domain will need a dmi-to-pci-bridge (to convert from PCIe to legacy PCI) and a pci-bridge (to provide hotpluggable legacy PCI slots which, again, usually aren't hotpluggable anyway).
To help reduce the need for these legacy controllers, this patch tries to assign virtio-1.0-capable devices to PCIe slots whenever possible, by setting appropriate connectFlags in virDomainDeviceConnectFlagsInternal(). Happily, when that function was written (just a few commits ago) it was created with a "virtioFlags" argument, set by both of its callers, which is the proper connectFlags to set for any virtio-*-pci device - depending on the arch/machinetype of the domain, and whether or not the qemu binary supports virtio-1.0, that flag will have either been set to PCI or PCIE. This patch merely enables the functionality by setting the flags for the device to whatever is in virtioFlags if the device is a virtio-*-pci device.
NB: since the slot must be hotpluggable, and pcie-root (the PCIe root complex) does *not* support hotplug, this means that suitable controllers must also be in the config (i.e. either pcie-root-port, or pcie-downstream-port). For now, libvirt doesn't add those automatically, so if you put virtio devices in a config for a qemu that has PCIe-capable virtio devices, you'll need to add extra pcie-root-ports yourself. That requirement will be eliminated in a future patch, but for now, it's simple to do this:
<controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> ...
Partially Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1330024 [...]
+ <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> I was initially baffled by this, because I expected it to be assigned to one of the available pcie-root-ports just like all the other virtio devices.
However, according to qemuDomainValidateDevicePCISlotsQ35() this is intentional, so I guess we're good :)
Actually, you bring up an interesting point in light of the "Should PCIe devices ever be placed directly on pcie-root?" debate on qemu-devel (I think it was in the thread about the PCI topology document that Marcel is writing). We currently always put the primary video device at 00:1 just because "we always have", and it has the nice side effect of eliminating the need for legacy-PCI controllers. But in this one case the device is PCIe - to follow Marcel's recommendation of putting only legacy devices on pcie-root, we should be putting the virtio video device on a root-port. As I recall, Marcel and Alex were the most vocal on this subject, so I'm Cc'ing them, with this bit of context - this patch auto-assigns the addresses for virtio devices to be on Express ports rather than legacy slots when appropriate, but there is a bit of Q35-specific code that overrides any of that and always places the primary video device at 00:01.0 - should we still do that for the primary video if it's virtio? Or should we put it behind a root-port?
One improvement I can recommend to this test case is to add one more pcie-root-port, so that it becomes quite clear that virtio-vga has been assigned to pcie-root on purpose and *not* due to a lack of pcie-root-ports.
Or possibly change the behavior for virtio video even if it's the primary (note to self - check if someone has done the patch to allow multiple virtio video devices yet)

On Thu, 2016-10-06 at 10:34 -0400, Laine Stump wrote:
+ <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> I was initially baffled by this, because I expected it to be assigned to one of the available pcie-root-ports just like all the other virtio devices. However, according to qemuDomainValidateDevicePCISlotsQ35() this is intentional, so I guess we're good :) Actually, you bring up an interesting point in light of the "Should PCIe devices ever be placed directly on pcie-root?" debate on qemu-devel (I think it was in the thread about the PCI topology document that Marcel is writing). We currently always put the primary video device at 00:1 just because "we always have", and it has the nice side effect of eliminating the need for legacy-PCI controllers. But in this one case the device is PCIe - to follow Marcel's recommendation of putting only legacy devices on pcie-root, we should be putting the virtio video device on a root-port. As I recall, Marcel and Alex were the most vocal on this subject, so I'm Cc'ing them, with this bit of context - this patch auto-assigns the addresses for virtio devices to be on Express ports rather than legacy slots when appropriate, but there is a bit of Q35-specific code that overrides any of that and always places the primary video device at 00:01.0 - should we still do that for the primary video if it's virtio? Or should we put it behind a root-port?
I don't think we ever got a reply... Bump? :) -- Andrea Bolognani / Red Hat / Virtualization

On 11/15/2016 07:21 AM, Andrea Bolognani wrote:
On Thu, 2016-10-06 at 10:34 -0400, Laine Stump wrote:
+ <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
I was initially baffled by this, because I expected it to be assigned to one of the available pcie-root-ports just like all the other virtio devices.
However, according to qemuDomainValidateDevicePCISlotsQ35() this is intentional, so I guess we're good :)
Actually, you bring up an interesting point in light of the "Should PCIe devices ever be placed directly on pcie-root?" debate on qemu-devel (I think it was in the thread about the PCI topology document that Marcel is writing). We currently always put the primary video device at 00:1 just because "we always have", and it has the nice side effect of eliminating the need for legacy-PCI controllers. But in this one case the device is PCIe - to follow Marcel's recommendation of putting only legacy devices on pcie-root, we should be putting the virtio video device on a root-port.
As I recall, Marcel and Alex were the most vocal on this subject, so I'm Cc'ing them, with this bit of context - this patch auto-assigns the addresses for virtio devices to be on Express ports rather than legacy slots when appropriate, but there is a bit of Q35-specific code that overrides any of that and always places the primary video device at 00:01.0 - should we still do that for the primary video if it's virtio? Or should we put it behind a root-port? I don't think we ever got a reply... Bump? :)
I looked at "lspci" of a guest that has virtio-gpu directly connected to pci-root, and found that it does show up as a legacy device in that case, which I guess is what we want, right? Let's ask the author of virtio-gpu: Gerd, what is your opinion - when using virtio-gpu as the primary video device, is it better to have it directly plugged into 00:01.0 (i.e. a legacy integrated device)? Or is it better to plug it into a pcie-root-port?

Hi,
I looked at "lspci" of a guest that has virtio-gpu directly connected to pci-root, and found that it does show up as a legacy device in that case, which I guess is what we want, right?
Let's ask the author of virtio-gpu: Gerd, what is your opinion - when using virtio-gpu as the primary video device, is it better to have it directly plugged into 00:01.0 (i.e. a legacy integrated device)? Or is it better to plug it into a pcie-root-port?
virtio-vga or virtio-gpu-pci? virtio-gpu-pci should have zero issues in a pcie-root-port. For virtio-vga I'd tend to place it directly in 00:01.0, to avoid ioport access issues for the vga compatibility part of the device. cheers, Gerd

On 11/16/2016 03:43 AM, Gerd Hoffmann wrote:
Hi,
I looked at "lspci" of a guest that has virtio-gpu directly connected to pci-root, and found that it does show up as a legacy device in that case, which I guess is what we want, right?
Let's ask the author of virtio-gpu: Gerd, what is your opinion - when using virtio-gpu as the primary video device, is it better to have it directly plugged into 00:01.0 (i.e. a legacy integrated device)? Or is it better to plug it into a pcie-root-port? virtio-vga or virtio-gpu-pci?
Ah, I didn't realize it until you asked, but libvirt uses virtio-vga for the primary video device (if model is set to "virtio"), and virtio-gpu-pci for any secondary video devices, and I had only specified a single device.
virtio-gpu-pci should have zero issues in a pcie-root-port.
For virtio-vga I'd tend to place it directly in 00:01.0, to avoid ioport access issues for the vga compatibility part of the device.
Okay, since this question is specifically for the primary video device, and vga compatibility is highly desired for that, I guess that's our answer - so the primary virtio video will stay on 00:01.0, and any additional virtio video devices will be plugged into a pcie-root-port. Thanks!

On Tue, 2016-11-15 at 11:15 -0500, Laine Stump wrote:
I looked at "lspci" of a guest that has virtio-gpu directly connected to pci-root
pcie-root?
and found that it does show up as a legacy device in that case, which I guess is what we want, right?
I tried with virtio-vga and it works as expected, eg. it presents itself as a legacy PCI device when plugged directly into pcie.0 and as a PCI Express device when plugged into a PCI Express Root Port instead. Not sure how that would influence our choice of slot for video devices one way or the other, but I wanted to point it out. -- Andrea Bolognani / Red Hat / Virtualization

On Tue, 15 Nov 2016 13:21:21 +0100 Andrea Bolognani <abologna@redhat.com> wrote:
On Thu, 2016-10-06 at 10:34 -0400, Laine Stump wrote:
+ <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> I was initially baffled by this, because I expected it to be assigned to one of the available pcie-root-ports just like all the other virtio devices. However, according to qemuDomainValidateDevicePCISlotsQ35() this is intentional, so I guess we're good :) Actually, you bring up an interesting point in light of the "Should PCIe devices ever be placed directly on pcie-root?" debate on qemu-devel (I think it was in the thread about the PCI topology document that Marcel is writing). We currently always put the primary video device at 00:1 just because "we always have", and it has the nice side effect of eliminating the need for legacy-PCI controllers. But in this one case the device is PCIe - to follow Marcel's recommendation of putting only legacy devices on pcie-root, we should be putting the virtio video device on a root-port. As I recall, Marcel and Alex were the most vocal on this subject, so I'm Cc'ing them, with this bit of context - this patch auto-assigns the addresses for virtio devices to be on Express ports rather than legacy slots when appropriate, but there is a bit of Q35-specific code that overrides any of that and always places the primary video device at 00:01.0 - should we still do that for the primary video if it's virtio? Or should we put it behind a root-port?
I don't think we ever got a reply... Bump? :)
The primary reason you're putting the device under a pcie-root-port is for hotplug, right? How many users care about hotplug of primary video? How many guest operating systems even support that? I'd feel pretty comfortable making the primary graphics non-hotpluggable by default. I actually lean towards making the user specify if they care about hotplugging a device rather than assuming they do, seems like we impose a lot of complexity on our configurations for something that might actually be a niche feature. Thanks, Alex

On 11/15/2016 12:44 PM, Alex Williamson wrote:
On Tue, 15 Nov 2016 13:21:21 +0100 Andrea Bolognani <abologna@redhat.com> wrote:
On Thu, 2016-10-06 at 10:34 -0400, Laine Stump wrote:
+ <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
I was initially baffled by this, because I expected it to be assigned to one of the available pcie-root-ports just like all the other virtio devices.
However, according to qemuDomainValidateDevicePCISlotsQ35() this is intentional, so I guess we're good :)
Actually, you bring up an interesting point in light of the "Should PCIe devices ever be placed directly on pcie-root?" debate on qemu-devel (I think it was in the thread about the PCI topology document that Marcel is writing). We currently always put the primary video device at 00:1 just because "we always have", and it has the nice side effect of eliminating the need for legacy-PCI controllers. But in this one case the device is PCIe - to follow Marcel's recommendation of putting only legacy devices on pcie-root, we should be putting the virtio video device on a root-port.
As I recall, Marcel and Alex were the most vocal on this subject, so I'm Cc'ing them, with this bit of context - this patch auto-assigns the addresses for virtio devices to be on Express ports rather than legacy slots when appropriate, but there is a bit of Q35-specific code that overrides any of that and always places the primary video device at 00:01.0 - should we still do that for the primary video if it's virtio? Or should we put it behind a root-port? I don't think we ever got a reply... Bump? :) The primary reason you're putting the device under a pcie-root-port is for hotplug, right?
That, and to avoid having Express devices as integrated devices (which there was some discussion about on the qemu thread for Marcel's "PCIe devices placement guidelines" patch, and the conclusion was that we shouldn't put Express devices directly on the root complex (right?). On the other hand, as I pointed out in the mail I sent just before yours, I tried out a virtio-gpu device on the root complex, and it shows up as a legacy PCI device, not Express, so I guess that's not an issue.
How many users care about hotplug of primary video? How many guest operating systems even support that? I'd feel pretty comfortable making the primary graphics non-hotpluggable by default. I actually lean towards making the user specify if they care about hotplugging a device rather than assuming they do,
I agree with that, but my patch to provide a means of specifying that in the XML was shot down, since it's seen as "libvirt dictating policy". And since it's less hostile to make hotplug a possibility (and then have it unused) than to make it impossible and then need it, when libvirt assigns addresses, we have to assume that the user *will* want it. There are a few exceptions, for various reasons: 1) devices that are unremovable (and unmovable) parts of the machinetype (for Q35 that's just the SATA controller) 2) primary and secondary USB2 controllers (because that's where the same device is on real Q35) 3) ich9 audio (again because that's where it is on real Q35, and because there is no Express audio device, so this is the only way to have a "legacy-free" (i.e. no dmi-to-pci-bridge and no pci-bridge) guest with audio) 4) primary video (because... well, er, just *because*. Eat your vegetables!) Looking at it from afar, it all seems kind of arbitrary (or at least inconsistent) though...
seems like we impose a lot of complexity on our configurations for something that might actually be a niche feature.
Yes. I keep saying "we're doing all this work to support hotplug by default for probably less than 1% of users", and yet we keep doing it...

On 11/15/2016 09:58 PM, Laine Stump wrote:
On 11/15/2016 12:44 PM, Alex Williamson wrote:
On Tue, 15 Nov 2016 13:21:21 +0100 Andrea Bolognani <abologna@redhat.com> wrote:
On Thu, 2016-10-06 at 10:34 -0400, Laine Stump wrote:
+ <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> I was initially baffled by this, because I expected it to be assigned to one of the available pcie-root-ports just like all the other virtio devices. However, according to qemuDomainValidateDevicePCISlotsQ35() this is intentional, so I guess we're good :) Actually, you bring up an interesting point in light of the "Should PCIe devices ever be placed directly on pcie-root?" debate on qemu-devel (I think it was in the thread about the PCI topology document that Marcel is writing). We currently always put the primary video device at 00:1 just because "we always have", and it has the nice side effect of eliminating the need for legacy-PCI controllers. But in this one case the device is PCIe - to follow Marcel's recommendation of putting only legacy devices on pcie-root, we should be putting the virtio video device on a root-port. As I recall, Marcel and Alex were the most vocal on this subject, so I'm Cc'ing them, with this bit of context - this patch auto-assigns the addresses for virtio devices to be on Express ports rather than legacy slots when appropriate, but there is a bit of Q35-specific code that overrides any of that and always places the primary video device at 00:01.0 - should we still do that for the primary video if it's virtio? Or should we put it behind a root-port? I don't think we ever got a reply... Bump? :) The primary reason you're putting the device under a pcie-root-port is for hotplug, right?
That, and to avoid having Express devices as integrated devices (which there was some discussion about on the qemu thread for Marcel's "PCIe devices placement guidelines" patch, and the conclusion was that we shouldn't put Express devices directly on the root complex (right?). On the other hand, as I pointed out in the mail I sent just before yours, I tried out a virtio-gpu device on the root complex, and it shows up as a legacy PCI device, not Express, so I guess that's not an issue.
Graphics card, sound cards are exceptions to the "rule". Laszlo tried to make this point calling them "special purpose" devices but was not clear enough.
How many users care about hotplug of primary video? How many guest operating systems even support that? I'd feel pretty comfortable making the primary graphics non-hotpluggable by default. I actually lean towards making the user specify if they care about hotplugging a device rather than assuming they do,
I agree with that, but my patch to provide a means of specifying that in the XML was shot down, since it's seen as "libvirt dictating policy".
And since it's less hostile to make hotplug a possibility (and then have it unused) than to make it impossible and then need it, when libvirt assigns addresses, we have to assume that the user *will* want it.
There are a few exceptions, for various reasons:
1) devices that are unremovable (and unmovable) parts of the machinetype (for Q35 that's just the SATA controller) 2) primary and secondary USB2 controllers (because that's where the same device is on real Q35) 3) ich9 audio (again because that's where it is on real Q35, and because there is no Express audio device, so this is the only way to have a "legacy-free" (i.e. no dmi-to-pci-bridge and no pci-bridge) guest with audio) 4) primary video (because... well, er, just *because*. Eat your vegetables!)
Looking at it from afar, it all seems kind of arbitrary (or at least inconsistent) though...
seems like we impose a lot of complexity on our configurations for something that might actually be a niche feature.
Yes. I keep saying "we're doing all this work to support hotplug by default for probably less than 1% of users", and yet we keep doing it...
My feelings got hurt :) - but I'll take 1% at any time! Marcel

The e1000e is an emulated network device based on the Intel 82574, present in qemu 2.7.0 and later. Among other differences from the e1000, it presents itself as a PCIe device rather than legacy PCI. In order to get it assigned to a PCIe controller, this patch updates the flags setting for network devices when the model name is "e1000e". (Note that for some reason libvirt has never validated the network device model names other than to check that there are no dangerous characters in them. That should probably change, but is the subject of another patch.) Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1343094 --- src/qemu/qemu_domain_address.c | 2 ++ tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 24 +++++++++++-------- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 5 ++++ .../qemuxml2argv-q35-virtio-pci.args | 4 ++++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 28 +++++++++++++++------- .../qemuxml2xmlout-q35-virtio-pci.xml | 10 ++++++++ 6 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index c8a8f6b..e11a23b 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -468,6 +468,8 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, flags = 0; else if (STREQ(net->model, "virtio")) flags = virtioFlags; + else if (STREQ(net->model, "e1000e")) + flags = pcieFlags; break; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args index 2ea0c08..40c8063 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args @@ -29,15 +29,16 @@ QEMU_AUDIO_DRV=none \ -device ioh3420,port=0x50,chassis=11,id=pci.11,bus=pcie.0,addr=0xa \ -device ioh3420,port=0x58,chassis=12,id=pci.12,bus=pcie.0,addr=0xb \ -device ioh3420,port=0x60,chassis=13,id=pci.13,bus=pcie.0,addr=0xc \ +-device ioh3420,port=0x68,chassis=14,id=pci.14,bus=pcie.0,addr=0xd \ -device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ addr=0x1d \ -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pcie.0,addr=0x1d.0x1 \ -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pcie.0,addr=0x1d.0x2 \ --device virtio-scsi-pci,id=scsi0,bus=pci.6,addr=0x0 \ --device virtio-serial-pci,id=virtio-serial0,bus=pci.5,addr=0x0 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.7,addr=0x0 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.6,addr=0x0 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk1 \ --device virtio-blk-pci,bus=pci.7,addr=0x0,drive=drive-virtio-disk1,\ +-device virtio-blk-pci,bus=pci.8,addr=0x0,drive=drive-virtio-disk1,\ id=virtio-disk1 \ -fsdev local,security_model=passthrough,id=fsdev-fs0,path=/export/to/guest \ -device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=/import/from/host,\ @@ -45,13 +46,16 @@ bus=pci.3,addr=0x0 \ -netdev user,id=hostnet0 \ -device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.4,\ addr=0x0 \ --device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.10,\ +-netdev user,id=hostnet1 \ +-device e1000e,netdev=hostnet1,id=net1,mac=00:11:22:33:44:66,bus=pci.5,\ addr=0x0 \ --device virtio-mouse-pci,id=input1,bus=pci.11,addr=0x0 \ --device virtio-keyboard-pci,id=input2,bus=pci.12,addr=0x0 \ --device virtio-tablet-pci,id=input3,bus=pci.13,addr=0x0 \ +-device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.11,\ +addr=0x0 \ +-device virtio-mouse-pci,id=input1,bus=pci.12,addr=0x0 \ +-device virtio-keyboard-pci,id=input2,bus=pci.13,addr=0x0 \ +-device virtio-tablet-pci,id=input3,bus=pci.14,addr=0x0 \ -device virtio-vga,id=video0,bus=pcie.0,addr=0x1 \ --device virtio-balloon-pci,id=balloon0,bus=pci.8,addr=0x0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.9,addr=0x0 \ -object rng-random,id=objrng0,filename=/dev/urandom \ --device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,bus=pci.9,\ -addr=0x0 +-device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,\ +bus=pci.10,addr=0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml index 7bed08c..39db5f0 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml @@ -28,6 +28,7 @@ <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> <controller type='virtio-serial'/> <controller type='scsi' model='virtio-scsi'/> <disk type='block' device='disk'> @@ -45,6 +46,10 @@ <mac address='00:11:22:33:44:55'/> <model type='virtio'/> </interface> + <interface type='user'> + <mac address='00:11:22:33:44:66'/> + <model type='e1000e'/> + </interface> <memballoon model='virtio'/> <rng model='virtio'> <rate bytes='123' period='1234'/> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args index 7cedc82..5723af7 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args @@ -29,6 +29,7 @@ QEMU_AUDIO_DRV=none \ -device ioh3420,port=0x50,chassis=11,id=pci.11,bus=pcie.0,addr=0xa \ -device ioh3420,port=0x58,chassis=12,id=pci.12,bus=pcie.0,addr=0xb \ -device ioh3420,port=0x60,chassis=13,id=pci.13,bus=pcie.0,addr=0xc \ +-device ioh3420,port=0x68,chassis=14,id=pci.14,bus=pcie.0,addr=0xd \ -device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ addr=0x1d \ @@ -45,6 +46,9 @@ bus=pci.2,addr=0x1 \ -netdev user,id=hostnet0 \ -device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.2,\ addr=0x2 \ +-netdev user,id=hostnet1 \ +-device e1000e,netdev=hostnet1,id=net1,mac=00:11:22:33:44:66,bus=pci.3,\ +addr=0x0 \ -device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.2,\ addr=0x8 \ -device virtio-mouse-pci,id=input1,bus=pci.2,addr=0x9 \ diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml index 60e29b5..5a23a51 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml @@ -17,7 +17,7 @@ <disk type='block' device='disk'> <source dev='/dev/HostVG/QEMUGuest1'/> <target dev='vdb' bus='virtio'/> - <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> </disk> <controller type='pci' index='0' model='pcie-root'/> <controller type='pci' index='1' model='dmi-to-pci-bridge'> @@ -84,11 +84,16 @@ <target chassis='13' port='0x60'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='14' port='0x68'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + </controller> <controller type='virtio-serial' index='0'> - <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> </controller> <controller type='scsi' index='0' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> </controller> <controller type='usb' index='0' model='ich9-ehci1'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/> @@ -118,18 +123,23 @@ <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> </interface> + <interface type='user'> + <mac address='00:11:22:33:44:66'/> + <model type='e1000e'/> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </interface> <input type='passthrough' bus='virtio'> <source evdev='/dev/input/event1234'/> - <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> </input> <input type='mouse' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> </input> <input type='keyboard' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> </input> <input type='tablet' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0e' slot='0x00' function='0x0'/> </input> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> @@ -138,12 +148,12 @@ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </video> <memballoon model='virtio'> - <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> </memballoon> <rng model='virtio'> <rate bytes='123' period='1234'/> <backend model='random'>/dev/urandom</backend> - <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> </rng> </devices> </domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml index 5c5acac..22c2c68 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml @@ -84,6 +84,11 @@ <target chassis='13' port='0x60'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='14' port='0x68'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + </controller> <controller type='virtio-serial' index='0'> <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/> </controller> @@ -118,6 +123,11 @@ <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> </interface> + <interface type='user'> + <mac address='00:11:22:33:44:66'/> + <model type='e1000e'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </interface> <input type='passthrough' bus='virtio'> <source evdev='/dev/input/event1234'/> <address type='pci' domain='0x0000' bus='0x02' slot='0x08' function='0x0'/> -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
The e1000e is an emulated network device based on the Intel 82574, present in qemu 2.7.0 and later. Among other differences from the e1000, it presents itself as a PCIe device rather than legacy PCI. In order to get it assigned to a PCIe controller, this patch updates the flags setting for network devices when the model name is "e1000e". (Note that for some reason libvirt has never validated the network device model names other than to check that there are no dangerous characters in them. That should probably change, but is the subject of another patch.) Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1343094
[...]
@@ -468,6 +468,8 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, flags = 0; else if (STREQ(net->model, "virtio")) flags = virtioFlags; + else if (STREQ(net->model, "e1000e")) + flags = pcieFlags;
pcieFlags should no longer be marked as ATTRIBUTE_UNUSED in the function declaration after this change. ACK -- Andrea Bolognani / Red Hat / Virtualization

The nec-usb-xhci device (which is a USB3 controller) has always presented itself as a PCI device when plugged into a legacy PCI slot, and a PCIe device when plugged into a PCIe slot, but libvirt has always auto-assigned it to a PCI slot. This patch changes that behavior to auto-assign to a PCIe slot on systems that have pcie-root (e.g. Q35 and aarch64/virt). Since we don't yet auto-create pcie-*-port controllers on demand, this means a config with an nec-xhci USB controller that has no PCI address assigned will also need to have an otherwise-unused pcie-*-port controller specified: <controller type='pci' model='pcie-root-port'/> <controller type='usb' model='nec-xhci'/> (this assumes there is an otherwise-unused slot on pcie-root to accept the pcie-root-port) --- src/qemu/qemu_domain_address.c | 3 ++ tests/qemuxml2argvdata/qemuxml2argv-autoindex.args | 10 +++---- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 21 ++++++------- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 2 ++ .../qemuxml2argv-q35-virtio-pci.args | 7 ++--- tests/qemuxml2argvtest.c | 2 ++ .../qemuxml2xmlout-autoindex.xml | 10 +++---- .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 35 +++++++++------------- .../qemuxml2xmlout-q35-virtio-pci.xml | 21 +++++-------- 9 files changed, 49 insertions(+), 62 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index e11a23b..83e3861 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -442,6 +442,9 @@ qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, cont->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI) || cont->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) { flags = virtioFlags; + } else if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI) { + flags = pcieFlags; } else if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || cont->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID || (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && diff --git a/tests/qemuxml2argvdata/qemuxml2argv-autoindex.args b/tests/qemuxml2argvdata/qemuxml2argv-autoindex.args index 43b9661..fc14dc4 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-autoindex.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-autoindex.args @@ -43,11 +43,11 @@ addr=0x1 \ -device ich9-usb-uhci2,masterbus=usb2.0,firstport=2,bus=pci.2,addr=0x1.0x1 \ -device ich9-usb-uhci3,masterbus=usb2.0,firstport=4,bus=pci.2,addr=0x1.0x2 \ -device ich9-usb-ehci1,id=usb2,bus=pci.2,addr=0x1.0x7 \ --device nec-usb-xhci,id=usb3,bus=pci.2,addr=0x2 \ +-device nec-usb-xhci,id=usb3,bus=pci.5,addr=0x0 \ -device ich9-usb-uhci1,masterbus=usb4.0,firstport=0,bus=pci.2,multifunction=on,\ -addr=0x3 \ --device ich9-usb-uhci2,masterbus=usb4.0,firstport=2,bus=pci.2,addr=0x3.0x1 \ --device ich9-usb-uhci3,masterbus=usb4.0,firstport=4,bus=pci.2,addr=0x3.0x2 \ --device ich9-usb-ehci1,id=usb4,bus=pci.2,addr=0x3.0x7 \ +addr=0x2 \ +-device ich9-usb-uhci2,masterbus=usb4.0,firstport=2,bus=pci.2,addr=0x2.0x1 \ +-device ich9-usb-uhci3,masterbus=usb4.0,firstport=4,bus=pci.2,addr=0x2.0x2 \ +-device ich9-usb-ehci1,id=usb4,bus=pci.2,addr=0x2.0x7 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-sata0-0-0 \ -device ide-drive,bus=ide.0,drive=drive-sata0-0-0,id=sata0-0-0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args index 40c8063..059b232 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args @@ -30,15 +30,12 @@ QEMU_AUDIO_DRV=none \ -device ioh3420,port=0x58,chassis=12,id=pci.12,bus=pcie.0,addr=0xb \ -device ioh3420,port=0x60,chassis=13,id=pci.13,bus=pcie.0,addr=0xc \ -device ioh3420,port=0x68,chassis=14,id=pci.14,bus=pcie.0,addr=0xd \ --device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ --device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ -addr=0x1d \ --device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pcie.0,addr=0x1d.0x1 \ --device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pcie.0,addr=0x1d.0x2 \ +-device ioh3420,port=0x70,chassis=15,id=pci.15,bus=pcie.0,addr=0xe \ +-device nec-usb-xhci,id=usb,bus=pci.8,addr=0x0 \ -device virtio-scsi-pci,id=scsi0,bus=pci.7,addr=0x0 \ -device virtio-serial-pci,id=virtio-serial0,bus=pci.6,addr=0x0 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk1 \ --device virtio-blk-pci,bus=pci.8,addr=0x0,drive=drive-virtio-disk1,\ +-device virtio-blk-pci,bus=pci.9,addr=0x0,drive=drive-virtio-disk1,\ id=virtio-disk1 \ -fsdev local,security_model=passthrough,id=fsdev-fs0,path=/export/to/guest \ -device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=/import/from/host,\ @@ -49,13 +46,13 @@ addr=0x0 \ -netdev user,id=hostnet1 \ -device e1000e,netdev=hostnet1,id=net1,mac=00:11:22:33:44:66,bus=pci.5,\ addr=0x0 \ --device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.11,\ +-device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.12,\ addr=0x0 \ --device virtio-mouse-pci,id=input1,bus=pci.12,addr=0x0 \ --device virtio-keyboard-pci,id=input2,bus=pci.13,addr=0x0 \ --device virtio-tablet-pci,id=input3,bus=pci.14,addr=0x0 \ +-device virtio-mouse-pci,id=input1,bus=pci.13,addr=0x0 \ +-device virtio-keyboard-pci,id=input2,bus=pci.14,addr=0x0 \ +-device virtio-tablet-pci,id=input3,bus=pci.15,addr=0x0 \ -device virtio-vga,id=video0,bus=pcie.0,addr=0x1 \ --device virtio-balloon-pci,id=balloon0,bus=pci.9,addr=0x0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.10,addr=0x0 \ -object rng-random,id=objrng0,filename=/dev/urandom \ -device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,\ -bus=pci.10,addr=0x0 +bus=pci.11,addr=0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml index 39db5f0..b6b971b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml @@ -29,8 +29,10 @@ <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-root-port'/> + <controller type='pci' model='pcie-root-port'/> <controller type='virtio-serial'/> <controller type='scsi' model='virtio-scsi'/> + <controller type='usb' model='nec-xhci'/> <disk type='block' device='disk'> <source dev='/dev/HostVG/QEMUGuest1'/> <target dev='vdb' bus='virtio'/> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args index 5723af7..a9a760f 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args @@ -30,11 +30,8 @@ QEMU_AUDIO_DRV=none \ -device ioh3420,port=0x58,chassis=12,id=pci.12,bus=pcie.0,addr=0xb \ -device ioh3420,port=0x60,chassis=13,id=pci.13,bus=pcie.0,addr=0xc \ -device ioh3420,port=0x68,chassis=14,id=pci.14,bus=pcie.0,addr=0xd \ --device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ --device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ -addr=0x1d \ --device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pcie.0,addr=0x1d.0x1 \ --device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pcie.0,addr=0x1d.0x2 \ +-device ioh3420,port=0x70,chassis=15,id=pci.15,bus=pcie.0,addr=0xe \ +-device nec-usb-xhci,id=usb,bus=pci.4,addr=0x0 \ -device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x4 \ -device virtio-serial-pci,id=virtio-serial0,bus=pci.2,addr=0x3 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk1 \ diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 582a02a..a7e21fd 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1713,6 +1713,7 @@ mymain(void) QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); /* same XML as q35-pcie, but don't set QEMU_CAPS_VIRTIO_PCI_LEGACY, * so virtio devices should be assigned to legacy pci slots @@ -1736,6 +1737,7 @@ mymain(void) QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root-port", QEMU_CAPS_DEVICE_PCI_BRIDGE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-autoindex.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-autoindex.xml index 086a1cf..2a8a44a 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-autoindex.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-autoindex.xml @@ -126,22 +126,22 @@ <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x7'/> </controller> <controller type='usb' index='3' model='nec-xhci'> - <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> </controller> <controller type='usb' index='4' model='ich9-uhci1'> <master startport='0'/> - <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0' multifunction='on'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0' multifunction='on'/> </controller> <controller type='usb' index='4' model='ich9-uhci2'> <master startport='2'/> - <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x1'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x1'/> </controller> <controller type='usb' index='4' model='ich9-uhci3'> <master startport='4'/> - <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x2'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x2'/> </controller> <controller type='usb' index='4' model='ich9-ehci1'> - <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x7'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x7'/> </controller> <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml index 5a23a51..8e727fb 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml @@ -17,7 +17,7 @@ <disk type='block' device='disk'> <source dev='/dev/HostVG/QEMUGuest1'/> <target dev='vdb' bus='virtio'/> - <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> </disk> <controller type='pci' index='0' model='pcie-root'/> <controller type='pci' index='1' model='dmi-to-pci-bridge'> @@ -89,26 +89,19 @@ <target chassis='14' port='0x68'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> </controller> + <controller type='pci' index='15' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='15' port='0x70'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + </controller> <controller type='virtio-serial' index='0'> <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> </controller> <controller type='scsi' index='0' model='virtio-scsi'> <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> </controller> - <controller type='usb' index='0' model='ich9-ehci1'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/> - </controller> - <controller type='usb' index='0' model='ich9-uhci1'> - <master startport='0'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/> - </controller> - <controller type='usb' index='0' model='ich9-uhci2'> - <master startport='2'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/> - </controller> - <controller type='usb' index='0' model='ich9-uhci3'> - <master startport='4'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/> + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> </controller> <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> @@ -130,16 +123,16 @@ </interface> <input type='passthrough' bus='virtio'> <source evdev='/dev/input/event1234'/> - <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> </input> <input type='mouse' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> </input> <input type='keyboard' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0e' slot='0x00' function='0x0'/> </input> <input type='tablet' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0e' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0f' slot='0x00' function='0x0'/> </input> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> @@ -148,12 +141,12 @@ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </video> <memballoon model='virtio'> - <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> </memballoon> <rng model='virtio'> <rate bytes='123' period='1234'/> <backend model='random'>/dev/urandom</backend> - <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> </rng> </devices> </domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml index 22c2c68..c4bd357 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml @@ -89,26 +89,19 @@ <target chassis='14' port='0x68'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> </controller> + <controller type='pci' index='15' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='15' port='0x70'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + </controller> <controller type='virtio-serial' index='0'> <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/> </controller> <controller type='scsi' index='0' model='virtio-scsi'> <address type='pci' domain='0x0000' bus='0x02' slot='0x04' function='0x0'/> </controller> - <controller type='usb' index='0' model='ich9-ehci1'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/> - </controller> - <controller type='usb' index='0' model='ich9-uhci1'> - <master startport='0'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/> - </controller> - <controller type='usb' index='0' model='ich9-uhci2'> - <master startport='2'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/> - </controller> - <controller type='usb' index='0' model='ich9-uhci3'> - <master startport='4'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/> + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> </controller> <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
The nec-usb-xhci device (which is a USB3 controller) has always presented itself as a PCI device when plugged into a legacy PCI slot, and a PCIe device when plugged into a PCIe slot, but libvirt has always auto-assigned it to a PCI slot. This patch changes that behavior to auto-assign to a PCIe slot on systems that have pcie-root (e.g. Q35 and aarch64/virt). Since we don't yet auto-create pcie-*-port controllers on demand, this means a config with an nec-xhci USB controller that has no PCI address assigned will also need to have an otherwise-unused pcie-*-port controller specified: <controller type='pci' model='pcie-root-port'/> <controller type='usb' model='nec-xhci'/> (this assumes there is an otherwise-unused slot on pcie-root to accept the pcie-root-port) --- src/qemu/qemu_domain_address.c | 3 ++ tests/qemuxml2argvdata/qemuxml2argv-autoindex.args | 10 +++---- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 21 ++++++------- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 2 ++ .../qemuxml2argv-q35-virtio-pci.args | 7 ++--- tests/qemuxml2argvtest.c | 2 ++ .../qemuxml2xmlout-autoindex.xml | 10 +++---- .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 35 +++++++++------------- .../qemuxml2xmlout-q35-virtio-pci.xml | 21 +++++-------- 9 files changed, 49 insertions(+), 62 deletions(-)
ACK -- Andrea Bolognani / Red Hat / Virtualization

Andrea had the right idea when he disabled the "reserve an extra unused slot" bit for aarch64/virt. For *any* PCI Express-based machine, it is pointless since 1) an extra legacy-PCI slot can't be used for hotplug, since hotplug into legacy PCI slots doesn't work on PCI Express machinetypes, and 2) even for "coldplug" expansion, everybody will want to expand using Express controllers, not legacy PCI. This patch eliminates the extra slot reserve unless the system has a pci-root (i.e. legacy PCI). --- src/qemu/qemu_domain_address.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 83e3861..1ff80e3 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1713,16 +1713,17 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, buses_reserved = false; } - /* Reserve 1 extra slot for a (potential) bridge only if buses - * are not fully reserved yet. + /* Reserve 1 extra slot for a (potential) bridge (for future + * expansion) only if buses are not fully reserved yet. * - * We don't reserve the extra slot for aarch64 mach-virt guests - * either because we want to be able to have pure virtio-mmio - * guests, and reserving this slot would force us to add at least - * a dmi-to-pci-bridge to an otherwise PCI-free topology + * We only do this for those domains that have pci-root, since + * those with pcie-root will usually want to expand using PCIe + * controllers, and we don't want to saddle all PCIe domains + * down with a dmi-to-pci-bridge *and* a pci-bridge when they + * will probably never use it. */ if (!buses_reserved && - !qemuDomainMachineIsVirt(def) && + qemuDomainMachineHasPCIRoot(def) && qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) goto cleanup; -- 2.7.4

Andrea had the right idea when he disabled the "reserve an extra unused slot" bit for aarch64/virt. For *any* PCI Express-based machine, it is pointless since 1) an extra legacy-PCI slot can't be used for hotplug, since hotplug into legacy PCI slots doesn't work on PCI Express machinetypes, and 2) even for "coldplug" expansion, everybody will want to expand using Express controllers, not legacy PCI. This patch eliminates the extra slot reserve unless the system has a pci-root (i.e. legacy PCI) --- change from v3: reorganize to short circuit the entire check when the root bus isn't PCI, rather than just preventing the slot reservation. Also improve the comment. src/qemu/qemu_domain_address.c | 44 ++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 89cab1d..6df373d 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1694,8 +1694,6 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, */ virDomainDeviceInfo info; - info.pciConnectFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; - /* 1st pass to figure out how many PCI bridges we need */ if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true))) goto cleanup; @@ -1704,23 +1702,35 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, addrs) < 0) goto cleanup; - for (i = 0; i < addrs->nbuses; i++) { - if (!qemuDomainPCIBusFullyReserved(&addrs->buses[i])) - buses_reserved = false; - } - - /* Reserve 1 extra slot for a (potential) bridge only if buses - * are not fully reserved yet. + /* For domains that have pci-root, reserve 1 extra slot for a + * (potential) bridge (for future expansion) only if buses are + * not fully reserved yet (if all buses are fully reserved + * with manually/previously assigned addresses, any attempt to + * reserve an extra slot would fail anyway. But if all buses + * are *not* fully reserved, this extra reservation might push + * the config to add a new pci-bridge to plug into the final + * available slot, thus preserving the ability to expand) * - * We don't reserve the extra slot for aarch64 mach-virt guests - * either because we want to be able to have pure virtio-mmio - * guests, and reserving this slot would force us to add at least - * a dmi-to-pci-bridge to an otherwise PCI-free topology + * We only do this for those domains that have pci-root, since + * those with pcie-root will usually want to expand using PCIe + * controllers, which we will do after assigning addresses for + * all *actual* devices. */ - if (!buses_reserved && - !qemuDomainMachineIsVirt(def) && - qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) - goto cleanup; + + if (qemuDomainMachineHasPCIRoot(def)) { + info.pciConnectFlags = (VIR_PCI_CONNECT_HOTPLUGGABLE | + VIR_PCI_CONNECT_TYPE_PCI_DEVICE); + + for (i = 0; i < addrs->nbuses; i++) { + if (!qemuDomainPCIBusFullyReserved(&addrs->buses[i])) { + buses_reserved = false; + break; + } + } + if (!buses_reserved && + qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) + goto cleanup; + } if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0) goto cleanup; -- 2.7.4

On Thu, 2016-09-29 at 10:14 -0400, Laine Stump wrote:
Andrea had the right idea when he disabled the "reserve an extra unused slot" bit for aarch64/virt. For *any* PCI Express-based machine, it is pointless since 1) an extra legacy-PCI slot can't be used for hotplug, since hotplug into legacy PCI slots doesn't work on PCI Express machinetypes, and 2) even for "coldplug" expansion, everybody will want to expand using Express controllers, not legacy PCI. This patch eliminates the extra slot reserve unless the system has a pci-root (i.e. legacy PCI)
[...]
@@ -1704,23 +1702,35 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, addrs) < 0) goto cleanup; - for (i = 0; i < addrs->nbuses; i++) { - if (!qemuDomainPCIBusFullyReserved(&addrs->buses[i])) - buses_reserved = false; - } - - /* Reserve 1 extra slot for a (potential) bridge only if buses - * are not fully reserved yet. + /* For domains that have pci-root, reserve 1 extra slot for a + * (potential) bridge (for future expansion) only if buses are + * not fully reserved yet (if all buses are fully reserved + * with manually/previously assigned addresses, any attempt to + * reserve an extra slot would fail anyway. But if all buses + * are *not* fully reserved, this extra reservation might push + * the config to add a new pci-bridge to plug into the final + * available slot, thus preserving the ability to expand) * - * We don't reserve the extra slot for aarch64 mach-virt guests - * either because we want to be able to have pure virtio-mmio - * guests, and reserving this slot would force us to add at least - * a dmi-to-pci-bridge to an otherwise PCI-free topology + * We only do this for those domains that have pci-root, since + * those with pcie-root will usually want to expand using PCIe + * controllers, which we will do after assigning addresses for + * all *actual* devices. */ - if (!buses_reserved && - !qemuDomainMachineIsVirt(def) && - qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) - goto cleanup; + + if (qemuDomainMachineHasPCIRoot(def)) {
Since now you're using info exclusively inside this block, you can move its declaration here as well. ACK -- Andrea Bolognani / Red Hat / Virtualization

On 10/06/2016 11:39 AM, Andrea Bolognani wrote:
On Thu, 2016-09-29 at 10:14 -0400, Laine Stump wrote:
Andrea had the right idea when he disabled the "reserve an extra unused slot" bit for aarch64/virt. For *any* PCI Express-based machine, it is pointless since 1) an extra legacy-PCI slot can't be used for hotplug, since hotplug into legacy PCI slots doesn't work on PCI Express machinetypes, and 2) even for "coldplug" expansion, everybody will want to expand using Express controllers, not legacy PCI.
This patch eliminates the extra slot reserve unless the system has a pci-root (i.e. legacy PCI) [...] @@ -1704,23 +1702,35 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, addrs) < 0) goto cleanup;
- for (i = 0; i < addrs->nbuses; i++) { - if (!qemuDomainPCIBusFullyReserved(&addrs->buses[i])) - buses_reserved = false; - } - - /* Reserve 1 extra slot for a (potential) bridge only if buses - * are not fully reserved yet. + /* For domains that have pci-root, reserve 1 extra slot for a + * (potential) bridge (for future expansion) only if buses are + * not fully reserved yet (if all buses are fully reserved + * with manually/previously assigned addresses, any attempt to + * reserve an extra slot would fail anyway. But if all buses + * are *not* fully reserved, this extra reservation might push + * the config to add a new pci-bridge to plug into the final + * available slot, thus preserving the ability to expand) * - * We don't reserve the extra slot for aarch64 mach-virt guests - * either because we want to be able to have pure virtio-mmio - * guests, and reserving this slot would force us to add at least - * a dmi-to-pci-bridge to an otherwise PCI-free topology + * We only do this for those domains that have pci-root, since + * those with pcie-root will usually want to expand using PCIe + * controllers, which we will do after assigning addresses for + * all *actual* devices. */ - if (!buses_reserved && - !qemuDomainMachineIsVirt(def) && - qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) - goto cleanup; + + if (qemuDomainMachineHasPCIRoot(def)) { Since now you're using info exclusively inside this block, you can move its declaration here as well.
Except that patch 19/18 uses it too (it was that patch that led to me re-doing this one and posting a v3.5)

On Thu, 2016-10-06 at 12:04 -0400, Laine Stump wrote:
Since now you're using info exclusively inside this block, you can move its declaration here as well.
Except that patch 19/18 uses it too (it was that patch that led to me re-doing this one and posting a v3.5)
Nevermind then :) -- Andrea Bolognani / Red Hat / Virtualization

Previously libvirt would only add pci-bridge devices automatically when an address was requested for a device that required a legacy PCI slot and none was available. This patch expands that support to dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a machine with a pcie-root), and pcie-root-port (which is needed to add a hotpluggable PCIe device). It does *not* automatically add pcie-switch-upstream-ports or pcie-switch-downstream-ports (and currently there are no plans for that). Given the existing code to auto-add pci-bridge devices, automatically adding pcie-root-ports is fairly straightforward. The dmi-to-pci-bridge support is a bit tricky though, for a few reasons: 1) Although the only reason to add a dmi-to-pci-bridge is so that there is a reasonable place to plug in a pci-bridge controller, most of the time it's not the presence of a pci-bridge *in the config* that triggers the requirement to add a dmi-to-pci-bridge. Rather, it is the presence of a legacy-PCI device in the config, which triggers auto-add of a pci-bridge, which triggers auto-add of a dmi-to-pci-bridge (this is handled in virDomainPCIAddressSetGrow() - if there's a request to add a pci-bridge we'll check if there is a suitable bus to plug it into; if not, we first add a dmi-to-pci-bridge). 2) Once there is already a single dmi-to-pci-bridge on the system, there won't be a need for any more, even if it's full, as long as there is a pci-bridge with an open slot - you can also plug pci-bridges into existing pci-bridges. So we have to make sure we don't add a dmi-to-pci-bridge unless there aren't any dmi-to-pci-bridges *or* any pci-bridges. 3) Although it is strongly discouraged, it is legal for a pci-bridge to be directly plugged into pcie-root, and we don't want to auto-add a dmi-to-pci-bridge if there is already a pci-bridge that's been forced directly into pcie-root. Finally, although I fail to see the utility of it, it is legal to have something like this in the xml: <controller type='pci' model='pcie-root' index='0'/> <controller type='pci' model='pci-bridge' index='2'/> and that will lead to an automatically added dmi-to-pci-bridge at index=1 (to give the unaddressed pci-bridge a proper place to plug in): <controller type='pci' model='dmi-to-pci-bridge' index='1'/> (for example, see the existing test case "usb-controller-default-q35"). This is handled in qemuDomainPCIAddressSetCreate() when it's adding in controllers to fill holes in the indexes. Although libvirt will now automatically create a dmi-to-pci-bridge when it's needed, the code still remains for now that forces a dmi-to-pci-bridge on all domains with pcie-root (in qemuDomainDefAddDefaultDevices()). That will be removed in the next patch. For now, the pcie-root-ports are added one to a slot, which is a bit wasteful and means it will fail after 31 total PCIe devices (30 if there are also some PCI devices), but helps keep the changeset down for this patch. A future patch will have 8 pcie-root-ports sharing the functions on a single slot. --- src/conf/domain_addr.c | 88 ++++++++++-- src/qemu/qemu_domain_address.c | 91 ++++++++++--- .../qemuxml2argv-q35-pcie-autoadd.args | 57 ++++++++ .../qemuxml2argv-q35-pcie-autoadd.xml | 51 +++++++ tests/qemuxml2argvtest.c | 23 ++++ .../qemuxml2xmlout-q35-pcie-autoadd.xml | 147 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 23 ++++ 7 files changed, 448 insertions(+), 32 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 12b5cb2..5f6f6f7 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -82,6 +82,30 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model) return 0; } + +static int +virDomainPCIControllerConnectTypeToModel(virDomainPCIConnectFlags flags) +{ + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE) + return VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; + if (flags & VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS) + return VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS; + if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) + return VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + + /* some connect types don't correspond to a controller model */ + return -1; +} + + bool virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr, const char *addrStr, @@ -349,32 +373,72 @@ virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, { int add; size_t i; + int model; + bool needDMIToPCIBridge = false; add = addr->bus - addrs->nbuses + 1; - i = addrs->nbuses; if (add <= 0) return 0; /* auto-grow only works when we're adding plain PCI devices */ - if (!(flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot automatically add a new PCI bus for a " - "device requiring a slot other than standard PCI.")); + if (flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) { + 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 && needDMIToPCIBridge; i++) { + if (addrs->buses[i].flags & + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) + needDMIToPCIBridge = false; + } + if (needDMIToPCIBridge && add == 1) { + /* we need to add at least two buses - one dmi-to-pci, + * and the other the requested pci-bridge + */ + add++; + addr->bus++; + } + } else if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { + model = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; + } else if (flags & (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE || + VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT)) { + model = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + } else { + int existingContModel = virDomainPCIControllerConnectTypeToModel(flags); + + if (existingContModel >= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("a PCI slot is needed to connect a PCI controller " + "model='%s', but none is available, and it " + "cannot be automatically added"), + virDomainControllerModelPCITypeToString(existingContModel)); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot automatically add a new PCI bus for a " + "device with connect Flags %.2x"), flags); + } return -1; } + i = addrs->nbuses; + if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0) return -1; - for (; i < addrs->nbuses; i++) { - /* Any time we auto-add a bus, we will want a multi-slot - * bus. Currently the only type of bus we will auto-add is a - * pci-bridge, which is hot-pluggable and provides standard - * PCI slots. + if (needDMIToPCIBridge) { + /* first of the new buses is dmi-to-pci-bridge, the + * rest are of the requested type */ - virDomainPCIAddressBusSetModel(&addrs->buses[i], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE); + virDomainPCIAddressBusSetModel(&addrs->buses[i++], + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE); } + + for (; i < addrs->nbuses; i++) + virDomainPCIAddressBusSetModel(&addrs->buses[i], model); + return add; } diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 1ff80e3..a9c4c32 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -797,6 +797,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, { virDomainPCIAddressSetPtr addrs; size_t i; + bool hasPCIeRoot = false; + int lowestDMIToPCIBridge = nbuses; + int lowestUnaddressedPCIBridge = nbuses; + int lowestAddressedPCIBridge = nbuses; + virDomainControllerModelPCI defaultModel; if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) return NULL; @@ -804,38 +809,84 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, addrs->nbuses = nbuses; addrs->dryRun = dryRun; - /* As a safety measure, set default model='pci-root' for first pci - * controller and 'pci-bridge' for all subsequent. After setting - * those defaults, then scan the config and set the actual model - * for all addrs[idx]->bus that already have a corresponding - * controller in the config. - * - */ - if (nbuses > 0) - virDomainPCIAddressBusSetModel(&addrs->buses[0], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT); - for (i = 1; i < nbuses; i++) { - virDomainPCIAddressBusSetModel(&addrs->buses[i], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE); - } - for (i = 0; i < def->ncontrollers; i++) { - size_t idx = def->controllers[i]->idx; + virDomainControllerDefPtr cont = def->controllers[i]; + size_t idx = cont->idx; - if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) continue; if (idx >= addrs->nbuses) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Inappropriate new pci controller index %zu " - "not found in addrs"), idx); + "exceeds addrs array length"), idx); goto error; } - if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], - def->controllers[i]->model) < 0) + if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; + + /* we'll use all this info later to determine if we need + * to add a dmi-to-pci-bridge due to unaddressed pci-bridge controllers + */ + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) { + hasPCIeRoot = true; + } else if (cont->model == + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) { + if (lowestDMIToPCIBridge > idx) + lowestDMIToPCIBridge = idx; + } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) { + if (virDeviceInfoPCIAddressWanted(&cont->info)) { + if (lowestUnaddressedPCIBridge > idx) + lowestUnaddressedPCIBridge = idx; + } else { + if (lowestAddressedPCIBridge > idx) + lowestAddressedPCIBridge = idx; + } } + } + + if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) + goto error; + } + + /* Now fill in a reasonable model for all the buses in the set + * that don't yet have a corresponding controller in the domain + * config. In the rare (and actually fairly idiotic, but still + * allowed for some reason) case that a domain has 1) a pcie-root + * at index 0, 2) *no* dmi-to-pci-bridge (or pci-bridge that was + * manually addressed to sit directly on pcie-root), and 3) does + * have an unaddressed pci-bridge at an index > 1, then we need to + * add a dmi-to-pci-bridge. + */ + + if (!hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + + else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge, + lowestDMIToPCIBridge)) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; + else + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + + for (i = 1; i < addrs->nbuses; i++) { + + if (addrs->buses[i].model) + continue; + + if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) < 0) + goto error; + + VIR_DEBUG("Auto-adding <controller type='pci' model='%s' index='%zu'/>", + virDomainControllerModelPCITypeToString(defaultModel), i); + /* only add a single dmi-to-pci-bridge, then add pcie-root-port + * for any other unspecified controller indexes. + */ + if (hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + } if (virDomainDeviceInfoIterate(def, qemuDomainCollectPCIAddress, addrs) < 0) goto error; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args new file mode 100644 index 0000000..6bea3e4 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args @@ -0,0 +1,57 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/libexec/qemu-kvm \ +-name q35-test \ +-S \ +-M q35 \ +-m 2048 \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \ +-no-acpi \ +-boot c \ +-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device ioh3420,port=0x10,chassis=2,id=pci.2,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=3,id=pci.3,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=4,id=pci.4,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=5,id=pci.5,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=6,id=pci.6,bus=pcie.0,addr=0x6 \ +-device ioh3420,port=0x38,chassis=7,id=pci.7,bus=pcie.0,addr=0x7 \ +-device ioh3420,port=0x40,chassis=8,id=pci.8,bus=pcie.0,addr=0x8 \ +-device ioh3420,port=0x48,chassis=9,id=pci.9,bus=pcie.0,addr=0x9 \ +-device ioh3420,port=0x50,chassis=10,id=pci.10,bus=pcie.0,addr=0xa \ +-device ioh3420,port=0x58,chassis=11,id=pci.11,bus=pcie.0,addr=0xb \ +-device ioh3420,port=0x60,chassis=12,id=pci.12,bus=pcie.0,addr=0xc \ +-device ioh3420,port=0x68,chassis=13,id=pci.13,bus=pcie.0,addr=0xd \ +-device ioh3420,port=0x70,chassis=14,id=pci.14,bus=pcie.0,addr=0xe \ +-device nec-usb-xhci,id=usb,bus=pci.7,addr=0x0 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.6,addr=0x0 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.5,addr=0x0 \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk1 \ +-device virtio-blk-pci,bus=pci.8,addr=0x0,drive=drive-virtio-disk1,\ +id=virtio-disk1 \ +-fsdev local,security_model=passthrough,id=fsdev-fs0,path=/export/to/guest \ +-device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=/import/from/host,\ +bus=pci.2,addr=0x0 \ +-netdev user,id=hostnet0 \ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.3,\ +addr=0x0 \ +-netdev user,id=hostnet1 \ +-device e1000e,netdev=hostnet1,id=net1,mac=00:11:22:33:44:66,bus=pci.4,\ +addr=0x0 \ +-device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.11,\ +addr=0x0 \ +-device virtio-mouse-pci,id=input1,bus=pci.12,addr=0x0 \ +-device virtio-keyboard-pci,id=input2,bus=pci.13,addr=0x0 \ +-device virtio-tablet-pci,id=input3,bus=pci.14,addr=0x0 \ +-device virtio-vga,id=video0,bus=pcie.0,addr=0x1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.9,addr=0x0 \ +-object rng-random,id=objrng0,filename=/dev/urandom \ +-device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,\ +bus=pci.10,addr=0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.xml new file mode 100644 index 0000000..06cdf61 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.xml @@ -0,0 +1,51 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <controller type='virtio-serial'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='usb' model='nec-xhci'/> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + </disk> + <filesystem type='mount'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + </filesystem> + <video> + <model type='virtio'/> + </video> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + </interface> + <interface type='user'> + <mac address='00:11:22:33:44:66'/> + <model type='e1000e'/> + </interface> + <memballoon model='virtio'/> + <rng model='virtio'> + <rate bytes='123' period='1234'/> + <backend model='random'>/dev/urandom</backend> + </rng> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + </input> + <input type='mouse' bus='virtio'/> + <input type='keyboard' bus='virtio'/> + <input type='tablet' bus='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a7e21fd..cfa522c 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1739,6 +1739,29 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + /* same as q35-pcie, but all PCI controllers are added automatically */ + DO_TEST("q35-pcie-autoadd", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root-port", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml new file mode 100644 index 0000000..b27dbe7 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml @@ -0,0 +1,147 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + </disk> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + </controller> + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='2' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x40'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x48'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='10' port='0x50'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='11' port='0x58'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='12' port='0x60'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='13' port='0x68'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='14' port='0x70'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + </controller> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </filesystem> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </interface> + <interface type='user'> + <mac address='00:11:22:33:44:66'/> + <model type='e1000e'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </interface> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + </input> + <input type='keyboard' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + </input> + <input type='tablet' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0e' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <rate bytes='123' period='1234'/> + <backend model='random'>/dev/urandom</backend> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + </rng> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 93f465d..4757093 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -733,6 +733,29 @@ mymain(void) QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + /* same as q35-pcie, but all PCI controllers are added automatically */ + DO_TEST("q35-pcie-autoadd", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Previously libvirt would only add pci-bridge devices automatically when an address was requested for a device that required a legacy PCI slot and none was available. This patch expands that support to dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a machine with a pcie-root), and pcie-root-port (which is needed to add a hotpluggable PCIe device). It does *not* automatically add pcie-switch-upstream-ports or pcie-switch-downstream-ports (and currently there are no plans for that). Given the existing code to auto-add pci-bridge devices, automatically adding pcie-root-ports is fairly straightforward. The dmi-to-pci-bridge support is a bit tricky though, for a few reasons: 1) Although the only reason to add a dmi-to-pci-bridge is so that there is a reasonable place to plug in a pci-bridge controller, most of the time it's not the presence of a pci-bridge *in the config* that triggers the requirement to add a dmi-to-pci-bridge. Rather, it is the presence of a legacy-PCI device in the config, which triggers auto-add of a pci-bridge, which triggers auto-add of a dmi-to-pci-bridge (this is handled in virDomainPCIAddressSetGrow() - if there's a request to add a pci-bridge we'll check if there is a suitable bus to plug it into; if not, we first add a dmi-to-pci-bridge). 2) Once there is already a single dmi-to-pci-bridge on the system, there won't be a need for any more, even if it's full, as long as there is a pci-bridge with an open slot - you can also plug pci-bridges into existing pci-bridges. So we have to make sure we don't add a dmi-to-pci-bridge unless there aren't any dmi-to-pci-bridges *or* any pci-bridges. 3) Although it is strongly discouraged, it is legal for a pci-bridge to be directly plugged into pcie-root, and we don't want to auto-add a dmi-to-pci-bridge if there is already a pci-bridge that's been forced directly into pcie-root. Finally, although I fail to see the utility of it, it is legal to have something like this in the xml: <controller type='pci' model='pcie-root' index='0'/> <controller type='pci' model='pci-bridge' index='2'/> and that will lead to an automatically added dmi-to-pci-bridge at index=1 (to give the unaddressed pci-bridge a proper place to plug in): <controller type='pci' model='dmi-to-pci-bridge' index='1'/> (for example, see the existing test case "usb-controller-default-q35"). This is handled in qemuDomainPCIAddressSetCreate() when it's adding in controllers to fill holes in the indexes.
I wonder how this "feature" came to be... It seems to be the reason for quite a bit of convoluted code down below, which we could avoid if this had never worked at all. As is so often the case, too late for that :(
Although libvirt will now automatically create a dmi-to-pci-bridge when it's needed, the code still remains for now that forces a dmi-to-pci-bridge on all domains with pcie-root (in qemuDomainDefAddDefaultDevices()). That will be removed in the next patch. For now, the pcie-root-ports are added one to a slot, which is a bit wasteful and means it will fail after 31 total PCIe devices (30 if there are also some PCI devices), but helps keep the changeset down for this patch. A future patch will have 8 pcie-root-ports sharing the functions on a single slot. --- src/conf/domain_addr.c | 88 ++++++++++-- src/qemu/qemu_domain_address.c | 91 ++++++++++--- .../qemuxml2argv-q35-pcie-autoadd.args | 57 ++++++++ .../qemuxml2argv-q35-pcie-autoadd.xml | 51 +++++++ tests/qemuxml2argvtest.c | 23 ++++ .../qemuxml2xmlout-q35-pcie-autoadd.xml | 147 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 23 ++++ 7 files changed, 448 insertions(+), 32 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 12b5cb2..5f6f6f7 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -82,6 +82,30 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model) return 0; } + +static int
s/int/virDomainControllerModelPCI/
+virDomainPCIControllerConnectTypeToModel(virDomainPCIConnectFlags flags) +{ + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE) + return VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; + if (flags & VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS) + return VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS; + if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) + return VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + + /* some connect types don't correspond to a controller model */ + return -1; +} + + bool virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr, const char *addrStr,
The comment right above the function states: /* Ensure addr fits in the address set, by expanding it if needed. * This will only grow if the flags say that we need a normal * hot-pluggable PCI slot. If we need a different type of slot, it * will fail. The bit about it only working when the connect flags indicate we need a hotpluggable legacy PCI slot is of course no longer accurate and should be updated, or possibly even removed altogether.
@@ -349,32 +373,72 @@ virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, { int add; size_t i; + int model;
s/int/virDomainControllerModelPCI/
+ bool needDMIToPCIBridge = false; add = addr->bus - addrs->nbuses + 1; - i = addrs->nbuses; if (add <= 0) return 0; /* auto-grow only works when we're adding plain PCI devices */
No longer accurate.
- if (!(flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot automatically add a new PCI bus for a " - "device requiring a slot other than standard PCI.")); + if (flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) { + 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 && needDMIToPCIBridge; i++) { + if (addrs->buses[i].flags & + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE)
Join those two lines.
+ needDMIToPCIBridge = false; + }
I feel like needDMIToPCIBridge = true; for (i = 0; i < addrs->nbuses; i++) { if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { needDMIToPCIBridge = false; break; } } would be slightly more readable, but either way is fine.
+ if (needDMIToPCIBridge && add == 1) { + /* we need to add at least two buses - one dmi-to-pci, + * and the other the requested pci-bridge + */ + add++; + addr->bus++; + } + } else if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { + model = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE;
I'm not so clear on this bit: if we're growing the address set to plug in a pci-bridge, can we just go ahead and assume a dmi-to-pci-bridge is what we need? What about eg. pseries machine types, where dmi-to-pci-bridge is not usable?
+ } else if (flags & (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE || + VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT)) {
Bitwise operations tend to trip me up, but shouldn't you be using | instead of || here? Alternatively you could turn it into if ((flags & VIR_PCI_CONNECT_PCIE_DEVICE) || (flags & VIR_PCI_CONNECT_PCIE_SWITCH_UPSTREAM_PORT)) which is more obviously correct and also nicer to look at :)
+ model = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + } else { + int existingContModel = virDomainPCIControllerConnectTypeToModel(flags);
s/int/virDomainControllerModelPCI/ It would be also neat if you could make the variable name shorter. With a scope this limited, pretty much anything would do.
+ if (existingContModel >= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("a PCI slot is needed to connect a PCI controller " + "model='%s', but none is available, and it " + "cannot be automatically added"), + virDomainControllerModelPCITypeToString(existingContModel)); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot automatically add a new PCI bus for a " + "device with connect Flags %.2x"), flags);
s/Flags/flags/
+ } return -1; } + i = addrs->nbuses; + if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0) return -1; - for (; i < addrs->nbuses; i++) { - /* Any time we auto-add a bus, we will want a multi-slot - * bus. Currently the only type of bus we will auto-add is a - * pci-bridge, which is hot-pluggable and provides standard - * PCI slots. + if (needDMIToPCIBridge) { + /* first of the new buses is dmi-to-pci-bridge, the + * rest are of the requested type */ - virDomainPCIAddressBusSetModel(&addrs->buses[i], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE); + virDomainPCIAddressBusSetModel(&addrs->buses[i++], + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE); } + + for (; i < addrs->nbuses; i++) + virDomainPCIAddressBusSetModel(&addrs->buses[i], model); + return add; } diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 1ff80e3..a9c4c32 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -797,6 +797,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, { virDomainPCIAddressSetPtr addrs; size_t i; + bool hasPCIeRoot = false; + int lowestDMIToPCIBridge = nbuses; + int lowestUnaddressedPCIBridge = nbuses; + int lowestAddressedPCIBridge = nbuses;
s/int/unsigned int/g
+ virDomainControllerModelPCI defaultModel; if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) return NULL; @@ -804,38 +809,84 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, addrs->nbuses = nbuses; addrs->dryRun = dryRun; - /* As a safety measure, set default model='pci-root' for first pci - * controller and 'pci-bridge' for all subsequent. After setting - * those defaults, then scan the config and set the actual model - * for all addrs[idx]->bus that already have a corresponding - * controller in the config. - * - */ - if (nbuses > 0) - virDomainPCIAddressBusSetModel(&addrs->buses[0], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT); - for (i = 1; i < nbuses; i++) { - virDomainPCIAddressBusSetModel(&addrs->buses[i], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE); - } - for (i = 0; i < def->ncontrollers; i++) { - size_t idx = def->controllers[i]->idx; + virDomainControllerDefPtr cont = def->controllers[i];
Again, love this, but it should really be its own separate commit :)
+ size_t idx = cont->idx; - if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) continue; if (idx >= addrs->nbuses) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Inappropriate new pci controller index %zu " - "not found in addrs"), idx); + "exceeds addrs array length"), idx);
... And this as well, I guess?
goto error; } - if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], - def->controllers[i]->model) < 0) + if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; + + /* we'll use all this info later to determine if we need + * to add a dmi-to-pci-bridge due to unaddressed pci-bridge controllers + */ + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) { + hasPCIeRoot = true; + } else if (cont->model == + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) {
These can be a single line - we apparently don't really care about enforcing the 80 column limit :)
+ if (lowestDMIToPCIBridge > idx) + lowestDMIToPCIBridge = idx; + } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) { + if (virDeviceInfoPCIAddressWanted(&cont->info)) { + if (lowestUnaddressedPCIBridge > idx) + lowestUnaddressedPCIBridge = idx; + } else { + if (lowestAddressedPCIBridge > idx) + lowestAddressedPCIBridge = idx; + } } + } + + if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) + goto error; + }
Shouldn't we use either PCI_ROOT or PCIE_ROOT based on the machine type here? And set hasPCIeRoot *after* doing so? Sorry for the questions, I guess this is the point in the patch where I got a bit lost :(
+ /* Now fill in a reasonable model for all the buses in the set + * that don't yet have a corresponding controller in the domain + * config. In the rare (and actually fairly idiotic, but still + * allowed for some reason) case that a domain has 1) a pcie-root + * at index 0, 2) *no* dmi-to-pci-bridge (or pci-bridge that was + * manually addressed to sit directly on pcie-root), and 3) does + * have an unaddressed pci-bridge at an index > 1, then we need to + * add a dmi-to-pci-bridge. + */ + + if (!hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE;
Add curly braces here as well as below.
+ else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge, + lowestDMIToPCIBridge)) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE;
Again, a bit lost here, sorry :( Basically if we've found a PCI bridge without address that can't be plugged into any existing PCI bridge or DMI-to-PCI bridge, we want to add a DMI-to-PCI bridge so that we have somewhere to plug it in, right?
+ else + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + + for (i = 1; i < addrs->nbuses; i++) { + + if (addrs->buses[i].model) + continue; + + if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) < 0) + goto error; + + VIR_DEBUG("Auto-adding <controller type='pci' model='%s' index='%zu'/>", + virDomainControllerModelPCITypeToString(defaultModel), i); + /* only add a single dmi-to-pci-bridge, then add pcie-root-port + * for any other unspecified controller indexes. + */ + if (hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
Okay, so * if the machine has a PCIe Root Bus and we have a PCI bridge that we don't know where to plug (no existing legacy PCI hierarchy below it), we add a single DMI-to-PCI bridge and then plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need * if the machine has a PCIe Root Bus and we're not in the situation above when it comes to PCI bridges (there is an existing legacy PCI hierarchy below it), we plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need * otherwise (no PCIe Root Bus) we just plug PCI bridges into PCI bridges until we have as many buses as we need Does that sound about right?
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a7e21fd..cfa522c 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1739,6 +1739,29 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + /* same as q35-pcie, but all PCI controllers are added automatically */ + DO_TEST("q35-pcie-autoadd", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1,
You've used one line per capability everywhere except for this line. Same for test cases added earlier in the series, now that I look at it. Weird :)
+ QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root-port", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml new file mode 100644 index 0000000..b27dbe7 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml @@ -0,0 +1,147 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + </disk> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + </controller> + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller>
A DMI-to-PCI bridge with index='1' has been added automatically here...
+ <controller type='pci' index='2' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='2' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x40'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x48'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='10' port='0x50'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='11' port='0x58'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='12' port='0x60'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='13' port='0x68'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='14' port='0x70'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + </controller> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </filesystem> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </interface> + <interface type='user'> + <mac address='00:11:22:33:44:66'/> + <model type='e1000e'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </interface> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + </input> + <input type='keyboard' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + </input> + <input type='tablet' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0e' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <rate bytes='123' period='1234'/> + <backend model='random'>/dev/urandom</backend> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + </rng>
... but it's not being used by any of the devices. So why would it be added in the first place? -- Andrea Bolognani / Red Hat / Virtualization

On 10/10/2016 02:14 PM, Andrea Bolognani wrote:
On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Previously libvirt would only add pci-bridge devices automatically when an address was requested for a device that required a legacy PCI slot and none was available. This patch expands that support to dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a machine with a pcie-root), and pcie-root-port (which is needed to add a hotpluggable PCIe device). It does *not* automatically add pcie-switch-upstream-ports or pcie-switch-downstream-ports (and currently there are no plans for that).
Given the existing code to auto-add pci-bridge devices, automatically adding pcie-root-ports is fairly straightforward. The dmi-to-pci-bridge support is a bit tricky though, for a few reasons:
1) Although the only reason to add a dmi-to-pci-bridge is so that there is a reasonable place to plug in a pci-bridge controller, most of the time it's not the presence of a pci-bridge *in the config* that triggers the requirement to add a dmi-to-pci-bridge. Rather, it is the presence of a legacy-PCI device in the config, which triggers auto-add of a pci-bridge, which triggers auto-add of a dmi-to-pci-bridge (this is handled in virDomainPCIAddressSetGrow() - if there's a request to add a pci-bridge we'll check if there is a suitable bus to plug it into; if not, we first add a dmi-to-pci-bridge).
2) Once there is already a single dmi-to-pci-bridge on the system, there won't be a need for any more, even if it's full, as long as there is a pci-bridge with an open slot - you can also plug pci-bridges into existing pci-bridges. So we have to make sure we don't add a dmi-to-pci-bridge unless there aren't any dmi-to-pci-bridges *or* any pci-bridges.
3) Although it is strongly discouraged, it is legal for a pci-bridge to be directly plugged into pcie-root, and we don't want to auto-add a dmi-to-pci-bridge if there is already a pci-bridge that's been forced directly into pcie-root. Finally, although I fail to see the utility of it, it is legal to have something like this in the xml:
<controller type='pci' model='pcie-root' index='0'/> <controller type='pci' model='pci-bridge' index='2'/>
and that will lead to an automatically added dmi-to-pci-bridge at index=1 (to give the unaddressed pci-bridge a proper place to plug in):
<controller type='pci' model='dmi-to-pci-bridge' index='1'/>
(for example, see the existing test case "usb-controller-default-q35"). This is handled in qemuDomainPCIAddressSetCreate() when it's adding in controllers to fill holes in the indexes. I wonder how this "feature" came to be... It seems to be the reason for quite a bit of convoluted code down below, which we could avoid if this had never worked at all. As is so often the case, too late for that :(
Maybe not. The only place I ever saw that was in the above test case, and another named "usb-controller-explicit-q35", and the author of both of those tests was (wait for it!), no, not Albert Einstein. Andrea Bolognani! The only reason it worked in the past was because we always automatically added the dmi-to-pci-bridge very early in the post-parse processing. This implies that any saved config anywhere will already have the necessary dmi-to-pci-bridge at index='1', so we only need to preserve the behavior for new domain definitions that have a pci-bridge at index='2' but nothing at index='1'. Since you're the only person documented to have ever created a config like that, and it would only be problematic if someone tried to create another new config, maybe we should just stop accidentally supporting it and count it as a bug that's being fixed. What's your opinion?
Although libvirt will now automatically create a dmi-to-pci-bridge when it's needed, the code still remains for now that forces a dmi-to-pci-bridge on all domains with pcie-root (in qemuDomainDefAddDefaultDevices()). That will be removed in the next patch.
For now, the pcie-root-ports are added one to a slot, which is a bit wasteful and means it will fail after 31 total PCIe devices (30 if there are also some PCI devices), but helps keep the changeset down for this patch. A future patch will have 8 pcie-root-ports sharing the functions on a single slot. --- src/conf/domain_addr.c | 88 ++++++++++-- src/qemu/qemu_domain_address.c | 91 ++++++++++--- .../qemuxml2argv-q35-pcie-autoadd.args | 57 ++++++++ .../qemuxml2argv-q35-pcie-autoadd.xml | 51 +++++++ tests/qemuxml2argvtest.c | 23 ++++ .../qemuxml2xmlout-q35-pcie-autoadd.xml | 147 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 23 ++++ 7 files changed, 448 insertions(+), 32 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 12b5cb2..5f6f6f7 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -82,6 +82,30 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model) return 0; }
+ +static int s/int/virDomainControllerModelPCI/
But then we can't return -1 when there isn't a perfect match (that's why I made it int)
+virDomainPCIControllerConnectTypeToModel(virDomainPCIConnectFlags flags) +{ + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT; + if (flags & VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE) + return VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; + if (flags & VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS) + return VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS; + if (flags & VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS) + return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS; + if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) + return VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + + /* some connect types don't correspond to a controller model */ + return -1; +} + + bool virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr, const char *addrStr, The comment right above the function states:
/* Ensure addr fits in the address set, by expanding it if needed. * This will only grow if the flags say that we need a normal * hot-pluggable PCI slot. If we need a different type of slot, it * will fail.
The bit about it only working when the connect flags indicate we need a hotpluggable legacy PCI slot is of course no longer accurate and should be updated, or possibly even removed altogether.
Yeah, I missed that.
@@ -349,32 +373,72 @@ virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, { int add; size_t i; + int model; s/int/virDomainControllerModelPCI/
+ bool needDMIToPCIBridge = false;
add = addr->bus - addrs->nbuses + 1; - i = addrs->nbuses; if (add <= 0) return 0;
/* auto-grow only works when we're adding plain PCI devices */ No longer accurate.
Yeah, missed that too.
- if (!(flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot automatically add a new PCI bus for a " - "device requiring a slot other than standard PCI.")); + if (flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) { + 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 && needDMIToPCIBridge; i++) { + if (addrs->buses[i].flags & + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) Join those two lines.
Strange. I wonder why I did that...
+ needDMIToPCIBridge = false; + } I feel like
needDMIToPCIBridge = true; for (i = 0; i < addrs->nbuses; i++) { if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { needDMIToPCIBridge = false; break; } }
would be slightly more readable, but either way is fine.
+ if (needDMIToPCIBridge && add == 1) { + /* we need to add at least two buses - one dmi-to-pci, + * and the other the requested pci-bridge + */ + add++; + addr->bus++; + } + } else if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { + model = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; I'm not so clear on this bit: if we're growing the address set to plug in a pci-bridge, can we just go ahead and assume a dmi-to-pci-bridge is what we need? What about eg. pseries machine types, where dmi-to-pci-bridge is not usable?
+ } else if (flags & (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE || + VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT)) { Bitwise operations tend to trip me up, but shouldn't you be using | instead of || here?
Yes. That's a typo. I'm surprised it's working...
Alternatively you could turn it into
if ((flags & VIR_PCI_CONNECT_PCIE_DEVICE) || (flags & VIR_PCI_CONNECT_PCIE_SWITCH_UPSTREAM_PORT))
which is more obviously correct and also nicer to look at :)
....but takes two operations instead of one.
+ model = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + } else { + int existingContModel = virDomainPCIControllerConnectTypeToModel(flags); s/int/virDomainControllerModelPCI/
Can't do that, because then you can't detect a "failure"
It would be also neat if you could make the variable name shorter. With a scope this limited, pretty much anything would do.
+ if (existingContModel >= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("a PCI slot is needed to connect a PCI controller " + "model='%s', but none is available, and it " + "cannot be automatically added"), + virDomainControllerModelPCITypeToString(existingContModel)); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot automatically add a new PCI bus for a " + "device with connect Flags %.2x"), flags); s/Flags/flags/
+ } return -1; }
+ i = addrs->nbuses; + if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0) return -1;
- for (; i < addrs->nbuses; i++) { - /* Any time we auto-add a bus, we will want a multi-slot - * bus. Currently the only type of bus we will auto-add is a - * pci-bridge, which is hot-pluggable and provides standard - * PCI slots. + if (needDMIToPCIBridge) { + /* first of the new buses is dmi-to-pci-bridge, the + * rest are of the requested type */ - virDomainPCIAddressBusSetModel(&addrs->buses[i], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE); + virDomainPCIAddressBusSetModel(&addrs->buses[i++], + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE); } + + for (; i < addrs->nbuses; i++) + virDomainPCIAddressBusSetModel(&addrs->buses[i], model); + return add; }
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 1ff80e3..a9c4c32 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -797,6 +797,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, { virDomainPCIAddressSetPtr addrs; size_t i; + bool hasPCIeRoot = false; + int lowestDMIToPCIBridge = nbuses; + int lowestUnaddressedPCIBridge = nbuses; + int lowestAddressedPCIBridge = nbuses; s/int/unsigned int/g
+ virDomainControllerModelPCI defaultModel;
if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) return NULL; @@ -804,38 +809,84 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, addrs->nbuses = nbuses; addrs->dryRun = dryRun;
- /* As a safety measure, set default model='pci-root' for first pci - * controller and 'pci-bridge' for all subsequent. After setting - * those defaults, then scan the config and set the actual model - * for all addrs[idx]->bus that already have a corresponding - * controller in the config. - * - */ - if (nbuses > 0) - virDomainPCIAddressBusSetModel(&addrs->buses[0], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT); - for (i = 1; i < nbuses; i++) { - virDomainPCIAddressBusSetModel(&addrs->buses[i], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE); - } - for (i = 0; i < def->ncontrollers; i++) { - size_t idx = def->controllers[i]->idx; + virDomainControllerDefPtr cont = def->controllers[i]; Again, love this, but it should really be its own separate commit :)
+ size_t idx = cont->idx;
- if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) continue;
if (idx >= addrs->nbuses) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Inappropriate new pci controller index %zu " - "not found in addrs"), idx); + "exceeds addrs array length"), idx); ... And this as well, I guess?
goto error; }
- if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], - def->controllers[i]->model) < 0) + if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; + + /* we'll use all this info later to determine if we need + * to add a dmi-to-pci-bridge due to unaddressed pci-bridge controllers + */ + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) { + hasPCIeRoot = true; + } else if (cont->model == + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) {
These can be a single line - we apparently don't really care about enforcing the 80 column limit :)
+ if (lowestDMIToPCIBridge > idx) + lowestDMIToPCIBridge = idx; + } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) { + if (virDeviceInfoPCIAddressWanted(&cont->info)) { + if (lowestUnaddressedPCIBridge > idx) + lowestUnaddressedPCIBridge = idx; + } else { + if (lowestAddressedPCIBridge > idx) + lowestAddressedPCIBridge = idx; + } } + } + + if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) + goto error; + } Shouldn't we use either PCI_ROOT or PCIE_ROOT based on the machine type here? And set hasPCIeRoot *after* doing so?
Sorry for the questions, I guess this is the point in the patch where I got a bit lost :(
+ /* Now fill in a reasonable model for all the buses in the set + * that don't yet have a corresponding controller in the domain + * config. In the rare (and actually fairly idiotic, but still + * allowed for some reason) case that a domain has 1) a pcie-root + * at index 0, 2) *no* dmi-to-pci-bridge (or pci-bridge that was + * manually addressed to sit directly on pcie-root), and 3) does + * have an unaddressed pci-bridge at an index > 1, then we need to + * add a dmi-to-pci-bridge. + */ + + if (!hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; Add curly braces here as well as below.
+ else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge, + lowestDMIToPCIBridge)) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; Again, a bit lost here, sorry :(
Basically if we've found a PCI bridge without address that can't be plugged into any existing PCI bridge or DMI-to-PCI bridge, we want to add a DMI-to-PCI bridge so that we have somewhere to plug it in, right?
+ else + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + + for (i = 1; i < addrs->nbuses; i++) { + + if (addrs->buses[i].model) + continue; + + if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) < 0) + goto error; + + VIR_DEBUG("Auto-adding <controller type='pci' model='%s' index='%zu'/>", + virDomainControllerModelPCITypeToString(defaultModel), i); + /* only add a single dmi-to-pci-bridge, then add pcie-root-port + * for any other unspecified controller indexes. + */ + if (hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; Okay, so
* if the machine has a PCIe Root Bus and we have a PCI bridge that we don't know where to plug (no existing legacy PCI hierarchy below it), we add a single DMI-to-PCI bridge and then plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need
You mean "plug pcie-root-ports into pcie-root".
* if the machine has a PCIe Root Bus and we're not in the situation above when it comes to PCI bridges (there is an existing legacy PCI hierarchy below it), we plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need
* otherwise (no PCIe Root Bus) we just plug PCI bridges into PCI bridges until we have as many buses as we need
Does that sound about right?
Yep.
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a7e21fd..cfa522c 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1739,6 +1739,29 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + /* same as q35-pcie, but all PCI controllers are added automatically */ + DO_TEST("q35-pcie-autoadd", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, You've used one line per capability everywhere except for this line. Same for test cases added earlier in the series, now that I look at it. Weird :)
Likely copy-pasted from somewhere else.
+ QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root-port", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml new file mode 100644 index 0000000..b27dbe7 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml @@ -0,0 +1,147 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='vdb' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + </disk> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + </controller> + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> A DMI-to-PCI bridge with index='1' has been added automatically here...
+ <controller type='pci' index='2' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='2' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x40'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x48'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='10' port='0x50'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='11' port='0x58'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='12' port='0x60'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='13' port='0x68'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='14' port='0x70'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + </controller> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/export/to/guest'/> + <target dir='/import/from/host'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </filesystem> + <interface type='user'> + <mac address='00:11:22:33:44:55'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </interface> + <interface type='user'> + <mac address='00:11:22:33:44:66'/> + <model type='e1000e'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </interface> + <input type='passthrough' bus='virtio'> + <source evdev='/dev/input/event1234'/> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + </input> + <input type='keyboard' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + </input> + <input type='tablet' bus='virtio'> + <address type='pci' domain='0x0000' bus='0x0e' slot='0x00' function='0x0'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <video> + <model type='virtio' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <rate bytes='123' period='1234'/> + <backend model='random'>/dev/urandom</backend> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + </rng> ... but it's not being used by any of the devices. So why would it be added in the first place?
That is a *very* good question!
-- Andrea Bolognani / Red Hat / Virtualization

On Mon, 2016-10-10 at 15:43 -0400, Laine Stump wrote:
3) Although it is strongly discouraged, it is legal for a pci-bridge to be directly plugged into pcie-root, and we don't want to auto-add a dmi-to-pci-bridge if there is already a pci-bridge that's been forced directly into pcie-root. Finally, although I fail to see the utility of it, it is legal to have something like this in the xml: <controller type='pci' model='pcie-root' index='0'/> <controller type='pci' model='pci-bridge' index='2'/> and that will lead to an automatically added dmi-to-pci-bridge at index=1 (to give the unaddressed pci-bridge a proper place to plug in): <controller type='pci' model='dmi-to-pci-bridge' index='1'/> (for example, see the existing test case "usb-controller-default-q35"). This is handled in qemuDomainPCIAddressSetCreate() when it's adding in controllers to fill holes in the indexes. I wonder how this "feature" came to be... It seems to be the reason for quite a bit of convoluted code down below, which we could avoid if this had never worked at all. As is so often the case, too late for that :( Maybe not. The only place I ever saw that was in the above test case, and another named "usb-controller-explicit-q35", and the author of both of those tests was (wait for it!), no, not Albert Einstein. Andrea Bolognani!
Oh, *that* guy! It's always *that* guy, isn't it? :P
The only reason it worked in the past was because we always automatically added the dmi-to-pci-bridge very early in the post-parse processing. This implies that any saved config anywhere will already have the necessary dmi-to-pci-bridge at index='1', so we only need to preserve the behavior for new domain definitions that have a pci-bridge at index='2' but nothing at index='1'. Since you're the only person documented to have ever created a config like that, and it would only be problematic if someone tried to create another new config, maybe we should just stop accidentally supporting it and count it as a bug that's being fixed. What's your opinion?
Given the evidence you're presenting, I'm all for getting rid of it, especially since it will make the code below much simpler and hence more maintainable. Considering how critical that part of libvirt is, anything we can do to make it leaner and meaner is going to be a huge win in the long run.
@@ -82,6 +82,30 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model) return 0; } + +static int s/int/virDomainControllerModelPCI/ But then we can't return -1 when there isn't a perfect match (that's why I made it int)
Right. Disregard my comments then :)
Alternatively you could turn it into if ((flags & VIR_PCI_CONNECT_PCIE_DEVICE) || (flags & VIR_PCI_CONNECT_PCIE_SWITCH_UPSTREAM_PORT)) which is more obviously correct and also nicer to look at :) ....but takes two operations instead of one.
I hardly think this would turn out to be a bottleneck, but feel free to stick to the original implementation - after fixing it, of course :)
+ if (lowestDMIToPCIBridge > idx) + lowestDMIToPCIBridge = idx; + } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) { + if (virDeviceInfoPCIAddressWanted(&cont->info)) { + if (lowestUnaddressedPCIBridge > idx) + lowestUnaddressedPCIBridge = idx; + } else { + if (lowestAddressedPCIBridge > idx) + lowestAddressedPCIBridge = idx; + } } + } + + if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) + goto error; + } Shouldn't we use either PCI_ROOT or PCIE_ROOT based on the machine type here? And set hasPCIeRoot *after* doing so? Sorry for the questions, I guess this is the point in the patch where I got a bit lost :(
I'm afraid you missed this question :)
+ else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge, + lowestDMIToPCIBridge)) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; Again, a bit lost here, sorry :( Basically if we've found a PCI bridge without address that can't be plugged into any existing PCI bridge or DMI-to-PCI bridge, we want to add a DMI-to-PCI bridge so that we have somewhere to plug it in, right?
And I'm pretty sure I got it right here, but just to be on the safe side, it would be great if you could confirm or deny :)
+ else + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + + for (i = 1; i < addrs->nbuses; i++) { + + if (addrs->buses[i].model) + continue; + + if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) < 0) + goto error; + + VIR_DEBUG("Auto-adding <controller type='pci' model='%s' index='%zu'/>", + virDomainControllerModelPCITypeToString(defaultModel), i); + /* only add a single dmi-to-pci-bridge, then add pcie-root-port + * for any other unspecified controller indexes. + */ + if (hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; Okay, so * if the machine has a PCIe Root Bus and we have a PCI bridge that we don't know where to plug (no existing legacy PCI hierarchy below it), we add a single DMI-to-PCI bridge and then plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need You mean "plug pcie-root-ports into pcie-root".
No, I actually meant what I wrote, but I think that thanks to your remark I see my error now. What I thought was going on was that whese additional buses were *chained* to each other, eg. the first PCIe Root Port (bus 1) would be plugged into the PCIe Root Bus (bus 0), the second PCIe Root Port (bus 2) would be plugged into the first PCIe Root Port (bus 1) and so on. What happens instead is that the first PCIe Root Port (bus 1) is plugged into the PCIe Root Bus (bus 0), and so is the second PCIe Root Port (bus 2) and all subsequent ones. Basically for a second there I forgot that the bus number doesn't increase only when increasing the depth of the PCI hierarchy, but also when increasing its breadth.
* if the machine has a PCIe Root Bus and we're not in the situation above when it comes to PCI bridges (there is an existing legacy PCI hierarchy below it), we plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need * otherwise (no PCIe Root Bus) we just plug PCI bridges into PCI bridges until we have as many buses as we need Does that sound about right? Yep.
The same as above applies, though. On the other hand, the virDomainPCIAddressSet structure doesn't really store any information about the relationship between controllers: whether eg. the PCIe Root Port providing bus 5 is plugged directly into the PCIe Root Bus, or into another PCIe Root Port, or into a PCIe Switch Downstream Port, is something that we just don't know at this stage.
+ <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> A DMI-to-PCI bridge with index='1' has been added automatically here... ... but it's not being used by any of the devices. So why would it be added in the first place? That is a *very* good question!
Can't wait to know the answer! ;) -- Andrea Bolognani / Red Hat / Virtualization

On 10/11/2016 05:34 AM, Andrea Bolognani wrote:
On Mon, 2016-10-10 at 15:43 -0400, Laine Stump wrote:
3) Although it is strongly discouraged, it is legal for a pci-bridge to be directly plugged into pcie-root, and we don't want to auto-add a dmi-to-pci-bridge if there is already a pci-bridge that's been forced directly into pcie-root. Finally, although I fail to see the utility of it, it is legal to have something like this in the xml:
<controller type='pci' model='pcie-root' index='0'/> <controller type='pci' model='pci-bridge' index='2'/>
and that will lead to an automatically added dmi-to-pci-bridge at index=1 (to give the unaddressed pci-bridge a proper place to plug in):
<controller type='pci' model='dmi-to-pci-bridge' index='1'/>
(for example, see the existing test case "usb-controller-default-q35"). This is handled in qemuDomainPCIAddressSetCreate() when it's adding in controllers to fill holes in the indexes.
I wonder how this "feature" came to be... It seems to be the reason for quite a bit of convoluted code down below, which we could avoid if this had never worked at all. As is so often the case, too late for that :(
Maybe not. The only place I ever saw that was in the above test case, and another named "usb-controller-explicit-q35", and the author of both of those tests was (wait for it!), no, not Albert Einstein. Andrea Bolognani! Oh, *that* guy! It's always *that* guy, isn't it? :P
The only reason it worked in the past was because we always automatically added the dmi-to-pci-bridge very early in the post-parse processing. This implies that any saved config anywhere will already have the necessary dmi-to-pci-bridge at index='1', so we only need to preserve the behavior for new domain definitions that have a pci-bridge at index='2' but nothing at index='1'.
Since you're the only person documented to have ever created a config like that, and it would only be problematic if someone tried to create another new config, maybe we should just stop accidentally supporting it and count it as a bug that's being fixed. What's your opinion? Given the evidence you're presenting, I'm all for getting rid of it, especially since it will make the code below much simpler and hence more maintainable.
Considering how critical that part of libvirt is, anything we can do to make it leaner and meaner is going to be a huge win in the long run.
I'm looking back through the code and wondering how to simplify it - it may be that the alternate method I had initially used (which failed that one test) is just as complicated as what I have now; unfortunately I didn't save it.
@@ -82,6 +82,30 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model) return 0; }
+ +static int s/int/virDomainControllerModelPCI/
But then we can't return -1 when there isn't a perfect match (that's why I made it int) Right. Disregard my comments then :)
Alternatively you could turn it into
if ((flags & VIR_PCI_CONNECT_PCIE_DEVICE) || (flags & VIR_PCI_CONNECT_PCIE_SWITCH_UPSTREAM_PORT))
which is more obviously correct and also nicer to look at :)
....but takes two operations instead of one. I hardly think this would turn out to be a bottleneck, but feel free to stick to the original implementation - after fixing it, of course :)
+ if (lowestDMIToPCIBridge > idx) + lowestDMIToPCIBridge = idx; + } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) { + if (virDeviceInfoPCIAddressWanted(&cont->info)) { + if (lowestUnaddressedPCIBridge > idx) + lowestUnaddressedPCIBridge = idx; + } else { + if (lowestAddressedPCIBridge > idx) + lowestAddressedPCIBridge = idx; + } } + } + + if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) + goto error; + }
Shouldn't we use either PCI_ROOT or PCIE_ROOT based on the machine type here? And set hasPCIeRoot *after* doing so?
Sorry for the questions, I guess this is the point in the patch where I got a bit lost :( I'm afraid you missed this question :)
Sorry about the omission. I've tried to limit the code that decides whether or not there should be a pci-root or a pcie-root to the one place when default controllers are being added (I forget the name of the function right now), and after that only decide based on whether a pci-root or pcie-root really is there in the config. My subconscious reasoning for this is that the extra calisthenics around supporting aarch64/virt with PCI(e) vs with mmio has made me wonder if there might be machinetypes in the future that could support one type of root bus or another (or none) according to what is in the config, rather than having a root bus just builtin to the machine. I don't know if that would ever happen, but if it did, this code would work without change - only the function adding the default controllers would need to be changed. (Note that I used the same logic when deciding how to right qemuDomainMachineHasPCI[e]Root())(still not sure about that name, but it can always be changed later to remove the "Machine" if someone doesn't like it)
+ else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge, + lowestDMIToPCIBridge)) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE;
Again, a bit lost here, sorry :(
Basically if we've found a PCI bridge without address that can't be plugged into any existing PCI bridge or DMI-to-PCI bridge, we want to add a DMI-to-PCI bridge so that we have somewhere to plug it in, right? And I'm pretty sure I got it right here, but just to be on the safe side, it would be great if you could confirm or deny :)
+ else + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + + for (i = 1; i < addrs->nbuses; i++) { + + if (addrs->buses[i].model) + continue; + + if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) < 0) + goto error; + + VIR_DEBUG("Auto-adding <controller type='pci' model='%s' index='%zu'/>", + virDomainControllerModelPCITypeToString(defaultModel), i); + /* only add a single dmi-to-pci-bridge, then add pcie-root-port + * for any other unspecified controller indexes. + */ + if (hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
Okay, so
* if the machine has a PCIe Root Bus and we have a PCI bridge that we don't know where to plug (no existing legacy PCI hierarchy below it), we add a single DMI-to-PCI bridge and then plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need
You mean "plug pcie-root-ports into pcie-root". No, I actually meant what I wrote, but I think that thanks to your remark I see my error now.
What I thought was going on was that whese additional buses were *chained* to each other, eg. the first PCIe Root Port (bus 1) would be plugged into the PCIe Root Bus (bus 0), the second PCIe Root Port (bus 2) would be plugged into the first PCIe Root Port (bus 1) and so on.
That wouldn't work because 1) pcie-root-port can only plug into pcie-root or pcie-expander-bus, and 2) even if it could plug into another pcie-root-port, there is only a single slot so you would have to plug the pcie-root-port and the endpoint device into different functions of the single slot, so hotplug would be impossible.
What happens instead is that the first PCIe Root Port (bus 1) is plugged into the PCIe Root Bus (bus 0), and so is the second PCIe Root Port (bus 2) and all subsequent ones.
Basically for a second there I forgot that the bus number doesn't increase only when increasing the depth of the PCI hierarchy, but also when increasing its breadth.
* if the machine has a PCIe Root Bus and we're not in the situation above when it comes to PCI bridges (there is an existing legacy PCI hierarchy below it), we plug PCIe Root Ports into PCIe Root Ports until we have as many buses as we need
* otherwise (no PCIe Root Bus) we just plug PCI bridges into PCI bridges until we have as many buses as we need
Does that sound about right?
Yep. The same as above applies, though.
On the other hand, the virDomainPCIAddressSet structure doesn't really store any information about the relationship between controllers: whether eg. the PCIe Root Port providing bus 5 is plugged directly into the PCIe Root Bus, or into another PCIe Root Port, or into a PCIe Switch Downstream Port, is something that we just don't know at this stage.
Yes, which may be necessary at some point - e.g. I've been thinking that we really don't want the buses that are children of a pci[e]-expander-bus to be used for auto-assigned addresses (although maybe that could just be solved with a flag that's set at the time the AddressSet is created, rather than needing to teach it the full intracacies of the topology.)
+ <controller type='pci' index='1' model='dmi-to-pci-bridge'> + <model name='i82801b11-bridge'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller>
A DMI-to-PCI bridge with index='1' has been added automatically here...
... but it's not being used by any of the devices. So why would it be added in the first place?
That is a *very* good question! Can't wait to know the answer! ;)
Oh, now that I've looked in context of the patch ordering, I undestand: it's because patch 16/18 hasn't been applied yet. I'd forgotten the ordering...

On 10/13/2016 01:43 PM, Laine Stump wrote:
On 10/11/2016 05:34 AM, Andrea Bolognani wrote:
On Mon, 2016-10-10 at 15:43 -0400, Laine Stump wrote:
3) Although it is strongly discouraged, it is legal for a pci-bridge to be directly plugged into pcie-root, and we don't want to auto-add a dmi-to-pci-bridge if there is already a pci-bridge that's been forced directly into pcie-root. Finally, although I fail to see the utility of it, it is legal to have something like this in the xml: <controller type='pci' model='pcie-root' index='0'/> <controller type='pci' model='pci-bridge' index='2'/> and that will lead to an automatically added dmi-to-pci-bridge at index=1 (to give the unaddressed pci-bridge a proper place to plug in): <controller type='pci' model='dmi-to-pci-bridge' index='1'/> (for example, see the existing test case "usb-controller-default-q35"). This is handled in qemuDomainPCIAddressSetCreate() when it's adding in controllers to fill holes in the indexes. I wonder how this "feature" came to be... It seems to be the reason for quite a bit of convoluted code down below, which we could avoid if this had never worked at all. As is so often the case, too late for that :( Maybe not. The only place I ever saw that was in the above test case, and another named "usb-controller-explicit-q35", and the author of both of those tests was (wait for it!), no, not Albert Einstein. Andrea Bolognani! Oh, *that* guy! It's always *that* guy, isn't it? :P
The only reason it worked in the past was because we always automatically added the dmi-to-pci-bridge very early in the post-parse processing. This implies that any saved config anywhere will already have the necessary dmi-to-pci-bridge at index='1', so we only need to preserve the behavior for new domain definitions that have a pci-bridge at index='2' but nothing at index='1'. Since you're the only person documented to have ever created a config like that, and it would only be problematic if someone tried to create another new config, maybe we should just stop accidentally supporting it and count it as a bug that's being fixed. What's your opinion? Given the evidence you're presenting, I'm all for getting rid of it, especially since it will make the code below much simpler and hence more maintainable.
Considering how critical that part of libvirt is, anything we can do to make it leaner and meaner is going to be a huge win in the long run.
I'm looking back through the code and wondering how to simplify it - it may be that the alternate method I had initially used (which failed that one test) is just as complicated as what I have now; unfortunately I didn't save it.
Okay, now I've reminded myself of what I did. Basically everything necessary for that is the changes to qemuDomainPCIAddressSetCreate() dealing with "lowest*Bridge" (see the patch excerpt below). I would still need to patch this function even if we didn't support "auto-adding dmi-to-pci-bridge when a pci-bridge is present in the config", but it would be slightly simpler. I'll split it into a separate patch so that it's more apparent, and we can decide based on that. On 09/20/2016 03:14 PM, Laine Stump wrote:
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 1ff80e3..a9c4c32 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -797,6 +797,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, { virDomainPCIAddressSetPtr addrs; size_t i; + bool hasPCIeRoot = false; + int lowestDMIToPCIBridge = nbuses; + int lowestUnaddressedPCIBridge = nbuses; + int lowestAddressedPCIBridge = nbuses; + virDomainControllerModelPCI defaultModel;
if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) return NULL; @@ -804,38 +809,84 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, addrs->nbuses = nbuses; addrs->dryRun = dryRun;
- /* As a safety measure, set default model='pci-root' for first pci - * controller and 'pci-bridge' for all subsequent. After setting - * those defaults, then scan the config and set the actual model - * for all addrs[idx]->bus that already have a corresponding - * controller in the config. - * - */ - if (nbuses > 0) - virDomainPCIAddressBusSetModel(&addrs->buses[0], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT); - for (i = 1; i < nbuses; i++) { - virDomainPCIAddressBusSetModel(&addrs->buses[i], - VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE); - } - for (i = 0; i < def->ncontrollers; i++) { - size_t idx = def->controllers[i]->idx; + virDomainControllerDefPtr cont = def->controllers[i]; + size_t idx = cont->idx;
- if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI) continue;
if (idx >= addrs->nbuses) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Inappropriate new pci controller index %zu " - "not found in addrs"), idx); + "exceeds addrs array length"), idx); goto error; }
- if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], - def->controllers[i]->model) < 0) + if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; + + /* we'll use all this info later to determine if we need + * to add a dmi-to-pci-bridge due to unaddressed pci-bridge controllers + */ + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) { + hasPCIeRoot = true; + } else if (cont->model == + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) { + if (lowestDMIToPCIBridge > idx) + lowestDMIToPCIBridge = idx; + } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) { + if (virDeviceInfoPCIAddressWanted(&cont->info)) { + if (lowestUnaddressedPCIBridge > idx) + lowestUnaddressedPCIBridge = idx; + } else { + if (lowestAddressedPCIBridge > idx) + lowestAddressedPCIBridge = idx; + } } + } + + if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) + goto error; + } + + /* Now fill in a reasonable model for all the buses in the set + * that don't yet have a corresponding controller in the domain + * config. In the rare (and actually fairly idiotic, but still + * allowed for some reason) case that a domain has 1) a pcie-root + * at index 0, 2)*no* dmi-to-pci-bridge (or pci-bridge that was + * manually addressed to sit directly on pcie-root), and 3) does + * have an unaddressed pci-bridge at an index > 1, then we need to + * add a dmi-to-pci-bridge. + */ + + if (!hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + + else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge, + lowestDMIToPCIBridge)) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; + else + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + + for (i = 1; i < addrs->nbuses; i++) { + + if (addrs->buses[i].model) + continue; + + if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) < 0) + goto error; + + VIR_DEBUG("Auto-adding <controller type='pci' model='%s' index='%zu'/>", + virDomainControllerModelPCITypeToString(defaultModel), i); + /* only add a single dmi-to-pci-bridge, then add pcie-root-port + * for any other unspecified controller indexes. + */ + if (hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + }

+ if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0)
+ } Shouldn't we use either PCI_ROOT or PCIE_ROOT based on the machine type here? And set hasPCIeRoot *after* doing so? Sorry for the questions, I guess this is the point in the
+ goto error; patch where I got a bit lost :( I'm afraid you missed this question :) Sorry about the omission. I've tried to limit the code that decides whether or not there should be a pci-root or a
On Thu, 2016-10-13 at 13:43 -0400, Laine Stump wrote: pcie-root to the one
place when default controllers are being added (I forget the name of the function right now),
I guess you mean qemuDomainDefAddDefaultDevices()? That's the function where pci{,e}-root is added, if not already present in the configuration.
and after that only decide based on whether a pci-root or pcie-root really is there in the config. My subconscious reasoning for this is that the extra calisthenics around supporting aarch64/virt with PCI(e) vs with mmio has made me wonder if there might be machinetypes in the future that could support one type of root bus or another (or none) according to what is in the config, rather than having a root bus just builtin to the machine. I don't know if that would ever happen, but if it did, this code would work without change - only the function adding the default controllers would need to be changed. (Note that I used the same logic when deciding how to right qemuDomainMachineHasPCI[e]Root())(still not sure about that name, but it can always be changed later to remove the "Machine" if someone doesn't like it)
That makes sense. My point is that the code above, if I'm reading it correctly, sets the model of bus 0 to PCI_ROOT if it's not already set. But 1) qemuDomainDefAddDefaultDevices() mentioned above should already have added pci{,e}-root to @def 2) if that's not the case, we should use either PCI_ROOT or PCIE_ROOT based on what's appropriate for the machine type Looking at the code in qemuDomainDefAddDefaultDevices() it seems like we would never find ourselves in the situation where pci{,e}-root is needed but not present in @def by the time qemuDomainPCIAddressSetCreate() is called, so I think that chunk of code should just be removed.
A DMI-to-PCI bridge with index='1' has been added automatically here... ... but it's not being used by any of the devices. So why would it be added in the first place? That is a *very* good question! Can't wait to know the answer! ;) Oh, now that I've looked in context of the patch ordering, I undestand: it's because patch 16/18 hasn't been applied yet. I'd forgotten the ordering...
Right you are :) -- Andrea Bolognani / Red Hat / Virtualization

On 10/14/2016 01:20 PM, Andrea Bolognani wrote:
On Thu, 2016-10-13 at 13:43 -0400, Laine Stump wrote:
+ if (nbuses > 0 && !addrs->buses[0].model) { + if (virDomainPCIAddressBusSetModel(&addrs->buses[0], + VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) + goto error; + }
Shouldn't we use either PCI_ROOT or PCIE_ROOT based on the machine type here? And set hasPCIeRoot *after* doing so?
Sorry for the questions, I guess this is the point in the patch where I got a bit lost :(
I'm afraid you missed this question :)
Sorry about the omission. I've tried to limit the code that decides whether or not there should be a pci-root or a pcie-root to the one place when default controllers are being added (I forget the name of the function right now), I guess you mean qemuDomainDefAddDefaultDevices()?
That's the function where pci{,e}-root is added, if not already present in the configuration.
and after that only decide based on whether a pci-root or pcie-root really is there in the config. My subconscious reasoning for this is that the extra calisthenics around supporting aarch64/virt with PCI(e) vs with mmio has made me wonder if there might be machinetypes in the future that could support one type of root bus or another (or none) according to what is in the config, rather than having a root bus just builtin to the machine. I don't know if that would ever happen, but if it did, this code would work without change - only the function adding the default controllers would need to be changed.
(Note that I used the same logic when deciding how to right qemuDomainMachineHasPCI[e]Root())(still not sure about that name, but it can always be changed later to remove the "Machine" if someone doesn't like it) That makes sense.
My point is that the code above, if I'm reading it correctly, sets the model of bus 0 to PCI_ROOT if it's not already set.
But
1) qemuDomainDefAddDefaultDevices() mentioned above should already have added pci{,e}-root to @def
2) if that's not the case, we should use either PCI_ROOT or PCIE_ROOT based on what's appropriate for the machine type
Looking at the code in qemuDomainDefAddDefaultDevices() it seems like we would never find ourselves in the situation where pci{,e}-root is needed but not present in @def by the time qemuDomainPCIAddressSetCreate() is called, so I think that chunk of code should just be removed.
Truthfully the only reason it's there at all is because there was similar code originally (which also was surely never needed). Even so, I'm nervous about totally removing the check for unset model even though a visual inspection of the current code tells us it won't be needed. So instead, I'm going to turn it into an internal error condition.

On 10/10/2016 02:14 PM, Andrea Bolognani wrote:
+ } else if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) {
+ model = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE; I'm not so clear on this bit: if we're growing the address set to plug in a pci-bridge, can we just go ahead and assume a dmi-to-pci-bridge is what we need? What about eg. pseries machine types, where dmi-to-pci-bridge is not usable?
What can you plug a pci-bridge into on a pseries machine? For all machinetypes, if there is an unaddressed pci-bridge in the config and there is a slot available that accepts a pci-bridge (i.e. pci-root, pci-bridge, or dmi-to-pci-bridge) then we won't be calling virDomainPCIAddressSetGrow() in the first place (since it's only called if no empty slot with correct flags can be found). And I don't know about pseries, but for 440fx, if there isn't a matching empty slot that accepts a pci-bridge at that point, then it's not possible to add one (you already have the one and only pci-root, and you're already trying to add a pci-bridge --> if you have to add a pci-bridge in order to add a pci-bridge, then you're in an infinite recursion). So a dmi-to-pci-bridge is the only thing that could possibly help, and in the cases where there is no pcie-root, it would just mean that you would get an error later when you're told there's no place to plug in the dmi-to-pci-bridge. So it makes sense for me to add a check here to see if the model of addrs->buses[0] is PCIE_ROOT, and only try adding the dmi-to-pci-bridge in that case.

Now the a dmi-to-pci-bridge is automatically added just as it's needed (when a pci-bridge is being added), we no longer have any need to force-add one to every single Q35 domain. --- src/qemu/qemu_domain.c | 12 ---- tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args | 3 +- .../qemuxml2argv-q35-pcie-autoadd.args | 55 +++++++-------- .../qemuxml2xmlout-pcie-root.xml | 4 -- .../qemuxml2xmlout-q35-pcie-autoadd.xml | 82 ++++++++++------------ 5 files changed, 67 insertions(+), 89 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 227134e..eed8cfe 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2084,18 +2084,6 @@ qemuDomainDefAddDefaultDevices(virDomainDefPtr def, VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)) { goto cleanup; } - /* Add a dmi-to-pci-bridge bridge if there are no PCI controllers - * other than the pcie-root. This is so that there will be hot-pluggable - * PCI slots available. - * - * We skip this step for aarch64 mach-virt guests, where we want to - * be able to have a pure virtio-mmio topology - */ - if (virDomainControllerFind(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 1) < 0 && - !qemuDomainMachineIsVirt(def) && - !virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 1, - VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE)) - goto cleanup; } if (addDefaultMemballoon && !def->memballoon) { diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args index 7ef03d3..59a849f 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args @@ -15,5 +15,4 @@ QEMU_AUDIO_DRV=none \ -nodefaults \ -monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \ -no-acpi \ --boot c \ --device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e +-boot c diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args index 6bea3e4..7b6f040 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args @@ -16,42 +16,41 @@ QEMU_AUDIO_DRV=none \ -monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \ -no-acpi \ -boot c \ --device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ --device ioh3420,port=0x10,chassis=2,id=pci.2,bus=pcie.0,addr=0x2 \ --device ioh3420,port=0x18,chassis=3,id=pci.3,bus=pcie.0,addr=0x3 \ --device ioh3420,port=0x20,chassis=4,id=pci.4,bus=pcie.0,addr=0x4 \ --device ioh3420,port=0x28,chassis=5,id=pci.5,bus=pcie.0,addr=0x5 \ --device ioh3420,port=0x30,chassis=6,id=pci.6,bus=pcie.0,addr=0x6 \ --device ioh3420,port=0x38,chassis=7,id=pci.7,bus=pcie.0,addr=0x7 \ --device ioh3420,port=0x40,chassis=8,id=pci.8,bus=pcie.0,addr=0x8 \ --device ioh3420,port=0x48,chassis=9,id=pci.9,bus=pcie.0,addr=0x9 \ --device ioh3420,port=0x50,chassis=10,id=pci.10,bus=pcie.0,addr=0xa \ --device ioh3420,port=0x58,chassis=11,id=pci.11,bus=pcie.0,addr=0xb \ --device ioh3420,port=0x60,chassis=12,id=pci.12,bus=pcie.0,addr=0xc \ --device ioh3420,port=0x68,chassis=13,id=pci.13,bus=pcie.0,addr=0xd \ --device ioh3420,port=0x70,chassis=14,id=pci.14,bus=pcie.0,addr=0xe \ --device nec-usb-xhci,id=usb,bus=pci.7,addr=0x0 \ --device virtio-scsi-pci,id=scsi0,bus=pci.6,addr=0x0 \ --device virtio-serial-pci,id=virtio-serial0,bus=pci.5,addr=0x0 \ +-device ioh3420,port=0x10,chassis=1,id=pci.1,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=2,id=pci.2,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=3,id=pci.3,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=4,id=pci.4,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=5,id=pci.5,bus=pcie.0,addr=0x6 \ +-device ioh3420,port=0x38,chassis=6,id=pci.6,bus=pcie.0,addr=0x7 \ +-device ioh3420,port=0x40,chassis=7,id=pci.7,bus=pcie.0,addr=0x8 \ +-device ioh3420,port=0x48,chassis=8,id=pci.8,bus=pcie.0,addr=0x9 \ +-device ioh3420,port=0x50,chassis=9,id=pci.9,bus=pcie.0,addr=0xa \ +-device ioh3420,port=0x58,chassis=10,id=pci.10,bus=pcie.0,addr=0xb \ +-device ioh3420,port=0x60,chassis=11,id=pci.11,bus=pcie.0,addr=0xc \ +-device ioh3420,port=0x68,chassis=12,id=pci.12,bus=pcie.0,addr=0xd \ +-device ioh3420,port=0x70,chassis=13,id=pci.13,bus=pcie.0,addr=0xe \ +-device nec-usb-xhci,id=usb,bus=pci.6,addr=0x0 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.5,addr=0x0 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.4,addr=0x0 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk1 \ --device virtio-blk-pci,bus=pci.8,addr=0x0,drive=drive-virtio-disk1,\ +-device virtio-blk-pci,bus=pci.7,addr=0x0,drive=drive-virtio-disk1,\ id=virtio-disk1 \ -fsdev local,security_model=passthrough,id=fsdev-fs0,path=/export/to/guest \ -device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=/import/from/host,\ -bus=pci.2,addr=0x0 \ +bus=pci.1,addr=0x0 \ -netdev user,id=hostnet0 \ --device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.3,\ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.2,\ addr=0x0 \ -netdev user,id=hostnet1 \ --device e1000e,netdev=hostnet1,id=net1,mac=00:11:22:33:44:66,bus=pci.4,\ +-device e1000e,netdev=hostnet1,id=net1,mac=00:11:22:33:44:66,bus=pci.3,\ addr=0x0 \ --device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.11,\ +-device virtio-input-host-pci,id=input0,evdev=/dev/input/event1234,bus=pci.10,\ addr=0x0 \ --device virtio-mouse-pci,id=input1,bus=pci.12,addr=0x0 \ --device virtio-keyboard-pci,id=input2,bus=pci.13,addr=0x0 \ --device virtio-tablet-pci,id=input3,bus=pci.14,addr=0x0 \ +-device virtio-mouse-pci,id=input1,bus=pci.11,addr=0x0 \ +-device virtio-keyboard-pci,id=input2,bus=pci.12,addr=0x0 \ +-device virtio-tablet-pci,id=input3,bus=pci.13,addr=0x0 \ -device virtio-vga,id=video0,bus=pcie.0,addr=0x1 \ --device virtio-balloon-pci,id=balloon0,bus=pci.9,addr=0x0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.8,addr=0x0 \ -object rng-random,id=objrng0,filename=/dev/urandom \ --device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,\ -bus=pci.10,addr=0x0 +-device virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=123,period=1234,bus=pci.9,\ +addr=0x0 diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml index 80dc35e..b53ce24 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml @@ -18,10 +18,6 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> - <controller type='pci' index='1' model='dmi-to-pci-bridge'> - <model name='i82801b11-bridge'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> - </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='none'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml index b27dbe7..d784801 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml @@ -17,117 +17,113 @@ <disk type='block' device='disk'> <source dev='/dev/HostVG/QEMUGuest1'/> <target dev='vdb' bus='virtio'/> - <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> </disk> <controller type='virtio-serial' index='0'> - <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> </controller> <controller type='scsi' index='0' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> </controller> <controller type='usb' index='0' model='nec-xhci'> - <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> </controller> <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> <controller type='pci' index='0' model='pcie-root'/> - <controller type='pci' index='1' model='dmi-to-pci-bridge'> - <model name='i82801b11-bridge'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> - </controller> - <controller type='pci' index='2' model='pcie-root-port'> + <controller type='pci' index='1' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='2' port='0x10'/> + <target chassis='1' port='0x10'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </controller> - <controller type='pci' index='3' model='pcie-root-port'> + <controller type='pci' index='2' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='3' port='0x18'/> + <target chassis='2' port='0x18'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </controller> - <controller type='pci' index='4' model='pcie-root-port'> + <controller type='pci' index='3' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='4' port='0x20'/> + <target chassis='3' port='0x20'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </controller> - <controller type='pci' index='5' model='pcie-root-port'> + <controller type='pci' index='4' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='5' port='0x28'/> + <target chassis='4' port='0x28'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </controller> - <controller type='pci' index='6' model='pcie-root-port'> + <controller type='pci' index='5' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='6' port='0x30'/> + <target chassis='5' port='0x30'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </controller> - <controller type='pci' index='7' model='pcie-root-port'> + <controller type='pci' index='6' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='7' port='0x38'/> + <target chassis='6' port='0x38'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </controller> - <controller type='pci' index='8' model='pcie-root-port'> + <controller type='pci' index='7' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='8' port='0x40'/> + <target chassis='7' port='0x40'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> </controller> - <controller type='pci' index='9' model='pcie-root-port'> + <controller type='pci' index='8' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='9' port='0x48'/> + <target chassis='8' port='0x48'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> </controller> - <controller type='pci' index='10' model='pcie-root-port'> + <controller type='pci' index='9' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='10' port='0x50'/> + <target chassis='9' port='0x50'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </controller> - <controller type='pci' index='11' model='pcie-root-port'> + <controller type='pci' index='10' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='11' port='0x58'/> + <target chassis='10' port='0x58'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> </controller> - <controller type='pci' index='12' model='pcie-root-port'> + <controller type='pci' index='11' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='12' port='0x60'/> + <target chassis='11' port='0x60'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> </controller> - <controller type='pci' index='13' model='pcie-root-port'> + <controller type='pci' index='12' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='13' port='0x68'/> + <target chassis='12' port='0x68'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> </controller> - <controller type='pci' index='14' model='pcie-root-port'> + <controller type='pci' index='13' model='pcie-root-port'> <model name='ioh3420'/> - <target chassis='14' port='0x70'/> + <target chassis='13' port='0x70'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> </controller> <filesystem type='mount' accessmode='passthrough'> <source dir='/export/to/guest'/> <target dir='/import/from/host'/> - <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </filesystem> <interface type='user'> <mac address='00:11:22:33:44:55'/> <model type='virtio'/> - <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> </interface> <interface type='user'> <mac address='00:11:22:33:44:66'/> <model type='e1000e'/> - <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> </interface> <input type='passthrough' bus='virtio'> <source evdev='/dev/input/event1234'/> - <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> </input> <input type='mouse' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> </input> <input type='keyboard' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0c' slot='0x00' function='0x0'/> </input> <input type='tablet' bus='virtio'> - <address type='pci' domain='0x0000' bus='0x0e' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x0d' slot='0x00' function='0x0'/> </input> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> @@ -136,12 +132,12 @@ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </video> <memballoon model='virtio'> - <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> </memballoon> <rng model='virtio'> <rate bytes='123' period='1234'/> <backend model='random'>/dev/urandom</backend> - <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> </rng> </devices> </domain> -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Now the a dmi-to-pci-bridge is automatically added just as it's needed (when a pci-bridge is being added), we no longer have any need to force-add one to every single Q35 domain. --- src/qemu/qemu_domain.c | 12 ---- tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args | 3 +- .../qemuxml2argv-q35-pcie-autoadd.args | 55 +++++++-------- .../qemuxml2xmlout-pcie-root.xml | 4 -- .../qemuxml2xmlout-q35-pcie-autoadd.xml | 82 ++++++++++------------ 5 files changed, 67 insertions(+), 89 deletions(-)
You didn't CC: me on this patch for some reason. Weird. ACK -- Andrea Bolognani / Red Hat / Virtualization

On 10/13/2016 11:50 AM, Andrea Bolognani wrote:
On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Now the a dmi-to-pci-bridge is automatically added just as it's needed (when a pci-bridge is being added), we no longer have any need to force-add one to every single Q35 domain. --- src/qemu/qemu_domain.c | 12 ---- tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args | 3 +- .../qemuxml2argv-q35-pcie-autoadd.args | 55 +++++++-------- .../qemuxml2xmlout-pcie-root.xml | 4 -- .../qemuxml2xmlout-q35-pcie-autoadd.xml | 82 ++++++++++------------ 5 files changed, 67 insertions(+), 89 deletions(-) You didn't CC: me on this patch for some reason. Weird.
I should learn to use --cc in git send-email rather than pasting Cc: lines into the individual messages with --annotate.
ACK

Previously we added a set of EHCI+UHCI controllers to Q35 machines to mimic real hardware as closely as possible, but recent discussions have pointed out that the nec-usb-xhci (USB3) controller is much more virtualization-friendly (uses less CPU), so this patch switches the default for Q35 machinetypes to add an XHCI instead (if it's supported, which it of course *will* be). Since none of the existing test cases left out USB controllers in the input XML, a new Q35 test case was added which has *no* devices, so ends up with only the defaults always put in by qemu, plus those added by libvirt. --- src/qemu/qemu_domain.c | 10 ++++-- .../qemuxml2argv-q35-default-devices-only.args | 22 ++++++++++++ .../qemuxml2argv-q35-default-devices-only.xml | 18 ++++++++++ tests/qemuxml2argvtest.c | 22 ++++++++++++ .../qemuxml2xmlout-q35-default-devices-only.xml | 40 ++++++++++++++++++++++ tests/qemuxml2xmltest.c | 22 ++++++++++++ 6 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index eed8cfe..e1060ba 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1976,10 +1976,14 @@ qemuDomainDefAddDefaultDevices(virDomainDefPtr def, addPCIeRoot = true; addImplicitSATA = true; - /* add a USB2 controller set, but only if the - * ich9-usb-ehci1 device is supported + /* Prefer adding USB3 controller if supported + * (nec-usb-xhci). Failing that, add a USB2 controller set + * if the ich9-usb-ehci1 device is supported. Otherwise + * don't add anything. */ - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_USB_EHCI1)) + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NEC_USB_XHCI)) + usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI; + else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_USB_EHCI1)) usbModel = VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1; else addDefaultUSB = false; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args new file mode 100644 index 0000000..9ac30dd --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/libexec/qemu-kvm \ +-name q35-test \ +-S \ +-M q35 \ +-m 2048 \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 \ +-nographic \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \ +-no-acpi \ +-boot c \ +-device ioh3420,port=0x8,chassis=1,id=pci.1,bus=pcie.0,addr=0x1 \ +-device ioh3420,port=0x10,chassis=2,id=pci.2,bus=pcie.0,addr=0x2 \ +-device nec-usb-xhci,id=usb,bus=pci.1,addr=0x0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.xml new file mode 100644 index 0000000..7436583 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.xml @@ -0,0 +1,18 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index cfa522c..db63b21 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1762,6 +1762,28 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + DO_TEST("q35-default-devices-only", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root-port", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml new file mode 100644 index 0000000..8d7bc9d --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml @@ -0,0 +1,40 @@ +<domain type='qemu'> + <name>q35-test</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static' cpuset='0-1'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>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/libexec/qemu-kvm</emulator> + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='2' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 4757093..6c3b6ea 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -756,6 +756,28 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + DO_TEST("q35-default-devices-only", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, -- 2.7.4

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Previously we added a set of EHCI+UHCI controllers to Q35 machines to mimic real hardware as closely as possible, but recent discussions have pointed out that the nec-usb-xhci (USB3) controller is much more virtualization-friendly (uses less CPU), so this patch switches the default for Q35 machinetypes to add an XHCI instead (if it's supported, which it of course *will* be).
Since none of the existing test cases left out USB controllers in the input XML, a new Q35 test case was added which has *no* devices, so ends up with only the defaults always put in by qemu, plus those added by libvirt. --- src/qemu/qemu_domain.c | 10 ++++-- .../qemuxml2argv-q35-default-devices-only.args | 22 ++++++++++++ .../qemuxml2argv-q35-default-devices-only.xml | 18 ++++++++++ tests/qemuxml2argvtest.c | 22 ++++++++++++ .../qemuxml2xmlout-q35-default-devices-only.xml | 40 ++++++++++++++++++++++ tests/qemuxml2xmltest.c | 22 ++++++++++++ 6 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml
ACK -- Andrea Bolognani / Red Hat / Virtualization

Real Q35 hardware has an ICH9 chip that includes several integrated devices at particular addresses (see the file docs/q35-chipset.cfg in the qemu source). libvirt already attempts to put the first two sets of ich9 USB2 controllers it finds at 00:1D.* and 00:1A.* to match the real hardware. This patch does the same for the ich9 "HD audio" device. The reason I made this patch is that currently the *only* device in a reasonable "workstation" type virtual machine config that requires a legacy PCI slot is the audio device, Without this patch, the standard Q35 machine created by virt-manager will have a dmi-to-pci-bridge and a pci-bridge just for the sound device; with the patch (and if you change the sound device model from the default "ich6" to "ich9"), the machine definition constructed by virt-manager has absolutely no legacy PCI controllers - any legacy PCI devices (e.g. video and sound) are on pcie-root as integrated devices. As cool as it is to have virt-manager making a legacy-PCI-free config so easily, I'm undecided whether or not this is a worthwhile patch. On one hand, it's following an existing convention of trying to place devices that are known to be integrated chipset devices on Q35 hardware at the same address they appear in real life (but doesn't insist on this address, and doesn't add any new device if one isn't already present in the config). On the other hand it creates yet another exception to "follow the same formula for everything", while it's probably better for us to be trying to *get away* from that. Two alternate solutions: 1) convince virt-manager to use "ich9" as the default sound for Q35, and explicitly place it at 00:1B.0 in the definition it sends to libvirt. 2) convince qemu to add a PCI Express sound device (I'm not sure which one would be most appropriate). --- src/qemu/qemu_domain_address.c | 25 +++++ .../qemuxml2argv-q35-virt-manager-basic.args | 56 ++++++++++ .../qemuxml2argv-q35-virt-manager-basic.xml | 76 ++++++++++++++ tests/qemuxml2argvtest.c | 31 ++++++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 116 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 23 ++++ 6 files changed, 327 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index a9c4c32..6cfd710 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1218,6 +1218,31 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, goto cleanup; } } + + memset(&tmp_addr, 0, sizeof(tmp_addr)); + tmp_addr.slot = 0x1B; + if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { + /* Since real Q35 hardware has an ICH9 chip that has an + * integrated HD audio device at 0000:00:1B.0 put any + * unaddressed ICH9 audio device at that address if it's not + * already taken. If there's something already there, let the + * normal device addressing assign something later. + */ + for (i = 0; i < def->nsounds; i++) { + virDomainSoundDefPtr sound = def->sounds[i]; + + if (sound->model != VIR_DOMAIN_SOUND_MODEL_ICH9) + continue; + if (!virDeviceInfoPCIAddressWanted(&sound->info)) + break; + if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) + goto cleanup; + sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + sound->info.addr.pci = tmp_addr; + break; + } + } + ret = 0; cleanup: VIR_FREE(addrStr); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args new file mode 100644 index 0000000..163e7f1 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args @@ -0,0 +1,56 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=spice \ +/usr/bin/qemu-system_x86_64 \ +-name virt-manager-basic \ +-S \ +-M pc-q35-2.7 \ +-m 4096 \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 1b826c23-8767-47ad-a6b5-c83a88277f71 \ +-nodefaults \ +-monitor unix:/tmp/lib/domain--1-virt-manager-basic/monitor.sock,server,nowait \ +-rtc base=utc,driftfix=slew \ +-no-kvm-pit-reinjection \ +-global ICH9-LPC.disable_s3=1 \ +-global ICH9-LPC.disable_s4=1 \ +-boot c \ +-device ioh3420,port=0x10,chassis=1,id=pci.1,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=2,id=pci.2,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=3,id=pci.3,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=4,id=pci.4,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=5,id=pci.5,bus=pcie.0,addr=0x6 \ +-device nec-usb-xhci,id=usb,bus=pci.2,addr=0x0 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.3,addr=0x0 \ +-drive file=/var/lib/libvirt/images/basic.qcow2,format=qcow2,if=none,\ +id=drive-virtio-disk0 \ +-device virtio-blk-pci,bus=pci.4,addr=0x0,drive=drive-virtio-disk0,\ +id=virtio-disk0 \ +-netdev user,id=hostnet0 \ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:9a:e6:c6,bus=pci.1,\ +addr=0x0 \ +-serial pty \ +-chardev socket,id=charchannel0,\ +path=/tmp/channel/domain--1-virt-manager-basic/org.qemu.guest_agent.0,server,\ +nowait \ +-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,\ +id=channel0,name=org.qemu.guest_agent.0 \ +-chardev spicevmc,id=charchannel1,name=vdagent \ +-device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel1,\ +id=channel1,name=com.redhat.spice.0 \ +-device usb-tablet,id=input0,bus=usb.0,port=1 \ +-spice port=5901,tls-port=5902,addr=127.0.0.1,x509-dir=/etc/pki/libvirt-spice,\ +image-compression=off \ +-vga qxl \ +-global qxl-vga.ram_size=67108864 \ +-global qxl-vga.vram_size=67108864 \ +-device ich9-intel-hda,id=sound0,bus=pcie.0,addr=0x1b \ +-device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 \ +-chardev spicevmc,id=charredir0,name=usbredir \ +-device usb-redir,chardev=charredir0,id=redir0,bus=usb.0,port=2 \ +-chardev spicevmc,id=charredir1,name=usbredir \ +-device usb-redir,chardev=charredir1,id=redir1,bus=usb.0,port=3 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.5,addr=0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.xml new file mode 100644 index 0000000..6d212a4 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.xml @@ -0,0 +1,76 @@ +<domain type='kvm'> + <name>virt-manager-basic</name> + <uuid>1b826c23-8767-47ad-a6b5-c83a88277f71</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='x86_64' machine='pc-q35-2.7'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <apic/> + <vmport state='off'/> + </features> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <pm> + <suspend-to-mem enabled='no'/> + <suspend-to-disk enabled='no'/> + </pm> + <devices> + <emulator>/usr/bin/qemu-system_x86_64</emulator> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/basic.qcow2'/> + <target dev='vda' bus='virtio'/> + </disk> + <controller type='usb' model='nec-xhci'/> + <controller type='sata'/> + <controller type='virtio-serial' index='0'/> + <interface type='user'> + <mac address='52:54:00:9a:e6:c6'/> + <model type='virtio'/> + </interface> + <serial type='pty'> + <target port='0'/> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <channel type='unix'> + <target type='virtio' name='org.qemu.guest_agent.0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <channel type='spicevmc'> + <target type='virtio' name='com.redhat.spice.0'/> + <address type='virtio-serial' controller='0' bus='0' port='2'/> + </channel> + <input type='tablet' bus='usb'> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='spice' autoport='yes'> + <listen type='address'/> + <image compression='off'/> + </graphics> + <sound model='ich9'/> + <video> + <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> + </video> + <redirdev bus='usb' type='spicevmc'> + <address type='usb' bus='0' port='2'/> + </redirdev> + <redirdev bus='usb' type='spicevmc'> + <address type='usb' bus='0' port='3'/> + </redirdev> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index db63b21..6c3c367 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1784,6 +1784,37 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + DO_TEST("q35-virt-manager-basic", + QEMU_CAPS_KVM, + QEMU_CAPS_RTC, + QEMU_CAPS_NO_KVM_PIT, + QEMU_CAPS_ICH9_DISABLE_S3, + QEMU_CAPS_ICH9_DISABLE_S4, + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_ICH9_INTEL_HDA, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY, + QEMU_CAPS_SPICE, QEMU_CAPS_CHARDEV_SPICEVMC, + QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL, + QEMU_CAPS_HDA_DUPLEX, QEMU_CAPS_USB_REDIR); DO_TEST("pcie-root-port", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml new file mode 100644 index 0000000..fe9ea4e --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml @@ -0,0 +1,116 @@ +<domain type='kvm'> + <name>virt-manager-basic</name> + <uuid>1b826c23-8767-47ad-a6b5-c83a88277f71</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='x86_64' machine='pc-q35-2.7'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <apic/> + <vmport state='off'/> + </features> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <pm> + <suspend-to-mem enabled='no'/> + <suspend-to-disk enabled='no'/> + </pm> + <devices> + <emulator>/usr/bin/qemu-system_x86_64</emulator> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/basic.qcow2'/> + <target dev='vda' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </disk> + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='1' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='2' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <interface type='user'> + <mac address='52:54:00:9a:e6:c6'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </interface> + <serial type='pty'> + <target port='0'/> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <channel type='unix'> + <target type='virtio' name='org.qemu.guest_agent.0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <channel type='spicevmc'> + <target type='virtio' name='com.redhat.spice.0'/> + <address type='virtio-serial' controller='0' bus='0' port='2'/> + </channel> + <input type='tablet' bus='usb'> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='spice' autoport='yes'> + <listen type='address'/> + <image compression='off'/> + </graphics> + <sound model='ich9'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> + </sound> + <video> + <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <redirdev bus='usb' type='spicevmc'> + <address type='usb' bus='0' port='2'/> + </redirdev> + <redirdev bus='usb' type='spicevmc'> + <address type='usb' bus='0' port='3'/> + </redirdev> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 6c3b6ea..331763b 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -778,6 +778,29 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_NEC_USB_XHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY); + DO_TEST("q35-virt-manager-basic", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM, + QEMU_CAPS_NETDEV, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_VIRTIO_GPU, + QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL, + QEMU_CAPS_VIRTIO_KEYBOARD, + QEMU_CAPS_VIRTIO_MOUSE, + QEMU_CAPS_VIRTIO_TABLET, + QEMU_CAPS_VIRTIO_INPUT_HOST, + QEMU_CAPS_VIRTIO_SCSI, + QEMU_CAPS_FSDEV, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_NEC_USB_XHCI, + QEMU_CAPS_DEVICE_ICH9_INTEL_HDA, + QEMU_CAPS_DEVICE_VIDEO_PRIMARY); DO_TEST("pcie-root", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, -- 2.7.4

Hi,
Real Q35 hardware has an ICH9 chip that includes several integrated devices at particular addresses (see the file docs/q35-chipset.cfg in the qemu source). libvirt already attempts to put the first two sets of ich9 USB2 controllers it finds at 00:1D.* and 00:1A.* to match the real hardware. This patch does the same for the ich9 "HD audio" device.
While being at it: Ethernet is in the same boat. It is a integrated device at slot 00:19.0. Some e1000 version on older chipsets, e1000e on newer ones (here my T530): nilsson root ~# lspci -vs19 00:19.0 Ethernet controller: Intel Corporation 82579LM Gigabit Network Connection (rev 04) Subsystem: Lenovo Device 21f3 Flags: bus master, fast devsel, latency 0, IRQ 27 Memory at f2500000 (32-bit, non-prefetchable) [size=128K] Memory at f253b000 (32-bit, non-prefetchable) [size=4K] I/O ports at 5080 [size=32] Capabilities: [c8] Power Management version 2 Capabilities: [d0] MSI: Enable+ Count=1/1 Maskable- 64bit+ Capabilities: [e0] PCI Advanced Features Kernel driver in use: e1000e Kernel modules: e1000e So we might do the same here instead of placing it in a pcie root port (patch 12/18). I think we don't emulate the ich9 e1000 variant though.
2) convince qemu to add a PCI Express sound device (I'm not sure which one would be most appropriate).
For reference: It's still @ 00:1b.0 in recent chipsets as integrated device, it is still the same hardware (again my T530): nilsson root ~# lspci -vs1b 00:1b.0 Audio device: Intel Corporation 7 Series/C210 Series Chipset Family High Definition Audio Controller (rev 04) Subsystem: Lenovo Device 21f6 Flags: bus master, fast devsel, latency 0, IRQ 32 Memory at f2530000 (64-bit, non-prefetchable) [size=16K] Capabilities: [50] Power Management version 2 Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+ Capabilities: [70] Express Root Complex Integrated Endpoint, MSI 00 Capabilities: [100] Virtual Channel Capabilities: [130] Root Complex Link Kernel driver in use: snd_hda_intel Kernel modules: snd_hda_intel cheers, Gerd

On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Real Q35 hardware has an ICH9 chip that includes several integrated devices at particular addresses (see the file docs/q35-chipset.cfg in the qemu source). libvirt already attempts to put the first two sets of ich9 USB2 controllers it finds at 00:1D.* and 00:1A.* to match the real hardware. This patch does the same for the ich9 "HD audio" device. The reason I made this patch is that currently the *only* device in a reasonable "workstation" type virtual machine config that requires a legacy PCI slot is the audio device, Without this patch, the standard Q35 machine created by virt-manager will have a dmi-to-pci-bridge and a pci-bridge just for the sound device; with the patch (and if you change the sound device model from the default "ich6" to "ich9"), the machine definition constructed by virt-manager has absolutely no legacy PCI controllers - any legacy PCI devices (e.g. video and sound) are on pcie-root as integrated devices.
Everything past this point, while valuable for the discussion, should IMHO be left out of the commit message.
As cool as it is to have virt-manager making a legacy-PCI-free config so easily, I'm undecided whether or not this is a worthwhile patch. On one hand, it's following an existing convention of trying to place devices that are known to be integrated chipset devices on Q35 hardware at the same address they appear in real life (but doesn't insist on this address, and doesn't add any new device if one isn't already present in the config). On the other hand it creates yet another exception to "follow the same formula for everything", while it's probably better for us to be trying to *get away* from that.
I'm for merging this: it's straighforward enough, and if we ever decide to start moving stuff off pcie.0 we can just get rid of the code you're adding without affecting existing guests at all.
Two alternate solutions: 1) convince virt-manager to use "ich9" as the default sound for Q35, and explicitly place it at 00:1B.0 in the definition it sends to libvirt.
After this has been merged, virt-manager will still want to change its default to ich9 (based on information retrieved from libosinfo, I assume), but it will not need to hardcode this kind of knowledge, which sounds perfectly fine to me.
2) convince qemu to add a PCI Express sound device (I'm not sure which one would be most appropriate).
That would probably be nice to have, but I'd rather have generic PCI/PCIe controllers than a PCIe sound card, if any QEMU developer is reading this ;)
--- src/qemu/qemu_domain_address.c | 25 +++++ .../qemuxml2argv-q35-virt-manager-basic.args | 56 ++++++++++ .../qemuxml2argv-q35-virt-manager-basic.xml | 76 ++++++++++++++ tests/qemuxml2argvtest.c | 31 ++++++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 116 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 23 ++++ 6 files changed, 327 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index a9c4c32..6cfd710 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1218,6 +1218,31 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, goto cleanup; } } + + memset(&tmp_addr, 0, sizeof(tmp_addr)); + tmp_addr.slot = 0x1B; + if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { + /* Since real Q35 hardware has an ICH9 chip that has an + * integrated HD audio device at 0000:00:1B.0 put any + * unaddressed ICH9 audio device at that address if it's not + * already taken. If there's something already there, let the + * normal device addressing assign something later. + */ + for (i = 0; i < def->nsounds; i++) { + virDomainSoundDefPtr sound = def->sounds[i]; + + if (sound->model != VIR_DOMAIN_SOUND_MODEL_ICH9) + continue; + if (!virDeviceInfoPCIAddressWanted(&sound->info)) + break;
Mh, why break instead of continue here? I'm assuming people won't have more than one ich9 sound card per guest, but if they did and one of them already had a PCI address assigned (which is not 0000:00:1B.0 because of the outer check) why wouldn't we want to try assigning the next one to 0000:00:1B.0?
+ if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) + goto cleanup;
Add an empty line here, please.
+ sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + sound->info.addr.pci = tmp_addr; + break; + } + } + ret = 0; cleanup: VIR_FREE(addrStr);
ACK -- Andrea Bolognani / Red Hat / Virtualization

On 10/13/2016 02:07 PM, Andrea Bolognani wrote:
On Tue, 2016-09-20 at 15:14 -0400, Laine Stump wrote:
Real Q35 hardware has an ICH9 chip that includes several integrated devices at particular addresses (see the file docs/q35-chipset.cfg in the qemu source). libvirt already attempts to put the first two sets of ich9 USB2 controllers it finds at 00:1D.* and 00:1A.* to match the real hardware. This patch does the same for the ich9 "HD audio" device.
The reason I made this patch is that currently the *only* device in a reasonable "workstation" type virtual machine config that requires a legacy PCI slot is the audio device, Without this patch, the standard Q35 machine created by virt-manager will have a dmi-to-pci-bridge and a pci-bridge just for the sound device; with the patch (and if you change the sound device model from the default "ich6" to "ich9"), the machine definition constructed by virt-manager has absolutely no legacy PCI controllers - any legacy PCI devices (e.g. video and sound) are on pcie-root as integrated devices. Everything past this point, while valuable for the discussion, should IMHO be left out of the commit message.
Yep. I just had it in the commit message because that's when I was thinking about it, and I didn't want to forget later (or even worse - have to *re*-type it because something went wrong and I decided to abort the send-email and start over).
As cool as it is to have virt-manager making a legacy-PCI-free config so easily, I'm undecided whether or not this is a worthwhile patch. On one hand, it's following an existing convention of trying to place devices that are known to be integrated chipset devices on Q35 hardware at the same address they appear in real life (but doesn't insist on this address, and doesn't add any new device if one isn't already present in the config). On the other hand it creates yet another exception to "follow the same formula for everything", while it's probably better for us to be trying to *get away* from that. I'm for merging this: it's straighforward enough, and if we ever decide to start moving stuff off pcie.0 we can just get rid of the code you're adding without affecting existing guests at all.
Okay, that's 2.5 votes in favor and 0 against, so I guess I'll go for it.
Two alternate solutions:
1) convince virt-manager to use "ich9" as the default sound for Q35, and explicitly place it at 00:1B.0 in the definition it sends to libvirt. After this has been merged, virt-manager will still want to change its default to ich9 (based on information retrieved from libosinfo, I assume),
I'm not sure if virt-manager is getting soundcard info from libosinfo or just creating it from thin air, but in the case of Q35, it probably doesn't apply, because I think libosinfo doesn't know about Q35; most likely it's using all the same info as it does for 440fx (and I don't think we want it to default to the ich9 audio device on 440fx, since the ich9 chipset was used first in the era of Q35, ie it was never put into the same motherboard as a 440fx chipset. But yeah, virt-manager needs to change its default. I had asked Cole about it on IRC one day, but maybe I should do that in a more formal manner.
but it will not need to hardcode this kind of knowledge, which sounds perfectly fine to me.
Yeah, I agree that (1) is a bad idea. I just put it there to be thorough :-)
2) convince qemu to add a PCI Express sound device (I'm not sure which one would be most appropriate). That would probably be nice to have, but I'd rather have generic PCI/PCIe controllers than a PCIe sound card, if any QEMU developer is reading this ;)
Yeah, I think I agree with that.
--- src/qemu/qemu_domain_address.c | 25 +++++ .../qemuxml2argv-q35-virt-manager-basic.args | 56 ++++++++++ .../qemuxml2argv-q35-virt-manager-basic.xml | 76 ++++++++++++++ tests/qemuxml2argvtest.c | 31 ++++++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 116 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 23 ++++ 6 files changed, 327 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index a9c4c32..6cfd710 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1218,6 +1218,31 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, goto cleanup; } } + + memset(&tmp_addr, 0, sizeof(tmp_addr)); + tmp_addr.slot = 0x1B; + if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { + /* Since real Q35 hardware has an ICH9 chip that has an + * integrated HD audio device at 0000:00:1B.0 put any + * unaddressed ICH9 audio device at that address if it's not + * already taken. If there's something already there, let the + * normal device addressing assign something later. + */ + for (i = 0; i < def->nsounds; i++) { + virDomainSoundDefPtr sound = def->sounds[i]; + + if (sound->model != VIR_DOMAIN_SOUND_MODEL_ICH9) + continue; + if (!virDeviceInfoPCIAddressWanted(&sound->info)) + break; Mh, why break instead of continue here?
I'm assuming people won't have more than one ich9 sound card per guest, but if they did and one of them already had a PCI address assigned (which is not 0000:00:1B.0 because of the outer check) why wouldn't we want to try assigning the next one to 0000:00:1B.0?
Good point. I'm changing it to continue.
+ if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) + goto cleanup; Add an empty line here, please.
Done.
+ sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; + sound->info.addr.pci = tmp_addr; + break; + } + } + ret = 0; cleanup: VIR_FREE(addrStr); ACK

For machinetypes with a pci-root bus (all legacy PCI), libvirt will make a "fake" reservation for one extra slot prior to assigning addresses to unaddressed PCI endpoint devices in the domain. This will trigger auto-adding of a pci-bridge for the final device to be assigned an address *if that device would have otherwise instead been the last device on the last available pci-bridge*; thus it assures that there will always be at least one slot left open in the domains bus topology for expansion (which is important both for hotplug (since a new pci-bridge can't be added while the guest is running) as well as for coldplug (since adding a new device might otherwise in some cases require re-addressing existing devices, which we want to avoid)). It's important to note that for this (legacy PCI) case, we must check for the special case of all slots on all buses being occupied *prior to assigning any addresses*, and avoid attempting to reserve the extra address in that case, because there is no free address in the existing topology, so no place to auto-add a pci-bridge for expansion. Since that condition can only be reached by manual intervention, this is acceptable. For machinetypes with pcie-root, libvirt's methodology for automatically expanding the bus topology is different - pcie-root-ports are plugged into slots (soon to be functions) of pcie-root as needed, and the new endpoint devices are assigned to the single slot in each pcie-root-port. This is done so that the devices are, by default, hotpluggable (the slots of pcie-root don't support hotplug, but the single slot of the pcie-root-port does). Since pcie-root-ports can only be plugged into pcie-root, and we don't auto-assign endpoint devices to those slots, this means topology expansion doesn't compete with endpoint devices for slots, so we don't need to worry about checking for all "useful" slots being free prior to assigning addresses to new endpoint devices - as a matter of fact, if we attempt to reserve the fake slots before the useful slots, it can lead to errors. Instead this patch just reserves slots for "fake" devices after doing the assignment for actual devices - if there were already enough unoccupied pcie-root-ports, then none will be added; if not, then enough will be added to support the desired (hardcoded) potential number of hotplugged devices. Since there hasn't been any other concrete suggestion for the number of "available hotpluggable slots" libvirt should assure, this patch uses "4" as the answer (thanks Drew!) Alternatives could be: 0 - hotplug would only work if the user had thought to add an extra pcie-root to the config *as an extra step after adding and saving each new device*. (this would preclude creating a new domain that had a pcie-root-port available for hotplug - the extra modify/save step would be needed even during initial domain creation, and would need to be repeated every time a device was added to the domain) 1 - this is the *minimum* number of hotpluggable slots libvirt guarantees for legacy PCI domains (with pci-root). Of course on average these domains are more likely to have *15* slots available (half of the slots on a pci-bridge). "anything else" - really any choice made for this is going to be considered wrong by *somebody*. I hope we can all agree that "0" is a wrong choice, just because it will require so much ongoing babysitting. A couple of us have brought up the idea of having "availableHotplugSlots" be configurable in the domain. There has also been sentiment against that. Perhaps it could be configurable in qemu.conf? (I don't really like that either, though - I think everything about the domain should be self-contained in the domain XML, and if something is tunable, it should be tunable separately for each domain). In the absense of anything configurable, we will need to pick a number though. I've done that here, and now we can argue about it (or not :-) --- src/qemu/qemu_domain_address.c | 27 ++++++++++++++++++ .../qemuxml2argv-aarch64-video-virtio-gpu-pci.args | 4 +++ ...l2argv-aarch64-virt-2.6-virtio-pci-default.args | 4 +++ .../qemuxml2argv-aarch64-virtio-pci-default.args | 4 +++ ...l2argv-aarch64-virtio-pci-manual-addresses.args | 4 +++ .../qemuxml2argv-bios-nvram-secure.args | 4 +++ .../qemuxml2argv-boot-floppy-q35.args | 4 +++ .../qemuxml2argv-bootindex-floppy-q35.args | 4 +++ .../qemuxml2argvdata/qemuxml2argv-intel-iommu.args | 4 +++ .../qemuxml2argv-machine-smm-opt.args | 4 +++ .../qemuxml2argv-pcie-expander-bus.args | 4 +++ .../qemuxml2argv-pcie-root-port.args | 2 ++ tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args | 6 +++- .../qemuxml2argv-pcie-switch-upstream-port.args | 4 +++ .../qemuxml2argv-pcihole64-q35.args | 4 +++ .../qemuxml2argv-q35-default-devices-only.args | 4 +++ .../qemuxml2argv-q35-pcie-autoadd.args | 4 +++ tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 4 +++ .../qemuxml2argv-q35-pm-disable-fallback.args | 4 +++ .../qemuxml2argv-q35-pm-disable.args | 4 +++ .../qemuxml2argv-q35-usb2-multi.args | 4 +++ .../qemuxml2argv-q35-usb2-reorder.args | 4 +++ tests/qemuxml2argvdata/qemuxml2argv-q35-usb2.args | 4 +++ .../qemuxml2argv-q35-virt-manager-basic.args | 4 +++ tests/qemuxml2argvdata/qemuxml2argv-q35.args | 4 +++ .../qemuxml2argv-usb-controller-default-q35.args | 4 +++ .../qemuxml2argv-usb-controller-explicit-q35.args | 4 +++ tests/qemuxml2argvtest.c | 33 ++++++++++++++++++---- ...qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml | 20 +++++++++++++ .../qemuxml2xmlout-aarch64-virtio-pci-default.xml | 20 +++++++++++++ ...2xmlout-aarch64-virtio-pci-manual-addresses.xml | 20 +++++++++++++ .../qemuxml2xmlout-intel-iommu.xml | 20 +++++++++++++ .../qemuxml2xmlout-pcie-expander-bus.xml | 20 +++++++++++++ .../qemuxml2xmlout-pcie-root-port.xml | 10 +++++++ .../qemuxml2xmlout-pcie-root.xml | 20 +++++++++++++ .../qemuxml2xmlout-pcie-switch-upstream-port.xml | 20 +++++++++++++ .../qemuxml2xmlout-pcihole64-q35.xml | 20 +++++++++++++ .../qemuxml2xmlout-q35-default-devices-only.xml | 20 +++++++++++++ .../qemuxml2xmlout-q35-pcie-autoadd.xml | 20 +++++++++++++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 20 +++++++++++++ .../qemuxml2xmlout-q35-usb2-multi.xml | 20 +++++++++++++ .../qemuxml2xmlout-q35-usb2-reorder.xml | 20 +++++++++++++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2.xml | 20 +++++++++++++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 20 +++++++++++++ tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml | 20 +++++++++++++ .../qemuxml2xmlout-usb-controller-default-q35.xml | 20 +++++++++++++ .../qemuxml2xmlout-usb-controller-explicit-q35.xml | 20 +++++++++++++ .../qemuxml2xmlout-vcpu-placement-static.xml | 20 +++++++++++++ tests/qemuxml2xmltest.c | 18 ++++++++++-- 49 files changed, 563 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 2016134..a56311c 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1811,6 +1811,33 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0) goto cleanup; + /* For domains with pcie-root only: After assigning + * addresses/reserving slots for all *actual* devices, we now + * do a reservation of four extra slots, which might cause us + * to add up to 4 extra pcie-root-ports. This is done so that + * there are slots available for hotplug. We do this after + * assigning addresses to actual devices rather than before + * because the devices and the pcie-root-ports aren't + * competing for the same slots (pcie-root-ports only plug + * into pcie-root, whose ports aren't hotpluggable). + */ + + if (qemuDomainMachineHasPCIeRoot(def)) { + info.pciConnectFlags = (VIR_PCI_CONNECT_HOTPLUGGABLE | + VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); + + for (i = 0; i < 4; i++) { + /* if there isn't an empty pcie-root-port, this will + * cause one to be added + */ + if (qemuDomainPCIAddressReserveNextSlot(addrs, &info) < 0) + goto cleanup; + } + } + + /* now reflect any controllers auto-added to addrs into the + * domain controllers list + */ for (i = 1; i < addrs->nbuses; i++) { virDomainDeviceDef dev; int contIndex; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args index 76ee977..910aa61 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args @@ -20,6 +20,10 @@ QEMU_AUDIO_DRV=none \ addr=0x1 \ -device ioh3420,port=0x9,chassis=2,id=pci.2,bus=pcie.0,multifunction=on,\ addr=0x1.0x1 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device virtio-net-pci,vlan=0,id=net0,mac=52:54:00:73:34:53,bus=pci.1,addr=0x0,\ bootindex=1 \ -net user,vlan=0,name=hostnet0 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virt-2.6-virtio-pci-default.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virt-2.6-virtio-pci-default.args index 75db1a4..45df440 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virt-2.6-virtio-pci-default.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virt-2.6-virtio-pci-default.args @@ -21,6 +21,10 @@ QEMU_AUDIO_DRV=none \ -initrd /aarch64.initrd \ -append 'earlyprintk console=ttyAMA0,115200n8 rw root=/dev/vda rootwait' \ -dtb /aarch64.dtb \ +-device ioh3420,port=0x8,chassis=1,id=pci.1,bus=pcie.0,addr=0x1 \ +-device ioh3420,port=0x10,chassis=2,id=pci.2,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=3,id=pci.3,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=4,id=pci.4,bus=pcie.0,addr=0x4 \ -device virtio-serial-device,id=virtio-serial0 \ -drive file=/aarch64.raw,format=raw,if=none,id=drive-virtio-disk0 \ -device virtio-blk-device,drive=drive-virtio-disk0,id=virtio-disk0 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-default.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-default.args index b5b010c..352b9b4 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-default.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-default.args @@ -21,6 +21,10 @@ QEMU_AUDIO_DRV=none \ -initrd /aarch64.initrd \ -append 'earlyprintk console=ttyAMA0,115200n8 rw root=/dev/vda rootwait' \ -dtb /aarch64.dtb \ +-device ioh3420,port=0x8,chassis=1,id=pci.1,bus=pcie.0,addr=0x1 \ +-device ioh3420,port=0x10,chassis=2,id=pci.2,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=3,id=pci.3,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=4,id=pci.4,bus=pcie.0,addr=0x4 \ -device virtio-serial-device,id=virtio-serial0 \ -drive file=/aarch64.raw,format=raw,if=none,id=drive-virtio-disk0 \ -device virtio-blk-device,drive=drive-virtio-disk0,id=virtio-disk0 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-manual-addresses.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-manual-addresses.args index 0640399..df2109b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-manual-addresses.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-virtio-pci-manual-addresses.args @@ -24,6 +24,10 @@ QEMU_AUDIO_DRV=none \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1 \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ -device pci-bridge,chassis_nr=3,id=pci.3,bus=pci.1,addr=0x1 \ +-device ioh3420,port=0x10,chassis=4,id=pci.4,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=5,id=pci.5,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=6,id=pci.6,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=7,id=pci.7,bus=pcie.0,addr=0x5 \ -device virtio-scsi-pci,id=scsi0,bus=pci.3,addr=0x1 \ -drive file=/aarch64.raw,format=raw,if=none,id=drive-scsi0-0-0-0 \ -device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args index c014254..6d0c1da 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args @@ -21,6 +21,10 @@ readonly=on \ -boot c \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x1 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-scsi0-0-0-0 \ -device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy-q35.args index b9c6126..d89ab93 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy-q35.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy-q35.args @@ -18,6 +18,10 @@ QEMU_AUDIO_DRV=none \ -boot a \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -drive file=/tmp/firmware.img,format=raw,if=none,id=drive-fdc0-0-0 \ -device isa-fdc,driveA=drive-fdc0-0-0 \ -device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bootindex-floppy-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-bootindex-floppy-q35.args index 8bcdc1f..69ad887 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-bootindex-floppy-q35.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-bootindex-floppy-q35.args @@ -17,6 +17,10 @@ QEMU_AUDIO_DRV=none \ -no-acpi \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -drive file=/tmp/firmware.img,format=raw,if=none,id=drive-fdc0-0-0 \ -device isa-fdc,driveA=drive-fdc0-0-0,bootindexA=1 \ -device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.args b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.args index fc64405..a2c5033 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu.args @@ -19,4 +19,8 @@ QEMU_AUDIO_DRV=none \ -device intel-iommu \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args index e49d7e9..1ea069b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args @@ -18,6 +18,10 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device virtio-scsi-pci,id=scsi0,bus=pci.2,addr=0x1 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-scsi0-0-0-0 \ -device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-expander-bus.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-expander-bus.args index 7ce957c..6caa8fb 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-expander-bus.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-expander-bus.args @@ -56,6 +56,10 @@ nowait \ -device xio3130-downstream,port=0x1d,chassis=35,id=pci.35,bus=pci.5,addr=0x1d \ -device xio3130-downstream,port=0x1e,chassis=36,id=pci.36,bus=pci.5,addr=0x1e \ -device xio3130-downstream,port=0x1f,chassis=37,id=pci.37,bus=pci.5,addr=0x1f \ +-device ioh3420,port=0x10,chassis=38,id=pci.38,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=39,id=pci.39,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x28,chassis=40,id=pci.40,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=41,id=pci.41,bus=pcie.0,addr=0x6 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-sata0-0-0 \ -device ide-drive,bus=ide.0,drive=drive-sata0-0-0,id=sata0-0-0 \ -device rtl8139,vlan=0,id=net0,mac=52:54:00:f1:95:51,bus=pci.6,addr=0x0 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root-port.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root-port.args index 35c2664..3968a72 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root-port.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root-port.args @@ -20,6 +20,8 @@ QEMU_AUDIO_DRV=none \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ -device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ -device ioh3420,port=0x1a,chassis=40,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-sata0-0-0 \ -device ide-drive,bus=ide.0,drive=drive-sata0-0-0,id=sata0-0-0 \ -vga qxl \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args index 59a849f..1c22cfb 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args @@ -15,4 +15,8 @@ QEMU_AUDIO_DRV=none \ -nodefaults \ -monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \ -no-acpi \ --boot c +-boot c \ +-device ioh3420,port=0x10,chassis=1,id=pci.1,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=2,id=pci.2,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=3,id=pci.3,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=4,id=pci.4,bus=pcie.0,addr=0x5 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-switch-upstream-port.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-switch-upstream-port.args index 24d5f37..dfd42b2 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-switch-upstream-port.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-switch-upstream-port.args @@ -22,6 +22,10 @@ QEMU_AUDIO_DRV=none \ -device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ -device x3130-upstream,id=pci.5,bus=pci.3,addr=0x0 \ -device x3130-upstream,id=pci.6,bus=pci.4,addr=0x0 \ +-device ioh3420,port=0x20,chassis=7,id=pci.7,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=8,id=pci.8,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=9,id=pci.9,bus=pcie.0,addr=0x6 \ +-device ioh3420,port=0x38,chassis=10,id=pci.10,bus=pcie.0,addr=0x7 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-sata0-0-0 \ -device ide-drive,bus=ide.0,drive=drive-sata0-0-0,id=sata0-0-0 \ -vga qxl \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcihole64-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-pcihole64-q35.args index ad28dde..61a2beb 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pcihole64-q35.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcihole64-q35.args @@ -19,6 +19,10 @@ QEMU_AUDIO_DRV=none \ -global q35-pcihost.pci-hole64-size=1048576K \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-sata0-0-0 \ -device ide-drive,bus=ide.0,drive=drive-sata0-0-0,id=sata0-0-0 \ -vga qxl \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args index 9ac30dd..9e0b89c 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args @@ -18,5 +18,9 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device ioh3420,port=0x8,chassis=1,id=pci.1,bus=pcie.0,addr=0x1 \ -device ioh3420,port=0x10,chassis=2,id=pci.2,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=3,id=pci.3,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=4,id=pci.4,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=5,id=pci.5,bus=pcie.0,addr=0x5 \ +-device ioh3420,port=0x30,chassis=6,id=pci.6,bus=pcie.0,addr=0x6 \ -device nec-usb-xhci,id=usb,bus=pci.1,addr=0x0 \ -device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x0 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args index 7b6f040..87a8ec9 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args @@ -29,6 +29,10 @@ QEMU_AUDIO_DRV=none \ -device ioh3420,port=0x60,chassis=11,id=pci.11,bus=pcie.0,addr=0xc \ -device ioh3420,port=0x68,chassis=12,id=pci.12,bus=pcie.0,addr=0xd \ -device ioh3420,port=0x70,chassis=13,id=pci.13,bus=pcie.0,addr=0xe \ +-device ioh3420,port=0x78,chassis=14,id=pci.14,bus=pcie.0,addr=0xf \ +-device ioh3420,port=0x80,chassis=15,id=pci.15,bus=pcie.0,addr=0x10 \ +-device ioh3420,port=0x88,chassis=16,id=pci.16,bus=pcie.0,addr=0x11 \ +-device ioh3420,port=0x90,chassis=17,id=pci.17,bus=pcie.0,addr=0x12 \ -device nec-usb-xhci,id=usb,bus=pci.6,addr=0x0 \ -device virtio-scsi-pci,id=scsi0,bus=pci.5,addr=0x0 \ -device virtio-serial-pci,id=virtio-serial0,bus=pci.4,addr=0x0 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args index 059b232..770164c 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args @@ -31,6 +31,10 @@ QEMU_AUDIO_DRV=none \ -device ioh3420,port=0x60,chassis=13,id=pci.13,bus=pcie.0,addr=0xc \ -device ioh3420,port=0x68,chassis=14,id=pci.14,bus=pcie.0,addr=0xd \ -device ioh3420,port=0x70,chassis=15,id=pci.15,bus=pcie.0,addr=0xe \ +-device ioh3420,port=0x78,chassis=16,id=pci.16,bus=pcie.0,addr=0xf \ +-device ioh3420,port=0x80,chassis=17,id=pci.17,bus=pcie.0,addr=0x10 \ +-device ioh3420,port=0x88,chassis=18,id=pci.18,bus=pcie.0,addr=0x11 \ +-device ioh3420,port=0x90,chassis=19,id=pci.19,bus=pcie.0,addr=0x12 \ -device nec-usb-xhci,id=usb,bus=pci.8,addr=0x0 \ -device virtio-scsi-pci,id=scsi0,bus=pci.7,addr=0x0 \ -device virtio-serial-pci,id=virtio-serial0,bus=pci.6,addr=0x0 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable-fallback.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable-fallback.args index deae687..c658177 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable-fallback.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable-fallback.args @@ -20,4 +20,8 @@ QEMU_AUDIO_DRV=none \ -boot n \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable.args index 871340f..aef95fe 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable.args @@ -20,4 +20,8 @@ QEMU_AUDIO_DRV=none \ -boot n \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-multi.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-multi.args index d465c69..1d90c62 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-multi.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-multi.args @@ -18,6 +18,10 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=56,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ addr=0x1d \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-reorder.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-reorder.args index 87d2ce7..5447fad 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-reorder.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2-reorder.args @@ -18,6 +18,10 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=56,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ addr=0x1d \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2.args index 1d44e7a..aa28390 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-usb2.args @@ -18,6 +18,10 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=56,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ addr=0x1d \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args index 163e7f1..6af428b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args @@ -23,6 +23,10 @@ QEMU_AUDIO_DRV=spice \ -device ioh3420,port=0x20,chassis=3,id=pci.3,bus=pcie.0,addr=0x4 \ -device ioh3420,port=0x28,chassis=4,id=pci.4,bus=pcie.0,addr=0x5 \ -device ioh3420,port=0x30,chassis=5,id=pci.5,bus=pcie.0,addr=0x6 \ +-device ioh3420,port=0x38,chassis=6,id=pci.6,bus=pcie.0,addr=0x7 \ +-device ioh3420,port=0x40,chassis=7,id=pci.7,bus=pcie.0,addr=0x8 \ +-device ioh3420,port=0x48,chassis=8,id=pci.8,bus=pcie.0,addr=0x9 \ +-device ioh3420,port=0x50,chassis=9,id=pci.9,bus=pcie.0,addr=0xa \ -device nec-usb-xhci,id=usb,bus=pci.2,addr=0x0 \ -device virtio-serial-pci,id=virtio-serial0,bus=pci.3,addr=0x0 \ -drive file=/var/lib/libvirt/images/basic.qcow2,format=qcow2,if=none,\ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-q35.args index 1d44e7a..aa28390 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35.args @@ -18,6 +18,10 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ -device pci-bridge,chassis_nr=56,id=pci.2,bus=pci.1,addr=0x0 \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \ -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\ addr=0x1d \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-default-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-default-q35.args index f98f838..718d761 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-default-q35.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-default-q35.args @@ -18,4 +18,8 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device pci-bridge,chassis_nr=56,id=pci.2,bus=pci.1,addr=0x0 \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device piix3-usb-uhci,id=usb,bus=pcie.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-explicit-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-explicit-q35.args index 5eb39ba..ca542fd 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-explicit-q35.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-controller-explicit-q35.args @@ -18,4 +18,8 @@ QEMU_AUDIO_DRV=none \ -boot c \ -device pci-bridge,chassis_nr=56,id=pci.2,bus=pci.1,addr=0x0 \ -device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \ +-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \ +-device ioh3420,port=0x18,chassis=4,id=pci.4,bus=pcie.0,addr=0x3 \ +-device ioh3420,port=0x20,chassis=5,id=pci.5,bus=pcie.0,addr=0x4 \ +-device ioh3420,port=0x28,chassis=6,id=pci.6,bus=pcie.0,addr=0x5 \ -device nec-usb-xhci,id=usb,bus=pcie.0,addr=0x1 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a0998ab..088cfb5 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -656,6 +656,7 @@ mymain(void) DO_TEST("machine-smm-opt", QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_MACHINE_SMM_OPT, @@ -673,10 +674,12 @@ mymain(void) DO_TEST("boot-floppy-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI); DO_TEST("bootindex-floppy-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_BOOT_MENU, QEMU_CAPS_BOOTINDEX); DO_TEST("boot-multi", QEMU_CAPS_BOOT_MENU); @@ -723,6 +726,7 @@ mymain(void) DO_TEST("bios-nvram-secure", QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_MACHINE_SMM_OPT, @@ -1297,18 +1301,22 @@ mymain(void) QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("usb-controller-default-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_PCI_OHCI, QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_NEC_USB_XHCI); DO_TEST_FAILURE("usb-controller-default-unavailable-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_PCI_OHCI, QEMU_CAPS_NEC_USB_XHCI); DO_TEST("usb-controller-explicit-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_PCI_OHCI, QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_NEC_USB_XHCI); DO_TEST_FAILURE("usb-controller-explicit-unavailable-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_PCI_OHCI, QEMU_CAPS_PIIX3_USB_UHCI); DO_TEST("usb-controller-xhci", @@ -1675,10 +1683,12 @@ mymain(void) DO_TEST("pcie-root", QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_DEVICE_PCI_BRIDGE, - QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE); + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420); DO_TEST("q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, @@ -1693,16 +1703,19 @@ mymain(void) QEMU_CAPS_DEVICE_IOH3420); DO_TEST("q35-pm-disable", QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PIIX_DISABLE_S3, QEMU_CAPS_PIIX_DISABLE_S4, QEMU_CAPS_ICH9_DISABLE_S3, QEMU_CAPS_ICH9_DISABLE_S4); DO_TEST("q35-pm-disable-fallback", QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PIIX_DISABLE_S3, QEMU_CAPS_PIIX_DISABLE_S4); DO_TEST("q35-usb2", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, @@ -1710,6 +1723,7 @@ mymain(void) DO_TEST("q35-usb2-multi", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, @@ -1717,6 +1731,7 @@ mymain(void) DO_TEST("q35-usb2-reorder", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, @@ -1864,6 +1879,7 @@ mymain(void) DO_TEST_PARSE_ERROR("q35-wrong-root", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, @@ -1977,6 +1993,7 @@ mymain(void) DO_TEST("pcihole64-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL, @@ -2009,13 +2026,15 @@ mymain(void) QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM, QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE, - QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE); + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420); DO_TEST("aarch64-virt-2.6-virtio-pci-default", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DTB, QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM, QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE, - QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE); + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420); /* Example of using virtio-pci with no explicit PCI controller but with manual PCI addresses */ DO_TEST("aarch64-virtio-pci-manual-addresses", @@ -2023,7 +2042,9 @@ mymain(void) QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM, QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE, - QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_VIRTIO_SCSI); DO_TEST("aarch64-video-virtio-gpu-pci", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420, @@ -2279,7 +2300,9 @@ mymain(void) DO_TEST("acpi-table", NONE); DO_TEST("intel-iommu", QEMU_CAPS_DEVICE_PCI_BRIDGE, - QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_DEVICE_INTEL_IOMMU); + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_DEVICE_INTEL_IOMMU); DO_TEST("cpu-hotplug-startup", QEMU_CAPS_QUERY_HOTPLUGGABLE_CPUS); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml index 26f6a51..1aefc8d 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml @@ -31,6 +31,26 @@ <target chassis='2' port='0x9'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1' multifunction='on'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <interface type='user'> <mac address='52:54:00:73:34:53'/> <model type='virtio'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-default.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-default.xml index 7c3fc19..8344599 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-default.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-default.xml @@ -36,6 +36,26 @@ <controller type='virtio-serial' index='0'> <address type='virtio-mmio'/> </controller> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='2' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> <interface type='user'> <mac address='52:54:00:09:a4:37'/> <model type='virtio'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-manual-addresses.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-manual-addresses.xml index 1b50f75..ad330c3 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-manual-addresses.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-virtio-pci-manual-addresses.xml @@ -50,6 +50,26 @@ <target chassisNr='3'/> <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <interface type='user'> <mac address='52:54:00:09:a4:37'/> <model type='virtio'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml index b5b2b51..2dfc9bb 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu.xml @@ -27,6 +27,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='virtio'> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-expander-bus.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-expander-bus.xml index 7a37870..c5fbf3f 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-expander-bus.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-expander-bus.xml @@ -217,6 +217,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='38' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='38' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='39' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='39' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='40' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='40' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='41' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='41' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> <interface type='user'> <mac address='52:54:00:f1:95:51'/> <model type='rtl8139'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root-port.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root-port.xml index a4ff820..3dc078a 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root-port.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root-port.xml @@ -42,6 +42,16 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <video> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml index b53ce24..00217bb 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml @@ -18,6 +18,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='2' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='none'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-switch-upstream-port.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-switch-upstream-port.xml index 53e10d0..6b250cb 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-switch-upstream-port.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-switch-upstream-port.xml @@ -50,6 +50,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='10' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <video> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcihole64-q35.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcihole64-q35.xml index dad7d1a..da88474 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcihole64-q35.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcihole64-q35.xml @@ -34,6 +34,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <video> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml index 8d7bc9d..96d2930 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml @@ -31,6 +31,26 @@ <target chassis='2' port='0x10'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x30'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='virtio'> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml index d784801..0e37b0e 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml @@ -97,6 +97,26 @@ <target chassis='13' port='0x70'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='14' port='0x78'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> + </controller> + <controller type='pci' index='15' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='15' port='0x80'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> + </controller> + <controller type='pci' index='16' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='16' port='0x88'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> + </controller> + <controller type='pci' index='17' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='17' port='0x90'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> + </controller> <filesystem type='mount' accessmode='passthrough'> <source dir='/export/to/guest'/> <target dir='/import/from/host'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml index 8e727fb..76e20da 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml @@ -106,6 +106,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='16' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='16' port='0x78'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> + </controller> + <controller type='pci' index='17' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='17' port='0x80'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> + </controller> + <controller type='pci' index='18' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='18' port='0x88'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> + </controller> + <controller type='pci' index='19' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='19' port='0x90'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> + </controller> <filesystem type='mount' accessmode='passthrough'> <source dir='/export/to/guest'/> <target dir='/import/from/host'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-multi.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-multi.xml index 06c0699..65a84a3 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-multi.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-multi.xml @@ -77,6 +77,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <video> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-reorder.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-reorder.xml index 1007095..f65a745 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-reorder.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2-reorder.xml @@ -77,6 +77,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <video> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2.xml index 58c7fab..b131ea1 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-usb2.xml @@ -47,6 +47,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <video> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml index fe9ea4e..7cd7a65 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml @@ -68,6 +68,26 @@ <target chassis='5' port='0x30'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x38'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='7' port='0x40'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='8' port='0x48'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='9' port='0x50'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> <interface type='user'> <mac address='52:54:00:9a:e6:c6'/> <model type='virtio'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml index 58c7fab..b131ea1 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml @@ -47,6 +47,26 @@ <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <video> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-default-q35.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-default-q35.xml index 082a92e..6ab2af3 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-default-q35.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-default-q35.xml @@ -30,6 +30,26 @@ <model name='i82801b11-bridge'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='none'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-explicit-q35.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-explicit-q35.xml index 540e817..96f2080 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-explicit-q35.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-controller-explicit-q35.xml @@ -30,6 +30,26 @@ <model name='i82801b11-bridge'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='none'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-vcpu-placement-static.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vcpu-placement-static.xml index c6471e3..89ae41a 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-vcpu-placement-static.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-vcpu-placement-static.xml @@ -35,6 +35,26 @@ <target chassisNr='2'/> <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='4' port='0x18'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='5' port='0x20'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='6' port='0x28'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='none'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 331763b..e13199d 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -592,10 +592,12 @@ mymain(void) QEMU_CAPS_PIIX3_USB_UHCI); DO_TEST("usb-controller-default-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_PCI_OHCI, QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_NEC_USB_XHCI); DO_TEST("usb-controller-explicit-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_PCI_OHCI, QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_NEC_USB_XHCI); DO_TEST("ppc64-usb-controller", @@ -673,23 +675,27 @@ mymain(void) DO_TEST("q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); DO_TEST("q35-usb2", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); DO_TEST("q35-usb2-multi", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); DO_TEST("q35-usb2-reorder", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); @@ -889,6 +895,7 @@ mymain(void) DO_TEST("pcihole64-none", NONE); DO_TEST("pcihole64-q35", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL, QEMU_CAPS_Q35_PCI_HOLE64_SIZE); @@ -932,13 +939,17 @@ mymain(void) QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM, QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE, - QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_VIRTIO_SCSI); DO_TEST("aarch64-virtio-pci-manual-addresses", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DTB, QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM, QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE, - QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_VIRTIO_SCSI); DO_TEST("aarch64-video-virtio-gpu-pci", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420, @@ -985,7 +996,8 @@ mymain(void) DO_TEST("video-qxl-noheads", NONE); DO_TEST("intel-iommu", - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE); + QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_DEVICE_IOH3420); qemuTestDriverFree(&driver); -- 2.7.4

On Thu, 2016-09-29 at 15:20 -0400, Laine Stump wrote:
For machinetypes with a pci-root bus (all legacy PCI), libvirt will make a "fake" reservation for one extra slot prior to assigning addresses to unaddressed PCI endpoint devices in the domain. This will trigger auto-adding of a pci-bridge for the final device to be assigned an address *if that device would have otherwise instead been the last device on the last available pci-bridge*; thus it assures that there will always be at least one slot left open in the domains bus topology for expansion (which is important both for hotplug (since a new pci-bridge can't be added while the guest is running) as well as for coldplug (since adding a new device might otherwise in some cases require re-addressing existing devices, which we want to avoid)). It's important to note that for this (legacy PCI) case, we must check for the special case of all slots on all buses being occupied *prior to assigning any addresses*, and avoid attempting to reserve the extra address in that case, because there is no free address in the existing topology, so no place to auto-add a pci-bridge for expansion. Since that condition can only be reached by manual intervention, this is acceptable. For machinetypes with pcie-root, libvirt's methodology for automatically expanding the bus topology is different - pcie-root-ports are plugged into slots (soon to be functions) of pcie-root as needed, and the new endpoint devices are assigned to the single slot in each pcie-root-port. This is done so that the devices are, by default, hotpluggable (the slots of pcie-root don't support hotplug, but the single slot of the pcie-root-port does). Since pcie-root-ports can only be plugged into pcie-root, and we don't auto-assign endpoint devices to those slots, this means topology expansion doesn't compete with endpoint devices for slots, so we don't need to worry about checking for all "useful" slots being free prior to assigning addresses to new endpoint devices - as a matter of fact, if we attempt to reserve the fake slots before the useful slots, it can lead to errors. Instead this patch just reserves slots for "fake" devices after doing the assignment for actual devices - if there were already enough unoccupied pcie-root-ports, then none will be added; if not, then enough will be added to support the desired (hardcoded) potential number of hotplugged devices. Since there hasn't been any other concrete suggestion for the number of "available hotpluggable slots" libvirt should assure, this patch uses "4" as the answer (thanks Drew!) Alternatives could be: 0 - hotplug would only work if the user had thought to add an extra pcie-root to the config *as an extra step after adding and saving each new device*. (this would preclude creating a new domain that had a pcie-root-port available for hotplug - the extra modify/save step would be needed even during initial domain creation, and would need to be repeated every time a device was added to the domain) 1 - this is the *minimum* number of hotpluggable slots libvirt guarantees for legacy PCI domains (with pci-root). Of course on average these domains are more likely to have *15* slots available (half of the slots on a pci-bridge). "anything else" - really any choice made for this is going to be considered wrong by *somebody*. I hope we can all agree that "0" is a wrong choice, just because it will require so much ongoing babysitting. A couple of us have brought up the idea of having "availableHotplugSlots" be configurable in the domain. There has also been sentiment against that. Perhaps it could be configurable in qemu.conf? (I don't really like that either, though - I think everything about the domain should be self-contained in the domain XML, and if something is tunable, it should be tunable separately for each domain). In the absense of anything configurable, we will need to pick a number though. I've done that here, and now we can argue about it (or not :-)
As we have already agreed on a slightly different approach,x eg. doing pretty much exactly this, but only if the configuration provided by the user contains no PCI controller (except possibly for pcie-root), I think it's fair to say: NACK -- Andrea Bolognani / Red Hat / Virtualization

On Thu, 2016-09-29 at 15:20 -0400, Laine Stump wrote:
In the absense of anything configurable, we will need to pick a number though. I've done that here, and now we can argue about it (or not :-)
Ján raised an interesting point: whatever number we choose, no matter how wrong doing so is, some user or application will end up relying on us providing at least that many hotpluggable ports, so there's no going back. For that reason, I would recommend leaving just a single empty hotpluggable port for now, and raise the number in the future if we find out that one's definitely not enough. -- Andrea Bolognani / Red Hat / Virtualization

On 10/14/2016 09:13 AM, Andrea Bolognani wrote:
On Thu, 2016-09-29 at 15:20 -0400, Laine Stump wrote:
In the absense of anything configurable, we will need to pick a number though. I've done that here, and now we can argue about it (or not :-) Ján raised an interesting point: whatever number we choose, no matter how wrong doing so is, some user or application will end up relying on us providing at least that many hotpluggable ports, so there's no going back.
For that reason, I would recommend leaving just a single empty hotpluggable port for now, and raise the number in the future if we find out that one's definitely not enough.
That makes sense. I've already updated the patch per our conversation in the other thread, but will update it further to reflect this idea as well.

On Fri, Oct 14, 2016 at 03:13:16PM +0200, Andrea Bolognani wrote:
On Thu, 2016-09-29 at 15:20 -0400, Laine Stump wrote:
In the absense of anything configurable, we will need to pick a number though. I've done that here, and now we can argue about it (or not :-)
Ján raised an interesting point:
[in person, there is no mailing list link]
whatever number we choose, no matter how wrong doing so is, some user or application will end up relying on us providing at least that many hotpluggable ports, so there's no going back.
For that reason, I would recommend leaving just a single empty hotpluggable port for now, and raise the number in the future if we find out that one's definitely not enough.
Also, would it be possible to make this feature of leaving free hot-pluggable slots opt-in? E.g. a <controller model='pcie-root-port'> without an index would be considered a port where we should not put devices with auto-assigned addresses. (This might actually be more ugly than the proposed solution, or the 'freeHotplugSlots' attribute, but I dislike implicit device additions after having model='none' memballoon and usb controller) Jan

On Fri, 2016-10-14 at 16:54 +0200, Ján Tomko wrote:
Also, would it be possible to make this feature of leaving free hot-pluggable slots opt-in? E.g. a <controller model='pcie-root-port'> without an index would be considered a port where we should not put devices with auto-assigned addresses. (This might actually be more ugly than the proposed solution, or the 'freeHotplugSlots' attribute, but I dislike implicit device additions after having model='none' memballoon and usb controller)
If we can find a way to make it opt-in without it turning out incredibly ugly (eg. 'freeHotplugSlots' or similar paramers) or requiring too much knowledge from the users / management applications (eg. "you have x legacy PCI devices and y PCI Express devices, that means adding x + y + z + 3 pcie-root-ports before passing the XML to libvirt") I'm all for that. So far we haven't been able to come up with anything like that, though :) I think the current proposal is fairly okay because it allows for easy opt-out, and if we reduce the number of extra ports to just one as per your comments I don't think people will care at all. As far as I'm concerned, that's a very good balance; it's certainly better than the status quo of adding a completely useless dmi-to-pci-bridge + pci-bridge combination to every single q35 guest. -- Andrea Bolognani / Red Hat / Virtualization
participants (6)
-
Alex Williamson
-
Andrea Bolognani
-
Gerd Hoffmann
-
Ján Tomko
-
Laine Stump
-
Marcel Apfelbaum