[PATCH] PCI PM: Fix initialization and kexec breakage for some devices

From: Rafael J. Wysocki
Date: Sun May 17 2009 - 14:17:59 EST


From: Rafael J. Wysocki <rjw@xxxxxxx>

Recent PCI PM changes introduced a bug that causes some devices to be
mishandled after kexec and during early initialization. The failure
scenario in the kexec case is the following:

* Assume a PCI device is not power-manageable by the platform and has
PCI_PM_CTRL_NO_SOFT_RESET set in PMCSR.
* The device is put into D3 before kexec (using the native PCI PM).
* After kexec, pci_setup_device() sets the device's power state to
PCI_UNKNOWN.
* pci_set_power_state(dev, PCI_D0) is called by the device's driver.
* __pci_start_power_transition(dev, PCI_D0) is called and since the
device is not power-manageable by the platform, it causes
pci_update_current_state(dev, PCI_D0) to be called. As a result
the device's current_state field is updated to PCI_D3, in
accordance with the contents of its PCI PM registers.
* pci_raw_set_power_state() is called and it changes the device power
state to D0. *However*, it should also call pci_restore_bars() to
reinitialize the device, but it doesn't, because the device's
current_state field has been modified earlier.

To prevent this from happening, modify
pci_platform_power_transition() so that it doesn't use
pci_update_current_state() to update the current_state field for
devices that aren't power-manageable by the platform. Instead, this
field should be updated directly for devices that don't support the
native PCI PM.

Signed-off-by: Rafael J. Wysocki <rjw@xxxxxxx>
---
drivers/pci/pci.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/pci/pci.c
===================================================================
--- linux-2.6.orig/drivers/pci/pci.c
+++ linux-2.6/drivers/pci/pci.c
@@ -557,7 +557,8 @@ static int pci_platform_power_transition
} else {
error = -ENODEV;
/* Fall back to PCI_D0 if native PM is not supported */
- pci_update_current_state(dev, PCI_D0);
+ if (!dev->pm_cap)
+ dev->current_state = PCI_D0;
}

return error;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/