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