The lowest level function of this trio aims to be the ultimate authority for the virDomainPCIConnectFlags to use for any given device using a particular arch/machinetype/qemu-binary. qemuDomainDeviceConnectFlagsInternal() returns the flags qemuDomainDeviceConnectFlags() sets info->pciConnectFlags in a single device (unless it has no virDomainDeviceInfo, in which case it's a NOP). qemuDomainDeviceSetAllConnectFlags() sets info->pciConnectFlags in all devices that have a virDomainDeviceInfo (using virDomainDeviceInfoIterate()) The latter two functions aren't called anywhere yet. This commit is just making them available. --- src/conf/device_conf.h | 5 + src/qemu/qemu_domain_address.c | 257 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 8443de6..f435fb5 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -142,6 +142,11 @@ typedef struct _virDomainDeviceInfo { /* bootIndex is only used for disk, network interface, hostdev * and redirdev devices */ unsigned int bootIndex; + + /* pciConnectFlags is only used internally during address + * assignment, never saved and never reported. + */ + int pciConnectFlags; /* enum virDomainPCIConnectFlags */ } virDomainDeviceInfo, *virDomainDeviceInfoPtr; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index dc4e4ee..7f86c32 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -398,6 +398,263 @@ qemuDomainAssignARMVirtioMMIOAddresses(virDomainDefPtr def, } +/** + * qemuDomainDeviceConnectFlagsInternal: + * + * Lowest level function to determine PCI connectFlags for a + * device. Assume HOTPLUGGABLE | PCI_ENDPOINT, then modify + * appropriately for exceptions. This function relies on the next + * higher-level function determining the value for pcieFlags and + * virtioFlags in advance - this is to make it more efficient to call + * multiple times. + * + * @dev: The device to be checked + * + * @pcieFlags: flags to use for a known PCI Express device + * + * @virtioFlags: flags to use for a virtio device (properly vetted + * for the current qemu binary and arch/machinetype) + * + * returns appropriate virDomainPCIConnectFlags for this device in + * this domain, or 0 if the device doesn't connect using PCI. There + * is no failure. + * + */ +static virDomainPCIConnectFlags +qemuDomainDeviceConnectFlagsInternal(virDomainDeviceDefPtr dev, + virDomainPCIConnectFlags pcieFlags + ATTRIBUTE_UNUSED, + virDomainPCIConnectFlags virtioFlags + ATTRIBUTE_UNUSED) +{ + virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + + /* Get these out of the way to simplify the rest */ + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER && + dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) + return virDomainPCIControllerModelToConnectType(dev->data.controller->model); + + /* remember - default flags is PCI_DEVICE, so only set if it's different. */ + switch (dev->type) { + case VIR_DOMAIN_DEVICE_CONTROLLER: { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID || + (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE)) + flags = 0; + break; + } + + case VIR_DOMAIN_DEVICE_FS: + /* the only type of filesystem so far is virtio-9p-pci */ + break; + + case VIR_DOMAIN_DEVICE_NET: { + virDomainNetDefPtr net = dev->data.net; + + /* NB: a type='hostdev' will use PCI, but its + * address is assigned when we're assigning the + * addresses for other hostdev devices. + */ + if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV || + STREQ(net->model, "usb-net")) + flags = 0; + break; + } + + case VIR_DOMAIN_DEVICE_SOUND: + switch (dev->data.sound->model) { + case VIR_DOMAIN_SOUND_MODEL_SB16: + case VIR_DOMAIN_SOUND_MODEL_PCSPK: + case VIR_DOMAIN_SOUND_MODEL_USB: + flags = 0; + break; + } + break; + + case VIR_DOMAIN_DEVICE_DISK: + if (dev->data.disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) + flags = 0; /* only virtio disks use PCI */ + break; + + case VIR_DOMAIN_DEVICE_HOSTDEV: + break; + + case VIR_DOMAIN_DEVICE_MEMBALLOON: + if (dev->data.memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_RNG: + if (dev->data.rng->model != VIR_DOMAIN_RNG_MODEL_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_WATCHDOG: + /* only one model connects using PCI */ + if (dev->data.watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_VIDEO: + break; + + case VIR_DOMAIN_DEVICE_SHMEM: + break; + + case VIR_DOMAIN_DEVICE_INPUT: + if (dev->data.input->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO) + flags = 0; + break; + + case VIR_DOMAIN_DEVICE_CHR: + if (dev->data.chr->targetType != VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) + flags = 0; + break; + + /* These devices don't ever connect with PCI */ + case VIR_DOMAIN_DEVICE_NVRAM: + case VIR_DOMAIN_DEVICE_TPM: + case VIR_DOMAIN_DEVICE_PANIC: + case VIR_DOMAIN_DEVICE_MEMORY: + case VIR_DOMAIN_DEVICE_HUB: + case VIR_DOMAIN_DEVICE_REDIRDEV: + case VIR_DOMAIN_DEVICE_SMARTCARD: + /* These devices don't even have a DeviceInfo */ + case VIR_DOMAIN_DEVICE_LEASE: + case VIR_DOMAIN_DEVICE_GRAPHICS: + case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_LAST: + case VIR_DOMAIN_DEVICE_NONE: + flags = 0; + break; + } + + if (flags) + flags |= VIR_PCI_CONNECT_HOTPLUGGABLE; + + return flags; +} + + +/** + * qemuDomainDeviceConnectFlags: + * + * The version of the function to call if it will be called just + * once. + * + * @def: the entire DomainDef + * + * @dev: The device to be checked + * + * @qemuCaps: as you'd expect + * + * sets device's info->pciConnectFlags when appropriate. + * There is no failure, so there is no return value. + * + */ +static void ATTRIBUTE_UNUSED +qemuDomainDeviceConnectFlags(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virQEMUCapsPtr qemuCaps) +{ + virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev); + + if (info) { + /* These flags are passed to qemuDomainDeviceConnectFlagsInternal + * after setting according to the machinetype and qemu + * capabilities. That may seem like pointless posturing, but + * it's done this way to eliminate duplicated code while + * allowing more efficient operation when it's being done + * repeatedly with the device iterator. + */ + virDomainPCIConnectFlags virtioFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + virDomainPCIConnectFlags pcieFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE; + + if (qemuDomainMachineHasPCIeRoot(def)) + pcieFlags = VIR_PCI_CONNECT_TYPE_PCIE_DEVICE; + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) + virtioFlags = pcieFlags; + + info->pciConnectFlags + = qemuDomainDeviceConnectFlagsInternal(dev, pcieFlags, virtioFlags); + } +} + + +typedef struct { + virDomainPCIConnectFlags virtioFlags; + virDomainPCIConnectFlags pcieFlags; +} qemuDomainDeviceConnectFlagsIteratorData; + +/** + * qemuDomainDeviceConnectFlagsIterator: + * + * The version of the function to call with + * virDomainDeviceInfoIterate() + * + * @def: the entire DomainDef + * + * @dev: The device to be checked + * + * @info: virDomainDeviceInfo within the device + * + * @opaque: points to iterator data setup beforehand. + * + * Sets @info->pciConnectFlags. Always returns 0 - there + * is no failure. + * + */ +static int +qemuDomainDeviceConnectFlagsIterator(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque) +{ + qemuDomainDeviceConnectFlagsIteratorData *data = opaque; + + info->pciConnectFlags + = qemuDomainDeviceConnectFlagsInternal(dev, data->pcieFlags, + data->virtioFlags); + return 0; +} + + +/** + * qemuDomainDeviceSetAllConnectFlags: + * + * Set the info->pciConnectFlags for all devices in the domain. + * + * @def: the entire DomainDef + * + * @qemuCaps: as you'd expect + * + * sets info->pciConnectFlags for all devices as appropriate. returns + * 0 on success or -1 on failure (the only possibility of failure would + * be some internal problem with virDomainDeviceInfoIterate()) + */ +static int ATTRIBUTE_UNUSED +qemuDomainDeviceSetAllConnectFlags(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps) +{ + qemuDomainDeviceConnectFlagsIteratorData data + = { .virtioFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE, + .pcieFlags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE }; + + if (qemuDomainMachineHasPCIeRoot(def)) + data.pcieFlags = VIR_PCI_CONNECT_TYPE_PCIE_DEVICE; + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) + data.virtioFlags = data.pcieFlags; + + return virDomainDeviceInfoIterate(def, qemuDomainDeviceConnectFlagsIterator, + &data); +} + + static int qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, virDomainDeviceDefPtr device, -- 2.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list