If a PCI device has VIR_PCI_CONNECT_AGGREGATE_SLOT set in its
pciConnectFlags, then during address assignment we allow multiple
instances of this type of device to be auto-assigned to multiple
functions on the same device. A slot is used for aggregating multiple
devices only if the first device assigned to that slot had
VIR_PCI_CONNECT_AGGREGATE_SLOT set. but any device types that have
AGGREGATE_SLOT set might be mix/matched on the same slot.

(NB: libvirt should never set the AGGREGATE_SLOT flag for a device
type that might need to be hotplugged. Currently it is only planned
for pcie-root-port and possibly other PCI controller types, and none
of those are hotpluggable anyway)

There aren't yet any devices that use this flag. That will be in a
later patch.
---
 src/conf/domain_addr.c         | 45 +++++++++++++++++++++++++++++++++++++++---
 src/conf/domain_addr.h         | 30 +++++++++++++++++++---------
 src/qemu/qemu_domain_address.c |  2 +-
 3 files changed, 64 insertions(+), 13 deletions(-)

diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 986d90e..1ab9a6d 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -506,8 +506,20 @@ virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr 
addrs,
                        addrStr);
         goto cleanup;
     }
+
+    /* if this is the first function to be reserved on this slot, and
+     * the device it's being reserved for can aggregate multiples on a
+     * slot, set the slot's aggregate flag.
+    */
+    if (!bus->slot[addr->slot].functions &&
+        flags & VIR_PCI_CONNECT_AGGREGATE_SLOT) {
+        bus->slot[addr->slot].aggregate = true;
+    }
+
+    /* mark the requested function as reserved */
     bus->slot[addr->slot].functions |= (1 << addr->function);
-    VIR_DEBUG("Reserving PCI address %s", addrStr);
+    VIR_DEBUG("Reserving PCI address %s (aggregate='%s')", addrStr,
+              bus->slot[addr->slot].aggregate ? "true" : "false");
 
     ret = 0;
  cleanup:
@@ -636,7 +648,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs)
 static int
 virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus,
                                            virPCIDeviceAddressPtr searchAddr,
-                                           int function ATTRIBUTE_UNUSED,
+                                           int function,
                                            virDomainPCIConnectFlags flags,
                                            bool *found)
 {
@@ -659,6 +671,33 @@ 
virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus,
                 break;
             }
 
+            if (flags & VIR_PCI_CONNECT_AGGREGATE_SLOT &&
+                bus->slot[searchAddr->slot].aggregate) {
+                /* slot and device are okay with aggregating devices */
+                if ((bus->slot[searchAddr->slot].functions &
+                     (1 << searchAddr->function)) == 0) {
+                    *found = true;
+                    break;
+                }
+
+                /* also check for *any* unused function if caller
+                 * sent function = -1
+                 */
+                if (function == -1) {
+                    while (searchAddr->function < 8) {
+                        if ((bus->slot[searchAddr->slot].functions &
+                             (1 << searchAddr->function)) == 0) {
+                            *found = true;
+                            break; /* out of inner while */
+                        }
+                        searchAddr->function++;
+                    }
+                    if (*found)
+                       break; /* out of outer while */
+                    searchAddr->function = 0; /* reset for next try */
+                }
+            }
+
             VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
                       searchAddr->domain, searchAddr->bus, searchAddr->slot);
             searchAddr->slot++;
@@ -805,7 +844,7 @@ 
virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
                                    virDomainDeviceInfoPtr dev,
                                    virDomainPCIConnectFlags flags)
 {
-    return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, 0);
+    return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
 }
 
 
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 50c4675..dd4cd5b 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -32,18 +32,23 @@
 typedef enum {
    VIR_PCI_CONNECT_HOTPLUGGABLE = 1 << 0, /* is hotplug needed/supported */
 
+   /* set for devices that can share a single slot in auto-assignment
+    * (by assigning one device to each of the 8 functions on the slot)
+    */
+   VIR_PCI_CONNECT_AGGREGATE_SLOT = 1 << 1,
+
    /* kinds of devices as a bitmap so they can be combined (some PCI
     * controllers permit connecting multiple types of devices)
     */
-   VIR_PCI_CONNECT_TYPE_PCI_DEVICE = 1 << 1,
-   VIR_PCI_CONNECT_TYPE_PCIE_DEVICE = 1 << 2,
-   VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT = 1 << 3,
-   VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT = 1 << 4,
-   VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT = 1 << 5,
-   VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE = 1 << 6,
-   VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS = 1 << 7,
-   VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS = 1 << 8,
-   VIR_PCI_CONNECT_TYPE_PCI_BRIDGE = 1 << 9,
+   VIR_PCI_CONNECT_TYPE_PCI_DEVICE = 1 << 2,
+   VIR_PCI_CONNECT_TYPE_PCIE_DEVICE = 1 << 3,
+   VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT = 1 << 4,
+   VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT = 1 << 5,
+   VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT = 1 << 6,
+   VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE = 1 << 7,
+   VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS = 1 << 8,
+   VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS = 1 << 9,
+   VIR_PCI_CONNECT_TYPE_PCI_BRIDGE = 1 << 10,
 } virDomainPCIConnectFlags;
 
 /* a combination of all bits that describe the type of connections
@@ -75,6 +80,13 @@ typedef struct {
      * in use by a device, or clear if it isn't.
      */
     uint8_t functions;
+
+    /* aggregate is true if this slot has only devices with
+     * VIR_PCI_CONNECT_AGGREGATE assigned to its functions (meaning
+     * that other devices with the same flags could also be
+     * auto-assigned to the other functions)
+     */
+    bool aggregate;
     } virDomainPCIAddressSlot;
 
 typedef struct {
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 37ce675..5b3765f 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -875,7 +875,7 @@ static int
 qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
                                     virDomainDeviceInfoPtr dev)
 {
-    return qemuDomainPCIAddressReserveNextAddr(addrs, dev, 0);
+    return qemuDomainPCIAddressReserveNextAddr(addrs, dev, -1);
 }
 
 
-- 
2.7.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to