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)