render / rpms / libvirt

Forked from rpms/libvirt 9 months ago
Clone
Mark McLoughlin c034c1
From 5aad00b08cadc4d9da8bffd3d255ffaac98d36dd Mon Sep 17 00:00:00 2001
Mark McLoughlin c034c1
From: Mark McLoughlin <markmc@redhat.com>
Mark McLoughlin c034c1
Date: Fri, 14 Aug 2009 08:31:11 +0100
Mark McLoughlin c034c1
Subject: [PATCH] Allow PM reset on multi-function PCI devices
Mark McLoughlin c034c1
Mark McLoughlin c034c1
https://bugzilla.redhat.com/515689
Mark McLoughlin c034c1
Mark McLoughlin c034c1
It turns out that a PCI Power Management reset only affects individual
Mark McLoughlin c034c1
functions, and not the whole device.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
The PCI Power Management spec talks about resetting the 'device' rather
Mark McLoughlin c034c1
than the 'function', but Intel's Dexuan Cui informs me that it is
Mark McLoughlin c034c1
actually a per-function reset.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Also, Yu Zhao has added pci_pm_reset() to the kernel, and it doesn't
Mark McLoughlin c034c1
reject multi-function devices, so it must be true! :-)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
(A side issue is that we could defer the PM reset to the kernel if we
Mark McLoughlin c034c1
could detect that the kernel has PM reset support, but barring version
Mark McLoughlin c034c1
number checks we don't have a way to detect that support)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
* src/pci.c: remove the pciDeviceContainsOtherFunctions() check from
Mark McLoughlin c034c1
  pciTryPowerManagementReset() and prefer PM reset over bus reset
Mark McLoughlin c034c1
  where both are available
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Cc: Cui, Dexuan <dexuan.cui@intel.com>
Mark McLoughlin c034c1
Cc: Yu Zhao <yu.zhao@intel.com>
Mark McLoughlin c034c1
Mark McLoughlin c034c1
(cherry picked from commit 64a6682b93a2a8aa38067a43979c9eaf993d2b41)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Fedora-patch: libvirt-allow-pm-reset-on-multi-function-pci-devices.patch
Mark McLoughlin c034c1
---
Mark McLoughlin c034c1
 src/pci.c |   48 +++++++++---------------------------------------
Mark McLoughlin c034c1
 1 files changed, 9 insertions(+), 39 deletions(-)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
diff --git a/src/pci.c b/src/pci.c
Mark McLoughlin c034c1
index 2dc2e1c..11b3e8b 100644
Mark McLoughlin c034c1
--- a/src/pci.c
Mark McLoughlin c034c1
+++ b/src/pci.c
Mark McLoughlin c034c1
@@ -402,29 +402,6 @@ pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
     return 1;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-/* Any other functions on this device ? */
Mark McLoughlin c034c1
-static int
Mark McLoughlin c034c1
-pciSharesDevice(pciDevice *a, pciDevice *b)
Mark McLoughlin c034c1
-{
Mark McLoughlin c034c1
-    return
Mark McLoughlin c034c1
-        a->domain == b->domain &&
Mark McLoughlin c034c1
-        a->bus == b->bus &&
Mark McLoughlin c034c1
-        a->slot == b->slot &&
Mark McLoughlin c034c1
-        a->function != b->function;
Mark McLoughlin c034c1
-}
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
-static int
Mark McLoughlin c034c1
-pciDeviceContainsOtherFunctions(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
-{
Mark McLoughlin c034c1
-    pciDevice *matched = NULL;
Mark McLoughlin c034c1
-    if (pciIterDevices(conn, pciSharesDevice, dev, &matched) < 0)
Mark McLoughlin c034c1
-        return 1;
Mark McLoughlin c034c1
-    if (!matched)
Mark McLoughlin c034c1
-        return 0;
Mark McLoughlin c034c1
-    pciFreeDevice(conn, matched);
Mark McLoughlin c034c1
-    return 1;
Mark McLoughlin c034c1
-}
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
 /* Is @a the parent of @b ? */
Mark McLoughlin c034c1
 static int
Mark McLoughlin c034c1
 pciIsParent(pciDevice *a, pciDevice *b)
Mark McLoughlin c034c1
@@ -529,7 +506,7 @@ out:
Mark McLoughlin c034c1
  * above we require the device supports a full internal reset.
Mark McLoughlin c034c1
  */
Mark McLoughlin c034c1
 static int
Mark McLoughlin c034c1
-pciTryPowerManagementReset(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
+pciTryPowerManagementReset(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
     uint8_t config_space[PCI_CONF_LEN];
Mark McLoughlin c034c1
     uint32_t ctl;
Mark McLoughlin c034c1
@@ -537,16 +514,6 @@ pciTryPowerManagementReset(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
     if (!dev->pci_pm_cap_pos)
Mark McLoughlin c034c1
         return -1;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    /* For now, we just refuse to do a power management reset
Mark McLoughlin c034c1
-     * if there are other functions on this device.
Mark McLoughlin c034c1
-     * In future, we could allow it so long as those functions
Mark McLoughlin c034c1
-     * are not in use by the host or other guests.
Mark McLoughlin c034c1
-     */
Mark McLoughlin c034c1
-    if (pciDeviceContainsOtherFunctions(conn, dev)) {
Mark McLoughlin c034c1
-        VIR_WARN("%s contains other functions, not resetting", dev->name);
Mark McLoughlin c034c1
-        return -1;
Mark McLoughlin c034c1
-    }
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
     /* Save and restore the device's config space. */
Mark McLoughlin c034c1
     if (pciRead(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
Mark McLoughlin c034c1
         VIR_WARN("Failed to save PCI config space for %s", dev->name);
Mark McLoughlin c034c1
@@ -604,14 +571,17 @@ pciResetDevice(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
     if (dev->has_flr)
Mark McLoughlin c034c1
         return 0;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+    /* If the device supports PCI power management reset,
Mark McLoughlin c034c1
+     * that's the next best thing because it only resets
Mark McLoughlin c034c1
+     * the function, not the whole device.
Mark McLoughlin c034c1
+     */
Mark McLoughlin c034c1
+    if (dev->has_pm_reset)
Mark McLoughlin c034c1
+        ret = pciTryPowerManagementReset(conn, dev);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
     /* Bus reset is not an option with the root bus */
Mark McLoughlin c034c1
-    if (dev->bus != 0)
Mark McLoughlin c034c1
+    if (ret < 0 && dev->bus != 0)
Mark McLoughlin c034c1
         ret = pciTrySecondaryBusReset(conn, dev);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    /* Next best option is a PCI power management reset */
Mark McLoughlin c034c1
-    if (ret < 0 && dev->has_pm_reset)
Mark McLoughlin c034c1
-        ret = pciTryPowerManagementReset(conn, dev);
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
     if (ret < 0)
Mark McLoughlin c034c1
         pciReportError(conn, VIR_ERR_NO_SUPPORT,
Mark McLoughlin c034c1
                        _("No PCI reset capability available for %s"),
Mark McLoughlin c034c1
-- 
Mark McLoughlin c034c1
1.6.2.5
Mark McLoughlin c034c1