Skip to content

Commit

Permalink
Merge branch 'pm-sleep'
Browse files Browse the repository at this point in the history
* pm-sleep:
  PM: sleep: Drop dev_pm_skip_next_resume_phases()
  ACPI: PM: Drop unused function and function header
  ACPI: PM: Introduce "poweroff" callbacks for ACPI PM domain and LPSS
  ACPI: PM: Simplify and fix PM domain hibernation callbacks
  PCI: PM: Simplify bus-level hibernation callbacks
  PM: ACPI/PCI: Resume all devices during hibernation
  kernel: power: swap: use kzalloc() instead of kmalloc() followed by memset()
  PM: sleep: Update struct wakeup_source documentation
  drivers: base: power: remove wakeup_sources_stats_dentry variable
  PM: suspend: Rename pm_suspend_via_s2idle()
  PM: sleep: Show how long dpm_suspend_start() and dpm_suspend_end() take
  PM: hibernate: powerpc: Expose pfn_is_nosave() prototype
  • Loading branch information
rafaeljw committed Jul 8, 2019
2 parents 50e163d + 02bd45a commit 3dbeb44
Show file tree
Hide file tree
Showing 15 changed files with 187 additions and 140 deletions.
1 change: 1 addition & 0 deletions arch/powerpc/kernel/suspend.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include <linux/mm.h>
#include <linux/suspend.h>
#include <asm/page.h>
#include <asm/sections.h>

Expand Down
1 change: 0 additions & 1 deletion arch/s390/kernel/entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ void __init startup_init(void);
void die(struct pt_regs *regs, const char *str);
int setup_profiling_timer(unsigned int multiplier);
void __init time_init(void);
int pfn_is_nosave(unsigned long);
void s390_early_resume(void);
unsigned long prepare_ftrace_return(unsigned long parent, unsigned long sp, unsigned long ip);

Expand Down
111 changes: 99 additions & 12 deletions drivers/acpi/acpi_lpss.c
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,13 @@ static int acpi_lpss_suspend_noirq(struct device *dev)
int ret;

if (pdata->dev_desc->resume_from_noirq) {
/*
* The driver's ->suspend_late callback will be invoked by
* acpi_lpss_do_suspend_late(), with the assumption that the
* driver really wanted to run that code in ->suspend_noirq, but
* it could not run after acpi_dev_suspend() and the driver
* expected the latter to be called in the "late" phase.
*/
ret = acpi_lpss_do_suspend_late(dev);
if (ret)
return ret;
Expand Down Expand Up @@ -1091,16 +1098,99 @@ static int acpi_lpss_resume_noirq(struct device *dev)
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
int ret;

ret = acpi_subsys_resume_noirq(dev);
/* Follow acpi_subsys_resume_noirq(). */
if (dev_pm_may_skip_resume(dev))
return 0;

if (dev_pm_smart_suspend_and_suspended(dev))
pm_runtime_set_active(dev);

ret = pm_generic_resume_noirq(dev);
if (ret)
return ret;

if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq)
ret = acpi_lpss_do_resume_early(dev);
if (!pdata->dev_desc->resume_from_noirq)
return 0;

return ret;
/*
* The driver's ->resume_early callback will be invoked by
* acpi_lpss_do_resume_early(), with the assumption that the driver
* really wanted to run that code in ->resume_noirq, but it could not
* run before acpi_dev_resume() and the driver expected the latter to be
* called in the "early" phase.
*/
return acpi_lpss_do_resume_early(dev);
}

static int acpi_lpss_do_restore_early(struct device *dev)
{
int ret = acpi_lpss_resume(dev);

return ret ? ret : pm_generic_restore_early(dev);
}

static int acpi_lpss_restore_early(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));

if (pdata->dev_desc->resume_from_noirq)
return 0;

return acpi_lpss_do_restore_early(dev);
}

static int acpi_lpss_restore_noirq(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
int ret;

ret = pm_generic_restore_noirq(dev);
if (ret)
return ret;

if (!pdata->dev_desc->resume_from_noirq)
return 0;

/* This is analogous to what happens in acpi_lpss_resume_noirq(). */
return acpi_lpss_do_restore_early(dev);
}

static int acpi_lpss_do_poweroff_late(struct device *dev)
{
int ret = pm_generic_poweroff_late(dev);

return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
}

static int acpi_lpss_poweroff_late(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));

if (dev_pm_smart_suspend_and_suspended(dev))
return 0;

if (pdata->dev_desc->resume_from_noirq)
return 0;

return acpi_lpss_do_poweroff_late(dev);
}

static int acpi_lpss_poweroff_noirq(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));

if (dev_pm_smart_suspend_and_suspended(dev))
return 0;

if (pdata->dev_desc->resume_from_noirq) {
/* This is analogous to the acpi_lpss_suspend_noirq() case. */
int ret = acpi_lpss_do_poweroff_late(dev);
if (ret)
return ret;
}

return pm_generic_poweroff_noirq(dev);
}
#endif /* CONFIG_PM_SLEEP */

static int acpi_lpss_runtime_suspend(struct device *dev)
Expand Down Expand Up @@ -1134,14 +1224,11 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
.resume_noirq = acpi_lpss_resume_noirq,
.resume_early = acpi_lpss_resume_early,
.freeze = acpi_subsys_freeze,
.freeze_late = acpi_subsys_freeze_late,
.freeze_noirq = acpi_subsys_freeze_noirq,
.thaw_noirq = acpi_subsys_thaw_noirq,
.poweroff = acpi_subsys_suspend,
.poweroff_late = acpi_lpss_suspend_late,
.poweroff_noirq = acpi_lpss_suspend_noirq,
.restore_noirq = acpi_lpss_resume_noirq,
.restore_early = acpi_lpss_resume_early,
.poweroff = acpi_subsys_poweroff,
.poweroff_late = acpi_lpss_poweroff_late,
.poweroff_noirq = acpi_lpss_poweroff_noirq,
.restore_noirq = acpi_lpss_restore_noirq,
.restore_early = acpi_lpss_restore_early,
#endif
.runtime_suspend = acpi_lpss_runtime_suspend,
.runtime_resume = acpi_lpss_runtime_resume,
Expand Down
94 changes: 52 additions & 42 deletions drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq);
* acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback.
* @dev: Device to handle.
*/
int acpi_subsys_resume_noirq(struct device *dev)
static int acpi_subsys_resume_noirq(struct device *dev)
{
if (dev_pm_may_skip_resume(dev))
return 0;
Expand All @@ -1135,7 +1135,6 @@ int acpi_subsys_resume_noirq(struct device *dev)

return pm_generic_resume_noirq(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq);

/**
* acpi_subsys_resume_early - Resume device using ACPI.
Expand All @@ -1145,12 +1144,11 @@ EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq);
* generic early resume procedure for it during system transition into the
* working state.
*/
int acpi_subsys_resume_early(struct device *dev)
static int acpi_subsys_resume_early(struct device *dev)
{
int ret = acpi_dev_resume(dev);
return ret ? ret : pm_generic_resume_early(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);

/**
* acpi_subsys_freeze - Run the device driver's freeze callback.
Expand All @@ -1159,65 +1157,81 @@ EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
int acpi_subsys_freeze(struct device *dev)
{
/*
* This used to be done in acpi_subsys_prepare() for all devices and
* some drivers may depend on it, so do it here. Ideally, however,
* runtime-suspended devices should not be touched during freeze/thaw
* transitions.
* Resume all runtime-suspended devices before creating a snapshot
* image of system memory, because the restore kernel generally cannot
* be expected to always handle them consistently and they need to be
* put into the runtime-active metastate during system resume anyway,
* so it is better to ensure that the state saved in the image will be
* always consistent with that.
*/
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
pm_runtime_resume(dev);
pm_runtime_resume(dev);

return pm_generic_freeze(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_freeze);

/**
* acpi_subsys_freeze_late - Run the device driver's "late" freeze callback.
* @dev: Device to handle.
* acpi_subsys_restore_early - Restore device using ACPI.
* @dev: Device to restore.
*/
int acpi_subsys_freeze_late(struct device *dev)
int acpi_subsys_restore_early(struct device *dev)
{
int ret = acpi_dev_resume(dev);
return ret ? ret : pm_generic_restore_early(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_restore_early);

if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
/**
* acpi_subsys_poweroff - Run the device driver's poweroff callback.
* @dev: Device to handle.
*
* Follow PCI and resume devices from runtime suspend before running their
* system poweroff callbacks, unless the driver can cope with runtime-suspended
* devices during system suspend and there are no ACPI-specific reasons for
* resuming them.
*/
int acpi_subsys_poweroff(struct device *dev)
{
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
pm_runtime_resume(dev);

return pm_generic_freeze_late(dev);
return pm_generic_poweroff(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late);
EXPORT_SYMBOL_GPL(acpi_subsys_poweroff);

/**
* acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback.
* acpi_subsys_poweroff_late - Run the device driver's poweroff callback.
* @dev: Device to handle.
*
* Carry out the generic late poweroff procedure for @dev and use ACPI to put
* it into a low-power state during system transition into a sleep state.
*/
int acpi_subsys_freeze_noirq(struct device *dev)
static int acpi_subsys_poweroff_late(struct device *dev)
{
int ret;

if (dev_pm_smart_suspend_and_suspended(dev))
return 0;

return pm_generic_freeze_noirq(dev);
ret = pm_generic_poweroff_late(dev);
if (ret)
return ret;

return acpi_dev_suspend(dev, device_may_wakeup(dev));
}
EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq);

/**
* acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback.
* @dev: Device to handle.
* acpi_subsys_poweroff_noirq - Run the driver's "noirq" poweroff callback.
* @dev: Device to suspend.
*/
int acpi_subsys_thaw_noirq(struct device *dev)
static int acpi_subsys_poweroff_noirq(struct device *dev)
{
/*
* If the device is in runtime suspend, the "thaw" code may not work
* correctly with it, so skip the driver callback and make the PM core
* skip all of the subsequent "thaw" callbacks for the device.
*/
if (dev_pm_smart_suspend_and_suspended(dev)) {
dev_pm_skip_next_resume_phases(dev);
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
}

return pm_generic_thaw_noirq(dev);
return pm_generic_poweroff_noirq(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq);
#endif /* CONFIG_PM_SLEEP */

static struct dev_pm_domain acpi_general_pm_domain = {
Expand All @@ -1233,14 +1247,10 @@ static struct dev_pm_domain acpi_general_pm_domain = {
.resume_noirq = acpi_subsys_resume_noirq,
.resume_early = acpi_subsys_resume_early,
.freeze = acpi_subsys_freeze,
.freeze_late = acpi_subsys_freeze_late,
.freeze_noirq = acpi_subsys_freeze_noirq,
.thaw_noirq = acpi_subsys_thaw_noirq,
.poweroff = acpi_subsys_suspend,
.poweroff_late = acpi_subsys_suspend_late,
.poweroff_noirq = acpi_subsys_suspend_noirq,
.restore_noirq = acpi_subsys_resume_noirq,
.restore_early = acpi_subsys_resume_early,
.poweroff = acpi_subsys_poweroff,
.poweroff_late = acpi_subsys_poweroff_late,
.poweroff_noirq = acpi_subsys_poweroff_noirq,
.restore_early = acpi_subsys_restore_early,
#endif
},
};
Expand Down
36 changes: 14 additions & 22 deletions drivers/base/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,21 +529,6 @@ 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;
}

/**
* suspend_event - Return a "suspend" message for given "resume" one.
* @resume_msg: PM message representing a system-wide resume transition.
Expand Down Expand Up @@ -681,6 +666,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
dev->power.is_noirq_suspended = false;

if (skip_resume) {
/* Make the next phases of resume skip the device. */
dev->power.is_late_suspended = false;
dev->power.is_suspended = false;
/*
* The device is going to be left in suspend, but it might not
* have been in runtime suspend before the system suspended, so
Expand All @@ -689,7 +677,6 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
* device again.
*/
pm_runtime_set_suspended(dev);
dev_pm_skip_next_resume_phases(dev);
}

Out:
Expand Down Expand Up @@ -1631,17 +1618,20 @@ int dpm_suspend_late(pm_message_t state)
*/
int dpm_suspend_end(pm_message_t state)
{
int error = dpm_suspend_late(state);
ktime_t starttime = ktime_get();
int error;

error = dpm_suspend_late(state);
if (error)
return error;
goto out;

error = dpm_suspend_noirq(state);
if (error) {
if (error)
dpm_resume_early(resume_event(state));
return error;
}

return 0;
out:
dpm_show_time(starttime, state, error, "end");
return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_end);

Expand Down Expand Up @@ -2034,6 +2024,7 @@ int dpm_prepare(pm_message_t state)
*/
int dpm_suspend_start(pm_message_t state)
{
ktime_t starttime = ktime_get();
int error;

error = dpm_prepare(state);
Expand All @@ -2042,6 +2033,7 @@ int dpm_suspend_start(pm_message_t state)
dpm_save_failed_step(SUSPEND_PREPARE);
} else
error = dpm_suspend(state);
dpm_show_time(starttime, state, error, "start");
return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_start);
Expand Down
Loading

0 comments on commit 3dbeb44

Please sign in to comment.