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