From: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413(a)gmail.com>
---
src/conf/device_conf.h | 6 +++
src/conf/domain_addr.c | 84 +++++++++++++++++++++++++++++++++++++++-
src/conf/domain_addr.h | 5 +++
src/libvirt_private.syms | 1 +
src/util/virpci.h | 2 +
5 files changed, 96 insertions(+), 2 deletions(-)
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index cc1707c1d1..e7d8e2539f 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -182,6 +182,12 @@ struct _virDomainDeviceInfo {
bool isolationGroupLocked;
};
+typedef struct _virDomainPCIMultifunctionAddressInfo
virDomainPCIMultifunctionAddressInfo;
+typedef virDomainPCIMultifunctionAddressInfo *virDomainPCIMultifunctionAddressInfoPtr;
+struct _virDomainPCIMultifunctionAddressInfo {
+ virDomainDeviceInfoPtr infos[VIR_PCI_MAX_FUNCTIONS];
+};
+
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
void virDomainDeviceInfoFree(virDomainDeviceInfoPtr info);
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 5c8fc62725..0a1c9ce142 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -21,11 +21,12 @@
#include <config.h>
+#include "device_conf.h"
+#include "domain_addr.h"
#include "viralloc.h"
+#include "virhashcode.h"
#include "virlog.h"
#include "virstring.h"
-#include "domain_addr.h"
-#include "virhashcode.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -990,6 +991,85 @@ virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr
addrs,
}
+int
+virDomainPCIAddressEnsureMultifunctionAddress(virDomainPCIAddressSetPtr addrs,
+ virDomainPCIMultifunctionAddressInfoPtr
pcicard)
+{
+ size_t i;
+ int ret = 0;
+ virPCIDeviceAddressPtr addr1 = NULL, addr2 = NULL;
+ virDomainDeviceInfoPtr dev = NULL;
+
+ if (!pcicard->infos[0]) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Function-Zero missing on the slot"));
+ return -1;
+ }
+
+ /* If the address is given by the user, make sure they belong
+ * to same slot */
+ for (i = 0; i < VIR_PCI_MAX_FUNCTIONS; i++) {
+ g_autofree char *addrStr = NULL;
+ dev = pcicard->infos[i];
+
+ if (dev && !dev->pciConnectFlags) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Not a PCI Multifunction device."));
+ return -1;
+ }
+ if (dev && virDeviceInfoPCIAddressIsPresent(dev)) {
+ /* Pick one and compare against rest of the user given */
+ addr1 = addr1 ? addr1 : &dev->addr.pci;
+ addr2 = &dev->addr.pci;
+
+ if (!(addrStr = virPCIDeviceAddressAsString(addr2)))
+ return -1;
+
+ if (!virDomainPCIAddressValidate(addrs, addr2, addrStr,
+ dev->pciConnectFlags, true))
+ return -1;
+
+ if (!(addr1->domain == addr2->domain && addr1->bus ==
addr2->bus &&
+ addr1->slot == addr2->slot)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Addresses belong to different PCI slots"));
+ return -1;
+ }
+ }
+ }
+
+ /* Reserve all the user given addresses. */
+ for (i = 0; i < VIR_PCI_MAX_FUNCTIONS; i++) {
+ dev = pcicard->infos[i];
+ if (dev && virDeviceInfoPCIAddressIsPresent(dev)) {
+ ret = virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci,
+ dev->pciConnectFlags,
+ dev->isolationGroup,
+ dev->aggregateSlotIdx,
+ true);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ /* If the user has not given addresses, start with function zero */
+ for (i = 0; i < VIR_PCI_MAX_FUNCTIONS; i++) {
+ dev = pcicard->infos[i];
+ if (dev && !virDeviceInfoPCIAddressIsPresent(dev)) {
+ ret = virDomainPCIAddressReserveNextAddr(addrs, dev,
+ dev->pciConnectFlags, i);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ /* Set multi on overriding what user has set. */
+ pcicard->infos[0]->addr.pci.multi = VIR_TRISTATE_SWITCH_ON;
+
+ return 0;
+}
+
+
void
virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr)
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index ddcff36e51..e3c1293e1d 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -180,6 +180,11 @@ int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
virDomainPCIConnectFlags flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int
+virDomainPCIAddressEnsureMultifunctionAddress(virDomainPCIAddressSetPtr addrs,
+ virDomainPCIMultifunctionAddressInfoPtr
pcicard)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
void virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 29c6ac8e5e..99afe20294 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -148,6 +148,7 @@ virDomainCCWAddressSetFree;
virDomainPCIAddressBusIsFullyReserved;
virDomainPCIAddressBusSetModel;
virDomainPCIAddressEnsureAddr;
+virDomainPCIAddressEnsureMultifunctionAddress;
virDomainPCIAddressExtensionReleaseAddr;
virDomainPCIAddressExtensionReserveAddr;
virDomainPCIAddressExtensionReserveNextAddr;
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 64a9109d9b..8f20e31b43 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -25,6 +25,8 @@
#include "virobject.h"
#include "virenum.h"
+#define VIR_PCI_MAX_FUNCTIONS 8
+
typedef struct _virPCIDevice virPCIDevice;
typedef virPCIDevice *virPCIDevicePtr;
typedef struct _virPCIDeviceAddress virPCIDeviceAddress;
--
2.26.2