This patch introduces two helpers that will be used in the next
patch. One is virpci.c:virPCIDeviceIsMultifunction(), and
the other is virhostdev.c:virHostdevIsPCIMultifunctionDevice().
Signed-off-by: Daniel Henrique Barboza <danielhb413(a)gmail.com>
---
src/libvirt_private.syms | 2 ++
src/util/virhostdev.c | 24 ++++++++++++++++++++++++
src/util/virhostdev.h | 3 +++
src/util/virpci.c | 17 +++++++++++++++++
src/util/virpci.h | 2 ++
5 files changed, 48 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 8fe0bf9365..345c9747e8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2137,6 +2137,7 @@ virHostCPUStatsAssign;
# util/virhostdev.h
virHostdevFindUSBDevice;
virHostdevIsMdevDevice;
+virHostdevIsPCIMultifunctionDevice;
virHostdevIsSCSIDevice;
virHostdevIsVFIODevice;
virHostdevManagerGetDefault;
@@ -2717,6 +2718,7 @@ virPCIDeviceGetUnbindFromStub;
virPCIDeviceGetUsedBy;
virPCIDeviceHasPCIExpressLink;
virPCIDeviceIsAssignable;
+virPCIDeviceIsMultifunction;
virPCIDeviceIsPCIExpress;
virPCIDeviceListAdd;
virPCIDeviceListAddCopy;
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 2e7885112f..803daaa995 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -2251,3 +2251,27 @@ virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
return 0;
}
+
+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/util/virhostdev.h b/src/util/virhostdev.h
index 2d61c21e9d..c5a1fdcf5e 100644
--- a/src/util/virhostdev.h
+++ b/src/util/virhostdev.h
@@ -194,6 +194,9 @@ bool
virHostdevIsMdevDevice(const virDomainHostdevDef *hostdev)
ATTRIBUTE_NONNULL(1);
bool
+virHostdevIsPCIMultifunctionDevice(virDomainHostdevDefPtr hostdev)
+ ATTRIBUTE_NONNULL(1);
+bool
virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev)
ATTRIBUTE_NONNULL(1);
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 9bea5a20d0..840cca77fc 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2818,6 +2818,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 cfb4581edf..8f37636809 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -266,6 +266,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.23.0