[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] Force FLR on for buggy SR-IOV devices.



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 redhat com>
---
 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]