Skip to content

Commit

Permalink
PCI PM: Fix suspend error paths and testing facility breakage
Browse files Browse the repository at this point in the history
If one of device drivers refuses to suspend by returning error code
from its ->suspend() callback, the devices that have already been
suspended are resumed by executing their drivers' ->resume()
callbacks.  Some of these callbacks expect the device's
configuration space to be restored if the device has been put into
D3 before they are called.  Unfortunately, this mechanism has been
broken by recent changes moving the restoration of config spaces
of some devices (most importantly, USB controllers and HDA Intel)
into the resume callbacks executed with interrupts off.  Obviously,
these callbacks are not invoked in the suspend error path and, as a
result, the system cannot be successfully brought back into the
working state in case of a suspend error.  The same thing happens
in the hibernation error path right before putting the system into
S4.

Similarly, the suspend testing facility associated with the
/sys/power/pm_test file is broken, because it uses the very same
mechanism that is used in the suspend and hibernation error paths.

Fix the breakage by making the PCI core restore the configuration
spaces of PCI devices that haven't been restored already before
pci_pm_resume() is called for those devices by the PM core.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
  • Loading branch information
Rafael J. Wysocki authored and Jesse Barnes committed Jan 27, 2009
1 parent 5ee8100 commit 418e4da
Showing 1 changed file with 16 additions and 0 deletions.
16 changes: 16 additions & 0 deletions drivers/pci/pci-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
}

pci_save_state(pci_dev);
pci_dev->state_saved = true;
/*
* This is for compatibility with existing code with legacy PM support.
*/
Expand Down Expand Up @@ -419,6 +420,7 @@ static int pci_legacy_resume(struct device *dev)
static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
{
pci_restore_standard_config(pci_dev);
pci_dev->state_saved = false;
pci_fixup_device(pci_fixup_resume_early, pci_dev);
}

Expand Down Expand Up @@ -555,6 +557,13 @@ static int pci_pm_resume(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;

/*
* This is necessary for the suspend error path in which resume is
* called without restoring the standard config registers of the device.
*/
if (pci_dev->state_saved)
pci_restore_standard_config(pci_dev);

if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume(dev);

Expand Down Expand Up @@ -710,6 +719,13 @@ static int pci_pm_restore(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;

/*
* This is necessary for the hibernation error path in which restore is
* called without restoring the standard config registers of the device.
*/
if (pci_dev->state_saved)
pci_restore_standard_config(pci_dev);

if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume(dev);

Expand Down

0 comments on commit 418e4da

Please sign in to comment.