43fe83
From efc2b6dc182a0d5a36b3791114f844bcc29e5e45 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <efc2b6dc182a0d5a36b3791114f844bcc29e5e45.1377873636.git.jdenemar@redhat.com>
43fe83
From: Laine Stump <laine@laine.org>
43fe83
Date: Tue, 6 Aug 2013 13:23:21 -0600
43fe83
Subject: [PATCH] qemu: enable auto-allocate of all PCI addresses
43fe83
43fe83
This patch is part of the resolution to:
43fe83
43fe83
   https://bugzilla.redhat.com/show_bug.cgi?id=819968
43fe83
43fe83
Previous refactoring of the guest PCI address reservation/allocation
43fe83
code allowed for slot types other than basic PCI (e.g. PCI express,
43fe83
non-hotpluggable slots, etc) but would not auto-allocate a slot for a
43fe83
device that required any type other than a basic hot-pluggable
43fe83
PCI slot.
43fe83
43fe83
This patch refactors the code to be aware of different slot types
43fe83
during auto-allocation of addresses as well - as long as there is an
43fe83
empty slot of the required type, it will be found and used.
43fe83
43fe83
The piece that *wasn't* added is that we don't auto-create a new PCI
43fe83
bus when needed for anything except basic PCI devices. This is because
43fe83
there are multiple different types of controllers that can provide,
43fe83
for example, a PCI express slot (in addition to the pcie-root
43fe83
controller, these can also be found on a "root-port" or on a
43fe83
"downstream-switch-port"). Since we currently don't support any PCIe
43fe83
devices (except pending support for dmi-to-pci-bridge), we can defer
43fe83
any decision on what to do about this.
43fe83
(cherry picked from commit c305783c65f2b552a08fc0e03e1d9b98157d91ca)
43fe83
---
43fe83
 src/qemu/qemu_command.c | 115 +++++++++++++++++++++++++++++++++++++++---------
43fe83
 1 file changed, 93 insertions(+), 22 deletions(-)
43fe83
43fe83
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
43fe83
index abc973a..2886e01 100644
43fe83
--- a/src/qemu/qemu_command.c
43fe83
+++ b/src/qemu/qemu_command.c
43fe83
@@ -1429,6 +1429,7 @@ struct _qemuDomainPCIAddressSet {
43fe83
     qemuDomainPCIAddressBus *buses;
43fe83
     size_t nbuses;
43fe83
     virDevicePCIAddress lastaddr;
43fe83
+    qemuDomainPCIConnectFlags lastFlags;
43fe83
     bool dryRun;          /* on a dry run, new buses are auto-added
43fe83
                              and addresses aren't saved in device infos */
43fe83
 };
43fe83
@@ -1630,7 +1631,7 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
43fe83
     int ret = -1;
43fe83
     virDevicePCIAddressPtr addr = &info->addr.pci;
43fe83
     bool entireSlot;
43fe83
-    /* FIXME: flags should be set according to the requirements of @device */
43fe83
+    /* flags may be changed from default below */
43fe83
     qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
43fe83
                                        QEMU_PCI_CONNECT_TYPE_PCI);
43fe83
 
43fe83
@@ -1644,28 +1645,60 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
43fe83
         return 0;
43fe83
     }
43fe83
 
43fe83
+    /* Change flags according to differing requirements of different
43fe83
+     * devices.
43fe83
+     */
43fe83
+    if (device->type == VIR_DOMAIN_DEVICE_CONTROLLER &&
43fe83
+        device->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
43fe83
+        switch (device->data.controller->model) {
43fe83
+        case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
43fe83
+            /* pci-bridge needs a PCI slot, but it isn't
43fe83
+             * hot-pluggable, so it doesn't need a hot-pluggable slot.
43fe83
+             */
43fe83
+            flags = QEMU_PCI_CONNECT_TYPE_PCI;
43fe83
+            break;
43fe83
+        default:
43fe83
+            break;
43fe83
+        }
43fe83
+    }
43fe83
+
43fe83
     /* Ignore implicit controllers on slot 0:0:1.0:
43fe83
      * implicit IDE controller on 0:0:1.1 (no qemu command line)
43fe83
      * implicit USB controller on 0:0:1.2 (-usb)
43fe83
      *
43fe83
      * If the machine does have a PCI bus, they will get reserved
43fe83
      * in qemuAssignDevicePCISlots().
43fe83
-     *
43fe83
-     * FIXME: When we have support for a pcie-root controller at bus
43fe83
-     * 0, we will no longer be able to skip checking of these devices,
43fe83
-     * as they are PCI, and thus can't be connected to bus 0 if it is
43fe83
-     * PCIe rather than PCI.
43fe83
+     */
43fe83
+
43fe83
+    /* These are the IDE and USB controllers in the PIIX3, hardcoded
43fe83
+     * to bus 0 slot 1.  They cannot be attached to a PCIe slot, only
43fe83
+     * PCI.
43fe83
      */
43fe83
     if (device->type == VIR_DOMAIN_DEVICE_CONTROLLER && addr->domain == 0 &&
43fe83
         addr->bus == 0 && addr->slot == 1) {
43fe83
         virDomainControllerDefPtr cont = device->data.controller;
43fe83
-        if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && cont->idx == 0 &&
43fe83
-            addr->function == 1)
43fe83
-            return 0;
43fe83
-        if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && cont->idx == 0 &&
43fe83
-            (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI ||
43fe83
-             cont->model == -1) && addr->function == 2)
43fe83
-            return 0;
43fe83
+
43fe83
+        if ((cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && cont->idx == 0 &&
43fe83
+             addr->function == 1) ||
43fe83
+            (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && cont->idx == 0 &&
43fe83
+             (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI ||
43fe83
+              cont->model == -1) && addr->function == 2)) {
43fe83
+            /* Note the check for nbuses > 0 - if there are no PCI
43fe83
+             * buses, we skip this check. This is a quirk required for
43fe83
+             * some machinetypes such as s390, which pretend to have a
43fe83
+             * PCI bus for long enough to generate the "-usb" on the
43fe83
+             * commandline, but that don't really care if a PCI bus
43fe83
+             * actually exists. */
43fe83
+            if (addrs->nbuses > 0 &&
43fe83
+                !(addrs->buses[0].flags & QEMU_PCI_CONNECT_TYPE_PCI)) {
43fe83
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
43fe83
+                               _("Bus 0 must be PCI for integrated PIIX3 "
43fe83
+                                 "USB or IDE controllers"));
43fe83
+                return -1;
43fe83
+            } else {
43fe83
+                return 0;
43fe83
+            }
43fe83
+        }
43fe83
     }
43fe83
 
43fe83
     entireSlot = (addr->function == 0 &&
43fe83
@@ -1695,8 +1728,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
43fe83
         int nbuses = 0;
43fe83
         size_t i;
43fe83
         int rv;
43fe83
-        qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
43fe83
-                                           QEMU_PCI_CONNECT_TYPE_PCI);
43fe83
+        qemuDomainPCIConnectFlags flags = QEMU_PCI_CONNECT_TYPE_PCI;
43fe83
 
43fe83
         for (i = 0; i < def->ncontrollers; i++) {
43fe83
             if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
43fe83
@@ -1941,7 +1973,11 @@ int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
43fe83
                                    virDomainDeviceInfoPtr dev)
43fe83
 {
43fe83
     int ret = 0;
43fe83
-    /* FIXME: flags should be set according to the particular device */
43fe83
+    /* Flags should be set according to the particular device,
43fe83
+     * but only the caller knows the type of device. Currently this
43fe83
+     * function is only used for hot-plug, though, and hot-plug is
43fe83
+     * only supported for standard PCI devices, so we can safely use
43fe83
+     * the setting below */
43fe83
     qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
43fe83
                                        QEMU_PCI_CONNECT_TYPE_PCI);
43fe83
 
43fe83
@@ -2005,7 +2041,16 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
                                 virDevicePCIAddressPtr next_addr,
43fe83
                                 qemuDomainPCIConnectFlags flags)
43fe83
 {
43fe83
-    virDevicePCIAddress a = addrs->lastaddr;
43fe83
+    /* default to starting the search for a free slot from
43fe83
+     * 0000:00:00.0
43fe83
+     */
43fe83
+    virDevicePCIAddress a = { 0, 0, 0, 0, false };
43fe83
+
43fe83
+    /* except if this search is for the exact same type of device as
43fe83
+     * last time, continue the search from the previous match
43fe83
+     */
43fe83
+    if (flags == addrs->lastFlags)
43fe83
+        a = addrs->lastaddr;
43fe83
 
43fe83
     if (addrs->nbuses == 0) {
43fe83
         virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
43fe83
@@ -2014,6 +2059,12 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
 
43fe83
     /* Start the search at the last used bus and slot */
43fe83
     for (a.slot++; a.bus < addrs->nbuses; a.bus++) {
43fe83
+        if (!qemuDomainPCIAddressFlagsCompatible(&a, addrs->buses[a.bus].flags,
43fe83
+                                                 flags, false)) {
43fe83
+            VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
43fe83
+                      a.domain, a.bus);
43fe83
+            continue;
43fe83
+        }
43fe83
         for (; a.slot <= QEMU_PCI_ADDRESS_SLOT_LAST; a.slot++) {
43fe83
             if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
43fe83
                 goto success;
43fe83
@@ -2030,9 +2081,15 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
         if (qemuDomainPCIAddressSetGrow(addrs, &a, flags) < 0)
43fe83
             return -1;
43fe83
         goto success;
43fe83
-    } else {
43fe83
+    } else if (flags == addrs->lastFlags) {
43fe83
         /* Check the buses from 0 up to the last used one */
43fe83
         for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) {
43fe83
+            if (!qemuDomainPCIAddressFlagsCompatible(&a, addrs->buses[a.bus].flags,
43fe83
+                                                     flags, false)) {
43fe83
+                VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
43fe83
+                          a.domain, a.bus);
43fe83
+                continue;
43fe83
+            }
43fe83
             for (a.slot = 1; a.slot <= QEMU_PCI_ADDRESS_SLOT_LAST; a.slot++) {
43fe83
                 if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
43fe83
                     goto success;
43fe83
@@ -2072,6 +2129,7 @@ qemuDomainPCIAddressReserveNextSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
     }
43fe83
 
43fe83
     addrs->lastaddr = addr;
43fe83
+    addrs->lastFlags = flags;
43fe83
     return 0;
43fe83
 }
43fe83
 
43fe83
@@ -2285,15 +2343,26 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
43fe83
         goto error;
43fe83
     }
43fe83
 
43fe83
-    flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
43fe83
-
43fe83
     /* PCI controllers */
43fe83
     for (i = 0; i < def->ncontrollers; i++) {
43fe83
         if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
43fe83
-            if (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT)
43fe83
-                continue;
43fe83
             if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
43fe83
                 continue;
43fe83
+            switch (def->controllers[i]->model) {
43fe83
+            case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
43fe83
+                /* pci-root is implicit in the machine,
43fe83
+                 * and needs no address */
43fe83
+                continue;
43fe83
+            case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
43fe83
+                /* pci-bridge doesn't require hot-plug
43fe83
+                 * (although it does provide hot-plug in its slots)
43fe83
+                 */
43fe83
+                flags = QEMU_PCI_CONNECT_TYPE_PCI;
43fe83
+                break;
43fe83
+            default:
43fe83
+                flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
43fe83
+                break;
43fe83
+            }
43fe83
             if (qemuDomainPCIAddressReserveNextSlot(addrs,
43fe83
                                                     &def->controllers[i]->info,
43fe83
                                                     flags) < 0)
43fe83
@@ -2301,6 +2370,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
43fe83
         }
43fe83
     }
43fe83
 
43fe83
+    flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
43fe83
+
43fe83
     for (i = 0; i < def->nfss; i++) {
43fe83
         if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
43fe83
             continue;
43fe83
-- 
43fe83
1.8.3.2
43fe83