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@xxxxxxxxx> --- 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