Blob Blame History Raw
From d026ab3f17ab1d8b2b0e41c543dc09a3204319b3 Mon Sep 17 00:00:00 2001
Message-Id: <d026ab3f17ab1d8b2b0e41c543dc09a3204319b3.1377873637.git.jdenemar@redhat.com>
From: Laine Stump <laine@laine.org>
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 @@
 
     <p>
       PCI controllers have an optional <code>model</code> attribute with
-      possible values <code>pci-root</code>, <code>pcie-root</code>
-      or <code>pci-bridge</code>.
+      possible values <code>pci-root</code>, <code>pcie-root</code>,
+      <code>pci-bridge</code>, or <code>dmi-to-pci-bridge</code>.
       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.  (<span class="since">since 1.1.2</span>).
+      devices. In order to connect standard PCI devices on a system
+      which has a pcie-root controller, a pci controller
+      with <code>model='dmi-to-pci-bridge'</code> 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.  (<span class="since">since 1.1.2</span>).
     </p>
 <pre>
   ...
   &lt;devices&gt;
     &lt;controller type='pci' index='0' model='pcie-root'/&gt;
+    &lt;controller type='pci' index='1' model='dmi-to-pci-bridge'&gt;
+      &lt;address type='pci' domain='0' bus='0' slot='0xe' function='0'/&gt;
+    &lt;/controller&gt;
+    &lt;controller type='pci' index='2' model='pci-bridge'&gt;
+      &lt;address type='pci' domain='0' bus='1' slot='1' function='0'/&gt;
+    &lt;/controller&gt;
   &lt;/devices&gt;
   ...</pre>
 
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 @@
                 <value>pci-root</value>
                 <value>pcie-root</value>
                 <value>pci-bridge</value>
+                <value>dmi-to-pci-bridge</value>
               </choice>
             </attribute>
           </group>
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 @@
+<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' index='0' model='pcie-root'/>
+    <controller type='pci' index='1' model='dmi-to-pci-bridge'/>
+    <controller type='pci' index='2' model='pci-bridge'/>
+    <video>
+      <model type='qxl' ram='65536' vram='18432' heads='1'/>
+    </video>
+    <memballoon model='none'/>
+  </devices>
+</domain>
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 @@
+<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' index='0' model='pcie-root'/>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='1' model='dmi-to-pci-bridge'/>
+    <controller type='pci' index='2' model='pci-bridge'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
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