This patch introduces two helpers that will be used in the next
patches. 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 | 25 +++++++++++++++++++++++++
src/util/virhostdev.h | 3 +++
src/util/virpci.c | 17 +++++++++++++++++
src/util/virpci.h | 2 ++
5 files changed, 49 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ebf830791e..962963a3ff 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2162,6 +2162,7 @@ virHostCPUStatsAssign;
# util/virhostdev.h
virHostdevFindUSBDevice;
virHostdevIsMdevDevice;
+virHostdevIsPCIMultifunctionDevice;
virHostdevIsSCSIDevice;
virHostdevIsVFIODevice;
virHostdevManagerGetDefault;
@@ -2768,6 +2769,7 @@ virPCIDeviceGetUnbindFromStub;
virPCIDeviceGetUsedBy;
virPCIDeviceHasPCIExpressLink;
virPCIDeviceIsAssignable;
+virPCIDeviceIsMultifunction;
virPCIDeviceIsPCIExpress;
virPCIDeviceListAdd;
virPCIDeviceListAddCopy;
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index f8f7989206..f0526d97d0 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -2564,3 +2564,28 @@ virHostdevUpdateActiveNVMeDevices(virHostdevManagerPtr
hostdev_mgr,
}
goto cleanup;
}
+
+
+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 ae84ed3d20..80aea577ed 100644
--- a/src/util/virhostdev.h
+++ b/src/util/virhostdev.h
@@ -198,6 +198,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 0b1222373e..f564d7b9fd 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2842,6 +2842,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 f6796fc422..9d8dcfec05 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -271,6 +271,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.24.1