Skip to content

Commit

Permalink
PM / sleep: Avoid excess pm_runtime_enable() calls in device_resume()
Browse files Browse the repository at this point in the history
Middle-layer code doing suspend-time optimizations for devices with
the DPM_FLAG_SMART_SUSPEND flag set (currently, the PCI bus type and
the ACPI PM domain) needs to make the core skip ->thaw_early and
->thaw callbacks for those devices in some cases and it sets the
power.direct_complete flag for them for this purpose.

However, it turns out that setting power.direct_complete outside of
the PM core is a bad idea as it triggers an excess invocation of
pm_runtime_enable() in device_resume().

For this reason, provide a helper to clear power.is_late_suspended
and power.is_suspended to be invoked by the middle-layer code in
question instead of setting power.direct_complete and make that code
call the new helper.

Fixes: c4b6515 (PCI / PM: Take SMART_SUSPEND driver flag into account)
Fixes: 0508736 (ACPI / PM: Take SMART_SUSPEND driver flag into account)
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
  • Loading branch information
Rafael J. Wysocki committed Dec 11, 2017
1 parent 50c4c4e commit 3487972
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 2 deletions.
2 changes: 1 addition & 1 deletion drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,7 @@ int acpi_subsys_thaw_noirq(struct device *dev)
* skip all of the subsequent "thaw" callbacks for the device.
*/
if (dev_pm_smart_suspend_and_suspended(dev)) {
dev->power.direct_complete = true;
dev_pm_skip_next_resume_phases(dev);
return 0;
}

Expand Down
15 changes: 15 additions & 0 deletions drivers/base/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,21 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)

/*------------------------- Resume routines -------------------------*/

/**
* dev_pm_skip_next_resume_phases - Skip next system resume phases for device.
* @dev: Target device.
*
* Make the core skip the "early resume" and "resume" phases for @dev.
*
* This function can be called by middle-layer code during the "noirq" phase of
* system resume if necessary, but not by device drivers.
*/
void dev_pm_skip_next_resume_phases(struct device *dev)
{
dev->power.is_late_suspended = false;
dev->power.is_suspended = false;
}

/**
* device_resume_noirq - Execute a "noirq resume" callback for given device.
* @dev: Device to handle.
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/pci-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,7 @@ static int pci_pm_thaw_noirq(struct device *dev)
* the subsequent "thaw" callbacks for the device.
*/
if (dev_pm_smart_suspend_and_suspended(dev)) {
dev->power.direct_complete = true;
dev_pm_skip_next_resume_phases(dev);
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions include/linux/pm.h
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ extern int pm_generic_poweroff_late(struct device *dev);
extern int pm_generic_poweroff(struct device *dev);
extern void pm_generic_complete(struct device *dev);

extern void dev_pm_skip_next_resume_phases(struct device *dev);
extern bool dev_pm_smart_suspend_and_suspended(struct device *dev);

#else /* !CONFIG_PM_SLEEP */
Expand Down

0 comments on commit 3487972

Please sign in to comment.