This patch introduces two helpers that will be used in the next patches, virPCIDeviceIsMultifunction() and virHostdevIsPCIMultifunctionDevice(). Signed-off-by: Daniel Henrique Barboza <danielhb413@xxxxxxxxx> --- src/conf/domain_conf.c | 31 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 3 +++ src/libvirt_private.syms | 2 ++ src/util/virpci.c | 17 +++++++++++++++++ src/util/virpci.h | 2 ++ 5 files changed, 55 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c201fc901d..0d289fbab5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -32659,3 +32659,34 @@ virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev) hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO; } + + +/** + * virHostdevIsPCIMultifunctionDevice + * @hostdev: host device to check + * + * Returns true if @hostdev is a PCI Multifunction device, false otherwise. + */ +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/conf/domain_conf.h b/src/conf/domain_conf.h index ddc75d8de2..e6d3e04109 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3840,3 +3840,6 @@ virHostdevIsMdevDevice(const virDomainHostdevDef *hostdev) bool virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev) ATTRIBUTE_NONNULL(1); +bool +virHostdevIsPCIMultifunctionDevice(virDomainHostdevDefPtr hostdev) + ATTRIBUTE_NONNULL(1); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index fd04fcece3..c143264382 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -723,6 +723,7 @@ virDomainEventWatchdogNewFromObj; virDomainQemuMonitorEventNew; virDomainQemuMonitorEventStateRegisterID; virHostdevIsMdevDevice; +virHostdevIsPCIMultifunctionDevice; virHostdevIsSCSIDevice; virHostdevIsVFIODevice; @@ -2794,6 +2795,7 @@ virPCIDeviceGetUnbindFromStub; virPCIDeviceGetUsedBy; virPCIDeviceHasPCIExpressLink; virPCIDeviceIsAssignable; +virPCIDeviceIsMultifunction; virPCIDeviceIsPCIExpress; virPCIDeviceListAdd; virPCIDeviceListAddCopy; diff --git a/src/util/virpci.c b/src/util/virpci.c index 6c7e6bbcab..82e86456c4 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -2837,6 +2837,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 f16d23614a..64a9109d9b 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -270,6 +270,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.26.2