This patch introduces two helpers that will be used in the
next patches, virPCIDeviceIsMultifunction() and
virHostdevIsPCIMultifunctionDevice().
Signed-off-by: Daniel Henrique Barboza <danielhb413(a)gmail.com>
---
src/conf/domain_conf.c | 31 +++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 3 +++
src/libvirt_private.syms | 2 ++
src/util/virpci.c | 17 +++++++++++++++++
src/util/virpci.h | 2 ++
5 files changed, 55 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index c201fc901d..0d289fbab5 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -32659,3 +32659,34 @@ virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev)
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
}
+
+
+/**
+ * virHostdevIsPCIMultifunctionDevice
+ * @hostdev: host device to check
+ *
+ * Returns true if @hostdev is a PCI Multifunction device, false otherwise.
+ */
+bool
+virHostdevIsPCIMultifunctionDevice(virDomainHostdevDefPtr hostdev)
+{
+ g_autoptr(virPCIDevice) pciDev = NULL;
+ virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
+
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+ hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ return false;
+
+ /* Libvirt should be able to perform all the operations in
+ * virPCIDeviceNew() even if it's running unprivileged, so if this
+ * fails, the device apparently doesn't currently exist on the host.
+ * Since we can't speculate, assume this device is not multifunction.
+ */
+ pciDev = virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
+ pcisrc->addr.slot, pcisrc->addr.function);
+
+ if (!pciDev)
+ return false;
+
+ return virPCIDeviceIsMultifunction(pciDev);
+}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ddc75d8de2..e6d3e04109 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3840,3 +3840,6 @@ virHostdevIsMdevDevice(const virDomainHostdevDef *hostdev)
bool
virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev)
ATTRIBUTE_NONNULL(1);
+bool
+virHostdevIsPCIMultifunctionDevice(virDomainHostdevDefPtr hostdev)
+ ATTRIBUTE_NONNULL(1);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fd04fcece3..c143264382 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -723,6 +723,7 @@ virDomainEventWatchdogNewFromObj;
virDomainQemuMonitorEventNew;
virDomainQemuMonitorEventStateRegisterID;
virHostdevIsMdevDevice;
+virHostdevIsPCIMultifunctionDevice;
virHostdevIsSCSIDevice;
virHostdevIsVFIODevice;
@@ -2794,6 +2795,7 @@ virPCIDeviceGetUnbindFromStub;
virPCIDeviceGetUsedBy;
virPCIDeviceHasPCIExpressLink;
virPCIDeviceIsAssignable;
+virPCIDeviceIsMultifunction;
virPCIDeviceIsPCIExpress;
virPCIDeviceListAdd;
virPCIDeviceListAddCopy;
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 6c7e6bbcab..82e86456c4 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2837,6 +2837,23 @@ int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType)
}
+bool
+virPCIDeviceIsMultifunction(virPCIDevicePtr dev)
+{
+ int fd;
+ uint8_t type;
+
+ if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
+ return -1;
+
+ type = virPCIDeviceRead8(dev, fd, PCI_HEADER_TYPE);
+
+ virPCIDeviceConfigClose(dev, fd);
+
+ return type & PCI_HEADER_TYPE_MULTI;
+}
+
+
void
virPCIEDeviceInfoFree(virPCIEDeviceInfoPtr dev)
{
diff --git a/src/util/virpci.h b/src/util/virpci.h
index f16d23614a..64a9109d9b 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -270,6 +270,8 @@ int virPCIDeviceGetLinkCapSta(virPCIDevicePtr dev,
int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType);
+bool virPCIDeviceIsMultifunction(virPCIDevicePtr dev);
+
void virPCIEDeviceInfoFree(virPCIEDeviceInfoPtr dev);
ssize_t virPCIGetMdevTypes(const char *sysfspath,
--
2.26.2