[libvirt] [PATCH 1/4] utils: introducing PCI multifunction detection helpers

Daniel Henrique Barboza posted 4 patches 5 years, 1 month ago
[libvirt] [PATCH 1/4] utils: introducing PCI multifunction detection helpers
Posted by Daniel Henrique Barboza 5 years, 1 month ago
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@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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list