[libvirt] [PATCH v3 04/18] qemu: new functions qemuDomainDeviceConnectFlags*()

Laine Stump laine at laine.org
Tue Sep 20 19:14:10 UTC 2016


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




More information about the libvir-list mailing list