Skip to content

Commit

Permalink
Merge branch 'pm-sleep'
Browse files Browse the repository at this point in the history
* pm-sleep:
  PM / Sleep: Require CAP_BLOCK_SUSPEND to use wake_lock/wake_unlock
  PM / Sleep: Add missing static storage class specifiers in main.c
  PM / Sleep: Fix build warning in sysfs.c for CONFIG_PM_SLEEP unset
  PM / Hibernate: Print hibernation/thaw progress indicator one line at a time.
  PM / Sleep: Separate printing suspend times from initcall_debug
  PM / Sleep: add knob for printing device resume times
  ftrace: Disable function tracing during suspend/resume and hibernation, again
  PM / Hibernate: Enable suspend to both for in-kernel hibernation.
  • Loading branch information
Rafael J. Wysocki committed Jul 18, 2012
2 parents 7791bd2 + 11388c8 commit d52fdf1
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 35 deletions.
13 changes: 13 additions & 0 deletions Documentation/ABI/testing/sysfs-power
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,16 @@ Description:
Reads from this file return a string consisting of the names of
wakeup sources created with the help of /sys/power/wake_lock
that are inactive at the moment, separated with spaces.

What: /sys/power/pm_print_times
Date: May 2012
Contact: Sameer Nanda <snanda@chromium.org>
Description:
The /sys/power/pm_print_times file allows user space to
control whether the time taken by devices to suspend and
resume is printed. These prints are useful for hunting down
devices that take too long to suspend or resume.

Writing a "1" enables this printing while writing a "0"
disables it. The default value is "0". Reading from this file
will display the current value.
5 changes: 5 additions & 0 deletions Documentation/power/swsusp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ echo shutdown > /sys/power/disk; echo disk > /sys/power/state

echo platform > /sys/power/disk; echo disk > /sys/power/state

. If you would like to write hibernation image to swap and then suspend
to RAM (provided your platform supports it), you can try

echo suspend > /sys/power/disk; echo disk > /sys/power/state

. If you have SATA disks, you'll need recent kernels with SATA suspend
support. For suspend and resume to work, make sure your disk drivers
are built into kernel -- not modules. [There's way to make
Expand Down
12 changes: 6 additions & 6 deletions drivers/base/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ typedef int (*pm_callback_t)(struct device *);
*/

LIST_HEAD(dpm_list);
LIST_HEAD(dpm_prepared_list);
LIST_HEAD(dpm_suspended_list);
LIST_HEAD(dpm_late_early_list);
LIST_HEAD(dpm_noirq_list);
static LIST_HEAD(dpm_prepared_list);
static LIST_HEAD(dpm_suspended_list);
static LIST_HEAD(dpm_late_early_list);
static LIST_HEAD(dpm_noirq_list);

struct suspend_stats suspend_stats;
static DEFINE_MUTEX(dpm_list_mtx);
Expand Down Expand Up @@ -166,7 +166,7 @@ static ktime_t initcall_debug_start(struct device *dev)
{
ktime_t calltime = ktime_set(0, 0);

if (initcall_debug) {
if (pm_print_times_enabled) {
pr_info("calling %s+ @ %i, parent: %s\n",
dev_name(dev), task_pid_nr(current),
dev->parent ? dev_name(dev->parent) : "none");
Expand All @@ -181,7 +181,7 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
{
ktime_t delta, rettime;

if (initcall_debug) {
if (pm_print_times_enabled) {
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
Expand Down
4 changes: 4 additions & 0 deletions drivers/base/power/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL);

#endif

#ifdef CONFIG_PM_SLEEP

static ssize_t async_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
Expand All @@ -500,6 +502,8 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
}

static DEVICE_ATTR(async, 0644, async_show, async_store);

#endif
#endif /* CONFIG_PM_ADVANCED_DEBUG */

static struct attribute *power_attrs[] = {
Expand Down
6 changes: 6 additions & 0 deletions include/linux/suspend.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,12 @@ static inline void unlock_system_sleep(void) {}

#endif /* !CONFIG_PM_SLEEP */

#ifdef CONFIG_PM_SLEEP_DEBUG
extern bool pm_print_times_enabled;
#else
#define pm_print_times_enabled (false)
#endif

#ifdef CONFIG_PM_AUTOSLEEP

/* kernel/power/autosleep.c */
Expand Down
4 changes: 2 additions & 2 deletions kernel/power/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ config PM_TEST_SUSPEND
You probably want to have your system's RTC driver statically
linked, ensuring that it's available when this test runs.

config CAN_PM_TRACE
config PM_SLEEP_DEBUG
def_bool y
depends on PM_DEBUG && PM_SLEEP

Expand All @@ -196,7 +196,7 @@ config PM_TRACE

config PM_TRACE_RTC
bool "Suspend/resume event tracing"
depends on CAN_PM_TRACE
depends on PM_SLEEP_DEBUG
depends on X86
select PM_TRACE
---help---
Expand Down
42 changes: 42 additions & 0 deletions kernel/power/hibernate.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Copyright (c) 2003 Open Source Development Lab
* Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
* Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
*
* This file is released under the GPLv2.
*/
Expand Down Expand Up @@ -46,6 +47,9 @@ enum {
HIBERNATION_PLATFORM,
HIBERNATION_SHUTDOWN,
HIBERNATION_REBOOT,
#ifdef CONFIG_SUSPEND
HIBERNATION_SUSPEND,
#endif
/* keep last */
__HIBERNATION_AFTER_LAST
};
Expand Down Expand Up @@ -354,6 +358,7 @@ int hibernation_snapshot(int platform_mode)
}

suspend_console();
ftrace_stop();
pm_restrict_gfp_mask();

error = dpm_suspend(PMSG_FREEZE);
Expand All @@ -379,6 +384,7 @@ int hibernation_snapshot(int platform_mode)
if (error || !in_suspend)
pm_restore_gfp_mask();

ftrace_start();
resume_console();
dpm_complete(msg);

Expand Down Expand Up @@ -481,13 +487,15 @@ int hibernation_restore(int platform_mode)

pm_prepare_console();
suspend_console();
ftrace_stop();
pm_restrict_gfp_mask();
error = dpm_suspend_start(PMSG_QUIESCE);
if (!error) {
error = resume_target_kernel(platform_mode);
dpm_resume_end(PMSG_RECOVER);
}
pm_restore_gfp_mask();
ftrace_start();
resume_console();
pm_restore_console();
return error;
Expand All @@ -514,6 +522,7 @@ int hibernation_platform_enter(void)

entering_platform_hibernation = true;
suspend_console();
ftrace_stop();
error = dpm_suspend_start(PMSG_HIBERNATE);
if (error) {
if (hibernation_ops->recover)
Expand Down Expand Up @@ -557,6 +566,7 @@ int hibernation_platform_enter(void)
Resume_devices:
entering_platform_hibernation = false;
dpm_resume_end(PMSG_RESTORE);
ftrace_start();
resume_console();

Close:
Expand All @@ -574,6 +584,10 @@ int hibernation_platform_enter(void)
*/
static void power_down(void)
{
#ifdef CONFIG_SUSPEND
int error;
#endif

switch (hibernation_mode) {
case HIBERNATION_REBOOT:
kernel_restart(NULL);
Expand All @@ -583,6 +597,25 @@ static void power_down(void)
case HIBERNATION_SHUTDOWN:
kernel_power_off();
break;
#ifdef CONFIG_SUSPEND
case HIBERNATION_SUSPEND:
error = suspend_devices_and_enter(PM_SUSPEND_MEM);
if (error) {
if (hibernation_ops)
hibernation_mode = HIBERNATION_PLATFORM;
else
hibernation_mode = HIBERNATION_SHUTDOWN;
power_down();
}
/*
* Restore swap signature.
*/
error = swsusp_unmark();
if (error)
printk(KERN_ERR "PM: Swap will be unusable! "
"Try swapon -a.\n");
return;
#endif
}
kernel_halt();
/*
Expand Down Expand Up @@ -827,6 +860,9 @@ static const char * const hibernation_modes[] = {
[HIBERNATION_PLATFORM] = "platform",
[HIBERNATION_SHUTDOWN] = "shutdown",
[HIBERNATION_REBOOT] = "reboot",
#ifdef CONFIG_SUSPEND
[HIBERNATION_SUSPEND] = "suspend",
#endif
};

/*
Expand Down Expand Up @@ -867,6 +903,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
switch (i) {
case HIBERNATION_SHUTDOWN:
case HIBERNATION_REBOOT:
#ifdef CONFIG_SUSPEND
case HIBERNATION_SUSPEND:
#endif
break;
case HIBERNATION_PLATFORM:
if (hibernation_ops)
Expand Down Expand Up @@ -907,6 +946,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
switch (mode) {
case HIBERNATION_SHUTDOWN:
case HIBERNATION_REBOOT:
#ifdef CONFIG_SUSPEND
case HIBERNATION_SUSPEND:
#endif
hibernation_mode = mode;
break;
case HIBERNATION_PLATFORM:
Expand Down
45 changes: 45 additions & 0 deletions kernel/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,47 @@ late_initcall(pm_debugfs_init);

#endif /* CONFIG_PM_SLEEP */

#ifdef CONFIG_PM_SLEEP_DEBUG
/*
* pm_print_times: print time taken by devices to suspend and resume.
*
* show() returns whether printing of suspend and resume times is enabled.
* store() accepts 0 or 1. 0 disables printing and 1 enables it.
*/
bool pm_print_times_enabled;

static ssize_t pm_print_times_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", pm_print_times_enabled);
}

static ssize_t pm_print_times_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
unsigned long val;

if (kstrtoul(buf, 10, &val))
return -EINVAL;

if (val > 1)
return -EINVAL;

pm_print_times_enabled = !!val;
return n;
}

power_attr(pm_print_times);

static inline void pm_print_times_init(void)
{
pm_print_times_enabled = !!initcall_debug;
}
#else /* !CONFIG_PP_SLEEP_DEBUG */
static inline void pm_print_times_init(void) {}
#endif /* CONFIG_PM_SLEEP_DEBUG */

struct kobject *power_kobj;

/**
Expand Down Expand Up @@ -531,6 +572,9 @@ static struct attribute * g[] = {
#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
#ifdef CONFIG_PM_SLEEP_DEBUG
&pm_print_times_attr.attr,
#endif
#endif
NULL,
};
Expand Down Expand Up @@ -566,6 +610,7 @@ static int __init pm_init(void)
error = sysfs_create_group(power_kobj, &attr_group);
if (error)
return error;
pm_print_times_init();
return pm_autosleep_init();
}

Expand Down
3 changes: 3 additions & 0 deletions kernel/power/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ extern void swsusp_free(void);
extern int swsusp_read(unsigned int *flags_p);
extern int swsusp_write(unsigned int flags);
extern void swsusp_close(fmode_t);
#ifdef CONFIG_SUSPEND
extern int swsusp_unmark(void);
#endif

/* kernel/power/block_io.c */
extern struct block_device *hib_resume_bdev;
Expand Down
3 changes: 3 additions & 0 deletions kernel/power/suspend.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/export.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/ftrace.h>
#include <trace/events/power.h>

#include "power.h"
Expand Down Expand Up @@ -212,6 +213,7 @@ int suspend_devices_and_enter(suspend_state_t state)
goto Close;
}
suspend_console();
ftrace_stop();
suspend_test_start();
error = dpm_suspend_start(PMSG_SUSPEND);
if (error) {
Expand All @@ -231,6 +233,7 @@ int suspend_devices_and_enter(suspend_state_t state)
suspend_test_start();
dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resume devices");
ftrace_start();
resume_console();
Close:
if (suspend_ops->end)
Expand Down
Loading

0 comments on commit d52fdf1

Please sign in to comment.