Merge branches 'pm-runtime' and 'pm-sleep'

Merge updates related to system sleep handling and runtime PM for 6.16-rc1:

 - Fix denying of auto suspend in pm_suspend_timer_fn() (Charan Teja
   Kalla).

 - Move debug runtime PM attributes to runtime_attrs[] (Rafael Wysocki).

 - Add new devm_ functions for enabling runtime PM and runtime PM
   reference counting (Bence Csókás).

 - Remove size arguments from strscpy() calls in the hibernation core
   code (Thorsten Blum).

 - Adjust the handling of devices with asynchronous suspend enabled
   during system suspend and resume to start resuming them immediately
   after resuming their parents and to start suspending such a device
   immediately after suspending its first child (Rafael Wysocki).

 - Adjust messages printed during tasks freezing to avoid using
   pr_cont() (Andrew Sayers, Paul Menzel).

 - Clean up unnecessary usage of !! in pm_print_times_init() (Zihuan
   Zhang).

 - Add missing wakeup source attribute relax_count to sysfs and
   remove the space character at the end ofi the string produced by
   pm_show_wakelocks() (Zijun Hu).

 - Add configurable pm_test delay for hibernation (Zihuan Zhang).

 - Disable asynchronous suspend in ucsi_ccg_probe() to prevent the
   cypd4226 device on Tegra boards from suspending prematurely (Jon
   Hunter).

 - Unbreak printing PM debug messages during hibernation and clean up
   some related code (Rafael Wysocki).

* pm-runtime:
  PM: runtime: fix denying of auto suspend in pm_suspend_timer_fn()
  PM: sysfs: Move debug runtime PM attributes to runtime_attrs[]
  PM: runtime: Add new devm functions

* pm-sleep:
  PM: freezer: Rewrite restarting tasks log to remove stray *done.*
  PM: sleep: Introduce pm_sleep_transition_in_progress()
  PM: sleep: Introduce pm_suspend_in_progress()
  PM: sleep: Print PM debug messages during hibernation
  ucsi_ccg: Disable async suspend in ucsi_ccg_probe()
  PM: hibernate: add configurable delay for pm_test
  PM: wakeup: Delete space in the end of string shown by pm_show_wakelocks()
  PM: wakeup: Add missing wakeup source attribute relax_count
  PM: sleep: Remove unnecessary !!
  PM: sleep: Use two lines for "Restarting..." / "done" messages
  PM: sleep: Make suspend of devices more asynchronous
  PM: sleep: Suspend async parents after suspending children
  PM: sleep: Resume children after resuming the parent
  PM: hibernate: Remove size arguments when calling strscpy()
This commit is contained in:
Rafael J. Wysocki 2025-05-26 21:21:58 +02:00
commit 76524ffd10
17 changed files with 300 additions and 60 deletions

View File

@ -1828,6 +1828,13 @@
lz4: Select LZ4 compression algorithm to
compress/decompress hibernation image.
hibernate.pm_test_delay=
[HIBERNATION]
Sets the number of seconds to remain in a hibernation test
mode before resuming the system (see
/sys/power/pm_test). Only available when CONFIG_PM_DEBUG
is set. Default value is 5.
highmem=nn[KMG] [KNL,BOOT,EARLY] forces the highmem zone to have an exact
size of <nn>. This works even on boxes that have no
highmem otherwise. This also works to reduce highmem

View File

@ -970,13 +970,13 @@ static void amd_rp_pme_suspend(struct pci_dev *dev)
struct pci_dev *rp;
/*
* PM_SUSPEND_ON means we're doing runtime suspend, which means
* If system suspend is not in progress, we're doing runtime suspend, so
* amd-pmc will not be involved so PMEs during D3 work as advertised.
*
* The PMEs *do* work if amd-pmc doesn't put the SoC in the hardware
* sleep state, but we assume amd-pmc is always present.
*/
if (pm_suspend_target_state == PM_SUSPEND_ON)
if (!pm_suspend_in_progress())
return;
rp = pcie_find_root_port(dev);

View File

@ -63,6 +63,7 @@ static LIST_HEAD(dpm_noirq_list);
static DEFINE_MUTEX(dpm_list_mtx);
static pm_message_t pm_transition;
static DEFINE_MUTEX(async_wip_mtx);
static int async_error;
static const char *pm_verb(int event)
@ -597,8 +598,11 @@ static bool is_async(struct device *dev)
&& !pm_trace_is_enabled();
}
static bool dpm_async_fn(struct device *dev, async_func_t func)
static bool __dpm_async(struct device *dev, async_func_t func)
{
if (dev->power.work_in_progress)
return true;
if (!is_async(dev))
return false;
@ -611,22 +615,52 @@ static bool dpm_async_fn(struct device *dev, async_func_t func)
put_device(dev);
/*
* async_schedule_dev_nocall() above has returned false, so func() is
* not running and it is safe to update power.work_in_progress without
* extra synchronization.
*/
dev->power.work_in_progress = false;
return false;
}
static bool dpm_async_fn(struct device *dev, async_func_t func)
{
guard(mutex)(&async_wip_mtx);
return __dpm_async(dev, func);
}
static int dpm_async_with_cleanup(struct device *dev, void *fn)
{
guard(mutex)(&async_wip_mtx);
if (!__dpm_async(dev, fn))
dev->power.work_in_progress = false;
return 0;
}
static void dpm_async_resume_children(struct device *dev, async_func_t func)
{
/*
* Start processing "async" children of the device unless it's been
* started already for them.
*
* This could have been done for the device's "async" consumers too, but
* they either need to wait for their parents or the processing has
* already started for them after their parents were processed.
*/
device_for_each_child(dev, func, dpm_async_with_cleanup);
}
static void dpm_clear_async_state(struct device *dev)
{
reinit_completion(&dev->power.completion);
dev->power.work_in_progress = false;
}
static bool dpm_root_device(struct device *dev)
{
return !dev->parent;
}
static void async_resume_noirq(void *data, async_cookie_t cookie);
/**
* device_resume_noirq - Execute a "noirq resume" callback for given device.
* @dev: Device to handle.
@ -710,6 +744,8 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
}
dpm_async_resume_children(dev, async_resume_noirq);
}
static void async_resume_noirq(void *data, async_cookie_t cookie)
@ -733,19 +769,20 @@ static void dpm_noirq_resume_devices(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
* Trigger the resume of "async" devices upfront so they don't have to
* wait for the "non-async" ones they don't depend on.
* Start processing "async" root devices upfront so they don't wait for
* the "sync" devices they don't depend on.
*/
list_for_each_entry(dev, &dpm_noirq_list, power.entry) {
dpm_clear_async_state(dev);
dpm_async_fn(dev, async_resume_noirq);
if (dpm_root_device(dev))
dpm_async_with_cleanup(dev, async_resume_noirq);
}
while (!list_empty(&dpm_noirq_list)) {
dev = to_device(dpm_noirq_list.next);
list_move_tail(&dev->power.entry, &dpm_late_early_list);
if (!dev->power.work_in_progress) {
if (!dpm_async_fn(dev, async_resume_noirq)) {
get_device(dev);
mutex_unlock(&dpm_list_mtx);
@ -781,6 +818,8 @@ void dpm_resume_noirq(pm_message_t state)
device_wakeup_disarm_wake_irqs();
}
static void async_resume_early(void *data, async_cookie_t cookie);
/**
* device_resume_early - Execute an "early resume" callback for given device.
* @dev: Device to handle.
@ -848,6 +887,8 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, async ? " async early" : " early", error);
}
dpm_async_resume_children(dev, async_resume_early);
}
static void async_resume_early(void *data, async_cookie_t cookie)
@ -875,19 +916,20 @@ void dpm_resume_early(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
* Trigger the resume of "async" devices upfront so they don't have to
* wait for the "non-async" ones they don't depend on.
* Start processing "async" root devices upfront so they don't wait for
* the "sync" devices they don't depend on.
*/
list_for_each_entry(dev, &dpm_late_early_list, power.entry) {
dpm_clear_async_state(dev);
dpm_async_fn(dev, async_resume_early);
if (dpm_root_device(dev))
dpm_async_with_cleanup(dev, async_resume_early);
}
while (!list_empty(&dpm_late_early_list)) {
dev = to_device(dpm_late_early_list.next);
list_move_tail(&dev->power.entry, &dpm_suspended_list);
if (!dev->power.work_in_progress) {
if (!dpm_async_fn(dev, async_resume_early)) {
get_device(dev);
mutex_unlock(&dpm_list_mtx);
@ -919,6 +961,8 @@ void dpm_resume_start(pm_message_t state)
}
EXPORT_SYMBOL_GPL(dpm_resume_start);
static void async_resume(void *data, async_cookie_t cookie);
/**
* device_resume - Execute "resume" callbacks for given device.
* @dev: Device to handle.
@ -1018,6 +1062,8 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, async ? " async" : "", error);
}
dpm_async_resume_children(dev, async_resume);
}
static void async_resume(void *data, async_cookie_t cookie)
@ -1049,19 +1095,20 @@ void dpm_resume(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
* Trigger the resume of "async" devices upfront so they don't have to
* wait for the "non-async" ones they don't depend on.
* Start processing "async" root devices upfront so they don't wait for
* the "sync" devices they don't depend on.
*/
list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
dpm_clear_async_state(dev);
dpm_async_fn(dev, async_resume);
if (dpm_root_device(dev))
dpm_async_with_cleanup(dev, async_resume);
}
while (!list_empty(&dpm_suspended_list)) {
dev = to_device(dpm_suspended_list.next);
list_move_tail(&dev->power.entry, &dpm_prepared_list);
if (!dev->power.work_in_progress) {
if (!dpm_async_fn(dev, async_resume)) {
get_device(dev);
mutex_unlock(&dpm_list_mtx);
@ -1189,6 +1236,41 @@ EXPORT_SYMBOL_GPL(dpm_resume_end);
/*------------------------- Suspend routines -------------------------*/
static bool dpm_leaf_device(struct device *dev)
{
struct device *child;
lockdep_assert_held(&dpm_list_mtx);
child = device_find_any_child(dev);
if (child) {
put_device(child);
return false;
}
return true;
}
static void dpm_async_suspend_parent(struct device *dev, async_func_t func)
{
guard(mutex)(&dpm_list_mtx);
/*
* If the device is suspended asynchronously and the parent's callback
* deletes both the device and the parent itself, the parent object may
* be freed while this function is running, so avoid that by checking
* if the device has been deleted already as the parent cannot be
* deleted before it.
*/
if (!device_pm_initialized(dev))
return;
/* Start processing the device's parent if it is "async". */
if (dev->parent)
dpm_async_with_cleanup(dev->parent, func);
}
/**
* resume_event - Return a "resume" message for given "suspend" sleep state.
* @sleep_state: PM message representing a sleep state.
@ -1226,6 +1308,8 @@ static void dpm_superior_set_must_resume(struct device *dev)
device_links_read_unlock(idx);
}
static void async_suspend_noirq(void *data, async_cookie_t cookie);
/**
* device_suspend_noirq - Execute a "noirq suspend" callback for given device.
* @dev: Device to handle.
@ -1304,7 +1388,13 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
Complete:
complete_all(&dev->power.completion);
TRACE_SUSPEND(error);
return error;
if (error || async_error)
return error;
dpm_async_suspend_parent(dev, async_suspend_noirq);
return 0;
}
static void async_suspend_noirq(void *data, async_cookie_t cookie)
@ -1318,6 +1408,7 @@ static void async_suspend_noirq(void *data, async_cookie_t cookie)
static int dpm_noirq_suspend_devices(pm_message_t state)
{
ktime_t starttime = ktime_get();
struct device *dev;
int error = 0;
trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
@ -1327,12 +1418,21 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
* Start processing "async" leaf devices upfront so they don't need to
* wait for the "sync" devices they don't depend on.
*/
list_for_each_entry_reverse(dev, &dpm_late_early_list, power.entry) {
dpm_clear_async_state(dev);
if (dpm_leaf_device(dev))
dpm_async_with_cleanup(dev, async_suspend_noirq);
}
while (!list_empty(&dpm_late_early_list)) {
struct device *dev = to_device(dpm_late_early_list.prev);
dev = to_device(dpm_late_early_list.prev);
list_move(&dev->power.entry, &dpm_noirq_list);
dpm_clear_async_state(dev);
if (dpm_async_fn(dev, async_suspend_noirq))
continue;
@ -1346,8 +1446,14 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
mutex_lock(&dpm_list_mtx);
if (error || async_error)
if (error || async_error) {
/*
* Move all devices to the target list to resume them
* properly.
*/
list_splice(&dpm_late_early_list, &dpm_noirq_list);
break;
}
}
mutex_unlock(&dpm_list_mtx);
@ -1400,6 +1506,8 @@ static void dpm_propagate_wakeup_to_parent(struct device *dev)
spin_unlock_irq(&parent->power.lock);
}
static void async_suspend_late(void *data, async_cookie_t cookie);
/**
* device_suspend_late - Execute a "late suspend" callback for given device.
* @dev: Device to handle.
@ -1476,7 +1584,13 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
Complete:
TRACE_SUSPEND(error);
complete_all(&dev->power.completion);
return error;
if (error || async_error)
return error;
dpm_async_suspend_parent(dev, async_suspend_late);
return 0;
}
static void async_suspend_late(void *data, async_cookie_t cookie)
@ -1494,6 +1608,7 @@ static void async_suspend_late(void *data, async_cookie_t cookie)
int dpm_suspend_late(pm_message_t state)
{
ktime_t starttime = ktime_get();
struct device *dev;
int error = 0;
trace_suspend_resume(TPS("dpm_suspend_late"), state.event, true);
@ -1505,12 +1620,21 @@ int dpm_suspend_late(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
* Start processing "async" leaf devices upfront so they don't need to
* wait for the "sync" devices they don't depend on.
*/
list_for_each_entry_reverse(dev, &dpm_suspended_list, power.entry) {
dpm_clear_async_state(dev);
if (dpm_leaf_device(dev))
dpm_async_with_cleanup(dev, async_suspend_late);
}
while (!list_empty(&dpm_suspended_list)) {
struct device *dev = to_device(dpm_suspended_list.prev);
dev = to_device(dpm_suspended_list.prev);
list_move(&dev->power.entry, &dpm_late_early_list);
dpm_clear_async_state(dev);
if (dpm_async_fn(dev, async_suspend_late))
continue;
@ -1524,8 +1648,14 @@ int dpm_suspend_late(pm_message_t state)
mutex_lock(&dpm_list_mtx);
if (error || async_error)
if (error || async_error) {
/*
* Move all devices to the target list to resume them
* properly.
*/
list_splice(&dpm_suspended_list, &dpm_late_early_list);
break;
}
}
mutex_unlock(&dpm_list_mtx);
@ -1614,6 +1744,8 @@ static void dpm_clear_superiors_direct_complete(struct device *dev)
device_links_read_unlock(idx);
}
static void async_suspend(void *data, async_cookie_t cookie);
/**
* device_suspend - Execute "suspend" callbacks for given device.
* @dev: Device to handle.
@ -1743,7 +1875,13 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
complete_all(&dev->power.completion);
TRACE_SUSPEND(error);
return error;
if (error || async_error)
return error;
dpm_async_suspend_parent(dev, async_suspend);
return 0;
}
static void async_suspend(void *data, async_cookie_t cookie)
@ -1761,6 +1899,7 @@ static void async_suspend(void *data, async_cookie_t cookie)
int dpm_suspend(pm_message_t state)
{
ktime_t starttime = ktime_get();
struct device *dev;
int error = 0;
trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
@ -1774,12 +1913,21 @@ int dpm_suspend(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
* Start processing "async" leaf devices upfront so they don't need to
* wait for the "sync" devices they don't depend on.
*/
list_for_each_entry_reverse(dev, &dpm_prepared_list, power.entry) {
dpm_clear_async_state(dev);
if (dpm_leaf_device(dev))
dpm_async_with_cleanup(dev, async_suspend);
}
while (!list_empty(&dpm_prepared_list)) {
struct device *dev = to_device(dpm_prepared_list.prev);
dev = to_device(dpm_prepared_list.prev);
list_move(&dev->power.entry, &dpm_suspended_list);
dpm_clear_async_state(dev);
if (dpm_async_fn(dev, async_suspend))
continue;
@ -1793,8 +1941,14 @@ int dpm_suspend(pm_message_t state)
mutex_lock(&dpm_list_mtx);
if (error || async_error)
if (error || async_error) {
/*
* Move all devices to the target list to resume them
* properly.
*/
list_splice(&dpm_prepared_list, &dpm_suspended_list);
break;
}
}
mutex_unlock(&dpm_list_mtx);

View File

@ -1011,7 +1011,7 @@ static enum hrtimer_restart pm_suspend_timer_fn(struct hrtimer *timer)
* If 'expires' is after the current time, we've been called
* too early.
*/
if (expires > 0 && expires < ktime_get_mono_fast_ns()) {
if (expires > 0 && expires <= ktime_get_mono_fast_ns()) {
dev->power.timer_expires = 0;
rpm_suspend(dev, dev->power.timer_autosuspends ?
(RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
@ -1568,6 +1568,32 @@ void pm_runtime_enable(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_runtime_enable);
static void pm_runtime_set_suspended_action(void *data)
{
pm_runtime_set_suspended(data);
}
/**
* devm_pm_runtime_set_active_enabled - set_active version of devm_pm_runtime_enable.
*
* @dev: Device to handle.
*/
int devm_pm_runtime_set_active_enabled(struct device *dev)
{
int err;
err = pm_runtime_set_active(dev);
if (err)
return err;
err = devm_add_action_or_reset(dev, pm_runtime_set_suspended_action, dev);
if (err)
return err;
return devm_pm_runtime_enable(dev);
}
EXPORT_SYMBOL_GPL(devm_pm_runtime_set_active_enabled);
static void pm_runtime_disable_action(void *data)
{
pm_runtime_dont_use_autosuspend(data);
@ -1590,6 +1616,24 @@ int devm_pm_runtime_enable(struct device *dev)
}
EXPORT_SYMBOL_GPL(devm_pm_runtime_enable);
static void pm_runtime_put_noidle_action(void *data)
{
pm_runtime_put_noidle(data);
}
/**
* devm_pm_runtime_get_noresume - devres-enabled version of pm_runtime_get_noresume.
*
* @dev: Device to handle.
*/
int devm_pm_runtime_get_noresume(struct device *dev)
{
pm_runtime_get_noresume(dev);
return devm_add_action_or_reset(dev, pm_runtime_put_noidle_action, dev);
}
EXPORT_SYMBOL_GPL(devm_pm_runtime_get_noresume);
/**
* pm_runtime_forbid - Block runtime PM of a device.
* @dev: Device to handle.

View File

@ -611,15 +611,9 @@ static DEVICE_ATTR_RW(async);
#endif /* CONFIG_PM_ADVANCED_DEBUG */
static struct attribute *power_attrs[] = {
#ifdef CONFIG_PM_ADVANCED_DEBUG
#ifdef CONFIG_PM_SLEEP
#if defined(CONFIG_PM_ADVANCED_DEBUG) && defined(CONFIG_PM_SLEEP)
&dev_attr_async.attr,
#endif
&dev_attr_runtime_status.attr,
&dev_attr_runtime_usage.attr,
&dev_attr_runtime_active_kids.attr,
&dev_attr_runtime_enabled.attr,
#endif /* CONFIG_PM_ADVANCED_DEBUG */
NULL,
};
static const struct attribute_group pm_attr_group = {
@ -650,13 +644,16 @@ static const struct attribute_group pm_wakeup_attr_group = {
};
static struct attribute *runtime_attrs[] = {
#ifndef CONFIG_PM_ADVANCED_DEBUG
&dev_attr_runtime_status.attr,
#endif
&dev_attr_control.attr,
&dev_attr_runtime_suspended_time.attr,
&dev_attr_runtime_active_time.attr,
&dev_attr_autosuspend_delay_ms.attr,
#ifdef CONFIG_PM_ADVANCED_DEBUG
&dev_attr_runtime_usage.attr,
&dev_attr_runtime_active_kids.attr,
&dev_attr_runtime_enabled.attr,
#endif
NULL,
};
static const struct attribute_group pm_runtime_attr_group = {

View File

@ -337,7 +337,7 @@ int device_wakeup_enable(struct device *dev)
if (!dev || !dev->power.can_wakeup)
return -EINVAL;
if (pm_suspend_target_state != PM_SUSPEND_ON)
if (pm_sleep_transition_in_progress())
dev_dbg(dev, "Suspicious %s() during system transition!\n", __func__);
ws = wakeup_source_register(dev, dev_name(dev));

View File

@ -34,6 +34,7 @@ wakeup_attr(active_count);
wakeup_attr(event_count);
wakeup_attr(wakeup_count);
wakeup_attr(expire_count);
wakeup_attr(relax_count);
static ssize_t active_time_ms_show(struct device *dev,
struct device_attribute *attr, char *buf)
@ -119,6 +120,7 @@ static struct attribute *wakeup_source_attrs[] = {
&dev_attr_event_count.attr,
&dev_attr_wakeup_count.attr,
&dev_attr_expire_count.attr,
&dev_attr_relax_count.attr,
&dev_attr_active_time_ms.attr,
&dev_attr_total_time_ms.attr,
&dev_attr_max_time_ms.attr,

View File

@ -641,7 +641,7 @@ static bool xe_pm_suspending_or_resuming(struct xe_device *xe)
return dev->power.runtime_status == RPM_SUSPENDING ||
dev->power.runtime_status == RPM_RESUMING ||
pm_suspend_target_state != PM_SUSPEND_ON;
pm_suspend_in_progress();
#else
return false;
#endif

View File

@ -1483,6 +1483,8 @@ static int ucsi_ccg_probe(struct i2c_client *client)
i2c_set_clientdata(client, uc);
device_disable_async_suspend(uc->dev);
pm_runtime_set_active(uc->dev);
pm_runtime_enable(uc->dev);
pm_runtime_use_autosuspend(uc->dev);

View File

@ -96,7 +96,9 @@ extern void pm_runtime_new_link(struct device *dev);
extern void pm_runtime_drop_link(struct device_link *link);
extern void pm_runtime_release_supplier(struct device_link *link);
int devm_pm_runtime_set_active_enabled(struct device *dev);
extern int devm_pm_runtime_enable(struct device *dev);
int devm_pm_runtime_get_noresume(struct device *dev);
/**
* pm_suspend_ignore_children - Set runtime PM behavior regarding children.
@ -294,7 +296,9 @@ static inline bool pm_runtime_blocked(struct device *dev) { return true; }
static inline void pm_runtime_allow(struct device *dev) {}
static inline void pm_runtime_forbid(struct device *dev) {}
static inline int devm_pm_runtime_set_active_enabled(struct device *dev) { return 0; }
static inline int devm_pm_runtime_enable(struct device *dev) { return 0; }
static inline int devm_pm_runtime_get_noresume(struct device *dev) { return 0; }
static inline void pm_suspend_ignore_children(struct device *dev, bool enable) {}
static inline void pm_runtime_get_noresume(struct device *dev) {}

View File

@ -298,6 +298,11 @@ static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {}
static inline void s2idle_wake(void) {}
#endif /* !CONFIG_SUSPEND */
static inline bool pm_suspend_in_progress(void)
{
return pm_suspend_target_state != PM_SUSPEND_ON;
}
/* struct pbe is used for creating lists of pages that should be restored
* atomically during the resume from disk, because the page frames they have
* occupied before the suspend are in use.
@ -470,6 +475,8 @@ extern void pm_print_active_wakeup_sources(void);
extern unsigned int lock_system_sleep(void);
extern void unlock_system_sleep(unsigned int);
extern bool pm_sleep_transition_in_progress(void);
#else /* !CONFIG_PM_SLEEP */
static inline int register_pm_notifier(struct notifier_block *nb)
@ -498,6 +505,8 @@ static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
static inline unsigned int lock_system_sleep(void) { return 0; }
static inline void unlock_system_sleep(unsigned int flags) {}
static inline bool pm_sleep_transition_in_progress(void) { return false; }
#endif /* !CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_SLEEP_DEBUG

View File

@ -90,6 +90,11 @@ void hibernate_release(void)
atomic_inc(&hibernate_atomic);
}
bool hibernation_in_progress(void)
{
return !atomic_read(&hibernate_atomic);
}
bool hibernation_available(void)
{
return nohibernate == 0 &&
@ -133,10 +138,15 @@ bool system_entering_hibernation(void)
EXPORT_SYMBOL(system_entering_hibernation);
#ifdef CONFIG_PM_DEBUG
static unsigned int pm_test_delay = 5;
module_param(pm_test_delay, uint, 0644);
MODULE_PARM_DESC(pm_test_delay,
"Number of seconds to wait before resuming from hibernation test");
static void hibernation_debug_sleep(void)
{
pr_info("debug: Waiting for 5 seconds.\n");
mdelay(5000);
pr_info("hibernation debug: Waiting for %d second(s).\n",
pm_test_delay);
mdelay(pm_test_delay * 1000);
}
static int hibernation_test(int level)
@ -757,7 +767,7 @@ int hibernate(void)
* Query for the compression algorithm support if compression is enabled.
*/
if (!nocompress) {
strscpy(hib_comp_algo, hibernate_compressor, sizeof(hib_comp_algo));
strscpy(hib_comp_algo, hibernate_compressor);
if (!crypto_has_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC)) {
pr_err("%s compression is not available\n", hib_comp_algo);
return -EOPNOTSUPP;
@ -1006,9 +1016,9 @@ static int software_resume(void)
*/
if (!(swsusp_header_flags & SF_NOCOMPRESS_MODE)) {
if (swsusp_header_flags & SF_COMPRESSION_ALG_LZ4)
strscpy(hib_comp_algo, COMPRESSION_ALGO_LZ4, sizeof(hib_comp_algo));
strscpy(hib_comp_algo, COMPRESSION_ALGO_LZ4);
else
strscpy(hib_comp_algo, COMPRESSION_ALGO_LZO, sizeof(hib_comp_algo));
strscpy(hib_comp_algo, COMPRESSION_ALGO_LZO);
if (!crypto_has_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC)) {
pr_err("%s compression is not available\n", hib_comp_algo);
error = -EOPNOTSUPP;
@ -1456,8 +1466,7 @@ static int hibernate_compressor_param_set(const char *compressor,
if (index >= 0) {
ret = param_set_copystring(comp_alg_enabled[index], kp);
if (!ret)
strscpy(hib_comp_algo, comp_alg_enabled[index],
sizeof(hib_comp_algo));
strscpy(hib_comp_algo, comp_alg_enabled[index]);
} else {
ret = index;
}

View File

@ -557,6 +557,10 @@ static int __init pm_debugfs_init(void)
late_initcall(pm_debugfs_init);
#endif /* CONFIG_DEBUG_FS */
bool pm_sleep_transition_in_progress(void)
{
return pm_suspend_in_progress() || hibernation_in_progress();
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_SLEEP_DEBUG
@ -594,7 +598,7 @@ power_attr(pm_print_times);
static inline void pm_print_times_init(void)
{
pm_print_times_enabled = !!initcall_debug;
pm_print_times_enabled = initcall_debug;
}
static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
@ -613,7 +617,7 @@ bool pm_debug_messages_on __read_mostly;
bool pm_debug_messages_should_print(void)
{
return pm_debug_messages_on && pm_suspend_target_state != PM_SUSPEND_ON;
return pm_debug_messages_on && pm_sleep_transition_in_progress();
}
EXPORT_SYMBOL_GPL(pm_debug_messages_should_print);

View File

@ -71,10 +71,14 @@ extern void enable_restore_image_protection(void);
static inline void enable_restore_image_protection(void) {}
#endif /* CONFIG_STRICT_KERNEL_RWX */
extern bool hibernation_in_progress(void);
#else /* !CONFIG_HIBERNATION */
static inline void hibernate_reserved_size_init(void) {}
static inline void hibernate_image_size_init(void) {}
static inline bool hibernation_in_progress(void) { return false; }
#endif /* !CONFIG_HIBERNATION */
#define power_attr(_name) \

View File

@ -189,7 +189,7 @@ void thaw_processes(void)
oom_killer_enable();
pr_info("Restarting tasks ... ");
pr_info("Restarting tasks: Starting\n");
__usermodehelper_set_disable_depth(UMH_FREEZING);
thaw_workqueues();
@ -208,7 +208,7 @@ void thaw_processes(void)
usermodehelper_enable();
schedule();
pr_cont("done.\n");
pr_info("Restarting tasks: Done\n");
trace_suspend_resume(TPS("thaw_processes"), 0, false);
}
@ -217,7 +217,7 @@ void thaw_kernel_threads(void)
struct task_struct *g, *p;
pm_nosig_freezing = false;
pr_info("Restarting kernel threads ... ");
pr_info("Restarting kernel threads ...\n");
thaw_workqueues();
@ -229,5 +229,5 @@ void thaw_kernel_threads(void)
read_unlock(&tasklist_lock);
schedule();
pr_cont("done.\n");
pr_info("Done restarting kernel threads.\n");
}

View File

@ -49,6 +49,9 @@ ssize_t pm_show_wakelocks(char *buf, bool show_active)
len += sysfs_emit_at(buf, len, "%s ", wl->name);
}
if (len > 0)
--len;
len += sysfs_emit_at(buf, len, "\n");
mutex_unlock(&wakelocks_lock);

View File

@ -4017,7 +4017,8 @@ def parseKernelLog(data):
'PM: early restore of devices complete after.*'],
'resume_complete': ['PM: resume of devices complete after.*',
'PM: restore of devices complete after.*'],
'post_resume': [r'.*Restarting tasks \.\.\..*'],
'post_resume': [r'.*Restarting tasks \.\.\..*',
'Done restarting tasks.*'],
}
# action table (expected events that occur and show up in dmesg)