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().
As the name suggests, the idea is to detect if a given dev/hostdev
is a PCI multifunction device.
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 | 15 +++++++++++++++
src/util/virpci.h | 2 ++
5 files changed, 46 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index eeab820eca..1c611ea8f4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2106,6 +2106,7 @@ virHostCPUStatsAssign;
# util/virhostdev.h
virHostdevFindUSBDevice;
virHostdevIsMdevDevice;
+virHostdevIsPCIMultifunctionDevice;
virHostdevIsSCSIDevice;
virHostdevManagerGetDefault;
virHostdevPCINodeDeviceDetach;
@@ -2684,6 +2685,7 @@ virPCIDeviceGetUnbindFromStub;
virPCIDeviceGetUsedBy;
virPCIDeviceHasPCIExpressLink;
virPCIDeviceIsAssignable;
+virPCIDeviceIsMultifunction;
virPCIDeviceIsPCIExpress;
virPCIDeviceListAdd;
virPCIDeviceListAddCopy;
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 41fcab7222..1aa8e9729d 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -2191,3 +2191,27 @@ virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
return 0;
}
+
+bool
+virHostdevIsPCIMultifunctionDevice(virDomainHostdevDefPtr hostdev)
+{
+ VIR_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 88501e2743..63a1d7367b 100644
--- a/src/util/virhostdev.h
+++ b/src/util/virhostdev.h
@@ -190,6 +190,9 @@ virHostdevIsSCSIDevice(virDomainHostdevDefPtr hostdev)
bool
virHostdevIsMdevDevice(virDomainHostdevDefPtr hostdev)
ATTRIBUTE_NONNULL(1);
+bool
+virHostdevIsPCIMultifunctionDevice(virDomainHostdevDefPtr hostdev)
+ ATTRIBUTE_NONNULL(1);
/* functions used by NodeDevDetach/Reattach/Reset */
int virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
diff --git a/src/util/virpci.c b/src/util/virpci.c
index ee78151e74..778e47ea08 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2863,6 +2863,21 @@ int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType)
return 0;
}
+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 dc20f91710..7199882d6b 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -264,6 +264,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.21.0