This utility function looks through a virPCIAddressSet for any slot of
any bus that has multiple functions in use, and sets the "multi" flag
in the virDomainDeviceInfo for the device that is assigned to function
0 of that slot (as long as it hasn't already been set explicitly by
someone who presumably has better information than we do).
It isn't yet called from anywhere, so will have no functional effect.
---
src/conf/domain_addr.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_addr.h | 4 +++
src/libvirt_private.syms | 1 +
3 files changed, 80 insertions(+)
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 4d14ac4..0364e95 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -867,6 +867,81 @@ virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
}
+static int
+virDomainPCIAddressSetMultiIter(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
+ virDomainDeviceInfoPtr info,
+ void *data)
+{
+ virPCIDeviceAddressPtr testAddr = data;
+ virPCIDeviceAddressPtr thisAddr;
+
+ if (!info || info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
+ return 0;
+
+ thisAddr = &info->addr.pci;
+
+ if (thisAddr->domain == testAddr->domain &&
+ thisAddr->bus == testAddr->bus &&
+ thisAddr->slot == testAddr->slot &&
+ thisAddr->function == 0) {
+
+ /* only set to ON if it wasn't previously set
+ * (assuming that the user must have better information
+ * than us if they explicitly set it OFF)
+ */
+ if (thisAddr->multi == VIR_TRISTATE_SWITCH_ABSENT)
+ thisAddr->multi = VIR_TRISTATE_SWITCH_ON;
+
+ return -1; /* finish early, *NOT* an error */
+ }
+
+ return 0;
+}
+
+
+/**
+ * virDomainPCIAddressSetAllMulti():
+ *
+ * @def: the domain definition whose devices may need adjusting
+ * @addrs: address set keeping track of all addresses in use.
+ *
+ * Look for any PCI slots that have multiple functions assigned, and
+ * set multi to YES in the address for the device at function 0
+ * (unless it has been explicitly set to NO).
+ *
+ * No return code, since there is no possibility of failure.
+ */
+void
+virDomainPCIAddressSetAllMulti(virDomainDefPtr def,
+ virDomainPCIAddressSetPtr addrs)
+{
+ /* Scan through all the slots in @addrs looking for any that have
+ * more than just function 0 marked as in use, then use an
+ * iterator to find the DeviceInfo that uses function 0 on that
+ * slot and mark it as multi = YES
+ */
+ size_t busIdx, slotIdx;
+
+ for (busIdx = 0; busIdx < addrs->nbuses; busIdx++) {
+ virDomainPCIAddressBusPtr bus = &addrs->buses[busIdx];
+
+ for (slotIdx = bus->minSlot; slotIdx <= bus->maxSlot; slotIdx++) {
+ if (bus->slot[slotIdx].functions > 1) {
+ virPCIDeviceAddress addr = { .domain = 0,
+ .bus = busIdx,
+ .slot = slotIdx,
+ .function = 0 };
+
+ ignore_value(virDomainDeviceInfoIterate(def,
+ virDomainPCIAddressSetMultiIter,
+ &addr));
+ }
+ }
+ }
+}
+
+
static char*
virDomainCCWAddressAsString(virDomainDeviceCCWAddressPtr addr)
{
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 5f0924e..2263114 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -173,6 +173,10 @@ int virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr
addrs,
virDomainPCIConnectFlags flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+void virDomainPCIAddressSetAllMulti(virDomainDefPtr def,
+ virDomainPCIAddressSetPtr addrs)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
struct _virDomainCCWAddressSet {
virHashTablePtr defined;
virDomainDeviceCCWAddress next;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a928e90..a0db583 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -104,6 +104,7 @@ virDomainPCIAddressReserveAddr;
virDomainPCIAddressReserveNextAddr;
virDomainPCIAddressReserveNextSlot;
virDomainPCIAddressReserveSlot;
+virDomainPCIAddressSetAllMulti;
virDomainPCIAddressSetAlloc;
virDomainPCIAddressSetFree;
virDomainPCIAddressSetGrow;
--
2.7.4