Part of the resolution to:
https://bugzilla.redhat.com/show_bug.cgi?id=1003983
Although most devices available in qemu area defined as PCI devices,
and strictly speaking should only be attached via a PCI slot, in
practice qemu allows them to be attached to a PCIe slot and sometimes
this makes sense.
For example, The UHCI and EHCI USB controllers are usually attached
directly to the PCIe "root complex" (i.e. PCIe slots) on real
hardware, so that should be possible for a Q35-based qemu virtual
machine as well.
We still want to prefer a standard PCi slot when auto-assigning
addresses, though, and in general to disallow attaching PCI devices
via PCIe slots.
This patch makes that possible by adding a new
QEMU_PCI_CONNECT_TYPE_EITHER_IF_CONFIG flag. Three things are done
with this flag:
1) It is set for the "pcie-root" controller
2) qemuCollectPCIAddress() now has a set of nested switches that set
this "EITHER" flag for devices that we want to allow connecting to
pcie-root when specifically requested in the config.
3) qemuDomainPCIAddressFlagsCompatible() adds this new flag to the
"flagsMatchMask" if the address being checked came from config rather
than being newly auto-allocated by libvirt (this knowledge is
conveniently already available in the "fromConfig" arg).
Now any device having the EITHER flag set can be connected to
pcie-root if explicitly requested, but auto-allocated addresses for
those devices will still be standard PCI slots instead.
This patch only loosens the restrictions on devices that have been
specifically requested, but the setup is such that it should be fairly
easy to add new devices.
---
src/qemu/qemu_command.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++---
src/qemu/qemu_command.h | 4 ++++
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 2683a9c..280d8d2 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1496,12 +1496,16 @@ qemuDomainPCIAddressFlagsCompatible(virDevicePCIAddressPtr addr,
{
virErrorNumber errType = (fromConfig
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
+ qemuDomainPCIConnectFlags flagsMatchMask = QEMU_PCI_CONNECT_TYPES_MASK;
+
+ if (fromConfig)
+ flagsMatchMask |= QEMU_PCI_CONNECT_TYPE_EITHER_IF_CONFIG;
/* If this bus doesn't allow the type of connection (PCI
* vs. PCIe) required by the device, or if the device requires
* hot-plug and this bus doesn't have it, return false.
*/
- if (!(devFlags & busFlags & QEMU_PCI_CONNECT_TYPES_MASK)) {
+ if (!(devFlags & busFlags & flagsMatchMask)) {
if (reportError) {
if (devFlags & QEMU_PCI_CONNECT_TYPE_PCI) {
virReportError(errType,
@@ -1620,8 +1624,12 @@ qemuDomainPCIAddressBusSetModel(qemuDomainPCIAddressBusPtr bus,
bus->maxSlot = QEMU_PCI_ADDRESS_SLOT_LAST;
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
- /* slots 1 - 31, PCIe devices only, no hotplug */
- bus->flags = QEMU_PCI_CONNECT_TYPE_PCIE;
+ /* slots 1 - 31, no hotplug, PCIe only unless the address was
+ * specified in user config *and* the particular device being
+ * attached also allows it
+ */
+ bus->flags = (QEMU_PCI_CONNECT_TYPE_PCIE |
+ QEMU_PCI_CONNECT_TYPE_EITHER_IF_CONFIG);
bus->minSlot = 1;
bus->maxSlot = QEMU_PCI_ADDRESS_SLOT_LAST;
break;
@@ -1759,6 +1767,42 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
*/
flags = QEMU_PCI_CONNECT_TYPE_PCI | QEMU_PCI_CONNECT_TYPE_PCIE;
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 = (QEMU_PCI_CONNECT_TYPE_PCI |
+ QEMU_PCI_CONNECT_TYPE_EITHER_IF_CONFIG);
+ 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 = QEMU_PCI_CONNECT_TYPE_PCI | QEMU_PCI_CONNECT_TYPE_PCIE;
+ 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:
+ flags = (QEMU_PCI_CONNECT_TYPE_PCI |
+ QEMU_PCI_CONNECT_TYPE_EITHER_IF_CONFIG);
+ break;
}
break;
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 0e16a3d..2e2acfb 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -239,6 +239,10 @@ typedef enum {
/* PCI devices can connect to this bus */
QEMU_PCI_CONNECT_TYPE_PCIE = 1 << 3,
/* PCI Express devices can connect to this bus */
+ QEMU_PCI_CONNECT_TYPE_EITHER_IF_CONFIG = 1 << 4,
+ /* PCI *and* PCIe devices allowed, if the address
+ * was specified in the config by the user
+ */
} qemuDomainPCIConnectFlags;
/* a combination of all bit that describe the type of connections
--
1.8.3.1