Some buggy PCI devices actually support FLR, but forget to advertise that fact in their PCI config space. However, Virtual Functions on SR-IOV devices are *required* to support FLR by the spec, so force has_flr on if this is a virtual function. Signed-off-by: Chris Lalancette <clalance@xxxxxxxxxx> --- src/util/pci.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/util/pci.c b/src/util/pci.c index c45b179..41e91af 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -183,6 +183,16 @@ pciOpenConfig(pciDevice *dev) return 0; } +static void +pciCloseConfig(pciDevice *dev) +{ + if (!dev) + return; + + if (dev->fd >= 0) + close(dev->fd); +} + static int pciRead(pciDevice *dev, unsigned pos, uint8_t *buf, unsigned buflen) { @@ -380,11 +390,16 @@ pciFindExtendedCapabilityOffset(pciDevice *dev, unsigned capability) return 0; } -static unsigned +/* detects whether this device has FLR. Returns 0 if the device does + * not have FLR, 1 if it does, and -1 on error + */ +static int pciDetectFunctionLevelReset(pciDevice *dev) { uint32_t caps; uint8_t pos; + char *path; + int found; /* The PCIe Function Level Reset capability allows * individual device functions to be reset without @@ -413,6 +428,25 @@ pciDetectFunctionLevelReset(pciDevice *dev) } } + /* there are some buggy devices that do support FLR, but forget to + * advertise that fact in their capabilities. However, FLR is *required* + * to be present for virtual functions (VFs), so if we see that this + * device is a VF, we just assume FLR works + */ + + if (virAsprintf(&path, PCI_SYSFS "devices/%s/physfn", dev->name) < 0) { + virReportOOMError(); + return -1; + } + + found = virFileExists(path); + VIR_FREE(path); + if (found) { + VIR_DEBUG("%s %s: buggy device didn't advertise FLR, but is a VF; forcing flr on", + dev->id, dev->name); + return 1; + } + VIR_DEBUG("%s %s: no FLR capability found", dev->id, dev->name); return 0; @@ -626,6 +660,8 @@ pciTryPowerManagementReset(pciDevice *dev) static int pciInitDevice(pciDevice *dev) { + int flr; + if (pciOpenConfig(dev) < 0) { virReportSystemError(errno, _("Failed to open config space file '%s'"), @@ -635,7 +671,12 @@ pciInitDevice(pciDevice *dev) dev->pcie_cap_pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_EXP); dev->pci_pm_cap_pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_PM); - dev->has_flr = pciDetectFunctionLevelReset(dev); + flr = pciDetectFunctionLevelReset(dev); + if (flr < 0) { + pciCloseConfig(dev); + return flr; + } + dev->has_flr = flr; dev->has_pm_reset = pciDetectPowerManagementReset(dev); dev->initted = 1; return 0; @@ -1098,8 +1139,7 @@ pciFreeDevice(pciDevice *dev) if (!dev) return; VIR_DEBUG("%s %s: freeing", dev->id, dev->name); - if (dev->fd >= 0) - close(dev->fd); + pciCloseConfig(dev); VIR_FREE(dev); } -- 1.7.1.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list