[libvirt] [PATCH 08/13] Move and rename qemuDomainAddressFindNewBusNr et al

Tomasz Flendrich t.flendrich at gmail.com
Wed Jul 20 00:07:22 UTC 2016


qemuDomainAddressFindNewBusNr is renamed to virDomainAddressFindNewBusNr
qemuDomainPCIAddressSetCreate is renamed to virDomainPCIAddressSetCreate
qemuDomainPCIBusFullyReserved is renamed to virDomainPCIBusFullyReserved
qemuDomainAssignDevicePCISlots is renamed to virDomainAssignDevicePCISlots

All of these are moved from qemu_domain_addr.c to domain_addr.c

These functions are being moved because they don't depend on qemu,
so they have the potential to be reused for more hypervisors.
---
 src/conf/domain_addr.c         | 486 ++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_addr.h         |  20 ++
 src/libvirt_private.syms       |   4 +
 src/qemu/qemu_domain_address.c | 498 +----------------------------------------
 4 files changed, 516 insertions(+), 492 deletions(-)

diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 0659842..32943e8 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -1731,3 +1731,489 @@ virDomainValidateDevicePCISlotsChipsets(virDomainDefPtr def,
 
     return 0;
 }
+
+
+int
+virDomainAddressFindNewBusNr(virDomainDefPtr def)
+{
+/* Try to find a nice default for busNr for a new pci-expander-bus.
+ * This is a bit tricky, since you need to satisfy the following:
+ *
+ * 1) There need to be enough unused bus numbers between busNr of this
+ *    bus and busNr of the next highest bus for the guest to assign a
+ *    unique bus number to each PCI bus that is a child of this
+ *    bus. Each PCI controller. On top of this, the pxb device (which
+ *    implements the pci-expander-bus) includes a pci-bridge within
+ *    it, and that bridge also uses one bus number (so each pxb device
+ *    requires at least 2 bus numbers).
+ *
+ * 2) There need to be enough bus numbers *below* this for all the
+ *    child controllers of the pci-expander-bus with the next lower
+ *    busNr (or the pci-root bus if there are no lower
+ *    pci-expander-buses).
+ *
+ * 3) If at all possible, we want to avoid needing to change the busNr
+ *    of a bus in the future, as that changes the guest's device ABI,
+ *    which could potentially lead to issues with a guest OS that is
+ *    picky about such things.
+ *
+ *  Due to the impossibility of predicting what might be added to the
+ *  config in the future, we can't make a foolproof choice, but since
+ *  a pci-expander-bus (pxb) has slots for 32 devices, and the only
+ *  practical use for it is to assign real devices on a particular
+ *  NUMA node in the host, it's reasonably safe to assume it should
+ *  never need any additional child buses (probably only a few of the
+ *  32 will ever be used). So for pci-expander-bus we find the lowest
+ *  existing busNr, and set this one to the current lowest - 2 (one
+ *  for the pxb, one for the intergrated pci-bridge), thus leaving the
+ *  maximum possible bus numbers available for other buses plugged
+ *  into pci-root (i.e. pci-bridges and other
+ *  pci-expander-buses). Anyone who needs more than 32 devices
+ *  descended from one pci-expander-bus should set the busNr manually
+ *  in the config.
+ *
+ *  There is room for more error checking here - in particular we
+ *  can/should determine the ultimate parent (root-bus) of each PCI
+ *  controller and determine if there is enough space for all the
+ *  buses within the current range allotted to the bus just prior to
+ *  this one.
+ */
+    size_t i;
+    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;
+
+            if (thisBusNr >= 0 && thisBusNr < lowestBusNr)
+                lowestBusNr = thisBusNr;
+        }
+    }
+
+    /* If we already have a busNR = 1, then we can't auto-assign (0 is
+     * the pci[e]-root, and the others may have been assigned
+     * purposefully).
+     */
+    if (lowestBusNr <= 2)
+        return -1;
+
+    return lowestBusNr - 2;
+}
+
+
+virDomainPCIAddressSetPtr
+virDomainPCIAddressSetCreate(virDomainDefPtr def,
+                             unsigned int nbuses,
+                             bool dryRun)
+{
+    virDomainPCIAddressSetPtr addrs;
+    size_t i;
+
+    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
+     * 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++) {
+        size_t idx = def->controllers[i]->idx;
+
+        if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
+            continue;
+
+        if (idx >= addrs->nbuses) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Inappropriate new pci controller index %zu "
+                             "not found in addrs"), idx);
+            goto error;
+        }
+
+        if (virDomainPCIAddressBusSetModel(&addrs->buses[idx],
+                                           def->controllers[i]->model) < 0)
+            goto error;
+        }
+
+    if (virDomainDeviceInfoIterate(def, virDomainCollectPCIAddress, addrs) < 0)
+        goto error;
+
+    return addrs;
+
+ error:
+    virDomainPCIAddressSetFree(addrs);
+    return NULL;
+}
+
+
+bool
+virDomainPCIBusFullyReserved(virDomainPCIAddressBusPtr bus)
+{
+    size_t i;
+
+    for (i = bus->minSlot; i <= bus->maxSlot; i++)
+        if (!bus->slots[i])
+            return false;
+
+    return true;
+}
+
+
+/*
+ * This assigns static PCI slots to all configured devices.
+ * The ordering here is chosen to match the ordering used
+ * with old QEMU < 0.12, so that if a user updates a QEMU
+ * host from old QEMU to QEMU >= 0.12, their guests should
+ * get PCI addresses in the same order as before.
+ *
+ * NB, if they previously hotplugged devices then all bets
+ * are off. Hotplug for old QEMU was unfixably broken wrt
+ * to stable PCI addressing.
+ *
+ * Order is:
+ *
+ *  - Host bridge (slot 0)
+ *  - PIIX3 ISA bridge, IDE controller, something else unknown, USB controller (slot 1)
+ *  - Video (slot 2)
+ *
+ *  - These integrated devices were already added by
+ *    qemuValidateDevicePCISlotsChipsets invoked right before this function
+ *
+ * Incrementally assign slots from 3 onwards:
+ *
+ *  - Net
+ *  - Sound
+ *  - SCSI controllers
+ *  - VirtIO block
+ *  - VirtIO balloon
+ *  - Host device passthrough
+ *  - Watchdog
+ *  - pci serial devices
+ *
+ * Prior to this function being invoked, virDomainCollectPCIAddress() will have
+ * added all existing PCI addresses from the 'def' to 'addrs'. Thus this
+ * function must only try to reserve addresses if info.type == NONE and
+ * skip over info.type == PCI
+ */
+int
+virDomainAssignDevicePCISlots(virDomainDefPtr def,
+                              virDomainPCIAddressSetPtr addrs,
+                              bool virtioMMIOEnabled)
+{
+    size_t i, j;
+    virDomainPCIConnectFlags flags = 0; /* initialize to quiet gcc warning */
+    virPCIDeviceAddress tmp_addr;
+
+    /* 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;
+
+            if (model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
+                model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT ||
+                !virDeviceInfoPCIAddressWanted(&def->controllers[i]->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 (virDomainPCIAddressReserveNextSlot(addrs,
+                                                   &def->controllers[i]->info,
+                                                   flags) < 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 (virDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* Network interfaces */
+    for (i = 0; i < def->nnets; 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)) {
+            continue;
+        }
+        if (virDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* Sound cards */
+    for (i = 0; i < def->nsounds; i++) {
+        if (!virDeviceInfoPCIAddressWanted(&def->sounds[i]->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)
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* Device controllers (SCSI, USB, but not IDE, FDC or CCID) */
+    for (i = 0; i < def->ncontrollers; i++) {
+        /* PCI controllers have been dealt with earlier */
+        if (def->controllers[i]->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)
+            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)
+            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)
+            continue;
+
+        if (!virDeviceInfoPCIAddressWanted(&def->controllers[i]->info))
+            continue;
+
+        /* USB2 needs special handling to put all companions in the same slot */
+        if (IS_USB2_CONTROLLER(def->controllers[i])) {
+            virPCIDeviceAddress addr = { 0, 0, 0, 0, false };
+            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 &&
+                    virDeviceInfoPCIAddressPresent(&def->controllers[j]->info)) {
+                    addr = def->controllers[j]->info.addr.pci;
+                    foundAddr = true;
+                    break;
+                }
+            }
+
+            switch (def->controllers[i]->model) {
+            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
+                addr.function = 7;
+                addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
+                break;
+            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
+                addr.function = 0;
+                addr.multi = VIR_TRISTATE_SWITCH_ON;
+                break;
+            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
+                addr.function = 1;
+                addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
+                break;
+            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
+                addr.function = 2;
+                addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
+                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)
+                    goto error;
+
+                addr.bus = tmp_addr.bus;
+                addr.slot = tmp_addr.slot;
+
+                addrs->lastaddr = addr;
+                addrs->lastaddr.function = 0;
+                addrs->lastaddr.multi = VIR_TRISTATE_SWITCH_ABSENT;
+            }
+            /* Finally we can reserve the slot+function */
+            if (virDomainPCIAddressReserveAddr(addrs, &addr, flags,
+                                               false, foundAddr) < 0)
+                goto error;
+
+            def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+            def->controllers[i]->info.addr.pci = addr;
+        } else {
+            if (virDomainPCIAddressReserveNextSlot(addrs,
+                                                   &def->controllers[i]->info,
+                                                   flags) < 0)
+                goto error;
+        }
+    }
+
+    /* Disks (VirtIO only for now) */
+    for (i = 0; i < def->ndisks; i++) {
+        /* Only VirtIO disks use PCI addrs */
+        if (def->disks[i]->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
+            continue;
+
+        /* don't touch s390 devices */
+        if (virDeviceInfoPCIAddressPresent(&def->disks[i]->info) ||
+            def->disks[i]->info.type ==
+            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 ||
+            def->disks[i]->info.type ==
+            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
+            continue;
+
+        /* Also ignore virtio-mmio disks if our machine allows them */
+        if (def->disks[i]->info.type ==
+            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
+            virtioMMIOEnabled)
+            continue;
+
+        if (!virDeviceInfoPCIAddressWanted(&def->disks[i]->info)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("virtio disk cannot have an address of type '%s'"),
+                           virDomainDeviceAddressTypeToString(def->disks[i]->info.type));
+            goto error;
+        }
+
+        if (virDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* Host PCI devices */
+    for (i = 0; i < def->nhostdevs; i++) {
+        if (!virDeviceInfoPCIAddressWanted(def->hostdevs[i]->info))
+            continue;
+        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+            def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs,
+                                               def->hostdevs[i]->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* VirtIO balloon */
+    if (def->memballoon &&
+        def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
+        virDeviceInfoPCIAddressWanted(&def->memballoon->info)) {
+        if (virDomainPCIAddressReserveNextSlot(addrs,
+                                               &def->memballoon->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* VirtIO RNG */
+    for (i = 0; i < def->nrngs; i++) {
+        if (def->rngs[i]->model != VIR_DOMAIN_RNG_MODEL_VIRTIO ||
+            !virDeviceInfoPCIAddressWanted(&def->rngs[i]->info))
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs,
+                                               &def->rngs[i]->info, flags) < 0)
+            goto error;
+    }
+
+    /* A watchdog - check if it is a PCI device */
+    if (def->watchdog &&
+        def->watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB &&
+        virDeviceInfoPCIAddressWanted(&def->watchdog->info)) {
+        if (virDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* Assign a PCI slot to the primary video card if there is not an
+     * assigned address. */
+    if (def->nvideos > 0 &&
+        virDeviceInfoPCIAddressWanted(&def->videos[0]->info)) {
+        if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* Further non-primary video cards which have to be qxl type */
+    for (i = 1; i < def->nvideos; i++) {
+        if (def->videos[i]->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("non-primary video device must be type of 'qxl'"));
+            goto error;
+        }
+        if (!virDeviceInfoPCIAddressWanted(&def->videos[i]->info))
+            continue;
+        if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info,
+                                               flags) < 0)
+            goto error;
+    }
+
+    /* Shared Memory */
+    for (i = 0; i < def->nshmems; i++) {
+        if (!virDeviceInfoPCIAddressWanted(&def->shmems[i]->info))
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs,
+                                               &def->shmems[i]->info, flags) < 0)
+            goto error;
+    }
+    for (i = 0; i < def->ninputs; i++) {
+        if (def->inputs[i]->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO ||
+            !virDeviceInfoPCIAddressWanted(&def->inputs[i]->info))
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs,
+                                               &def->inputs[i]->info, flags) < 0)
+            goto error;
+    }
+    for (i = 0; i < def->nparallels; i++) {
+        /* Nada - none are PCI based (yet) */
+    }
+    for (i = 0; i < def->nserials; i++) {
+        virDomainChrDefPtr chr = def->serials[i];
+
+        if (chr->targetType != VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI ||
+            !virDeviceInfoPCIAddressWanted(&chr->info))
+            continue;
+
+        if (virDomainPCIAddressReserveNextSlot(addrs, &chr->info, flags) < 0)
+            goto error;
+    }
+    for (i = 0; i < def->nchannels; i++) {
+        /* Nada - none are PCI based (yet) */
+    }
+    for (i = 0; i < def->nhubs; i++) {
+        /* Nada - none are PCI based (yet) */
+    }
+
+    return 0;
+
+ error:
+    return -1;
+}
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 42424f9..a1e572b 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -262,4 +262,24 @@ virDomainValidateDevicePCISlotsChipsets(virDomainDefPtr def,
                                          bool videoPrimaryEnabled)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
+int
+virDomainAddressFindNewBusNr(virDomainDefPtr def)
+    ATTRIBUTE_NONNULL(1);
+
+virDomainPCIAddressSetPtr
+virDomainPCIAddressSetCreate(virDomainDefPtr def,
+                             unsigned int nbuses,
+                             bool dryRun)
+    ATTRIBUTE_NONNULL(1);
+
+bool
+virDomainPCIBusFullyReserved(virDomainPCIAddressBusPtr bus)
+    ATTRIBUTE_NONNULL(1);
+
+int
+virDomainAssignDevicePCISlots(virDomainDefPtr def,
+                              virDomainPCIAddressSetPtr addrs,
+                              bool virtioMMIOEnabled)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 #endif /* __DOMAIN_ADDR_H__ */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3e468b5..66144fd 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -85,6 +85,8 @@ virPCIDeviceAddressParseXML;
 
 
 # conf/domain_addr.h
+virDomainAddressFindNewBusNr;
+virDomainAssignDevicePCISlots;
 virDomainAssignVirtioSerialAddresses;
 virDomainCCWAddressAllocate;
 virDomainCCWAddressAssign;
@@ -104,10 +106,12 @@ virDomainPCIAddressReserveAddr;
 virDomainPCIAddressReserveNextSlot;
 virDomainPCIAddressReserveSlot;
 virDomainPCIAddressSetAlloc;
+virDomainPCIAddressSetCreate;
 virDomainPCIAddressSetFree;
 virDomainPCIAddressSetGrow;
 virDomainPCIAddressSlotInUse;
 virDomainPCIAddressValidate;
+virDomainPCIBusFullyReserved;
 virDomainPCIControllerModelToConnectType;
 virDomainValidateDevicePCISlotsChipsets;
 virDomainValidateDevicePCISlotsPIIX3;
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index ec67e37..a0bc752 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -360,424 +360,6 @@ qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def,
 }
 
 
-static virDomainPCIAddressSetPtr
-qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
-                              unsigned int nbuses,
-                              bool dryRun)
-{
-    virDomainPCIAddressSetPtr addrs;
-    size_t i;
-
-    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
-     * 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++) {
-        size_t idx = def->controllers[i]->idx;
-
-        if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
-            continue;
-
-        if (idx >= addrs->nbuses) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Inappropriate new pci controller index %zu "
-                             "not found in addrs"), idx);
-            goto error;
-        }
-
-        if (virDomainPCIAddressBusSetModel(&addrs->buses[idx],
-                                           def->controllers[i]->model) < 0)
-            goto error;
-        }
-
-    if (virDomainDeviceInfoIterate(def, virDomainCollectPCIAddress, addrs) < 0)
-        goto error;
-
-    return addrs;
-
- error:
-    virDomainPCIAddressSetFree(addrs);
-    return NULL;
-}
-
-
-static bool
-qemuDomainPCIBusFullyReserved(virDomainPCIAddressBusPtr bus)
-{
-    size_t i;
-
-    for (i = bus->minSlot; i <= bus->maxSlot; i++)
-        if (!bus->slots[i])
-            return false;
-
-    return true;
-}
-
-
-/*
- * This assigns static PCI slots to all configured devices.
- * The ordering here is chosen to match the ordering used
- * with old QEMU < 0.12, so that if a user updates a QEMU
- * host from old QEMU to QEMU >= 0.12, their guests should
- * get PCI addresses in the same order as before.
- *
- * NB, if they previously hotplugged devices then all bets
- * are off. Hotplug for old QEMU was unfixably broken wrt
- * to stable PCI addressing.
- *
- * Order is:
- *
- *  - Host bridge (slot 0)
- *  - PIIX3 ISA bridge, IDE controller, something else unknown, USB controller (slot 1)
- *  - Video (slot 2)
- *
- *  - These integrated devices were already added by
- *    qemuValidateDevicePCISlotsChipsets invoked right before this function
- *
- * Incrementally assign slots from 3 onwards:
- *
- *  - Net
- *  - Sound
- *  - SCSI controllers
- *  - VirtIO block
- *  - VirtIO balloon
- *  - Host device passthrough
- *  - Watchdog
- *  - pci serial devices
- *
- * Prior to this function being invoked, virDomainCollectPCIAddress() will have
- * added all existing PCI addresses from the 'def' to 'addrs'. Thus this
- * function must only try to reserve addresses if info.type == NONE and
- * skip over info.type == PCI
- */
-static int
-qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
-                               virDomainPCIAddressSetPtr addrs,
-                               bool virtioMMIOEnabled)
-{
-    size_t i, j;
-    virDomainPCIConnectFlags flags = 0; /* initialize to quiet gcc warning */
-    virPCIDeviceAddress tmp_addr;
-
-    /* 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;
-
-            if (model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
-                model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT ||
-                !virDeviceInfoPCIAddressWanted(&def->controllers[i]->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 (virDomainPCIAddressReserveNextSlot(addrs,
-                                                   &def->controllers[i]->info,
-                                                   flags) < 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 (virDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* Network interfaces */
-    for (i = 0; i < def->nnets; 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)) {
-            continue;
-        }
-        if (virDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* Sound cards */
-    for (i = 0; i < def->nsounds; i++) {
-        if (!virDeviceInfoPCIAddressWanted(&def->sounds[i]->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)
-            continue;
-
-        if (virDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* Device controllers (SCSI, USB, but not IDE, FDC or CCID) */
-    for (i = 0; i < def->ncontrollers; i++) {
-        /* PCI controllers have been dealt with earlier */
-        if (def->controllers[i]->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)
-            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)
-            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)
-            continue;
-
-        if (!virDeviceInfoPCIAddressWanted(&def->controllers[i]->info))
-            continue;
-
-        /* USB2 needs special handling to put all companions in the same slot */
-        if (IS_USB2_CONTROLLER(def->controllers[i])) {
-            virPCIDeviceAddress addr = { 0, 0, 0, 0, false };
-            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 &&
-                    virDeviceInfoPCIAddressPresent(&def->controllers[j]->info)) {
-                    addr = def->controllers[j]->info.addr.pci;
-                    foundAddr = true;
-                    break;
-                }
-            }
-
-            switch (def->controllers[i]->model) {
-            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
-                addr.function = 7;
-                addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
-                break;
-            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
-                addr.function = 0;
-                addr.multi = VIR_TRISTATE_SWITCH_ON;
-                break;
-            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
-                addr.function = 1;
-                addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
-                break;
-            case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
-                addr.function = 2;
-                addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
-                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)
-                    goto error;
-
-                addr.bus = tmp_addr.bus;
-                addr.slot = tmp_addr.slot;
-
-                addrs->lastaddr = addr;
-                addrs->lastaddr.function = 0;
-                addrs->lastaddr.multi = VIR_TRISTATE_SWITCH_ABSENT;
-            }
-            /* Finally we can reserve the slot+function */
-            if (virDomainPCIAddressReserveAddr(addrs, &addr, flags,
-                                               false, foundAddr) < 0)
-                goto error;
-
-            def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
-            def->controllers[i]->info.addr.pci = addr;
-        } else {
-            if (virDomainPCIAddressReserveNextSlot(addrs,
-                                                   &def->controllers[i]->info,
-                                                   flags) < 0)
-                goto error;
-        }
-    }
-
-    /* Disks (VirtIO only for now) */
-    for (i = 0; i < def->ndisks; i++) {
-        /* Only VirtIO disks use PCI addrs */
-        if (def->disks[i]->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
-            continue;
-
-        /* don't touch s390 devices */
-        if (virDeviceInfoPCIAddressPresent(&def->disks[i]->info) ||
-            def->disks[i]->info.type ==
-            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 ||
-            def->disks[i]->info.type ==
-            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
-            continue;
-
-        /* Also ignore virtio-mmio disks if our machine allows them */
-        if (def->disks[i]->info.type ==
-            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
-            virtioMMIOEnabled)
-            continue;
-
-        if (!virDeviceInfoPCIAddressWanted(&def->disks[i]->info)) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("virtio disk cannot have an address of type '%s'"),
-                           virDomainDeviceAddressTypeToString(def->disks[i]->info.type));
-            goto error;
-        }
-
-        if (virDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* Host PCI devices */
-    for (i = 0; i < def->nhostdevs; i++) {
-        if (!virDeviceInfoPCIAddressWanted(def->hostdevs[i]->info))
-            continue;
-        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-            def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-            continue;
-
-        if (virDomainPCIAddressReserveNextSlot(addrs,
-                                               def->hostdevs[i]->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* VirtIO balloon */
-    if (def->memballoon &&
-        def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
-        virDeviceInfoPCIAddressWanted(&def->memballoon->info)) {
-        if (virDomainPCIAddressReserveNextSlot(addrs,
-                                               &def->memballoon->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* VirtIO RNG */
-    for (i = 0; i < def->nrngs; i++) {
-        if (def->rngs[i]->model != VIR_DOMAIN_RNG_MODEL_VIRTIO ||
-            !virDeviceInfoPCIAddressWanted(&def->rngs[i]->info))
-            continue;
-
-        if (virDomainPCIAddressReserveNextSlot(addrs,
-                                               &def->rngs[i]->info, flags) < 0)
-            goto error;
-    }
-
-    /* A watchdog - check if it is a PCI device */
-    if (def->watchdog &&
-        def->watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB &&
-        virDeviceInfoPCIAddressWanted(&def->watchdog->info)) {
-        if (virDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* Assign a PCI slot to the primary video card if there is not an
-     * assigned address. */
-    if (def->nvideos > 0 &&
-        virDeviceInfoPCIAddressWanted(&def->videos[0]->info)) {
-        if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* Further non-primary video cards which have to be qxl type */
-    for (i = 1; i < def->nvideos; i++) {
-        if (def->videos[i]->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("non-primary video device must be type of 'qxl'"));
-            goto error;
-        }
-        if (!virDeviceInfoPCIAddressWanted(&def->videos[i]->info))
-            continue;
-        if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info,
-                                               flags) < 0)
-            goto error;
-    }
-
-    /* Shared Memory */
-    for (i = 0; i < def->nshmems; i++) {
-        if (!virDeviceInfoPCIAddressWanted(&def->shmems[i]->info))
-            continue;
-
-        if (virDomainPCIAddressReserveNextSlot(addrs,
-                                               &def->shmems[i]->info, flags) < 0)
-            goto error;
-    }
-    for (i = 0; i < def->ninputs; i++) {
-        if (def->inputs[i]->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO ||
-            !virDeviceInfoPCIAddressWanted(&def->inputs[i]->info))
-            continue;
-
-        if (virDomainPCIAddressReserveNextSlot(addrs,
-                                               &def->inputs[i]->info, flags) < 0)
-            goto error;
-    }
-    for (i = 0; i < def->nparallels; i++) {
-        /* Nada - none are PCI based (yet) */
-    }
-    for (i = 0; i < def->nserials; i++) {
-        virDomainChrDefPtr chr = def->serials[i];
-
-        if (chr->targetType != VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI ||
-            !virDeviceInfoPCIAddressWanted(&chr->info))
-            continue;
-
-        if (virDomainPCIAddressReserveNextSlot(addrs, &chr->info, flags) < 0)
-            goto error;
-    }
-    for (i = 0; i < def->nchannels; i++) {
-        /* Nada - none are PCI based (yet) */
-    }
-    for (i = 0; i < def->nhubs; i++) {
-        /* Nada - none are PCI based (yet) */
-    }
-
-    return 0;
-
- error:
-    return -1;
-}
-
-
 static bool
 qemuDomainSupportsPCI(virDomainDefPtr def,
                       bool gpexEnabled)
@@ -833,74 +415,6 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont)
     }
 }
 
-
-static int
-qemuDomainAddressFindNewBusNr(virDomainDefPtr def)
-{
-/* Try to find a nice default for busNr for a new pci-expander-bus.
- * This is a bit tricky, since you need to satisfy the following:
- *
- * 1) There need to be enough unused bus numbers between busNr of this
- *    bus and busNr of the next highest bus for the guest to assign a
- *    unique bus number to each PCI bus that is a child of this
- *    bus. Each PCI controller. On top of this, the pxb device (which
- *    implements the pci-expander-bus) includes a pci-bridge within
- *    it, and that bridge also uses one bus number (so each pxb device
- *    requires at least 2 bus numbers).
- *
- * 2) There need to be enough bus numbers *below* this for all the
- *    child controllers of the pci-expander-bus with the next lower
- *    busNr (or the pci-root bus if there are no lower
- *    pci-expander-buses).
- *
- * 3) If at all possible, we want to avoid needing to change the busNr
- *    of a bus in the future, as that changes the guest's device ABI,
- *    which could potentially lead to issues with a guest OS that is
- *    picky about such things.
- *
- *  Due to the impossibility of predicting what might be added to the
- *  config in the future, we can't make a foolproof choice, but since
- *  a pci-expander-bus (pxb) has slots for 32 devices, and the only
- *  practical use for it is to assign real devices on a particular
- *  NUMA node in the host, it's reasonably safe to assume it should
- *  never need any additional child buses (probably only a few of the
- *  32 will ever be used). So for pci-expander-bus we find the lowest
- *  existing busNr, and set this one to the current lowest - 2 (one
- *  for the pxb, one for the intergrated pci-bridge), thus leaving the
- *  maximum possible bus numbers available for other buses plugged
- *  into pci-root (i.e. pci-bridges and other
- *  pci-expander-buses). Anyone who needs more than 32 devices
- *  descended from one pci-expander-bus should set the busNr manually
- *  in the config.
- *
- *  There is room for more error checking here - in particular we
- *  can/should determine the ultimate parent (root-bus) of each PCI
- *  controller and determine if there is enough space for all the
- *  buses within the current range allotted to the bus just prior to
- *  this one.
- */
-    size_t i;
-    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;
-
-            if (thisBusNr >= 0 && thisBusNr < lowestBusNr)
-                lowestBusNr = thisBusNr;
-        }
-    }
-
-    /* If we already have a busNR = 1, then we can't auto-assign (0 is
-     * the pci[e]-root, and the others may have been assigned
-     * purposefully).
-     */
-    if (lowestBusNr <= 2)
-        return -1;
-
-    return lowestBusNr - 2;
-}
-
 virDomainPCIAddressSetPtr
 qemuDomainPCIAddrSetCreateFromDomain(virDomainDefPtr def,
                                      bool virtioMMIOEnabled,
@@ -922,7 +436,7 @@ qemuDomainPCIAddrSetCreateFromDomain(virDomainDefPtr def,
 
     nbuses = max_idx + 1;
 
-    if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, false)))
+    if (!(addrs = virDomainPCIAddressSetCreate(def, nbuses, false)))
         goto cleanup;
 
     if (qemuDomainSupportsPCI(def, gpexEnabled)) {
@@ -930,7 +444,7 @@ qemuDomainPCIAddrSetCreateFromDomain(virDomainDefPtr def,
                                              videoPrimaryEnabled) < 0)
             goto cleanup;
 
-        if (qemuDomainAssignDevicePCISlots(def, addrs, virtioMMIOEnabled) < 0)
+        if (virDomainAssignDevicePCISlots(def, addrs, virtioMMIOEnabled) < 0)
             goto cleanup;
     }
 
@@ -974,7 +488,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
         virDomainDeviceInfo info;
 
         /* 1st pass to figure out how many PCI bridges we need */
-        if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true)))
+        if (!(addrs = virDomainPCIAddressSetCreate(def, nbuses, true)))
             goto cleanup;
 
         if (virDomainValidateDevicePCISlotsChipsets(def, addrs,
@@ -982,7 +496,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
             goto cleanup;
 
         for (i = 0; i < addrs->nbuses; i++) {
-            if (!qemuDomainPCIBusFullyReserved(&addrs->buses[i]))
+            if (!virDomainPCIBusFullyReserved(&addrs->buses[i]))
                 buses_reserved = false;
         }
 
@@ -999,7 +513,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
             virDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0)
             goto cleanup;
 
-        if (qemuDomainAssignDevicePCISlots(def, addrs, virtioMMIOEnabled) < 0)
+        if (virDomainAssignDevicePCISlots(def, addrs, virtioMMIOEnabled) < 0)
             goto cleanup;
 
         for (i = 1; i < addrs->nbuses; i++) {
@@ -1074,7 +588,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
             case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
             case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
                 if (options->busNr == -1)
-                    options->busNr = qemuDomainAddressFindNewBusNr(def);
+                    options->busNr = virDomainAddressFindNewBusNr(def);
                 if (options->busNr == -1) {
                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                    _("No free busNr lower than current "
-- 
2.7.4 (Apple Git-66)




More information about the libvir-list mailing list