From d026ab3f17ab1d8b2b0e41c543dc09a3204319b3 Mon Sep 17 00:00:00 2001 Message-Id: From: Laine Stump Date: Tue, 6 Aug 2013 13:23:23 -0600 Subject: [PATCH] qemu: add dmi-to-pci-bridge controller This patch is part of the resolution to: https://bugzilla.redhat.com/show_bug.cgi?id=819968 This PCI controller, named "dmi-to-pci-bridge" in the libvirt config, and implemented with qemu's "i82801b11-bridge" device, connects to a PCI Express slot (e.g. one of the slots provided by the pcie-root controller, aka "pcie.0" on the qemu commandline), and provides 31 *non-hot-pluggable* PCI (*not* PCIe) slots, numbered 1-31. Any time a machine is defined which has a pcie-root controller (i.e. any q35-based machinetype), libvirt will automatically add a dmi-to-pci-bridge controller if one doesn't exist, and also add a pci-bridge controller. The reasoning here is that any useful domain will have either an immediate (startup time) or eventual (subsequent hot-plug) need for a standard PCI slot; since the pcie-root controller only provides PCIe slots, we need to connect a dmi-to-pci-bridge controller to it in order to get a non-hot-plug PCI slot that we can then use to connect a pci-bridge - the slots provided by the pci-bridge will be both standard PCI and hot-pluggable. Since pci-bridge devices themselves can not be hot-plugged into a running system (although you can hot-plug other devices into a pci-bridge's slots), any new pci-bridge controller that is added can (and will) be plugged into the dmi-to-pci-bridge as long as it has empty slots available. This patch is also changing the qemuxml2xml-pcie test from a "DO_TEST" to a "DO_DIFFERENT_TEST". This is so that the "before" xml can omit the automatically added dmi-to-pci-bridge and pci-bridge devices, and the "after" xml can include it - this way we are testing if libvirt is properly adding these devices. (cherry picked from commit 62ac6b43541e46605d62a569d6480c3de9805b98) --- docs/formatdomain.html.in | 26 +++++++++++++++-- docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 3 +- src/conf/domain_conf.h | 1 + src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 33 ++++++++++++++++++++++ src/qemu/qemu_domain.c | 21 ++++++++++---- tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args | 3 +- tests/qemuxml2argvdata/qemuxml2argv-q35.args | 7 +++++ tests/qemuxml2argvdata/qemuxml2argv-q35.xml | 25 ++++++++++++++++ tests/qemuxml2argvtest.c | 8 +++++- .../qemuxml2xmlout-pcie-root.xml | 23 +++++++++++++++ tests/qemuxml2xmltest.c | 3 +- 14 files changed, 145 insertions(+), 12 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-q35.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 55a6e71..562d991 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2338,11 +2338,14 @@

PCI controllers have an optional model attribute with - possible values pci-root, pcie-root - or pci-bridge. + possible values pci-root, pcie-root, + pci-bridge, or dmi-to-pci-bridge. For machine types which provide an implicit PCI bus, the pci-root controller with index=0 is auto-added and required to use PCI devices. pci-root has no address. + PCI bridges are auto-added if there are too many devices to fit on + the one bus provided by pci-root, or a PCI bus number greater than zero + was specified. PCI bridges can also be specified manually, but their addresses should only refer to PCI buses provided by already specified PCI controllers. Leaving gaps in the PCI controller indexes might lead to an invalid @@ -2365,12 +2368,29 @@ the pcie-root controller with index=0 is auto-added to the domain's configuration. pcie-root has also no address, provides 31 slots (numbered 1-31) and can only be used to attach PCIe - devices. (since 1.1.2). + devices. In order to connect standard PCI devices on a system + which has a pcie-root controller, a pci controller + with model='dmi-to-pci-bridge' is automatically + added. A dmi-to-pci-bridge controller plugs into a PCIe slot (as + provided by pcie-root), and itself provides 31 standard PCI + slots (which are not hot-pluggable). In order to have + hot-pluggable PCI slots in the guest system, a pci-bridge + controller will also be automatically created and connected to + one of the slots of the auto-created dmi-to-pci-bridge + controller; all guest devices with PCI addresses that are + auto-determined by libvirt will be placed on this pci-bridge + device. (since 1.1.2).

   ...
   <devices>
     <controller type='pci' index='0' model='pcie-root'/>
+    <controller type='pci' index='1' model='dmi-to-pci-bridge'>
+      <address type='pci' domain='0' bus='0' slot='0xe' function='0'/>
+    </controller>
+    <controller type='pci' index='2' model='pci-bridge'>
+      <address type='pci' domain='0' bus='1' slot='1' function='0'/>
+    </controller>
   </devices>
   ...
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index e04be12..173359c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1540,6 +1540,7 @@ pci-root pcie-root pci-bridge + dmi-to-pci-bridge diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 02f1cf6..f46b17e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -311,7 +311,8 @@ VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST, VIR_ENUM_IMPL(virDomainControllerModelPCI, VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST, "pci-root", "pcie-root", - "pci-bridge") + "pci-bridge", + "dmi-to-pci-bridge") VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, "auto", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 68f36fd..536fc96 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -770,6 +770,7 @@ typedef enum { VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT, VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT, VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE, + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE, VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST } virDomainControllerModelPCI; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 08406b8..47cc07a 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -234,6 +234,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "vnc-share-policy", /* 150 */ "device-del-event", + "dmi-to-pci-bridge", ); struct _virQEMUCaps { @@ -1381,6 +1382,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "pci-bridge", QEMU_CAPS_DEVICE_PCI_BRIDGE }, { "vfio-pci", QEMU_CAPS_DEVICE_VFIO_PCI }, { "scsi-generic", QEMU_CAPS_DEVICE_SCSI_GENERIC }, + { "i82801b11-bridge", QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE }, }; static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBlk[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index f5f685d..074e55d 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -190,6 +190,7 @@ enum virQEMUCapsFlags { QEMU_CAPS_MLOCK = 149, /* -realtime mlock=on|off */ QEMU_CAPS_VNC_SHARE_POLICY = 150, /* set display sharing policy */ QEMU_CAPS_DEVICE_DEL_EVENT = 151, /* DEVICE_DELETED event */ + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE = 152, /* -device i82801b11-bridge */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8ac39ff..50f37ae 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1561,6 +1561,13 @@ qemuDomainPCIAddressBusSetModel(qemuDomainPCIAddressBusPtr bus, bus->minSlot = 1; bus->maxSlot = QEMU_PCI_ADDRESS_SLOT_LAST; break; + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + /* slots 1 - 31, standard PCI slots, + * but *not* hot-pluggable */ + bus->flags = QEMU_PCI_CONNECT_TYPE_PCI; + bus->minSlot = 1; + bus->maxSlot = QEMU_PCI_ADDRESS_SLOT_LAST; + break; default: virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid PCI controller model %d"), model); @@ -1669,6 +1676,12 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, */ flags = QEMU_PCI_CONNECT_TYPE_PCI; break; + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + /* pci-bridge needs a PCIe slot, but it isn't + * hot-pluggable, so it doesn't need a hot-pluggable slot. + */ + flags = QEMU_PCI_CONNECT_TYPE_PCIE; + break; default: break; } @@ -2372,6 +2385,12 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, */ flags = QEMU_PCI_CONNECT_TYPE_PCI; break; + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + /* dmi-to-pci-bridge requires a non-hotplug PCIe + * slot + */ + flags = QEMU_PCI_CONNECT_TYPE_PCIE; + break; default: flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI; break; @@ -4351,6 +4370,20 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef, virBufferAsprintf(&buf, "pci-bridge,chassis_nr=%d,id=pci.%d", def->idx, def->idx); break; + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("The dmi-to-pci-bridge (i82801b11-bridge) " + "controller is not supported in this QEMU binary")); + goto error; + } + if (def->idx == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("dmi-to-pci-bridge index should be > 0")); + goto error; + } + virBufferAsprintf(&buf, "i82801b11-bridge,id=pci.%d", def->idx); + break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 40b813c..bdbe5a9 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -760,12 +760,23 @@ qemuDomainDefPostParse(virDomainDefPtr def, VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0) return -1; - if (addPCIeRoot && - virDomainDefMaybeAddController( - def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0, - VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) < 0) + /* When a machine has a pcie-root, make sure that there is always + * a dmi-to-pci-bridge controller added as bus 1, and a pci-bridge + * as bus 2, so that standard PCI devices can be connected + */ + if (addPCIeRoot) { + if (virDomainDefMaybeAddController( + def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0, + VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) < 0 || + virDomainDefMaybeAddController( + def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 1, + VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) < 0 || + virDomainDefMaybeAddController( + def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 2, + VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) < 0) { return -1; - + } + } return 0; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args index e937189..23db85c 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args @@ -1,4 +1,5 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/libexec/qemu-kvm \ -S -M q35 -m 2048 -smp 2 -nographic -nodefaults \ -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.1,addr=0x1 -usb +-device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x1 \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-q35.args new file mode 100644 index 0000000..ddff6f0 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35.args @@ -0,0 +1,7 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/libexec/qemu-kvm -S -M q35 -m 2048 -smp 2 -nographic -nodefaults \ +-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \ +-device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x1 \ +-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 \ +-usb \ +-vga qxl -global qxl.ram_size=67108864 -global qxl.vram_size=18874368 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35.xml new file mode 100644 index 0000000..3541b14 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-q35.xml @@ -0,0 +1,25 @@ + + q35-test + 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 + 2097152 + 2097152 + 2 + + hvm + + + + destroy + restart + destroy + + /usr/libexec/qemu-kvm + + + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 57c6989..aba0f88 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -995,7 +995,13 @@ mymain(void) DO_TEST("pci-bridge-many-disks", QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE_PCI_BRIDGE); DO_TEST("pcie-root", - QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE); + QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE); + DO_TEST("q35", + QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, + QEMU_CAPS_VGA, QEMU_CAPS_DEVICE_VIDEO_PRIMARY, + QEMU_CAPS_VGA, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL); DO_TEST("hostdev-scsi-lsi", QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml new file mode 100644 index 0000000..25c77f1 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml @@ -0,0 +1,23 @@ + + q35-test + 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 + 2097152 + 2097152 + 2 + + hvm + + + + destroy + restart + destroy + + /usr/libexec/qemu-kvm + + + + + + + diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index ea511b8..8b4590a 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -294,7 +294,8 @@ mymain(void) DO_TEST_DIFFERENT("pci-bridge-many-disks"); DO_TEST_DIFFERENT("pci-autoadd-addr"); DO_TEST_DIFFERENT("pci-autoadd-idx"); - DO_TEST("pcie-root"); + DO_TEST_DIFFERENT("pcie-root"); + DO_TEST("q35"); DO_TEST("hostdev-scsi-lsi"); DO_TEST("hostdev-scsi-virtio-scsi"); -- 1.8.3.2