[libvirt] [PATCH v4 00/25] Use more PCIe less legacy PCI

The latest version of patches to auto-assign appropriate devices in PCIe-capable domains to PCIe slots rather than legacy PCI, and to also auto-add pcie-root-ports as necessary to make this easier. I *think* I've dealt with all of Andrea's great critiques of V3, either in my email responses or in these revised patches. Aside from fixing typos and formatting problems, I also moved several "little cosmetic fixes" out of the bigger functionality-changing patches, and also split out the most confusing part of patch 20 (previously patch 15 - the one that auto-adds pcie-root-port and dmi-to-pci-bridge controllers) into its own patch (doubly useful since the value of that part of the patch is dubious - it is now the [RFC] patch 21) As many of the simple costmetic patches as possible were pushed up to the front of the series (if they weren't already there). If those are ACKed on this round but others aren't, I'll push them immediately so I don't need to resubmit the whole series again. Some of these patches were ACKed last time, but I either had to change them further due to changes in other patches, or I couldn't push them because they have prerequisites that weren't ACKed. I've marked those in the subject line (I've also marked entirely new patches in the subject line). Laine Stump (25): qemu: new functions qemuDomainMachineHasPCI[e]Root() qemu: replace a lot of "def->controllers[i]" with equivalent "cont" qemu: replace "def->nets[i]" with "net" and "def->sounds[i]" with "sound" conf: add typedef for anonymous enum used for memballoon device model qemu: remove superfluous setting of addrs->nbuses qemu: make error message in qemuDomainPCIAddressSetCreate more clear. qemu: change first arg of qemuDomainAttachChrDeviceAssignAddr() 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: new functions to calculate/set device pciConnectFlags qemu: set/use info->pciConnectFlags when validating/assigning PCI addresses qemu: set/use proper pciConnectFlags during hotplug qemu: set pciConnectFlags to 0 instead of PCI|HOTPLUGGABLE if device isn't PCI 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 [RFC] qemu: if pci-bridge is in PCIe config w/o dmi-to-pci-bridge, add it qemu: don't force-add a dmi-to-pci-bridge just on principle qemu: add a USB3 controller to Q35 domains by default qemu: try to put ich9 sound device at 00:1B.0 qemu: initially reserve one open pcie-root-port for hotplug src/conf/device_conf.h | 5 + src/conf/domain_addr.c | 163 ++- src/conf/domain_addr.h | 11 +- src/conf/domain_conf.h | 4 +- src/libvirt_private.syms | 2 +- src/qemu/qemu_domain.c | 52 +- src/qemu/qemu_domain.h | 2 + src/qemu/qemu_domain_address.c | 1097 +++++++++++++++----- src/qemu/qemu_domain_address.h | 4 + src/qemu/qemu_hotplug.c | 27 +- tests/qemuxml2argvdata/qemuxml2argv-autoindex.args | 10 +- .../qemuxml2argv-bios-nvram-secure.args | 1 + .../qemuxml2argv-machine-smm-opt.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args | 3 +- .../qemuxml2argv-q35-default-devices-only.args | 23 + .../qemuxml2argv-q35-default-devices-only.xml | 18 + .../qemuxml2argv-q35-pcie-autoadd.args | 57 + .../qemuxml2argv-q35-pcie-autoadd.xml | 51 + tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 58 ++ tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 67 ++ .../qemuxml2argv-q35-pm-disable-fallback.args | 1 + .../qemuxml2argv-q35-pm-disable.args | 1 + .../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 | 164 ++- .../qemuxml2xmlout-autoindex.xml | 10 +- .../qemuxml2xmlout-pcie-root.xml | 4 - .../qemuxml2xmlout-q35-default-devices-only.xml | 45 + .../qemuxml2xmlout-q35-pcie-autoadd.xml | 148 +++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 152 +++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 121 +++ .../qemuxml2xmlout-q35-virtio-pci.xml | 152 +++ tests/qemuxml2xmltest.c | 136 ++- 35 files changed, 2417 insertions(+), 364 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

These functions provide a simple one line method of learning if the current domain has a pci-root or pcie-root bus. --- Changes: "reversed polarity" of 2nd if clause as suggested by Andrea. src/qemu/qemu_domain.c | 30 ++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 2 ++ 2 files changed, 32 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0c9416f..aa54206 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5352,6 +5352,36 @@ 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 false; + + return true; +} + + +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 false; + + return true; +} + + +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 dee5d93..8302630 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -640,6 +640,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 Fri, 2016-10-14 at 15:53 -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. ---
Changes: "reversed polarity" of 2nd if clause as suggested by Andrea.
src/qemu/qemu_domain.c | 30 ++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 2 ++ 2 files changed, 32 insertions(+)
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. --- Change: added more instances of the same change. src/qemu/qemu_domain_address.c | 208 ++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 97 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index dc67d51..e6abadf 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -220,18 +220,22 @@ qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def, } for (i = 0; i < def->ncontrollers; i++) { - model = def->controllers[i]->model; - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { + virDomainControllerDefPtr cont = def->controllers[i]; + + model = cont->model; + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { if (qemuDomainSetSCSIControllerModel(def, qemuCaps, &model) < 0) goto cleanup; } if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI && - def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) - def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO; - if (qemuDomainAssignSpaprVIOAddress(def, &def->controllers[i]->info, - VIO_ADDR_SCSI) < 0) + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { + cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO; + } + if (qemuDomainAssignSpaprVIOAddress(def, &cont->info, + VIO_ADDR_SCSI) < 0) { goto cleanup; + } } for (i = 0; i < def->nserials; i++) { @@ -292,13 +296,13 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDefPtr def, } for (i = 0; i < def->ncontrollers; i++) { - if ((def->controllers[i]->type == - VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL || - def->controllers[i]->type == - VIR_DOMAIN_CONTROLLER_TYPE_SCSI) && - def->controllers[i]->info.type == - VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) - def->controllers[i]->info.type = type; + virDomainControllerDefPtr cont = def->controllers[i]; + + if ((cont->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL || + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) && + cont->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + cont->info.type = type; + } } if (def->memballoon && @@ -568,9 +572,10 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, } 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) { @@ -580,8 +585,7 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, goto error; } - if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], - def->controllers[i]->model) < 0) + if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; } @@ -611,44 +615,46 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, /* Verify that first IDE and USB controllers (if any) is on the PIIX3, fn 1 */ for (i = 0; i < def->ncontrollers; i++) { + virDomainControllerDefPtr cont = def->controllers[i]; + /* First IDE controller lives on the PIIX3 at slot=1, function=1 */ - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && - 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 != 1 || - def->controllers[i]->info.addr.pci.function != 1) { + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && + 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 != 1 || + cont->info.addr.pci.function != 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Primary IDE controller must have PCI address 0:0:1.1")); 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 = 1; - def->controllers[i]->info.addr.pci.function = 1; + 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 = 1; + cont->info.addr.pci.function = 1; } - } else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && - def->controllers[i]->idx == 0 && - (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI || - def->controllers[i]->model == -1)) { - 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 != 1 || - def->controllers[i]->info.addr.pci.function != 2) { + } else if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + cont->idx == 0 && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI || + cont->model == -1)) { + if (virDeviceInfoPCIAddressPresent(&cont->info)) { + if (cont->info.addr.pci.domain != 0 || + cont->info.addr.pci.bus != 0 || + cont->info.addr.pci.slot != 1 || + cont->info.addr.pci.function != 2) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("PIIX3 USB controller must have PCI address 0:0:1.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 = 1; - 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 = 1; + cont->info.addr.pci.function = 2; } } } @@ -743,36 +749,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 +806,19 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, false, true) < 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 = tmp_addr.slot; - def->controllers[i]->info.addr.pci.function = 0; - def->controllers[i]->info.addr.pci.multi - = VIR_TRISTATE_SWITCH_ON; + 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 = 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 +829,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 +1007,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" @@ -1015,9 +1023,9 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, */ flags = virDomainPCIControllerModelToConnectType(model); if (virDomainPCIAddressReserveNextSlot(addrs, - &def->controllers[i]->info, - flags) < 0) + &cont->info, flags) < 0) { goto error; + } } } @@ -1071,38 +1079,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 +1120,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,13 +1157,13 @@ 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) + &cont->info, flags) < 0) { goto error; + } } } @@ -1400,8 +1410,10 @@ qemuDomainAddressFindNewBusNr(virDomainDefPtr def) int lowestBusNr = 256; for (i = 0; i < def->ncontrollers; i++) { - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { - int thisBusNr = def->controllers[i]->opts.pciopts.busNr; + virDomainControllerDefPtr cont = def->controllers[i]; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { + int thisBusNr = cont->opts.pciopts.busNr; if (thisBusNr >= 0 && thisBusNr < lowestBusNr) lowestBusNr = thisBusNr; @@ -1436,9 +1448,11 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, 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) - max_idx = def->controllers[i]->idx; + virDomainControllerDefPtr cont = def->controllers[i]; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { + if ((int) cont->idx > max_idx) + max_idx = cont->idx; } } -- 2.7.4

On Fri, 2016-10-14 at 15:53 -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. --- Change: added more instances of the same change. src/qemu/qemu_domain_address.c | 208 ++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 97 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index dc67d51..e6abadf 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -220,18 +220,22 @@ qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def, } for (i = 0; i < def->ncontrollers; i++) { - model = def->controllers[i]->model; - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { + virDomainControllerDefPtr cont = def->controllers[i]; + + model = cont->model; + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { if (qemuDomainSetSCSIControllerModel(def, qemuCaps, &model) < 0)
Definitely not something that should be touched by this patch, but shouldn't we pass &cont->model here? I mean, if the value stored in model will be different than the one that was already in cont->model, it means that the default controller model was not set properly earlier... On the other hand, the default model should really have been set in PostParse() or something like that.
@@ -743,36 +749,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) &&
You can now join these two lines...
- (def->controllers[i]->info.type + (cont->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) {
... and these two. ACK with that nit fixed. -- Andrea Bolognani / Red Hat / Virtualization

On 10/18/2016 07:22 AM, Andrea Bolognani wrote:
On Fri, 2016-10-14 at 15:53 -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. ---
Change: added more instances of the same change.
src/qemu/qemu_domain_address.c | 208 ++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 97 deletions(-)
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index dc67d51..e6abadf 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -220,18 +220,22 @@ qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def, }
for (i = 0; i < def->ncontrollers; i++) { - model = def->controllers[i]->model; - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { + virDomainControllerDefPtr cont = def->controllers[i]; + + model = cont->model; + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { if (qemuDomainSetSCSIControllerModel(def, qemuCaps, &model) < 0) Definitely not something that should be touched by this patch, but shouldn't we pass &cont->model here?
I mean, if the value stored in model will be different than the one that was already in cont->model, it means that the default controller model was not set properly earlier...
On the other hand, the default model should really have been set in PostParse() or something like that.
The function qemuDomainSetSCSIControllerModel() seems to be a confused mess. If model is set (non-0) then it checks the qemuCaps to makes sure the model that's set is allowed. Otherwise, it sets a default model. *All* calls to this function are on a temporary variable rather than the item in the controller object, so any non-zero model set will never be stored in the config. Why it is that way, I have no idea. I choose to not touch it, for fear that something offbeat would break. (Maybe it's done this way because some old version of libvirt 6 or 7 years ago didn't support setting a scsi controller model or something? Who knows...)

More occurences of repeatedly dereferencing the same pointer stored in an array are replaced with the definition of a temporary pointer that is then used directly. No functional change. --- src/qemu/qemu_domain_address.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index e6abadf..d2a3237 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -211,11 +211,12 @@ qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def, /* Default values match QEMU. See spapr_(llan|vscsi|vty).c */ for (i = 0; i < def->nnets; i++) { - if (def->nets[i]->model && - STREQ(def->nets[i]->model, "spapr-vlan")) - def->nets[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO; - if (qemuDomainAssignSpaprVIOAddress(def, &def->nets[i]->info, - VIO_ADDR_NET) < 0) + virDomainNetDefPtr net = def->nets[i]; + + if (net->model && + STREQ(net->model, "spapr-vlan")) + net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO; + if (qemuDomainAssignSpaprVIOAddress(def, &net->info, VIO_ADDR_NET) < 0) goto cleanup; } @@ -283,9 +284,11 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDefPtr def, } for (i = 0; i < def->nnets; i++) { - if (STREQ(def->nets[i]->model, "virtio") && - def->nets[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { - def->nets[i]->info.type = type; + virDomainNetDefPtr net = def->nets[i]; + + if (STREQ(net->model, "virtio") && + net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + net->info.type = type; } } @@ -1049,31 +1052,33 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, /* Network interfaces */ for (i = 0; i < def->nnets; i++) { + virDomainNetDefPtr net = def->nets[i]; + /* type='hostdev' network devices might be USB, and are also * 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)) { + if ((net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) || + !virDeviceInfoPCIAddressWanted(&net->info)) { continue; } - if (virDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info, - flags) < 0) + if (virDomainPCIAddressReserveNextSlot(addrs, &net->info, flags) < 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 (virDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info, - flags) < 0) + if (virDomainPCIAddressReserveNextSlot(addrs, &sound->info, flags) < 0) goto error; } -- 2.7.4

On Fri, 2016-10-14 at 15:53 -0400, Laine Stump wrote:
More occurences of repeatedly dereferencing the same pointer stored in an array are replaced with the definition of a temporary pointer that is then used directly. No functional change. --- src/qemu/qemu_domain_address.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index e6abadf..d2a3237 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -211,11 +211,12 @@ qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def, /* Default values match QEMU. See spapr_(llan|vscsi|vty).c */ for (i = 0; i < def->nnets; i++) { - if (def->nets[i]->model && - STREQ(def->nets[i]->model, "spapr-vlan")) - def->nets[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO; - if (qemuDomainAssignSpaprVIOAddress(def, &def->nets[i]->info, - VIO_ADDR_NET) < 0) + virDomainNetDefPtr net = def->nets[i]; + + if (net->model && + STREQ(net->model, "spapr-vlan")) + net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO;
Our coding style requires brackets here, please add them. [...]
/* 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;
This one needs brackets as well. ACK with those nits fixed. -- Andrea Bolognani / Red Hat / Virtualization

For some reason the values of memballoon model are set using an anonymous enum, making it impossible to perform nice tricks like demanding there are cases for all possible values in a switch. This patch turns the anonymous enum into virDomainMemBalloonModel. --- src/conf/domain_conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3e85ae4..d415d2e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1536,13 +1536,13 @@ struct _virDomainRedirFilterDef { virDomainRedirFilterUSBDevDefPtr *usbdevs; }; -enum { +typedef enum { VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO, VIR_DOMAIN_MEMBALLOON_MODEL_XEN, VIR_DOMAIN_MEMBALLOON_MODEL_NONE, VIR_DOMAIN_MEMBALLOON_MODEL_LAST -}; +} virDomainMemBalloonModel; struct _virDomainMemballoonDef { int model; -- 2.7.4

On Fri, 2016-10-14 at 15:54 -0400, Laine Stump wrote:
For some reason the values of memballoon model are set using an anonymous enum, making it impossible to perform nice tricks like demanding there are cases for all possible values in a switch. This patch turns the anonymous enum into virDomainMemBalloonModel. --- src/conf/domain_conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3e85ae4..d415d2e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1536,13 +1536,13 @@ struct _virDomainRedirFilterDef { virDomainRedirFilterUSBDevDefPtr *usbdevs; }; -enum { +typedef enum { VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO, VIR_DOMAIN_MEMBALLOON_MODEL_XEN, VIR_DOMAIN_MEMBALLOON_MODEL_NONE, VIR_DOMAIN_MEMBALLOON_MODEL_LAST -}; +} virDomainMemBalloonModel; struct _virDomainMemballoonDef { int model;
Great catch! However, you'll want to s/MemBalloon/Memballoon/ because further down the file you can find VIR_ENUM_DECL(virDomainMemballoonModel) I like your name better, by the way, so if you feel like renameing every instance in a separate patch I'll gladly review and ACK it :) ACK with the above taken care of. -- Andrea Bolognani / Red Hat / Virtualization

This is already set by virDomainPCIAddressSetAlloc(). --- src/qemu/qemu_domain_address.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index d2a3237..3926b18 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -556,7 +556,6 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) return NULL; - addrs->nbuses = nbuses; addrs->dryRun = dryRun; /* As a safety measure, set default model='pci-root' for first pci -- 2.7.4

On Fri, 2016-10-14 at 15:54 -0400, Laine Stump wrote:
This is already set by virDomainPCIAddressSetAlloc(). --- src/qemu/qemu_domain_address.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index d2a3237..3926b18 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -556,7 +556,6 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) return NULL;
- addrs->nbuses = nbuses; addrs->dryRun = dryRun;
/* As a safety measure, set default model='pci-root' for first pci
ACK -- Andrea Bolognani / Red Hat / Virtualization

This error should only ever be seen by a developer anyway, but the existing message made even less sense that this new version. --- src/qemu/qemu_domain_address.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 3926b18..8628dc1 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -583,7 +583,7 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, 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; } -- 2.7.4

On Fri, 2016-10-14 at 15:54 -0400, Laine Stump wrote:
This error should only ever be seen by a developer anyway, but the existing message made even less sense that this new version. --- src/qemu/qemu_domain_address.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 3926b18..8628dc1 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -583,7 +583,7 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, 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; }
ACK -- Andrea Bolognani / Red Hat / Virtualization

from virDomainDefPtr to virDomainObjPtr so that the function has access to the other parts of the virDomainObjPtr. Take advantage of this by removing the "priv" arg and retrieving it from the virDomainObjPtr instead. No functional change. --- src/qemu/qemu_hotplug.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 14af4e1..dc0faa6 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1636,10 +1636,11 @@ qemuDomainChrRemove(virDomainDefPtr vmdef, } static int -qemuDomainAttachChrDeviceAssignAddr(virDomainDefPtr def, - qemuDomainObjPrivatePtr priv, +qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm, virDomainChrDefPtr chr) { + virDomainDefPtr def = vm->def; + qemuDomainObjPrivatePtr priv = vm->privateData; int ret = -1; virDomainVirtioSerialAddrSetPtr vioaddrs = NULL; @@ -1715,7 +1716,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, chr)) < 0) goto cleanup; if (rc == 1) need_release = true; -- 2.7.4

On Fri, 2016-10-14 at 15:54 -0400, Laine Stump wrote:
from virDomainDefPtr to virDomainObjPtr so that the function has access to the other parts of the virDomainObjPtr. Take advantage of this by removing the "priv" arg and retrieving it from the virDomainObjPtr instead.
No functional change. --- src/qemu/qemu_hotplug.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 14af4e1..dc0faa6 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1636,10 +1636,11 @@ qemuDomainChrRemove(virDomainDefPtr vmdef, }
static int -qemuDomainAttachChrDeviceAssignAddr(virDomainDefPtr def, - qemuDomainObjPrivatePtr priv, +qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm, virDomainChrDefPtr chr) { + virDomainDefPtr def = vm->def; + qemuDomainObjPrivatePtr priv = vm->privateData; int ret = -1; virDomainVirtioSerialAddrSetPtr vioaddrs = NULL;
@@ -1715,7 +1716,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, chr)) < 0) goto cleanup; if (rc == 1) need_release = true;
ACK -- 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). --- Changes: Fixed indentation and comments, and removed unnecessary setting of lastaddr.function and lastaddr.multi. src/conf/domain_addr.c | 49 +++++++++++++++++++++++++++++++++++++++++++----- src/conf/domain_addr.h | 7 +++++++ src/libvirt_private.syms | 1 + 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 080d882..1710220 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -691,29 +691,68 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, return 0; } + +/** + * virDomainPCIAddressReserveNextAddr: + * + * find the next *completely unreserved* slot with compatible + * connection @flags, mark either one function or the entire + * slot as in-use (according to @function and @reserveEntireSlot), + * and set @dev->addr.pci with this newly reserved address. + * + * @addrs: a set of PCI addresses. + * + * @dev: virDomainDeviceInfo that should get the new address. + * + * @flags: CONNECT_TYPE flags for the device that needs an address. + * + * @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 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->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 55b6a24..9f9512a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -102,6 +102,7 @@ virDomainPCIAddressFlagsCompatible; virDomainPCIAddressGetNextSlot; virDomainPCIAddressReleaseSlot; virDomainPCIAddressReserveAddr; +virDomainPCIAddressReserveNextAddr; virDomainPCIAddressReserveNextSlot; virDomainPCIAddressReserveSlot; virDomainPCIAddressSetAlloc; -- 2.7.4

On Fri, 2016-10-14 at 15:54 -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). --- Changes: Fixed indentation and comments, and removed unnecessary setting of lastaddr.function and lastaddr.multi. src/conf/domain_addr.c | 49 +++++++++++++++++++++++++++++++++++++++++++----- src/conf/domain_addr.h | 7 +++++++ src/libvirt_private.syms | 1 + 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 080d882..1710220 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -691,29 +691,68 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, return 0; } + +/** + * virDomainPCIAddressReserveNextAddr: + * + * find the next *completely unreserved* slot with compatible + * connection @flags, mark either one function or the entire + * slot as in-use (according to @function and @reserveEntireSlot), + * and set @dev->addr.pci with this newly reserved address.
This looks much much better...
+ * @addrs: a set of PCI addresses. + * + * @dev: virDomainDeviceInfo that should get the new address. + * + * @flags: CONNECT_TYPE flags for the device that needs an address. + * + * @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
... but these are still weird. Please take a look at include/libvirt/libvirt-domain.h to see what I mean. Interestingly, in that file the arguments are documented *before* describing the function itself. We should probably stick to that order here as well.
+ *
Extra line here, didn't notice it the first time around.
+ * + * returns 0 on success, or -1 on failure. + */ int -virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, +virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
ACK after you tweak indentation for the comment :) -- Andrea Bolognani / Red Hat / Virtualization

instead of calling virDomainPCIAddressGetNextSlot() (which I want to turn into a local static in domain_addr.c). --- Change: fixed line length src/qemu/qemu_domain_address.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 8628dc1..fa52383 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1005,7 +1005,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++) { @@ -1113,7 +1112,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 && @@ -1143,26 +1141,25 @@ 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) { -- 2.7.4

On Fri, 2016-10-14 at 15:54 -0400, Laine Stump wrote:
instead of calling virDomainPCIAddressGetNextSlot() (which I want to turn into a local static in domain_addr.c). ---
Change: fixed line length
src/qemu/qemu_domain_address.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-)
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 1710220..3a9e474 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 9f9512a..0c76f17 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -99,7 +99,6 @@ virDomainPCIAddressAsString; virDomainPCIAddressBusSetModel; virDomainPCIAddressEnsureAddr; virDomainPCIAddressFlagsCompatible; -virDomainPCIAddressGetNextSlot; virDomainPCIAddressReleaseSlot; virDomainPCIAddressReserveAddr; virDomainPCIAddressReserveNextAddr; -- 2.7.4

On Fri, 2016-10-14 at 15:54 -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 1710220..3a9e474 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);
As noted while reviewing v3, you're losing both ATTRIBUTE_NONNULL() with this commit. I was probably not clear enough last time around, sorry about that :( ACK with the attributes properly carried over. -- Andrea Bolognani / Red Hat / Virtualization

On 10/18/2016 10:46 AM, Andrea Bolognani wrote:
On Fri, 2016-10-14 at 15:54 -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 1710220..3a9e474 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); As noted while reviewing v3, you're losing both ATTRIBUTE_NONNULL() with this commit. I was probably not clear enough last time around, sorry about that :(
Nah, I just assumed you were merely pointing it out, not that you actually wanted me to maintain it in the static function. I actually dislike ATTRIBUTE_NONNULL() because it doesn't guarantee any behavior of the functions callers, and even worse - it ends up optimizing out any code in the function that actually *checks* for those arguments being NULL. So it ends up being 0 help in catching any accidental NULL references (*maybe* it can be used by a static analyzer, but I remember at least one occasion where it actually covered up / created a bug by removing the check for NULL when one of the callers of a function actually was sending a NULL). Still, I'll move the ATTRIBUTE_NONNULL over to the static function, and leave the debate of whether or not it really should be there to another day.

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. --- Change: realigned/reformatted src/qemu/qemu_domain_address.c | 96 ++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index fa52383..b4ea906 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -406,6 +406,27 @@ qemuDomainAssignARMVirtioMMIOAddresses(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, @@ -691,7 +712,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { - if (virDomainPCIAddressReserveNextSlot(addrs, + if (qemuDomainPCIAddressReserveNextSlot(addrs, &primaryVideo->info, flags) < 0) goto cleanup; @@ -882,7 +903,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { - if (virDomainPCIAddressReserveNextSlot(addrs, + if (qemuDomainPCIAddressReserveNextSlot(addrs, &primaryVideo->info, flags) < 0) goto cleanup; @@ -919,7 +940,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, " device will not be possible without manual" " intervention"); virResetLastError(); - } else if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) { + } else if (virDomainPCIAddressReserveSlot(addrs, + &tmp_addr, flags) < 0) { goto cleanup; } } @@ -1023,8 +1045,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; } } @@ -1043,8 +1065,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; } @@ -1060,7 +1082,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&net->info)) { continue; } - if (virDomainPCIAddressReserveNextSlot(addrs, &net->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &net->info, flags) < 0) goto error; } @@ -1076,7 +1098,7 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, sound->model == VIR_DOMAIN_SOUND_MODEL_USB) continue; - if (virDomainPCIAddressReserveNextSlot(addrs, &sound->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &sound->info, flags) < 0) goto error; } @@ -1152,17 +1174,18 @@ 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; } } @@ -1195,8 +1218,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; } @@ -1208,9 +1231,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; } @@ -1218,9 +1240,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; } @@ -1230,8 +1252,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; } @@ -1239,8 +1261,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; } @@ -1248,16 +1270,16 @@ 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; } for (i = 1; i < def->nvideos; i++) { 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; } @@ -1266,8 +1288,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++) { @@ -1275,8 +1297,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++) { @@ -1289,7 +1311,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++) { @@ -1486,7 +1508,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) @@ -1501,7 +1523,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 Fri, 2016-10-14 at 15:54 -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. --- Change: realigned/reformatted src/qemu/qemu_domain_address.c | 96 ++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 37 deletions(-)
[...]
@@ -691,7 +712,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { if (qemuDeviceVideoUsable) { - if (virDomainPCIAddressReserveNextSlot(addrs, + if (qemuDomainPCIAddressReserveNextSlot(addrs, &primaryVideo->info, flags) < 0)
Alignment's still off here. ACK with that fixed. -- Andrea Bolognani / Red Hat / Virtualization

The lowest level function of this trio (qemuDomainDeviceCalculatePCIConnectFlags()) aims to be the single authority for the virDomainPCIConnectFlags to use for any given device using a particular arch/machinetype/qemu-binary. qemuDomainFillDevicePCIConnectFlags() sets info->pciConnectFlags in a single device (unless it has no virDomainDeviceInfo, in which case it's a NOP). qemuDomainFillAllPCIConnectFlags() sets info->pciConnectFlags in all devices that have a virDomainDeviceInfo The latter two functions aren't called anywhere yet. This commit is just making them available. Later patches will replace all the current hodge-podge of flag settings with calls to this single authority. --- Change: re-implemented as a giant two-level compound switch statement with no default cases, as suggested by Andrea. Also start off with the function setting the flags for *all* devices to PCI_DEVICE|HOTPLUGGABLE, which is what's currently used when assigning addresses (as opposed to merely validating addresses, which is much less strict). src/conf/device_conf.h | 5 + src/qemu/qemu_domain_address.c | 379 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 384 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 b4ea906..457eae6 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -405,6 +405,385 @@ qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def, } +/** + * qemuDomainDeviceCalculatePCIConnectFlags: + * + * Lowest level function to determine PCI connectFlags for a + * device. 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 +qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, + virDomainPCIConnectFlags pcieFlags + ATTRIBUTE_UNUSED, + virDomainPCIConnectFlags virtioFlags + ATTRIBUTE_UNUSED) +{ + virDomainPCIConnectFlags pciFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_HOTPLUGGABLE); + + switch ((virDomainDeviceType)dev->type) { + case VIR_DOMAIN_DEVICE_CONTROLLER: { + virDomainControllerDefPtr cont = dev->data.controller; + + switch ((virDomainControllerType)cont->type) { + case VIR_DOMAIN_CONTROLLER_TYPE_PCI: + return virDomainPCIControllerModelToConnectType(cont->model); + + case VIR_DOMAIN_CONTROLLER_TYPE_SATA: + return pciFlags; + + case VIR_DOMAIN_CONTROLLER_TYPE_USB: + switch ((virDomainControllerModelUSB)cont->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: + return pciFlags; + + 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: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: + return pciFlags; + + case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1: /* xen only */ + case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2: /* xen only */ + case VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_CONTROLLER_TYPE_IDE: + case VIR_DOMAIN_CONTROLLER_TYPE_SCSI: + case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: + return pciFlags; + + case VIR_DOMAIN_CONTROLLER_TYPE_FDC: + case VIR_DOMAIN_CONTROLLER_TYPE_CCID: + case VIR_DOMAIN_CONTROLLER_TYPE_LAST: + /* should be 0 */ + return pciFlags; + } + } + + case VIR_DOMAIN_DEVICE_FS: + /* the only type of filesystem so far is virtio-9p-pci */ + return pciFlags; + + 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")) { + /* should be 0 */ + return pciFlags; + } + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_SOUND: + switch ((virDomainSoundModel)dev->data.sound->model) { + case VIR_DOMAIN_SOUND_MODEL_ES1370: + case VIR_DOMAIN_SOUND_MODEL_AC97: + case VIR_DOMAIN_SOUND_MODEL_ICH6: + case VIR_DOMAIN_SOUND_MODEL_ICH9: + return pciFlags; + + case VIR_DOMAIN_SOUND_MODEL_SB16: + case VIR_DOMAIN_SOUND_MODEL_PCSPK: + case VIR_DOMAIN_SOUND_MODEL_USB: + case VIR_DOMAIN_SOUND_MODEL_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_DISK: + switch ((virDomainDiskBus)dev->data.disk->bus) { + case VIR_DOMAIN_DISK_BUS_VIRTIO: + return pciFlags; /* only virtio disks use PCI */ + + case VIR_DOMAIN_DISK_BUS_IDE: + case VIR_DOMAIN_DISK_BUS_FDC: + case VIR_DOMAIN_DISK_BUS_SCSI: + case VIR_DOMAIN_DISK_BUS_XEN: + case VIR_DOMAIN_DISK_BUS_USB: + case VIR_DOMAIN_DISK_BUS_UML: + case VIR_DOMAIN_DISK_BUS_SATA: + case VIR_DOMAIN_DISK_BUS_SD: + case VIR_DOMAIN_DISK_BUS_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_HOSTDEV: + return pciFlags; + + case VIR_DOMAIN_DEVICE_MEMBALLOON: + switch ((virDomainMemBalloonModel)dev->data.memballoon->model) { + case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO: + return pciFlags; + + case VIR_DOMAIN_MEMBALLOON_MODEL_XEN: + case VIR_DOMAIN_MEMBALLOON_MODEL_NONE: + case VIR_DOMAIN_MEMBALLOON_MODEL_LAST: + /* should be 0 (not PCI) */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_RNG: + switch ((virDomainRNGModel)dev->data.rng->model) { + case VIR_DOMAIN_RNG_MODEL_VIRTIO: + return pciFlags; + + case VIR_DOMAIN_RNG_MODEL_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_WATCHDOG: + /* only one model connects using PCI */ + switch ((virDomainWatchdogModel)dev->data.watchdog->model) { + case VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB: + return pciFlags; + + case VIR_DOMAIN_WATCHDOG_MODEL_IB700: + case VIR_DOMAIN_WATCHDOG_MODEL_DIAG288: + case VIR_DOMAIN_WATCHDOG_MODEL_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_VIDEO: + switch ((virDomainVideoType)dev->data.video->type) { + case VIR_DOMAIN_VIDEO_TYPE_VIRTIO: + case VIR_DOMAIN_VIDEO_TYPE_VGA: + case VIR_DOMAIN_VIDEO_TYPE_CIRRUS: + case VIR_DOMAIN_VIDEO_TYPE_VMVGA: + case VIR_DOMAIN_VIDEO_TYPE_XEN: + case VIR_DOMAIN_VIDEO_TYPE_VBOX: + case VIR_DOMAIN_VIDEO_TYPE_QXL: + case VIR_DOMAIN_VIDEO_TYPE_PARALLELS: + return pciFlags; + + case VIR_DOMAIN_VIDEO_TYPE_LAST: + /* should be 0 */ + return pciFlags; + } + + + case VIR_DOMAIN_DEVICE_SHMEM: + return pciFlags; + + case VIR_DOMAIN_DEVICE_INPUT: + switch ((virDomainInputBus)dev->data.input->bus) { + case VIR_DOMAIN_INPUT_BUS_VIRTIO: + return pciFlags; + + case VIR_DOMAIN_INPUT_BUS_PS2: + case VIR_DOMAIN_INPUT_BUS_USB: + case VIR_DOMAIN_INPUT_BUS_XEN: + case VIR_DOMAIN_INPUT_BUS_PARALLELS: + case VIR_DOMAIN_INPUT_BUS_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_CHR: + switch ((virDomainChrSerialTargetType)dev->data.chr->targetType) { + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI: + return pciFlags; + + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA: + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB: + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST: + /* should be 0 */ + return pciFlags; + } + + /* 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: + /* should be 0 */ + return pciFlags; + } + + /* We can never get here, because all cases are covered in the + * switch, and they all return, but the compiler will still + * complain "control reaches end of non-void function" unless + * we add the following return. + */ + return 0; +} + + +typedef struct { + virDomainPCIConnectFlags virtioFlags; + virDomainPCIConnectFlags pcieFlags; +} qemuDomainFillDevicePCIConnectFlagsIterData; + +/** + * qemuDomainFillDevicePCIConnectIterInit: + * + * Initialize the iterator data that is used when calling + * qemuDomainCalculateDevicePCIConnectFlags(). + * + */ +static void +qemuDomainFillDevicePCIConnectIterInit(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps, + qemuDomainFillDevicePCIConnectFlagsIterData *data) +{ + if (qemuDomainMachineHasPCIeRoot(def)) { + data->pcieFlags = (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE | + VIR_PCI_CONNECT_HOTPLUGGABLE); + } else { + data->pcieFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_HOTPLUGGABLE); + } + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) { + data->virtioFlags = data->pcieFlags; + } else { + data->virtioFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_HOTPLUGGABLE); + } +} + + +/** + * qemuDomainFillDevicePCIConnectFlagsIter: + * + * 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 +qemuDomainFillDevicePCIConnectFlagsIter(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque) +{ + qemuDomainFillDevicePCIConnectFlagsIterData *data = opaque; + + info->pciConnectFlags + = qemuDomainDeviceCalculatePCIConnectFlags(dev, data->pcieFlags, + data->virtioFlags); + return 0; +} + + +/** + * qemuDomainFillAllPCIConnectFlags: + * + * 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 +qemuDomainFillAllPCIConnectFlags(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps) +{ + qemuDomainFillDevicePCIConnectFlagsIterData data; + + qemuDomainFillDevicePCIConnectIterInit(def, qemuCaps, &data); + + return virDomainDeviceInfoIterate(def, + qemuDomainFillDevicePCIConnectFlagsIter, + &data); +} + + +/** + * qemuDomainFillDevicePCIConnectFlags: + * + * 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. + * + */ +static void ATTRIBUTE_UNUSED +qemuDomainFillDevicePCIConnectFlags(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virQEMUCapsPtr qemuCaps) +{ + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + + if (info) { + /* qemuDomainDeviceCalculatePCIConnectFlags() is called with + * the data setup in the ...IterData by ...IterInit() rather + * than setting the values directly here. It may seem like + * pointless posturing, but it's done this way to eliminate + * duplicated setup code while allowing more efficient + * operation when it's being done repeatedly with the device + * iterator (since qemuDomainFillAllPCIConnectFlags() only + * calls ...IterInit() once for all devices). + */ + qemuDomainFillDevicePCIConnectFlagsIterData data; + + qemuDomainFillDevicePCIConnectIterInit(def, qemuCaps, &data); + + info->pciConnectFlags + = qemuDomainDeviceCalculatePCIConnectFlags(dev, data.pcieFlags, + data.virtioFlags); + } +} + + static int qemuDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, -- 2.7.4

On Fri, 2016-10-14 at 15:54 -0400, Laine Stump wrote:
The lowest level function of this trio (qemuDomainDeviceCalculatePCIConnectFlags()) aims to be the single authority for the virDomainPCIConnectFlags to use for any given device using a particular arch/machinetype/qemu-binary. qemuDomainFillDevicePCIConnectFlags() sets info->pciConnectFlags in a single device (unless it has no virDomainDeviceInfo, in which case it's a NOP). qemuDomainFillAllPCIConnectFlags() sets info->pciConnectFlags in all devices that have a virDomainDeviceInfo The latter two functions aren't called anywhere yet. This commit is just making them available. Later patches will replace all the current hodge-podge of flag settings with calls to this single authority. --- Change: re-implemented as a giant two-level compound switch statement with no default cases, as suggested by Andrea. Also start off with the function setting the flags for *all* devices to PCI_DEVICE|HOTPLUGGABLE, which is what's currently used when assigning addresses (as opposed to merely validating addresses, which is much less strict). src/conf/device_conf.h | 5 + src/qemu/qemu_domain_address.c | 379 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 384 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 b4ea906..457eae6 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -405,6 +405,385 @@ qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def, } +/** + * qemuDomainDeviceCalculatePCIConnectFlags: + * + * Lowest level function to determine PCI connectFlags for a + * device. 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. + */
Please adjust the formatting of this and later comments to match the guidelines we discussed for earlier patches.
+static virDomainPCIConnectFlags +qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, + virDomainPCIConnectFlags pcieFlags + ATTRIBUTE_UNUSED, + virDomainPCIConnectFlags virtioFlags + ATTRIBUTE_UNUSED) +{ + virDomainPCIConnectFlags pciFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
Double space.
+ VIR_PCI_CONNECT_HOTPLUGGABLE); + + switch ((virDomainDeviceType)dev->type) {
We use both '(type)expr' and '(type) expr', but the latter seems to be more popular. Up to you whether or not you want to conform :)
+ case VIR_DOMAIN_DEVICE_CONTROLLER: { + virDomainControllerDefPtr cont = dev->data.controller; + + switch ((virDomainControllerType)cont->type) { + case VIR_DOMAIN_CONTROLLER_TYPE_PCI: + return virDomainPCIControllerModelToConnectType(cont->model); + + case VIR_DOMAIN_CONTROLLER_TYPE_SATA: + return pciFlags; + + case VIR_DOMAIN_CONTROLLER_TYPE_USB: + switch ((virDomainControllerModelUSB)cont->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: + return pciFlags; + + 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: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI: + return pciFlags; + + case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1: /* xen only */ + case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2: /* xen only */ + case VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE: + case VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_CONTROLLER_TYPE_IDE: + case VIR_DOMAIN_CONTROLLER_TYPE_SCSI: + case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: + return pciFlags; + + case VIR_DOMAIN_CONTROLLER_TYPE_FDC: + case VIR_DOMAIN_CONTROLLER_TYPE_CCID: + case VIR_DOMAIN_CONTROLLER_TYPE_LAST: + /* should be 0 */ + return pciFlags; + } + } + + case VIR_DOMAIN_DEVICE_FS: + /* the only type of filesystem so far is virtio-9p-pci */ + return pciFlags; + + 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")) { + /* should be 0 */ + return pciFlags; + } + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_SOUND: + switch ((virDomainSoundModel)dev->data.sound->model) { + case VIR_DOMAIN_SOUND_MODEL_ES1370: + case VIR_DOMAIN_SOUND_MODEL_AC97: + case VIR_DOMAIN_SOUND_MODEL_ICH6: + case VIR_DOMAIN_SOUND_MODEL_ICH9: + return pciFlags; + + case VIR_DOMAIN_SOUND_MODEL_SB16: + case VIR_DOMAIN_SOUND_MODEL_PCSPK: + case VIR_DOMAIN_SOUND_MODEL_USB: + case VIR_DOMAIN_SOUND_MODEL_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_DISK: + switch ((virDomainDiskBus)dev->data.disk->bus) { + case VIR_DOMAIN_DISK_BUS_VIRTIO: + return pciFlags; /* only virtio disks use PCI */ + + case VIR_DOMAIN_DISK_BUS_IDE: + case VIR_DOMAIN_DISK_BUS_FDC: + case VIR_DOMAIN_DISK_BUS_SCSI: + case VIR_DOMAIN_DISK_BUS_XEN: + case VIR_DOMAIN_DISK_BUS_USB: + case VIR_DOMAIN_DISK_BUS_UML: + case VIR_DOMAIN_DISK_BUS_SATA: + case VIR_DOMAIN_DISK_BUS_SD: + case VIR_DOMAIN_DISK_BUS_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_HOSTDEV: + return pciFlags; + + case VIR_DOMAIN_DEVICE_MEMBALLOON: + switch ((virDomainMemBalloonModel)dev->data.memballoon->model) {
You will of course need to s/MemBalloon/Memballoon/ here now.
+ case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO: + return pciFlags; + + case VIR_DOMAIN_MEMBALLOON_MODEL_XEN: + case VIR_DOMAIN_MEMBALLOON_MODEL_NONE: + case VIR_DOMAIN_MEMBALLOON_MODEL_LAST: + /* should be 0 (not PCI) */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_RNG: + switch ((virDomainRNGModel)dev->data.rng->model) { + case VIR_DOMAIN_RNG_MODEL_VIRTIO: + return pciFlags; + + case VIR_DOMAIN_RNG_MODEL_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_WATCHDOG: + /* only one model connects using PCI */ + switch ((virDomainWatchdogModel)dev->data.watchdog->model) { + case VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB: + return pciFlags; + + case VIR_DOMAIN_WATCHDOG_MODEL_IB700: + case VIR_DOMAIN_WATCHDOG_MODEL_DIAG288: + case VIR_DOMAIN_WATCHDOG_MODEL_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_VIDEO: + switch ((virDomainVideoType)dev->data.video->type) { + case VIR_DOMAIN_VIDEO_TYPE_VIRTIO: + case VIR_DOMAIN_VIDEO_TYPE_VGA: + case VIR_DOMAIN_VIDEO_TYPE_CIRRUS: + case VIR_DOMAIN_VIDEO_TYPE_VMVGA: + case VIR_DOMAIN_VIDEO_TYPE_XEN: + case VIR_DOMAIN_VIDEO_TYPE_VBOX: + case VIR_DOMAIN_VIDEO_TYPE_QXL: + case VIR_DOMAIN_VIDEO_TYPE_PARALLELS: + return pciFlags; + + case VIR_DOMAIN_VIDEO_TYPE_LAST: + /* should be 0 */ + return pciFlags; + } + + + case VIR_DOMAIN_DEVICE_SHMEM: + return pciFlags; + + case VIR_DOMAIN_DEVICE_INPUT: + switch ((virDomainInputBus)dev->data.input->bus) { + case VIR_DOMAIN_INPUT_BUS_VIRTIO: + return pciFlags; + + case VIR_DOMAIN_INPUT_BUS_PS2: + case VIR_DOMAIN_INPUT_BUS_USB: + case VIR_DOMAIN_INPUT_BUS_XEN: + case VIR_DOMAIN_INPUT_BUS_PARALLELS: + case VIR_DOMAIN_INPUT_BUS_LAST: + /* should be 0 */ + return pciFlags; + } + + case VIR_DOMAIN_DEVICE_CHR: + switch ((virDomainChrSerialTargetType)dev->data.chr->targetType) { + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI: + return pciFlags; + + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA: + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB: + case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST: + /* should be 0 */ + return pciFlags; + } + + /* 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: + /* should be 0 */ + return pciFlags; + } + + /* We can never get here, because all cases are covered in the + * switch, and they all return, but the compiler will still + * complain "control reaches end of non-void function" unless + * we add the following return. + */ + return 0; +} + + +typedef struct { + virDomainPCIConnectFlags virtioFlags; + virDomainPCIConnectFlags pcieFlags; +} qemuDomainFillDevicePCIConnectFlagsIterData; +
Add one more empty line here.
+/** + * qemuDomainFillDevicePCIConnectIterInit:
Should be qemuDomainFillDevicePCIConnectFlagsIterInit(), even though it's already quite a mouthful as it is.
+ * + * Initialize the iterator data that is used when calling + * qemuDomainCalculateDevicePCIConnectFlags(). + *
Remove this empty line.
+ */ +static void +qemuDomainFillDevicePCIConnectIterInit(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps, + qemuDomainFillDevicePCIConnectFlagsIterData *data) +{ + if (qemuDomainMachineHasPCIeRoot(def)) { + data->pcieFlags = (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE | + VIR_PCI_CONNECT_HOTPLUGGABLE);
Double space here...
+ } else { + data->pcieFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_HOTPLUGGABLE);
... and again here.
+ } + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) { + data->virtioFlags = data->pcieFlags; + } else { + data->virtioFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | + VIR_PCI_CONNECT_HOTPLUGGABLE); + } +} + + +/** + * qemuDomainFillDevicePCIConnectFlagsIter: + * + * The version of the function to call with + * virDomainDeviceInfoIterate()
Please change this to something along the lines of Sets PCI connect flags for @dev. For use 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 +qemuDomainFillDevicePCIConnectFlagsIter(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque) +{ + qemuDomainFillDevicePCIConnectFlagsIterData *data = opaque; + + info->pciConnectFlags + = qemuDomainDeviceCalculatePCIConnectFlags(dev, data->pcieFlags, + data->virtioFlags); + return 0; +} + + +/** + * qemuDomainFillAllPCIConnectFlags: + * + * 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 +qemuDomainFillAllPCIConnectFlags(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps) +{ + qemuDomainFillDevicePCIConnectFlagsIterData data; + + qemuDomainFillDevicePCIConnectIterInit(def, qemuCaps, &data); + + return virDomainDeviceInfoIterate(def, + qemuDomainFillDevicePCIConnectFlagsIter, + &data); +} + + +/** + * qemuDomainFillDevicePCIConnectFlags: + * + * The version of the function to call if it will be called just + * once.
The description for qemuDomainFillAllPCIConnectFlags() is pretty good, please change this one to be 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. + * + */ +static void ATTRIBUTE_UNUSED +qemuDomainFillDevicePCIConnectFlags(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virQEMUCapsPtr qemuCaps) +{ + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + + if (info) { + /* qemuDomainDeviceCalculatePCIConnectFlags() is called with + * the data setup in the ...IterData by ...IterInit() rather + * than setting the values directly here. It may seem like + * pointless posturing, but it's done this way to eliminate + * duplicated setup code while allowing more efficient + * operation when it's being done repeatedly with the device + * iterator (since qemuDomainFillAllPCIConnectFlags() only + * calls ...IterInit() once for all devices). + */
I feel like this comment would be a better fit for qemuDomainFillDevicePCIConnectIterInit().
+ qemuDomainFillDevicePCIConnectFlagsIterData data; + + qemuDomainFillDevicePCIConnectIterInit(def, qemuCaps, &data); + + info->pciConnectFlags + = qemuDomainDeviceCalculatePCIConnectFlags(dev, data.pcieFlags, + data.virtioFlags); + } +} + + static int qemuDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev,
ACK after you take care of the stuff mentioned. -- Andrea Bolognani / Red Hat / Virtualization

Set pciConnectFlags in each device's DeviceInfo and then use those flags later when validating existing addresses in qemuDomainCollectPCIAddress() and when assigning new addresses with qemuDomainPCIAddressReserveNextAddr() (rather than scattering the logic about which devices need which type of slot all over the place). Note that the exact flags set by qemuDomainDeviceCalculatePCIConnectFlags() are different from the flags previously set manually in qemuDomainCollectPCIAddress(), but this doesn't matter because all validation of addresses in that case ignores the setting of the HOTPLUGGABLE flag, and treats PCIE_DEVICE and PCI_DEVICE the same (this lax checking was done on purpose, because there are some things that we want to allow the user to specify manually, e.g. assigning a PCIe device to a PCI slot, that we *don't* ever want libvirt to do automatically. The flag settings that we *really* want to match are 1) the old flag settings in qemuDomainAssignDevicePCISlots() (which is HOTPLUGGABLE | PCI_DEVICE for everything except PCI controllers) and the new flag settings done by qemuDomainDeviceCalculatePCIConnectFlags() (which are currently exactly that - HOTPLUGGABLE | PCI_DEVICE for everything except PCI controllers). --- Changes: expanded commit log to detail why these flags are different from those set in qemuDomainCollectPCIAddress(). src/qemu/qemu_domain_address.c | 206 +++++++++++++++-------------------------- 1 file changed, 75 insertions(+), 131 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 457eae6..3a685e7 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -727,7 +727,7 @@ qemuDomainFillDevicePCIConnectFlagsIter(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 qemuDomainFillAllPCIConnectFlags(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) { @@ -787,21 +787,20 @@ qemuDomainFillDevicePCIConnectFlags(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); } @@ -815,9 +814,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) && @@ -829,71 +825,6 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, return 0; } - /* Change flags according to differing requirements of different - * devices. - */ - 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; - } - /* Ignore implicit controllers on slot 0:0:1.0: * implicit IDE controller on 0:0:1.1 (no qemu command line) * implicit USB controller on 0:0:1.2 (-usb) @@ -936,7 +867,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; @@ -1092,8 +1023,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", @@ -1283,8 +1213,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", @@ -1405,7 +1334,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++) { @@ -1419,33 +1347,18 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&cont->info)) continue; - /* convert the type of controller into a "CONNECT_TYPE" - * 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; } @@ -1461,7 +1374,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&net->info)) { continue; } - if (qemuDomainPCIAddressReserveNextSlot(addrs, &net->info, flags) < 0) + + if (qemuDomainPCIAddressReserveNextSlot(addrs, &net->info) < 0) goto error; } @@ -1471,13 +1385,14 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (!virDeviceInfoPCIAddressWanted(&sound->info)) continue; + /* Skip ISA sound card, PCSPK and usb-audio */ 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, &sound->info, flags) < 0) + if (qemuDomainPCIAddressReserveNextSlot(addrs, &sound->info) < 0) goto error; } @@ -1544,7 +1459,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; @@ -1553,8 +1469,7 @@ 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; @@ -1563,10 +1478,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, 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; } } @@ -1597,8 +1510,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; } @@ -1610,8 +1522,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; } @@ -1620,8 +1532,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; } @@ -1631,8 +1543,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; } @@ -1640,8 +1551,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; } @@ -1649,16 +1559,15 @@ 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; } for (i = 1; i < def->nvideos; i++) { 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; } @@ -1667,8 +1576,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++) { @@ -1676,8 +1584,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++) { @@ -1690,7 +1597,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++) { @@ -1847,8 +1754,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++) { virDomainControllerDefPtr cont = def->controllers[i]; @@ -1860,10 +1765,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 (qemuDomainFillAllPCIConnectFlags(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; @@ -1887,24 +1805,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 */ + qemuDomainFillDevicePCIConnectFlags(def, &dev, qemuCaps); + if (qemuDomainPCIAddressReserveNextSlot(addrs, + &dev.data.controller->info) < 0) goto cleanup; } + nbuses = addrs->nbuses; virDomainPCIAddressSetFree(addrs); addrs = NULL; -- 2.7.4

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 qemuDomainDeviceCalculatePCIConnectFlags(). 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. --- Change: modified comments as suggested. src/conf/domain_addr.c | 10 ++-------- 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 | 20 ++++++++++++++------ 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 3a9e474..fcd5fc1 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -485,17 +485,11 @@ 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 (!(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 3a685e7..991cfa7 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -2136,6 +2136,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, and set it in @dev->...info. If there is an + * address already, validate that it is on a compatible bus, based on + * @dev->...info.pciConnectFlags. + * + * @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 -1 on failure. + */ +int +qemuDomainEnsurePCIAddress(virDomainObjPtr obj, + virDomainDeviceDefPtr dev) +{ + qemuDomainObjPrivatePtr priv = obj->privateData; + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + + qemuDomainFillDevicePCIConnectFlags(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 dc0faa6..56256e7 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; @@ -1110,7 +1114,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; } @@ -1339,6 +1343,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; @@ -1409,7 +1415,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 && @@ -1641,6 +1647,7 @@ qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm, { virDomainDefPtr def = vm->def; qemuDomainObjPrivatePtr priv = vm->privateData; + virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CHR, { .chr = chr } }; int ret = -1; virDomainVirtioSerialAddrSetPtr vioaddrs = NULL; @@ -1656,7 +1663,7 @@ qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm, } 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; @@ -1802,6 +1809,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; @@ -1838,7 +1846,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

This patch cleans up the connect flags for certain types/models of devices that aren't PCI to return 0. In the future that may be used as an indicator to the caller about whether or not a device needs a PCI address. For now it's just ignored, except for in virDomainPCIAddressEnsureAddr() - called during device hotplug - (and in some cases actually needs to be re-set to PCI|HOTPLUGGABLE just in case someone (in some old config) has manually set a PCI address for a device that isn't PCI. --- This was previously a part of patch 12. split out to enable demonstrating that it is a NOP. src/conf/domain_addr.c | 6 +++++ src/qemu/qemu_domain_address.c | 54 +++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index fcd5fc1..e25a63f 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -491,6 +491,12 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, int ret = -1; char *addrStr = NULL; + /* if flags 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/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 991cfa7..22d859e 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -465,8 +465,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2: /* xen only */ case VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE: case VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST: - /* should be 0 */ - return pciFlags; + return 0; } case VIR_DOMAIN_CONTROLLER_TYPE_IDE: @@ -495,8 +494,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, */ if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || STREQ(net->model, "usb-net")) { - /* should be 0 */ - return pciFlags; + return 0; } return pciFlags; } @@ -513,8 +511,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_SOUND_MODEL_PCSPK: case VIR_DOMAIN_SOUND_MODEL_USB: case VIR_DOMAIN_SOUND_MODEL_LAST: - /* should be 0 */ - return pciFlags; + return 0; } case VIR_DOMAIN_DEVICE_DISK: @@ -531,8 +528,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DISK_BUS_SATA: case VIR_DOMAIN_DISK_BUS_SD: case VIR_DOMAIN_DISK_BUS_LAST: - /* should be 0 */ - return pciFlags; + return 0; } case VIR_DOMAIN_DEVICE_HOSTDEV: @@ -546,8 +542,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_MEMBALLOON_MODEL_XEN: case VIR_DOMAIN_MEMBALLOON_MODEL_NONE: case VIR_DOMAIN_MEMBALLOON_MODEL_LAST: - /* should be 0 (not PCI) */ - return pciFlags; + return 0; } case VIR_DOMAIN_DEVICE_RNG: @@ -556,8 +551,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, return pciFlags; case VIR_DOMAIN_RNG_MODEL_LAST: - /* should be 0 */ - return pciFlags; + return 0; } case VIR_DOMAIN_DEVICE_WATCHDOG: @@ -569,8 +563,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_WATCHDOG_MODEL_IB700: case VIR_DOMAIN_WATCHDOG_MODEL_DIAG288: case VIR_DOMAIN_WATCHDOG_MODEL_LAST: - /* should be 0 */ - return pciFlags; + return 0; } case VIR_DOMAIN_DEVICE_VIDEO: @@ -586,8 +579,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, return pciFlags; case VIR_DOMAIN_VIDEO_TYPE_LAST: - /* should be 0 */ - return pciFlags; + return 0; } @@ -604,8 +596,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_INPUT_BUS_XEN: case VIR_DOMAIN_INPUT_BUS_PARALLELS: case VIR_DOMAIN_INPUT_BUS_LAST: - /* should be 0 */ - return pciFlags; + return 0; } case VIR_DOMAIN_DEVICE_CHR: @@ -616,8 +607,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA: case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB: case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST: - /* should be 0 */ - return pciFlags; + return 0; } /* These devices don't ever connect with PCI */ @@ -634,8 +624,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: - /* should be 0 */ - return pciFlags; + return 0; } /* We can never get here, because all cases are covered in the @@ -825,6 +814,27 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, return 0; } + /* 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. + */ + if (info->pciConnectFlags == 0) { + char *addrStr = virDomainPCIAddressAsString(&info->addr.pci); + + VIR_WARN("qemuDomainDeviceCalculatePCIConnectFlags() 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: * implicit IDE controller on 0:0:1.1 (no qemu command line) * implicit USB controller on 0:0:1.2 (-usb) -- 2.7.4

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 virDomainCalculateDevicePCIConnectFlags(). 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: the first virtio video device will be placed directly on bus 0 slot 1 rather than on a pcie-root-port due to the override for primary video devices in qemuDomainValidateDevicePCISlotsQ35(). Whether or not to change that is a topic of discussion, but this patch doesn't change that particular behavior. NB2: 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 --- Change: modified due to changes in patch 12. src/qemu/qemu_domain_address.c | 41 ++++-- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 58 ++++++++ tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 61 ++++++++ .../qemuxml2argv-q35-virtio-pci.args | 58 ++++++++ .../qemuxml2argv-q35-virtio-pci.xml | 1 + tests/qemuxml2argvtest.c | 48 +++++++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 154 +++++++++++++++++++++ .../qemuxml2xmlout-q35-virtio-pci.xml | 154 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 43 ++++++ 9 files changed, 609 insertions(+), 9 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 22d859e..e4cea91 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -428,8 +428,7 @@ static virDomainPCIConnectFlags qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, virDomainPCIConnectFlags pcieFlags ATTRIBUTE_UNUSED, - virDomainPCIConnectFlags virtioFlags - ATTRIBUTE_UNUSED) + virDomainPCIConnectFlags virtioFlags) { virDomainPCIConnectFlags pciFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | VIR_PCI_CONNECT_HOTPLUGGABLE); @@ -469,9 +468,28 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, } case VIR_DOMAIN_CONTROLLER_TYPE_IDE: + return pciFlags; + case VIR_DOMAIN_CONTROLLER_TYPE_SCSI: + switch ((virDomainControllerModelSCSI)cont->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI: + return virtioFlags; + + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO: + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC: + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC: + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068: + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI: + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI: + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078: + return pciFlags; + + case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST: + return 0; + } + case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: - return pciFlags; + return virtioFlags; case VIR_DOMAIN_CONTROLLER_TYPE_FDC: case VIR_DOMAIN_CONTROLLER_TYPE_CCID: @@ -483,7 +501,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_FS: /* the only type of filesystem so far is virtio-9p-pci */ - return pciFlags; + return virtioFlags; case VIR_DOMAIN_DEVICE_NET: { virDomainNetDefPtr net = dev->data.net; @@ -496,6 +514,10 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, STREQ(net->model, "usb-net")) { return 0; } + + if (STREQ(net->model, "virtio")) + return virtioFlags; + return pciFlags; } @@ -517,7 +539,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_DISK: switch ((virDomainDiskBus)dev->data.disk->bus) { case VIR_DOMAIN_DISK_BUS_VIRTIO: - return pciFlags; /* only virtio disks use PCI */ + return virtioFlags; /* only virtio disks use PCI */ case VIR_DOMAIN_DISK_BUS_IDE: case VIR_DOMAIN_DISK_BUS_FDC: @@ -537,7 +559,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_MEMBALLOON: switch ((virDomainMemBalloonModel)dev->data.memballoon->model) { case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO: - return pciFlags; + return virtioFlags; case VIR_DOMAIN_MEMBALLOON_MODEL_XEN: case VIR_DOMAIN_MEMBALLOON_MODEL_NONE: @@ -548,7 +570,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_RNG: switch ((virDomainRNGModel)dev->data.rng->model) { case VIR_DOMAIN_RNG_MODEL_VIRTIO: - return pciFlags; + return virtioFlags; case VIR_DOMAIN_RNG_MODEL_LAST: return 0; @@ -569,6 +591,8 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_VIDEO: switch ((virDomainVideoType)dev->data.video->type) { case VIR_DOMAIN_VIDEO_TYPE_VIRTIO: + return virtioFlags; + case VIR_DOMAIN_VIDEO_TYPE_VGA: case VIR_DOMAIN_VIDEO_TYPE_CIRRUS: case VIR_DOMAIN_VIDEO_TYPE_VMVGA: @@ -582,14 +606,13 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, return 0; } - case VIR_DOMAIN_DEVICE_SHMEM: return pciFlags; case VIR_DOMAIN_DEVICE_INPUT: switch ((virDomainInputBus)dev->data.input->bus) { case VIR_DOMAIN_INPUT_BUS_VIRTIO: - return pciFlags; + return virtioFlags; case VIR_DOMAIN_INPUT_BUS_PS2: case VIR_DOMAIN_INPUT_BUS_USB: diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args new file mode 100644 index 0000000..f07c085 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args @@ -0,0 +1,58 @@ +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 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 \ +-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-gpu-pci,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..be2439e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml @@ -0,0 +1,61 @@ +<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='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..98284a2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args @@ -0,0 +1,58 @@ +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 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.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-gpu-pci,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 e8438b4..fe25237 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1740,6 +1740,54 @@ mymain(void) QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, 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_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_DISABLE_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_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..48e9b02 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml @@ -0,0 +1,154 @@ +<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='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'/> + </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..ae541d3 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml @@ -0,0 +1,154 @@ +<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='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> + <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 62bff8c..53f8ffd 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -694,6 +694,49 @@ mymain(void) QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, 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_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_DISABLE_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_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

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 --- Change: removed ATTRIBUTE_UNUSED, changed to fit reimplemented qemuDomainDeviceCalculatePCIConnectFlags() src/qemu/qemu_domain_address.c | 6 ++++-- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args | 23 ++++++++++++---------- tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml | 4 ++++ .../qemuxml2argv-q35-virtio-pci.args | 3 +++ .../qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie.xml | 23 +++++++++++++--------- .../qemuxml2xmlout-q35-virtio-pci.xml | 5 +++++ 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index e4cea91..69e530e 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -426,8 +426,7 @@ qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def, */ static virDomainPCIConnectFlags qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, - virDomainPCIConnectFlags pcieFlags - ATTRIBUTE_UNUSED, + virDomainPCIConnectFlags pcieFlags, virDomainPCIConnectFlags virtioFlags) { virDomainPCIConnectFlags pciFlags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE | @@ -518,6 +517,9 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, if (STREQ(net->model, "virtio")) return virtioFlags; + if (STREQ(net->model, "e1000e")) + return pcieFlags; + return pciFlags; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args index f07c085..d92e0b8 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.args @@ -35,10 +35,10 @@ QEMU_AUDIO_DRV=none \ 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,\ @@ -46,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-gpu-pci,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 be2439e..39db5f0 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie.xml @@ -46,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 98284a2..68d19ca 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virtio-pci.args @@ -46,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 48e9b02..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'> @@ -90,10 +90,10 @@ <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'/> @@ -123,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'/> @@ -143,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 ae541d3..22c2c68 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virtio-pci.xml @@ -123,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

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 legacy 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) --- Change: changed to fit reimplemented qemuDomainDeviceCalculatePCIConnectFlags() src/qemu/qemu_domain_address.c | 2 +- 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 +++++-------- tests/qemuxml2xmltest.c | 2 ++ 10 files changed, 49 insertions(+), 63 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 69e530e..5262ad3 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -446,7 +446,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_CONTROLLER_TYPE_USB: switch ((virDomainControllerModelUSB)cont->model) { case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI: - return pciFlags; + return pcieFlags; case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI: case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1: 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 d92e0b8..2738749 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-gpu-pci,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 68d19ca..cada05e 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 fe25237..2779eb3 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1762,6 +1762,7 @@ mymain(void) 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_DISABLE_LEGACY, so virtio devices should @@ -1787,6 +1788,7 @@ mymain(void) 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'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 53f8ffd..4c2f310 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -714,6 +714,7 @@ mymain(void) 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_DISABLE_LEGACY */ @@ -736,6 +737,7 @@ mymain(void) 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", -- 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) --- 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 5262ad3..4e4e0d6 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1815,8 +1815,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; @@ -1825,23 +1823,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

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. 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. --- Change: split out special code to add dmi-to-pci-bridge if config has a pci-bridge without a dmi-to-pci-bridge (now in RFC patch 21) src/conf/domain_addr.c | 96 +++++++++++--- src/qemu/qemu_domain_address.c | 55 +++++--- .../qemuxml2argv-q35-pcie-autoadd.args | 57 ++++++++ .../qemuxml2argv-q35-pcie-autoadd.xml | 51 +++++++ tests/qemuxml2argvtest.c | 24 ++++ .../qemuxml2xmlout-q35-pcie-autoadd.xml | 147 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 25 +++- 7 files changed, 421 insertions(+), 34 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 e25a63f..7a7fd00 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, @@ -332,10 +356,7 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus, } -/* 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. +/* Ensure addr fits in the address set, by expanding it if needed * * Return value: * -1 = OOM @@ -349,32 +370,73 @@ 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; i++) { + if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { + needDMIToPCIBridge = false; + break; + } + } + 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 && + addrs->buses[0].model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) { + 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 4e4e0d6..38b7775 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -918,27 +918,14 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, { virDomainPCIAddressSetPtr addrs; size_t i; + bool hasPCIeRoot = false; + virDomainControllerModelPCI defaultModel; if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) return NULL; 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++) { virDomainControllerDefPtr cont = def->controllers[i]; size_t idx = cont->idx; @@ -955,7 +942,43 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; - } + + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) + hasPCIeRoot = true; + } + + if (nbuses > 0 && !addrs->buses[0].model) { + /* This is just here to replicate a safety measure already in + * an older version of this code. In practice, the root bus + * should have already been added at index 0 prior to + * assigning addresses to devices. + */ + 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. + */ + + if (hasPCIeRoot) + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; + else + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + + 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); + } 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..70c759e --- /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-gpu-pci,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 2779eb3..6f2ba6b 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1790,6 +1790,30 @@ mymain(void) 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_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 4c2f310..92d3b2a 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -739,7 +739,30 @@ mymain(void) 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_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, QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, -- 2.7.4

I'm undecided if it is worthwhile to add this... Up until now it has been 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'/> (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.) Since we have always added the following to every config: <controller type='pci' model='dmi-to-pci-bridge' index='1'/> there has always been a proper place for the unaddressed pci-bridge to plug in. A upcoming commit will eliminate the forced adding of a dmi-to-pci-bridge to *every* Q35 domain config, though. This would mean the above-mentioned test case (and one other) would begin to fail. There are two possible solutions to this problem: 1) change the test cases, and made the above construct an error (note that in the future it will work just fine to not list *any* pci controller, and they will all be auto-added as needed). or 2) This patch, which specifically looks for the case where we have a pci-bridge (but no dmi-to-pci-bridge) in a PCIe domain config and auto-adds the necessary dmi-to-pci-bridge. This can only work in the case that the pci-bridge has been given an index such that there is an unused index with a lower value for the dmi-to-pci-bridge to occupy. This seems like a kind of odd corner case that nobody should need to do in the future anyway. On the other hand, I already wrote the code and it works, so I might as well send it and see what opinions (if any) it generates. --- src/qemu/qemu_domain_address.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 38b7775..e81d212 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -919,6 +919,9 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, virDomainPCIAddressSetPtr addrs; size_t i; bool hasPCIeRoot = false; + unsigned int lowestDMIToPCIBridge = nbuses; + unsigned int lowestUnaddressedPCIBridge = nbuses; + unsigned int lowestAddressedPCIBridge = nbuses; virDomainControllerModelPCI defaultModel; if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) @@ -943,8 +946,24 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; - if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) + /* 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) { @@ -960,13 +979,21 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, /* 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. + * config. In the rare (and ... strange, but still allowed) 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_PCIE_ROOT_PORT; - else + 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++) { @@ -978,6 +1005,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, 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) -- 2.7.4

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 aa54206..bd5c7ec 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 70c759e..daecf96 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-gpu-pci,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

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 | 23 +++++++++++++ .../qemuxml2xmlout-q35-default-devices-only.xml | 40 ++++++++++++++++++++++ tests/qemuxml2xmltest.c | 23 +++++++++++++ 6 files changed, 133 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 bd5c7ec..b00e7c3 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 6f2ba6b..b78bce0 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1814,6 +1814,29 @@ mymain(void) 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_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 92d3b2a..1e4767e 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -763,6 +763,29 @@ mymain(void) 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_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, QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, -- 2.7.4

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 main inspiration for 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. --- Change: continue instead of break, as suggested by Andrea. src/qemu/qemu_domain_address.c | 26 +++++ .../qemuxml2argv-q35-virt-manager-basic.args | 55 ++++++++++ .../qemuxml2argv-q35-virt-manager-basic.xml | 76 ++++++++++++++ tests/qemuxml2argvtest.c | 34 ++++++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 116 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 24 +++++ 6 files changed, 331 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 e81d212..8c4a5de 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1343,6 +1343,32 @@ 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 || + !virDeviceInfoPCIAddressWanted(&sound->info)) { + continue; + } + 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..d3217d5 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args @@ -0,0 +1,55 @@ +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 \ +-device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,bus=pcie.0,\ +addr=0x1 \ +-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 b78bce0..2dd23cd 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1837,6 +1837,40 @@ mymain(void) 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_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_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 1e4767e..eb47466 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -786,6 +786,30 @@ mymain(void) 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_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, QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_ICH9_AHCI, -- 2.7.4

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 domain's 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 offline additions to the config (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 the above case (legacy PCI), 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 (i.e. it would always fail anyway). Since that condition can only be reached by manual intervention, this is acceptable. For machinetypes with pcie-root (Q35, aarch64 virt), 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 the pcie-root 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 open slots before the used slots, it can lead to errors. Instead this patch just reserves one slot for a "future potential" PCIe device after doing the assignment for actual devices, but only if the only PCI controller defined prior to starting address assignment was pcie-root, and only if we auto-added at least one PCI controller during address assignment. This assures two things: 1) that reserving the open slots will only be done when the domain is initially defined, never at any time after, and 2) that if the user understands enough about PCI controllers that they are adding them manually, that we don't mess up their plan by adding extras - if they know enough to add one pcie-root-port, or to manually assign addresses such that no pcie-root-ports are needed, they know enough to add extra pcie-root-ports if they want them (this could be called the "libguestfs clause", since libguestfs needs to be able to create domains with as few devices/controllers as possible). This is set to reserve a single free port for now, but could be increased in the future if public sentiment goes in that direction (it's easy to increase later, but essential impossible to decrease) --- Change: now adds a single root-port instead of 4, and only does so during initial definition, not at a later time. src/qemu/qemu_domain_address.c | 30 ++++++++++++++++++++ .../qemuxml2argv-bios-nvram-secure.args | 1 + .../qemuxml2argv-machine-smm-opt.args | 1 + .../qemuxml2argv-q35-default-devices-only.args | 1 + .../qemuxml2argv-q35-pcie-autoadd.args | 1 + .../qemuxml2argv-q35-pm-disable-fallback.args | 1 + .../qemuxml2argv-q35-pm-disable.args | 1 + .../qemuxml2argv-q35-virt-manager-basic.args | 1 + tests/qemuxml2argvtest.c | 33 ++++++++++++++++++---- .../qemuxml2xmlout-q35-default-devices-only.xml | 5 ++++ .../qemuxml2xmlout-q35-pcie-autoadd.xml | 5 ++++ .../qemuxml2xmlout-q35-virt-manager-basic.xml | 5 ++++ tests/qemuxml2xmltest.c | 19 +++++++++++-- 13 files changed, 96 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 8c4a5de..f27d1e3 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1937,6 +1937,36 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0) goto cleanup; + /* Only for *new* domains with pcie-root (and no other + * manually specified PCI controllers in the definition): If, + * after assigning addresses/reserving slots for all devices, + * we see that any extra buses have been auto-added, we + * understand that the application has left management of PCI + * addresses and controllers up to libvirt. In order to allow + * such applications to easily support hotplug, we will do a + * "one time" reservation of one extra PCIE|HOTPLUGGABLE + * slots, which should cause su to auto-add 1 extra + * pcie-root-ports The single slot in this root-port will be + * available for hotplug, or may also be used when a device is + * added to the config offline. + */ + + if (max_idx <= 0 && + addrs->nbuses > max_idx + 1 && + qemuDomainMachineHasPCIeRoot(def)) { + info.pciConnectFlags = (VIR_PCI_CONNECT_HOTPLUGGABLE | + VIR_PCI_CONNECT_TYPE_PCIE_DEVICE); + + /* 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-bios-nvram-secure.args b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args index c014254..c5fe72b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram-secure.args @@ -21,6 +21,7 @@ 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 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-machine-smm-opt.args b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args index e49d7e9..cc9c355 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-machine-smm-opt.args @@ -18,6 +18,7 @@ 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 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-q35-default-devices-only.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args index 9ac30dd..9d13466 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-default-devices-only.args @@ -18,5 +18,6 @@ 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 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 daecf96..ba26326 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pcie-autoadd.args @@ -29,6 +29,7 @@ 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 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-pm-disable-fallback.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable-fallback.args index deae687..739c918 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable-fallback.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable-fallback.args @@ -20,4 +20,5 @@ 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 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..5ee16b7 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-pm-disable.args @@ -20,4 +20,5 @@ 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 virtio-balloon-pci,id=balloon0,bus=pci.2,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args index d3217d5..60af251 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35-virt-manager-basic.args @@ -23,6 +23,7 @@ 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 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/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 2dd23cd..dcf0605 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, @@ -1311,18 +1315,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", @@ -1694,10 +1702,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, @@ -1712,16 +1722,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, @@ -1729,6 +1742,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, @@ -1736,6 +1750,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, @@ -1891,6 +1906,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, @@ -2004,6 +2020,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_DEVICE_QXL, @@ -2036,13 +2053,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", @@ -2050,7 +2069,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, @@ -2306,7 +2327,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("intel-iommu-machine", QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_MACHINE_IOMMU); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml index 8d7bc9d..e64b80c 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-default-devices-only.xml @@ -31,6 +31,11 @@ <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> <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..3742e14 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-pcie-autoadd.xml @@ -97,6 +97,11 @@ <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> <filesystem type='mount' accessmode='passthrough'> <source dir='/export/to/guest'/> <target dir='/import/from/host'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml index fe9ea4e..236d955 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35-virt-manager-basic.xml @@ -68,6 +68,11 @@ <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> <interface type='user'> <mac address='52:54:00:9a:e6:c6'/> <model type='virtio'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index eb47466..bc1250c 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", @@ -674,23 +676,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_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_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_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_DEVICE_QXL); @@ -897,6 +903,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_DEVICE_QXL, QEMU_CAPS_Q35_PCI_HOLE64_SIZE); @@ -940,13 +947,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, @@ -994,7 +1005,9 @@ mymain(void) DO_TEST("video-virtio-gpu-secondary", 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 Fri, 2016-10-14 at 15:53 -0400, Laine Stump wrote:
The latest version of patches to auto-assign appropriate devices in PCIe-capable domains to PCIe slots rather than legacy PCI, and to also auto-add pcie-root-ports as necessary to make this easier. I *think* I've dealt with all of Andrea's great critiques of V3, either in my email responses or in these revised patches. Aside from fixing typos and formatting problems, I also moved several "little cosmetic fixes" out of the bigger functionality-changing patches, and also split out the most confusing part of patch 20 (previously patch 15 - the one that auto-adds pcie-root-port and dmi-to-pci-bridge controllers) into its own patch (doubly useful since the value of that part of the patch is dubious - it is now the [RFC] patch 21) As many of the simple costmetic patches as possible were pushed up to the front of the series (if they weren't already there). If those are ACKed on this round but others aren't, I'll push them immediately so I don't need to resubmit the whole series again.
I think you can go ahead and push patches 2-11 now - of course after taking care of the trivial stuff I pointed out during this last round of reviews. Patch 1 doesn't make sense until patch 12, so please hold off pushing that one for the time being. -- Andrea Bolognani / Red Hat / Virtualization
participants (2)
-
Andrea Bolognani
-
Laine Stump