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) -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list