Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.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, 98 insertions(+)
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index cdb2040fb8..ae7a651ee0 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -177,6 +177,12 @@ struct _virDomainDeviceInfo {
bool isolationGroupLocked;
};
+typedef struct _virDomainPCIMultifunctionAddressInfo
virDomainPCIMultifunctionAddressInfo;
+typedef virDomainPCIMultifunctionAddressInfo *virDomainPCIMultifunctionAddressInfoPtr;
+struct _virDomainPCIMultifunctionAddressInfo {
+ virDomainDeviceInfoPtr infos[VIR_PCI_MAX_FUNCTIONS];
+};
+
int virDomainDeviceInfoCopy(virDomainDeviceInfoPtr dst,
virDomainDeviceInfoPtr src);
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index c4a0b99628..43227a4b25 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -27,6 +27,7 @@
#include "virlog.h"
#include "virstring.h"
#include "domain_addr.h"
+#include "device_conf.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -697,6 +698,89 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
}
+/*
+ *virDomainPCIAddressEnsureMultifunctionAddress:
+ *
+ *
+ *
+ */
+
+int
+virDomainPCIAddressEnsureMultifunctionAddress(virDomainPCIAddressSetPtr addrs,
+ virDomainPCIMultifunctionAddressInfoPtr
pcicard)
+{
+ size_t i;
+ int ret = 0;
+ virPCIDeviceAddressPtr addr1 = NULL, addr2 = NULL;
+ virDomainDeviceInfoPtr dev = NULL;
+ char *addrStr = 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++) {
+ dev = pcicard->infos[i];
+ if (dev && !dev->pciConnectFlags) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Not a PCI Multifunction device."));
+ goto cleanup;
+ }
+ if (dev && virDeviceInfoPCIAddressPresent(dev)) {
+ /* Pick one and compare against rest of the user given */
+ addr1 = addr1 ? addr1 : &dev->addr.pci;
+ addr2 = &dev->addr.pci;
+ if (!(addrStr = virDomainPCIAddressAsString(addr2)))
+ goto cleanup;
+ if (!virDomainPCIAddressValidate(addrs, addr2,
+ addrStr, dev->pciConnectFlags, true))
+ goto cleanup;
+ 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"));
+ goto cleanup;
+ }
+ VIR_FREE(addrStr);
+ }
+ }
+
+ /* Reserve all the user given addresses. */
+ for (i = 0; i < VIR_PCI_MAX_FUNCTIONS; i++) {
+ dev = pcicard->infos[i];
+ if (dev && virDeviceInfoPCIAddressPresent(dev)) {
+ ret = virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci,
+ dev->pciConnectFlags,
dev->isolationGroup,
+ dev->aggregateSlotIdx,
+ true);
+ if (ret < 0)
+ goto cleanup;
+ }
+ }
+
+ /* 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 && !virDeviceInfoPCIAddressPresent(dev)) {
+ ret = virDomainPCIAddressReserveNextAddr(addrs, dev, dev->pciConnectFlags,
i);
+ if (ret < 0)
+ goto cleanup;
+ }
+ }
+
+ /* Set multi on overriding what user has set. */
+ pcicard->infos[0]->addr.pci.multi = VIR_TRISTATE_SWITCH_ON;
+
+ cleanup:
+ VIR_FREE(addrStr);
+ return ret;
+}
+
+
void
virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr)
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index fa98b67e5c..e80e1e9089 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -162,6 +162,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 d1ff2f5f99..3e4d627004 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -114,6 +114,7 @@ virDomainPCIAddressAsString;
virDomainPCIAddressBusIsFullyReserved;
virDomainPCIAddressBusSetModel;
virDomainPCIAddressEnsureAddr;
+virDomainPCIAddressEnsureMultifunctionAddress;
virDomainPCIAddressReleaseAddr;
virDomainPCIAddressReserveAddr;
virDomainPCIAddressReserveNextAddr;
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 5830fb4c12..65e586ed15 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -29,6 +29,8 @@
# include "virobject.h"
# include "virutil.h"
+# define VIR_PCI_MAX_FUNCTIONS 8
+
typedef struct _virPCIDevice virPCIDevice;
typedef virPCIDevice *virPCIDevicePtr;
typedef struct _virPCIDeviceAddress virPCIDeviceAddress;