2008-02-01 04:43:07

by Len Brown

[permalink] [raw]
Subject: suspend patches for 2.6.25-rc0

This is the suspend queue for 2.6.25 --
freshly re-based to the HEAD of Linus' tree.
I plan to send a pull request tomorrow.

thanks,
-Len


2008-02-01 04:42:16

by Len Brown

[permalink] [raw]
Subject: [PATCH 01/37] Hibernation: Introduce SNAPSHOT_GET_IMAGE_SIZE ioctl

From: Rafael J. Wysocki <[email protected]>

Add a new ioctl, SNAPSHOT_GET_IMAGE_SIZE, returning the size of the (just
created) hibernation image, to the hibernation userland interface.

This ioctl is necessary so that the userland utilities using the interface need
not access the hibernation image header, owned by the kernel, in order to obtain
the size of the image.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/userland-swsusp.txt | 12 +++++-------
kernel/power/power.h | 4 +++-
kernel/power/snapshot.c | 7 ++++++-
kernel/power/user.c | 18 ++++++++++++++----
4 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index e00c6cf..32f1874 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -54,6 +54,8 @@ SNAPSHOT_SET_IMAGE_SIZE - set the preferred maximum size of the image
this number, but if it turns out to be impossible, the kernel will
create the smallest image possible)

+SNAPSHOT_GET_IMAGE_SIZE - return the actual size of the hibernation image
+
SNAPSHOT_AVAIL_SWAP - return the amount of available swap in bytes (the last
argument should be a pointer to an unsigned int variable that will
contain the result if the call is successful).
@@ -136,13 +138,9 @@ required, as they can use, for example, a special (blank) suspend partition or
a file on a partition that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and
mounted afterwards.

-These utilities SHOULD NOT make any assumptions regarding the ordering of
-data within the snapshot image, except for the image header that MAY be
-assumed to start with an swsusp_info structure, as specified in
-kernel/power/power.h. This structure MAY be used by the userland utilities
-to obtain some information about the snapshot image, such as the size
-of the snapshot image, including the metadata and the header itself,
-contained in the .size member of swsusp_info.
+These utilities MUST NOT make any assumptions regarding the ordering of
+data within the snapshot image. The contents of the image are entirely owned
+by the kernel and its structure may be changed in future kernel releases.

The snapshot image MUST be written to the kernel unaltered (ie. all of the image
data, metadata and header MUST be written in _exactly_ the same amount, form
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 2093c3a..23c1703 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -128,6 +128,7 @@ struct snapshot_handle {
#define data_of(handle) ((handle).buffer + (handle).buf_offset)

extern unsigned int snapshot_additional_pages(struct zone *zone);
+extern unsigned long snapshot_get_image_size(void);
extern int snapshot_read_next(struct snapshot_handle *handle, size_t count);
extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
extern void snapshot_write_finalize(struct snapshot_handle *handle);
@@ -158,7 +159,8 @@ struct resume_swap_area {
#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
struct resume_swap_area)
-#define SNAPSHOT_IOC_MAXNR 13
+#define SNAPSHOT_GET_IMAGE_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
+#define SNAPSHOT_IOC_MAXNR 14

#define PMOPS_PREPARE 1
#define PMOPS_ENTER 2
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 78039b4..c5ce0f3 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1264,12 +1264,17 @@ static char *check_image_kernel(struct swsusp_info *info)
}
#endif /* CONFIG_ARCH_HIBERNATION_HEADER */

+unsigned long snapshot_get_image_size(void)
+{
+ return nr_copy_pages + nr_meta_pages + 1;
+}
+
static int init_header(struct swsusp_info *info)
{
memset(info, 0, sizeof(struct swsusp_info));
info->num_physpages = num_physpages;
info->image_pages = nr_copy_pages;
- info->pages = nr_copy_pages + nr_meta_pages + 1;
+ info->pages = snapshot_get_image_size();
info->size = info->pages;
info->size <<= PAGE_SHIFT;
return init_header_complete(info);
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 5bd321b..88aac26 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -133,7 +133,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
{
int error = 0;
struct snapshot_data *data;
- loff_t avail;
+ loff_t size;
sector_t offset;

if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
@@ -210,10 +210,20 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
image_size = arg;
break;

+ case SNAPSHOT_GET_IMAGE_SIZE:
+ if (!data->ready) {
+ error = -ENODATA;
+ break;
+ }
+ size = snapshot_get_image_size();
+ size <<= PAGE_SHIFT;
+ error = put_user(size, (loff_t __user *)arg);
+ break;
+
case SNAPSHOT_AVAIL_SWAP:
- avail = count_swap_pages(data->swap, 1);
- avail <<= PAGE_SHIFT;
- error = put_user(avail, (loff_t __user *)arg);
+ size = count_swap_pages(data->swap, 1);
+ size <<= PAGE_SHIFT;
+ error = put_user(size, (loff_t __user *)arg);
break;

case SNAPSHOT_GET_SWAP_PAGE:
--
1.5.4.rc5.16.gc0279

2008-02-01 04:43:47

by Len Brown

[permalink] [raw]
Subject: [PATCH 02/37] Hibernation: Rework platform support ioctls (rev. 2)

From: Rafael J. Wysocki <[email protected]>

Modify the hibernation userland interface by adding two new ioctls to it,
SNAPSHOT_PLATFORM_SUPPORT and SNAPSHOT_POWER_OFF, that can be used,
respectively, to switch the hibernation platform support on/off and to make the
kernel transition the system to the hibernation state (eg. ACPI S4) using the
platform (eg. ACPI) driver.

These ioctls are intended to replace the misdesigned SNAPSHOT_PMOPS ioctl,
which from now is regarded as obsolete and will be removed in the future.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/userland-swsusp.txt | 24 ++++--------------
kernel/power/power.h | 9 ++----
kernel/power/user.c | 39 +++++++++++++++++++++++--------
3 files changed, 38 insertions(+), 34 deletions(-)

diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index 32f1874..381e9c0 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -85,6 +85,12 @@ SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
recommended to always use this call, because the code to set the resume
partition may be removed from future kernels

+SNAPSHOT_PLATFORM_SUPPORT - enable/disable the hibernation platform support,
+ depending on the argument value (enable, if the argument is nonzero)
+
+SNAPSHOT_POWER_OFF - make the kernel transition the system to the hibernation
+ state (eg. ACPI S4) using the platform (eg. ACPI) driver
+
SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
immediately enter the suspend-to-RAM state, so this call must always
be preceded by the SNAPSHOT_FREEZE call and it is also necessary
@@ -95,24 +101,6 @@ SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
to resume the system from RAM if there's enough battery power or restore
its state on the basis of the saved suspend image otherwise)

-SNAPSHOT_PMOPS - enable the usage of the hibernation_ops->prepare,
- hibernate_ops->enter and hibernation_ops->finish methods (the in-kernel
- swsusp knows these as the "platform method") which are needed on many
- machines to (among others) speed up the resume by letting the BIOS skip
- some steps or to let the system recognise the correct state of the
- hardware after the resume (in particular on many machines this ensures
- that unplugged AC adapters get correctly detected and that kacpid does
- not run wild after the resume). The last ioctl() argument can take one
- of the three values, defined in kernel/power/power.h:
- PMOPS_PREPARE - make the kernel carry out the
- hibernation_ops->prepare() operation
- PMOPS_ENTER - make the kernel power off the system by calling
- hibernation_ops->enter()
- PMOPS_FINISH - make the kernel carry out the
- hibernation_ops->finish() operation
- Note that the actual constants are misnamed because they surface
- internal kernel implementation details that have changed.
-
The device's read() operation can be used to transfer the snapshot image from
the kernel. It has the following limitations:
- you cannot read() more than one virtual memory page at a time
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 23c1703..6ca85fd 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -156,15 +156,12 @@ struct resume_swap_area {
#define SNAPSHOT_FREE_SWAP_PAGES _IO(SNAPSHOT_IOC_MAGIC, 9)
#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
#define SNAPSHOT_S2RAM _IO(SNAPSHOT_IOC_MAGIC, 11)
-#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
struct resume_swap_area)
#define SNAPSHOT_GET_IMAGE_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
-#define SNAPSHOT_IOC_MAXNR 14
-
-#define PMOPS_PREPARE 1
-#define PMOPS_ENTER 2
-#define PMOPS_FINISH 3
+#define SNAPSHOT_PLATFORM_SUPPORT _IO(SNAPSHOT_IOC_MAGIC, 15)
+#define SNAPSHOT_POWER_OFF _IO(SNAPSHOT_IOC_MAGIC, 16)
+#define SNAPSHOT_IOC_MAXNR 16

/* If unset, the snapshot device cannot be open. */
extern atomic_t snapshot_device_available;
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 88aac26..de3fb43 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -28,6 +28,18 @@

#include "power.h"

+/*
+ * NOTE: The SNAPSHOT_PMOPS ioctl is obsolete and will be removed in the
+ * future. It is only preserved here for compatibility with existing userland
+ * utilities.
+ */
+#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
+
+#define PMOPS_PREPARE 1
+#define PMOPS_ENTER 2
+#define PMOPS_FINISH 3
+
+
#define SNAPSHOT_MINOR 231

static struct snapshot_data {
@@ -36,7 +48,7 @@ static struct snapshot_data {
int mode;
char frozen;
char ready;
- char platform_suspend;
+ char platform_support;
} snapshot_state;

atomic_t snapshot_device_available = ATOMIC_INIT(1);
@@ -70,7 +82,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
}
data->frozen = 0;
data->ready = 0;
- data->platform_suspend = 0;
+ data->platform_support = 0;

return 0;
}
@@ -183,7 +195,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -EPERM;
break;
}
- error = hibernation_snapshot(data->platform_suspend);
+ error = hibernation_snapshot(data->platform_support);
if (!error)
error = put_user(in_suspend, (unsigned int __user *)arg);
if (!error)
@@ -197,7 +209,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -EPERM;
break;
}
- error = hibernation_restore(data->platform_suspend);
+ error = hibernation_restore(data->platform_support);
break;

case SNAPSHOT_FREE:
@@ -285,26 +297,33 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
mutex_unlock(&pm_mutex);
break;

- case SNAPSHOT_PMOPS:
+ case SNAPSHOT_PLATFORM_SUPPORT:
+ data->platform_support = !!arg;
+ break;
+
+ case SNAPSHOT_POWER_OFF:
+ if (data->platform_support)
+ error = hibernation_platform_enter();
+ break;
+
+ case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
error = -EINVAL;

switch (arg) {

case PMOPS_PREPARE:
- data->platform_suspend = 1;
+ data->platform_support = 1;
error = 0;
break;

case PMOPS_ENTER:
- if (data->platform_suspend)
+ if (data->platform_support)
error = hibernation_platform_enter();
-
break;

case PMOPS_FINISH:
- if (data->platform_suspend)
+ if (data->platform_support)
error = 0;
-
break;

default:
--
1.5.4.rc5.16.gc0279

2008-02-01 04:44:14

by Len Brown

[permalink] [raw]
Subject: [PATCH 11/37] Hibernation: New testing facility (rev. 2)

From: Rafael J. Wysocki <[email protected]>

Make it possible to test the hibernation core code with the help of the
/sys/power/pm_test attribute introduced for suspend testing in the previous
patch.

Writing an appropriate string to this file causes the hibernation code to work
in one of the test modes defined as follows:

freezer
- test the freezing of processes

devices
- test the freezing of processes and suspending of devices

platform
- test the freezing of processes, suspending of devices and platform global
  control methods(*)

processors
- test the freezing of processes, suspending of devices, platform global
  control methods(*) and the disabling of nonboot CPUs

core
- test the freezing of processes, suspending of devices, platform global
  control methods(*), the disabling of nonboot CPUs and suspending of
  platform/system devices

(*) - the platform global control methods are only available on ACPI systems
      and are only tested if the hibernation mode is set to "platform"

Then, if a hibernation is started by normal means, the hibernation core will
perform its normal operations up to the point indicated by given test level.
Next, it will wait for 5 seconds and carry out the resume operations needed to
transition the system back to the fully functional state.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/disk.c | 70 +++++++++++++++++++++++++++++++++++++++----------
kernel/power/power.h | 2 +
2 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 6597365..0866b16 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -70,6 +70,35 @@ void hibernation_set_ops(struct platform_hibernation_ops *ops)
mutex_unlock(&pm_mutex);
}

+#ifdef CONFIG_PM_DEBUG
+static void hibernation_debug_sleep(void)
+{
+ printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
+ mdelay(5000);
+}
+
+static int hibernation_testmode(int mode)
+{
+ if (hibernation_mode == mode) {
+ hibernation_debug_sleep();
+ return 1;
+ }
+ return 0;
+}
+
+static int hibernation_test(int level)
+{
+ if (pm_test_level == level) {
+ hibernation_debug_sleep();
+ return 1;
+ }
+ return 0;
+}
+#else /* !CONFIG_PM_DEBUG */
+static int hibernation_testmode(int mode) { return 0; }
+static int hibernation_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
/**
* platform_start - tell the platform driver that we're starting
* hibernation
@@ -167,6 +196,10 @@ int create_image(int platform_mode)
goto Enable_irqs;
}

+ if (hibernation_test(TEST_CORE))
+ goto Power_up;
+
+ in_suspend = 1;
save_processor_state();
error = swsusp_arch_suspend();
if (error)
@@ -175,6 +208,7 @@ int create_image(int platform_mode)
restore_processor_state();
if (!in_suspend)
platform_leave(platform_mode);
+ Power_up:
/* NOTE: device_power_up() is just a resume() for devices
* that suspended with irqs off ... no overall powerup.
*/
@@ -211,24 +245,29 @@ int hibernation_snapshot(int platform_mode)
if (error)
goto Resume_console;

- error = platform_pre_snapshot(platform_mode);
- if (error)
+ if (hibernation_test(TEST_DEVICES))
goto Resume_devices;

+ error = platform_pre_snapshot(platform_mode);
+ if (error || hibernation_test(TEST_PLATFORM))
+ goto Finish;
+
error = disable_nonboot_cpus();
if (!error) {
- if (hibernation_mode != HIBERNATION_TEST) {
- in_suspend = 1;
- error = create_image(platform_mode);
- /* Control returns here after successful restore */
- } else {
- printk("swsusp debug: Waiting for 5 seconds.\n");
- mdelay(5000);
- }
+ if (hibernation_test(TEST_CPUS))
+ goto Enable_cpus;
+
+ if (hibernation_testmode(HIBERNATION_TEST))
+ goto Enable_cpus;
+
+ error = create_image(platform_mode);
+ /* Control returns here after successful restore */
}
+ Enable_cpus:
enable_nonboot_cpus();
- Resume_devices:
+ Finish:
platform_finish(platform_mode);
+ Resume_devices:
device_resume();
Resume_console:
resume_console();
@@ -406,11 +445,12 @@ int hibernate(void)
if (error)
goto Finish;

- if (hibernation_mode == HIBERNATION_TESTPROC) {
- printk("swsusp debug: Waiting for 5 seconds.\n");
- mdelay(5000);
+ if (hibernation_test(TEST_FREEZER))
goto Thaw;
- }
+
+ if (hibernation_testmode(HIBERNATION_TESTPROC))
+ goto Thaw;
+
error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
if (in_suspend && !error) {
unsigned int flags = 0;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 9f9e16e..f9f0d4d 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -206,3 +206,5 @@ enum {

#define TEST_FIRST TEST_NONE
#define TEST_MAX (__TEST_AFTER_LAST - 1)
+
+extern int pm_test_level;
--
1.5.4.rc5.16.gc0279

2008-02-01 04:44:42

by Len Brown

[permalink] [raw]
Subject: [PATCH 13/37] PM: Make PM_TRACE more architecture independent

From: Johannes Berg <[email protected]>

When trying to debug a suspend failure I started implementing
PM_TRACE for powerpc. I then noticed that I'm debugging a suspend
failure and so PM_TRACE isn't useful at all, but thought that
nonetheless this could be useful in the future.

Basically, to support PM_TRACE, you add a Kconfig option that
selects PM_TRACE and provides the infrastructure as per the
help text of PM_TRACE.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/base/power/Makefile | 2 +-
kernel/power/Kconfig | 23 ++++++++++++++++++++++-
2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index de28dfd..911208b 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_PM) += sysfs.o
obj-$(CONFIG_PM_SLEEP) += main.o
-obj-$(CONFIG_PM_TRACE) += trace.o
+obj-$(CONFIG_PM_TRACE_RTC) += trace.o

ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 8e186c6..06a08f7 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -44,9 +44,30 @@ config PM_VERBOSE
---help---
This option enables verbose messages from the Power Management code.

+config CAN_PM_TRACE
+ def_bool y
+ depends on PM_DEBUG && PM_SLEEP && EXPERIMENTAL
+
config PM_TRACE
+ bool
+ help
+ This enables code to save the last PM event point across
+ reboot. The architecture needs to support this, x86 for
+ example does by saving things in the RTC, see below.
+
+ The architecture specific code must provide the extern
+ functions from <linux/resume-trace.h> as well as the
+ <asm/resume-trace.h> header with a TRACE_RESUME() macro.
+
+ The way the information is presented is architecture-
+ dependent, x86 will print the information during a
+ late_initcall.
+
+config PM_TRACE_RTC
bool "Suspend/resume event tracing"
- depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL
+ depends on CAN_PM_TRACE
+ depends on X86
+ select PM_TRACE
default n
---help---
This enables some cheesy code to save the last PM event point in the
--
1.5.4.rc5.16.gc0279

2008-02-01 04:45:14

by Len Brown

[permalink] [raw]
Subject: [PATCH 03/37] Hibernation: Mark SNAPSHOT_SET_SWAP_FILE ioctl as deprecated (rev. 2)

From: Rafael J. Wysocki <[email protected]>

Mark the SNAPSHOT_SET_SWAP_FILE ioctl belonging to the hibernation userland
interface as deprecated.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/userland-swsusp.txt | 14 ++------------
kernel/power/power.h | 1 -
kernel/power/user.c | 9 +++++----
3 files changed, 7 insertions(+), 17 deletions(-)

diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index 381e9c0..0785500 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -67,23 +67,13 @@ SNAPSHOT_GET_SWAP_PAGE - allocate a swap page from the resume partition
SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated with
SNAPSHOT_GET_SWAP_PAGE

-SNAPSHOT_SET_SWAP_FILE - set the resume partition (the last ioctl() argument
- should specify the device's major and minor numbers in the old
- two-byte format, as returned by the stat() function in the .st_rdev
- member of the stat structure)
-
SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
units) from the beginning of the partition at which the swap header is
located (the last ioctl() argument should point to a struct
resume_swap_area, as defined in kernel/power/power.h, containing the
- resume device specification, as for the SNAPSHOT_SET_SWAP_FILE ioctl(),
- and the offset); for swap partitions the offset is always 0, but it is
- different to zero for swap files (please see
+ resume device specification and the offset); for swap partitions the
+ offset is always 0, but it is different from zero for swap files (see
Documentation/swsusp-and-swap-files.txt for details).
- The SNAPSHOT_SET_SWAP_AREA ioctl() is considered as a replacement for
- SNAPSHOT_SET_SWAP_FILE which is regarded as obsolete. It is
- recommended to always use this call, because the code to set the resume
- partition may be removed from future kernels

SNAPSHOT_PLATFORM_SUPPORT - enable/disable the hibernation platform support,
depending on the argument value (enable, if the argument is nonzero)
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 6ca85fd..8837ea3 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -154,7 +154,6 @@ struct resume_swap_area {
#define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
#define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
#define SNAPSHOT_FREE_SWAP_PAGES _IO(SNAPSHOT_IOC_MAGIC, 9)
-#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
#define SNAPSHOT_S2RAM _IO(SNAPSHOT_IOC_MAGIC, 11)
#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
struct resume_swap_area)
diff --git a/kernel/power/user.c b/kernel/power/user.c
index de3fb43..5e866e0 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -29,10 +29,11 @@
#include "power.h"

/*
- * NOTE: The SNAPSHOT_PMOPS ioctl is obsolete and will be removed in the
- * future. It is only preserved here for compatibility with existing userland
- * utilities.
+ * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and
+ * will be removed in the future. They are only preserved here for
+ * compatibility with existing userland utilities.
*/
+#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)

#define PMOPS_PREPARE 1
@@ -260,7 +261,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
free_all_swap_pages(data->swap);
break;

- case SNAPSHOT_SET_SWAP_FILE:
+ case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
if (!swsusp_swap_in_use()) {
/*
* User space encodes device types as two-byte values,
--
1.5.4.rc5.16.gc0279

2008-02-01 04:45:48

by Len Brown

[permalink] [raw]
Subject: [PATCH 06/37] ACPI: Fix mismerge in acpi_hibernation_finish

From: Rafael J. Wysocki <[email protected]>

Some code in acpi_hibernation_finish() was moved to acpi_hibernation_leave(),
but the old copy had been left (it's harmless, but also useless). Remove it.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/acpi/sleep/main.c | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 2c0b663..cbfa058 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -267,11 +267,6 @@ static void acpi_hibernation_leave(void)

static void acpi_hibernation_finish(void)
{
- /*
- * If ACPI is not enabled by the BIOS and the boot kernel, we need to
- * enable it here.
- */
- acpi_enable();
acpi_disable_wakeup_device(ACPI_STATE_S4);
acpi_leave_sleep_state(ACPI_STATE_S4);

--
1.5.4.rc5.16.gc0279

2008-02-01 04:46:18

by Len Brown

[permalink] [raw]
Subject: [PATCH 07/37] Hibernation: Move function prototypes to header

From: Adrian Bunk <[email protected]>

This patch moves the prototypes of count_highmem_pages() and
restore_highmem() to kernel/power/power.h

Signed-off-by: Adrian Bunk <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/power.h | 8 ++++++++
kernel/power/snapshot.c | 1 -
kernel/power/swsusp.c | 8 --------
3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/kernel/power/power.h b/kernel/power/power.h
index ef90605..c5321eb 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -180,3 +180,11 @@ static inline int pm_notifier_call_chain(unsigned long val)
return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
== NOTIFY_BAD) ? -EINVAL : 0;
}
+
+#ifdef CONFIG_HIGHMEM
+unsigned int count_highmem_pages(void);
+int restore_highmem(void);
+#else
+static inline unsigned int count_highmem_pages(void) { return 0; }
+static inline int restore_highmem(void) { return 0; }
+#endif
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index c5ce0f3..1ec3ecc 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -872,7 +872,6 @@ unsigned int count_highmem_pages(void)
}
#else
static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
-static inline unsigned int count_highmem_pages(void) { return 0; }
#endif /* CONFIG_HIGHMEM */

/**
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index e1722d3..605c536 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -64,14 +64,6 @@ unsigned long image_size = 500 * 1024 * 1024;

int in_suspend __nosavedata = 0;

-#ifdef CONFIG_HIGHMEM
-unsigned int count_highmem_pages(void);
-int restore_highmem(void);
-#else
-static inline int restore_highmem(void) { return 0; }
-static inline unsigned int count_highmem_pages(void) { return 0; }
-#endif
-
/**
* The following functions are used for tracing the allocated
* swap pages, so that they can be freed in case of an error.
--
1.5.4.rc5.16.gc0279

2008-02-01 04:46:42

by Len Brown

[permalink] [raw]
Subject: [PATCH 23/37] Suspend: Clean up Kconfig (V2)

From: Johannes Berg <[email protected]>

This cleans up the suspend Kconfig and removes the need to
declare centrally which architectures support suspend. All
architectures that currently support suspend are modified
accordingly.

Signed-off-by: Johannes Berg <[email protected]>
Acked-by: Russell King <[email protected]>
Acked-by: Paul Mackerras <[email protected]>
Acked-by: Ralf Baechle <[email protected]>
Acked-by: Paul Mundt <[email protected]>
Cc: Pavel Machek <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
arch/arm/Kconfig | 3 +++
arch/blackfin/Kconfig | 4 ++++
arch/frv/Kconfig | 5 +++++
arch/mips/Kconfig | 4 ++++
arch/powerpc/Kconfig | 4 ++++
arch/sh/Kconfig | 4 ++++
arch/x86/Kconfig | 4 ++++
kernel/power/Kconfig | 21 +++------------------
8 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 77201d3..a00d8b9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1035,6 +1035,9 @@ menu "Power management options"

source "kernel/power/Kconfig"

+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+
endmenu

source "net/Kconfig"
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index fc7ca86..4802eb7 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -898,6 +898,10 @@ endmenu
menu "Power management options"
source "kernel/power/Kconfig"

+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
choice
prompt "Select PM Wakeup Event Source"
default PM_WAKEUP_GPIO_BY_SIC_IWR
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 43153e7..2e25b95 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -357,6 +357,11 @@ source "drivers/pcmcia/Kconfig"
# should probably wait a while.

menu "Power management options"
+
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
source kernel/power/Kconfig
endmenu

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 4fad0a3..e387f3a 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2086,6 +2086,10 @@ endmenu

menu "Power management options"

+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
source "kernel/power/Kconfig"

endmenu
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 68f0cf7..824140d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -166,6 +166,10 @@ config ARCH_HIBERNATION_POSSIBLE
depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
default y

+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200
+
config PPC_DCR_NATIVE
bool
default n
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 1cd9c8f..b30c4c3 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -882,6 +882,10 @@ endmenu
menu "Power management options (EXPERIMENTAL)"
depends on EXPERIMENTAL && SYS_SUPPORTS_PM

+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
source kernel/power/Kconfig

endmenu
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 9c511dd..340e81a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -113,6 +113,10 @@ config ARCH_HIBERNATION_POSSIBLE
def_bool y
depends on !SMP || !X86_VOYAGER

+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !X86_VOYAGER
+
config ZONE_DMA32
bool
default X86_64
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index fd76d54..f8153fd 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -85,7 +85,7 @@ config PM_TRACE_RTC
config PM_SLEEP_SMP
bool
depends on SMP
- depends on SUSPEND_SMP_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
+ depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
depends on PM_SLEEP
select HOTPLUG_CPU
default y
@@ -95,29 +95,14 @@ config PM_SLEEP
depends on SUSPEND || HIBERNATION
default y

-config SUSPEND_UP_POSSIBLE
- bool
- depends on (X86 && !X86_VOYAGER) || PPC || ARM || BLACKFIN || MIPS \
- || SUPERH || FRV
- depends on !SMP
- default y
-
-config SUSPEND_SMP_POSSIBLE
- bool
- depends on (X86 && !X86_VOYAGER) \
- || (PPC && (PPC_PSERIES || PPC_PMAC)) || ARM
- depends on SMP
- default y
-
config SUSPEND
bool "Suspend to RAM and standby"
- depends on PM
- depends on SUSPEND_UP_POSSIBLE || SUSPEND_SMP_POSSIBLE
+ depends on PM && ARCH_SUSPEND_POSSIBLE
default y
---help---
Allow the system to enter sleep states in which main memory is
powered and thus its contents are preserved, such as the
- suspend-to-RAM state (i.e. the ACPI S3 state).
+ suspend-to-RAM state (e.g. the ACPI S3 state).

config HIBERNATION
bool "Hibernation (aka 'suspend to disk')"
--
1.5.4.rc5.16.gc0279

2008-02-01 04:47:09

by Len Brown

[permalink] [raw]
Subject: [PATCH 08/37] Hibernation: Add PM_RESTORE_PREPARE and PM_POST_RESTORE notifiers (rev. 2)

From: Alan Stern <[email protected]>

Add PM_RESTORE_PREPARE and PM_POST_RESTORE notifiers to the PM core, to be used
in analogy with the existing PM_HIBERNATION_PREPARE and PM_POST_HIBERNATION
notifiers.

Signed-off-by: Alan Stern <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: "Rafael J. Wysocki" <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/notifiers.txt | 8 ++++++++
include/linux/notifier.h | 2 ++
kernel/power/disk.c | 5 +++++
kernel/power/user.c | 31 +++++++++++++++++++------------
4 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt
index 9293e4b..ae1b7ec 100644
--- a/Documentation/power/notifiers.txt
+++ b/Documentation/power/notifiers.txt
@@ -28,6 +28,14 @@ PM_POST_HIBERNATION The system memory state has been restored from a
hibernation. Device drivers' .resume() callbacks have
been executed and tasks have been thawed.

+PM_RESTORE_PREPARE The system is going to restore a hibernation image.
+ If all goes well the restored kernel will issue a
+ PM_POST_HIBERNATION notification.
+
+PM_POST_RESTORE An error occurred during the hibernation restore.
+ Device drivers' .resume() callbacks have been executed
+ and tasks have been thawed.
+
PM_SUSPEND_PREPARE The system is preparing for a suspend.

PM_POST_SUSPEND The system has just resumed or an error occured during
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 5dfbc68..f4df400 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -228,6 +228,8 @@ static inline int notifier_to_errno(int ret)
#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */
#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */
#define PM_POST_SUSPEND 0x0004 /* Suspend finished */
+#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */
+#define PM_POST_RESTORE 0x0006 /* Restore failed */

/* Console keyboard events.
* Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index b138b43..6597365 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -499,6 +499,10 @@ static int software_resume(void)
goto Unlock;
}

+ error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+ if (error)
+ goto Finish;
+
error = create_basic_memory_bitmaps();
if (error)
goto Finish;
@@ -522,6 +526,7 @@ static int software_resume(void)
Done:
free_basic_memory_bitmaps();
Finish:
+ pm_notifier_call_chain(PM_POST_RESTORE);
atomic_inc(&snapshot_device_available);
/* For success case, the suspend path will release the lock */
Unlock:
diff --git a/kernel/power/user.c b/kernel/power/user.c
index b902a7e..f5512cb 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -67,6 +67,7 @@ atomic_t snapshot_device_available = ATOMIC_INIT(1);
static int snapshot_open(struct inode *inode, struct file *filp)
{
struct snapshot_data *data;
+ int error;

if (!atomic_add_unless(&snapshot_device_available, -1, 0))
return -EBUSY;
@@ -87,9 +88,19 @@ static int snapshot_open(struct inode *inode, struct file *filp)
data->swap = swsusp_resume_device ?
swap_type_of(swsusp_resume_device, 0, NULL) : -1;
data->mode = O_RDONLY;
+ error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+ if (error)
+ pm_notifier_call_chain(PM_POST_RESTORE);
} else {
data->swap = -1;
data->mode = O_WRONLY;
+ error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+ if (error)
+ pm_notifier_call_chain(PM_POST_HIBERNATION);
+ }
+ if (error) {
+ atomic_inc(&snapshot_device_available);
+ return error;
}
data->frozen = 0;
data->ready = 0;
@@ -111,6 +122,8 @@ static int snapshot_release(struct inode *inode, struct file *filp)
thaw_processes();
mutex_unlock(&pm_mutex);
}
+ pm_notifier_call_chain(data->mode == O_WRONLY ?
+ PM_POST_HIBERNATION : PM_POST_RESTORE);
atomic_inc(&snapshot_device_available);
return 0;
}
@@ -174,18 +187,13 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
if (data->frozen)
break;
mutex_lock(&pm_mutex);
- error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
- if (!error) {
- printk("Syncing filesystems ... ");
- sys_sync();
- printk("done.\n");
-
- error = freeze_processes();
- if (error)
- thaw_processes();
- }
+ printk("Syncing filesystems ... ");
+ sys_sync();
+ printk("done.\n");
+
+ error = freeze_processes();
if (error)
- pm_notifier_call_chain(PM_POST_HIBERNATION);
+ thaw_processes();
mutex_unlock(&pm_mutex);
if (!error)
data->frozen = 1;
@@ -196,7 +204,6 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
break;
mutex_lock(&pm_mutex);
thaw_processes();
- pm_notifier_call_chain(PM_POST_HIBERNATION);
mutex_unlock(&pm_mutex);
data->frozen = 0;
break;
--
1.5.4.rc5.16.gc0279

2008-02-01 04:47:35

by Len Brown

[permalink] [raw]
Subject: [PATCH 09/37] Suspend: Testing facility (rev. 2)

From: Rafael J. Wysocki <[email protected]>

Introduce sysfs attribute /sys/power/pm_test allowing one to test the suspend
core code.  Namely, writing one of the strings:

freezer
devices
platform
processors
core

to this file causes the suspend code to work in one of the test modes defined as
follows:

freezer
- test the freezing of processes

devices
- test the freezing of processes and suspending of devices

platform
- test the freezing of processes, suspending of devices and platform global
  control methods(*)

processors
- test the freezing of processes, suspending of devices, platform global
  control methods and the disabling of nonboot CPUs

core
- test the freezing of processes, suspending of devices, platform global
  control methods, the disabling of nonboot CPUs and suspending of
  platform/system devices

(*) These are ACPI global control methods on ACPI systems

Then, if a suspend is started by normal means, the suspend core will perform
its normal operations up to the point indicated by given test level.  Next, it
will wait for 5 seconds and carry out the resume operations needed to transition
the system back to the fully functional state.

Writing "none" to /sys/power/pm_test turns the testing off.

When open for reading, /sys/power/pm_test contains a space-separated list of all
available tests (including "none" that represents the normal functionality) in
which the current test level is indicated by square brackets.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/main.c | 108 +++++++++++++++++++++++++++++++++++++++++++++----
kernel/power/power.h | 18 ++++++++
2 files changed, 117 insertions(+), 9 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index efc0836..84e1ae6 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -31,6 +31,79 @@ DEFINE_MUTEX(pm_mutex);
unsigned int pm_flags;
EXPORT_SYMBOL(pm_flags);

+#ifdef CONFIG_PM_DEBUG
+int pm_test_level = TEST_NONE;
+
+static int suspend_test(int level)
+{
+ if (pm_test_level == level) {
+ printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
+ mdelay(5000);
+ return 1;
+ }
+ return 0;
+}
+
+static const char * const pm_tests[__TEST_AFTER_LAST] = {
+ [TEST_NONE] = "none",
+ [TEST_CORE] = "core",
+ [TEST_CPUS] = "processors",
+ [TEST_PLATFORM] = "platform",
+ [TEST_DEVICES] = "devices",
+ [TEST_FREEZER] = "freezer",
+};
+
+static ssize_t pm_test_show(struct kset *kset, char *buf)
+{
+ char *s = buf;
+ int level;
+
+ for (level = TEST_FIRST; level <= TEST_MAX; level++)
+ if (pm_tests[level]) {
+ if (level == pm_test_level)
+ s += sprintf(s, "[%s] ", pm_tests[level]);
+ else
+ s += sprintf(s, "%s ", pm_tests[level]);
+ }
+
+ if (s != buf)
+ /* convert the last space to a newline */
+ *(s-1) = '\n';
+
+ return (s - buf);
+}
+
+static ssize_t pm_test_store(struct kset *kset, const char *buf, size_t n)
+{
+ const char * const *s;
+ int level;
+ char *p;
+ int len;
+ int error = -EINVAL;
+
+ p = memchr(buf, '\n', n);
+ len = p ? p - buf : n;
+
+ mutex_lock(&pm_mutex);
+
+ level = TEST_FIRST;
+ for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
+ if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
+ pm_test_level = level;
+ error = 0;
+ break;
+ }
+
+ mutex_unlock(&pm_mutex);
+
+ return error ? error : n;
+}
+
+power_attr(pm_test);
+#else /* !CONFIG_PM_DEBUG */
+static inline int suspend_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
#ifdef CONFIG_SUSPEND

/* This is just an arbitrary number */
@@ -136,7 +209,10 @@ static int suspend_enter(suspend_state_t state)
printk(KERN_ERR "Some devices failed to power down\n");
goto Done;
}
- error = suspend_ops->enter(state);
+
+ if (!suspend_test(TEST_CORE))
+ error = suspend_ops->enter(state);
+
device_power_up();
Done:
arch_suspend_enable_irqs();
@@ -167,16 +243,25 @@ int suspend_devices_and_enter(suspend_state_t state)
printk(KERN_ERR "Some devices failed to suspend\n");
goto Resume_console;
}
+
+ if (suspend_test(TEST_DEVICES))
+ goto Resume_devices;
+
if (suspend_ops->prepare) {
error = suspend_ops->prepare();
if (error)
goto Resume_devices;
}
+
+ if (suspend_test(TEST_PLATFORM))
+ goto Finish;
+
error = disable_nonboot_cpus();
- if (!error)
+ if (!error && !suspend_test(TEST_CPUS))
suspend_enter(state);

enable_nonboot_cpus();
+ Finish:
if (suspend_ops->finish)
suspend_ops->finish();
Resume_devices:
@@ -243,12 +328,17 @@ static int enter_state(suspend_state_t state)
printk("done.\n");

pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
- if ((error = suspend_prepare()))
+ error = suspend_prepare();
+ if (error)
goto Unlock;

+ if (suspend_test(TEST_FREEZER))
+ goto Finish;
+
pr_debug("PM: Entering %s sleep\n", pm_states[state]);
error = suspend_devices_and_enter(state);

+ Finish:
pr_debug("PM: Finishing wakeup.\n");
suspend_finish();
Unlock:
@@ -369,18 +459,18 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
}

power_attr(pm_trace);
+#endif /* CONFIG_PM_TRACE */

static struct attribute * g[] = {
&state_attr.attr,
+#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
+#endif
+#ifdef CONFIG_PM_DEBUG
+ &pm_test_attr.attr,
+#endif
NULL,
};
-#else
-static struct attribute * g[] = {
- &state_attr.attr,
- NULL,
-};
-#endif /* CONFIG_PM_TRACE */

static struct attribute_group attr_group = {
.attrs = g,
diff --git a/kernel/power/power.h b/kernel/power/power.h
index c5321eb..9f9e16e 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -188,3 +188,21 @@ int restore_highmem(void);
static inline unsigned int count_highmem_pages(void) { return 0; }
static inline int restore_highmem(void) { return 0; }
#endif
+
+/*
+ * Suspend test levels
+ */
+enum {
+ /* keep first */
+ TEST_NONE,
+ TEST_CORE,
+ TEST_CPUS,
+ TEST_PLATFORM,
+ TEST_DEVICES,
+ TEST_FREEZER,
+ /* keep last */
+ __TEST_AFTER_LAST
+};
+
+#define TEST_FIRST TEST_NONE
+#define TEST_MAX (__TEST_AFTER_LAST - 1)
--
1.5.4.rc5.16.gc0279

2008-02-01 04:47:54

by Len Brown

[permalink] [raw]
Subject: [PATCH 10/37] suspend: build fix responding to 2.6.25 kset change

From: Rafael J. Wysocki <[email protected]>

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/main.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index 84e1ae6..fc717b8 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -53,7 +53,8 @@ static const char * const pm_tests[__TEST_AFTER_LAST] = {
[TEST_FREEZER] = "freezer",
};

-static ssize_t pm_test_show(struct kset *kset, char *buf)
+static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
{
char *s = buf;
int level;
@@ -73,7 +74,8 @@ static ssize_t pm_test_show(struct kset *kset, char *buf)
return (s - buf);
}

-static ssize_t pm_test_store(struct kset *kset, const char *buf, size_t n)
+static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
{
const char * const *s;
int level;
@@ -104,6 +106,7 @@ power_attr(pm_test);
static inline int suspend_test(int level) { return 0; }
#endif /* !CONFIG_PM_DEBUG */

+
#ifdef CONFIG_SUSPEND

/* This is just an arbitrary number */
--
1.5.4.rc5.16.gc0279

2008-02-01 04:48:30

by Len Brown

[permalink] [raw]
Subject: [PATCH 24/37] ACPI: clear GPE earily in resume to avoid warning

From: Shaohua Li <[email protected]>

Wakeup GPE hasn't a handler. If system is waked up by such GPE like a
USB hotplug, I saw a lot of error reporting the GPE hasn't handler.
acpi_leave_sleep_state will clear the GPE but it's too late, we should
do it before interrupt is re-enabled.

Signed-off-by: Shaohua Li <[email protected]>
Acked-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/acpi/sleep/main.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index cbfa058..96d23b3 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -146,6 +146,13 @@ static int acpi_pm_enter(suspend_state_t pm_state)
if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
acpi_clear_event(ACPI_EVENT_POWER_BUTTON);

+ /*
+ * Disable and clear GPE status before interrupt is enabled. Some GPEs
+ * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
+ * acpi_leave_sleep_state will reenable specific GPEs later
+ */
+ acpi_hw_disable_all_gpes();
+
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");

--
1.5.4.rc5.16.gc0279

2008-02-01 04:48:54

by Len Brown

[permalink] [raw]
Subject: [PATCH 19/37] Hibernation: Remove unnecessary variable declaration

From: Rafael J. Wysocki <[email protected]>

Remove the unnecessary extern declaration of resume_file[]
from kernel/power/swap.c .

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/swap.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 917aba1..ef41440 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -28,8 +28,6 @@

#include "power.h"

-extern char resume_file[];
-
#define SWSUSP_SIG "S1SUSPEND"

struct swsusp_header {
--
1.5.4.rc5.16.gc0279

2008-02-01 04:49:22

by Len Brown

[permalink] [raw]
Subject: [PATCH 12/37] PM: Suspend/hibernation debug documentation update (rev. 2)

From: Rafael J. Wysocki <[email protected]>

Update the suspend/hibernation debugging and testing documentation to describe
the newly introduced testing facilities.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/basic-pm-debugging.txt | 216 ++++++++++++++++++++--------
Documentation/power/drivers-testing.txt | 30 +++--
2 files changed, 174 insertions(+), 72 deletions(-)

diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
index 57aef2f..1555001 100644
--- a/Documentation/power/basic-pm-debugging.txt
+++ b/Documentation/power/basic-pm-debugging.txt
@@ -1,45 +1,111 @@
-Debugging suspend and resume
+Debugging hibernation and suspend
(C) 2007 Rafael J. Wysocki <[email protected]>, GPL

-1. Testing suspend to disk (STD)
+1. Testing hibernation (aka suspend to disk or STD)

-To verify that the STD works, you can try to suspend in the "reboot" mode:
+To check if hibernation works, you can try to hibernate in the "reboot" mode:

# echo reboot > /sys/power/disk
# echo disk > /sys/power/state

-and the system should suspend, reboot, resume and get back to the command prompt
-where you have started the transition. If that happens, the STD is most likely
-to work correctly, but you need to repeat the test at least a couple of times in
-a row for confidence. This is necessary, because some problems only show up on
-a second attempt at suspending and resuming the system. You should also test
-the "platform" and "shutdown" modes of suspend:
+and the system should create a hibernation image, reboot, resume and get back to
+the command prompt where you have started the transition. If that happens,
+hibernation is most likely to work correctly. Still, you need to repeat the
+test at least a couple of times in a row for confidence. [This is necessary,
+because some problems only show up on a second attempt at suspending and
+resuming the system.] Moreover, hibernating in the "reboot" and "shutdown"
+modes causes the PM core to skip some platform-related callbacks which on ACPI
+systems might be necessary to make hibernation work. Thus, if you machine fails
+to hibernate or resume in the "reboot" mode, you should try the "platform" mode:

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

-or
+which is the default and recommended mode of hibernation.
+
+Unfortunately, the "platform" mode of hibernation does not work on some systems
+with broken BIOSes. In such cases the "shutdown" mode of hibernation might
+work:

# echo shutdown > /sys/power/disk
# echo disk > /sys/power/state

-in which cases you will have to press the power button to make the system
-resume. If that does not work, you will need to identify what goes wrong.
+(it is similar to the "reboot" mode, but it requires you to press the power
+button to make the system resume).
+
+If neither "platform" nor "shutdown" hibernation mode works, you will need to
+identify what goes wrong.
+
+a) Test modes of hibernation
+
+To find out why hibernation fails on your system, you can use a special testing
+facility available if the kernel is compiled with CONFIG_PM_DEBUG set. Then,
+there is the file /sys/power/pm_test that can be used to make the hibernation
+core run in a test mode. There are 5 test modes available:
+
+freezer
+- test the freezing of processes
+
+devices
+- test the freezing of processes and suspending of devices

-a) Test mode of STD
+platform
+- test the freezing of processes, suspending of devices and platform
+ global control methods(*)

-To verify if there are any drivers that cause problems you can run the STD
-in the test mode:
+processors
+- test the freezing of processes, suspending of devices, platform
+ global control methods(*) and the disabling of nonboot CPUs

-# echo test > /sys/power/disk
+core
+- test the freezing of processes, suspending of devices, platform global
+ control methods(*), the disabling of nonboot CPUs and suspending of
+ platform/system devices
+
+(*) the platform global control methods are only available on ACPI systems
+ and are only tested if the hibernation mode is set to "platform"
+
+To use one of them it is necessary to write the corresponding string to
+/sys/power/pm_test (eg. "devices" to test the freezing of processes and
+suspending devices) and issue the standard hibernation commands. For example,
+to use the "devices" test mode along with the "platform" mode of hibernation,
+you should do the following:
+
+# echo devices > /sys/power/pm_test
+# echo platform > /sys/power/disk
# echo disk > /sys/power/state

-in which case the system should freeze tasks, suspend devices, disable nonboot
-CPUs (if any), wait for 5 seconds, enable nonboot CPUs, resume devices, thaw
-tasks and return to your command prompt. If that fails, most likely there is
-a driver that fails to either suspend or resume (in the latter case the system
-may hang or be unstable after the test, so please take that into consideration).
-To find this driver, you can carry out a binary search according to the rules:
+Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds,
+resume devices and thaw processes. If "platform" is written to
+/sys/power/pm_test , then after suspending devices the kernel will additionally
+invoke the global control methods (eg. ACPI global control methods) used to
+prepare the platform firmware for hibernation. Next, it will wait 5 seconds and
+invoke the platform (eg. ACPI) global methods used to cancel hibernation etc.
+
+Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
+hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test
+contains a space-separated list of all available tests (including "none" that
+represents the normal functionality) in which the current test level is
+indicated by square brackets.
+
+Generally, as you can see, each test level is more "invasive" than the previous
+one and the "core" level tests the hardware and drivers as deeply as possible
+without creating a hibernation image. Obviously, if the "devices" test fails,
+the "platform" test will fail as well and so on. Thus, as a rule of thumb, you
+should try the test modes starting from "freezer", through "devices", "platform"
+and "processors" up to "core" (repeat the test on each level a couple of times
+to make sure that any random factors are avoided).
+
+If the "freezer" test fails, there is a task that cannot be frozen (in that case
+it usually is possible to identify the offending task by analysing the output of
+dmesg obtained after the failing test). Failure at this level usually means
+that there is a problem with the tasks freezer subsystem that should be
+reported.
+
+If the "devices" test fails, most likely there is a driver that cannot suspend
+or resume its device (in the latter case the system may hang or become unstable
+after the test, so please take that into consideration). To find this driver,
+you can carry out a binary search according to the rules:
- if the test fails, unload a half of the drivers currently loaded and repeat
(that would probably involve rebooting the system, so always note what drivers
have been loaded before the test),
@@ -47,23 +113,46 @@ have been loaded before the test),
recently and repeat.

Once you have found the failing driver (there can be more than just one of
-them), you have to unload it every time before the STD transition. In that case
-please make sure to report the problem with the driver.
-
-It is also possible that a cycle can still fail after you have unloaded
-all modules. In that case, you would want to look in your kernel configuration
-for the drivers that can be compiled as modules (testing again with them as
-modules), and possibly also try boot time options such as "noapic" or "noacpi".
+them), you have to unload it every time before hibernation. In that case please
+make sure to report the problem with the driver.
+
+It is also possible that the "devices" test will still fail after you have
+unloaded all modules. In that case, you may want to look in your kernel
+configuration for the drivers that can be compiled as modules (and test again
+with these drivers compiled as modules). You may also try to use some special
+kernel command line options such as "noapic", "noacpi" or even "acpi=off".
+
+If the "platform" test fails, there is a problem with the handling of the
+platform (eg. ACPI) firmware on your system. In that case the "platform" mode
+of hibernation is not likely to work. You can try the "shutdown" mode, but that
+is rather a poor man's workaround.
+
+If the "processors" test fails, the disabling/enabling of nonboot CPUs does not
+work (of course, this only may be an issue on SMP systems) and the problem
+should be reported. In that case you can also try to switch the nonboot CPUs
+off and on using the /sys/devices/system/cpu/cpu*/online sysfs attributes and
+see if that works.
+
+If the "core" test fails, which means that suspending of the system/platform
+devices has failed (these devices are suspended on one CPU with interrupts off),
+the problem is most probably hardware-related and serious, so it should be
+reported.
+
+A failure of any of the "platform", "processors" or "core" tests may cause your
+system to hang or become unstable, so please beware. Such a failure usually
+indicates a serious problem that very well may be related to the hardware, but
+please report it anyway.

b) Testing minimal configuration

-If the test mode of STD works, you can boot the system with "init=/bin/bash"
-and attempt to suspend in the "reboot", "shutdown" and "platform" modes. If
-that does not work, there probably is a problem with a driver statically
-compiled into the kernel and you can try to compile more drivers as modules,
-so that they can be tested individually. Otherwise, there is a problem with a
-modular driver and you can find it by loading a half of the modules you normally
-use and binary searching in accordance with the algorithm:
+If all of the hibernation test modes work, you can boot the system with the
+"init=/bin/bash" command line parameter and attempt to hibernate in the
+"reboot", "shutdown" and "platform" modes. If that does not work, there
+probably is a problem with a driver statically compiled into the kernel and you
+can try to compile more drivers as modules, so that they can be tested
+individually. Otherwise, there is a problem with a modular driver and you can
+find it by loading a half of the modules you normally use and binary searching
+in accordance with the algorithm:
- if there are n modules loaded and the attempt to suspend and resume fails,
unload n/2 of the modules and try again (that would probably involve rebooting
the system),
@@ -71,19 +160,19 @@ the system),
load n/2 modules more and try again.

Again, if you find the offending module(s), it(they) must be unloaded every time
-before the STD transition, and please report the problem with it(them).
+before hibernation, and please report the problem with it(them).

c) Advanced debugging

-In case the STD does not work on your system even in the minimal configuration
-and compiling more drivers as modules is not practical or some modules cannot
-be unloaded, you can use one of the more advanced debugging techniques to find
-the problem. First, if there is a serial port in your box, you can boot the
-kernel with the 'no_console_suspend' parameter and try to log kernel
-messages using the serial console. This may provide you with some information
-about the reasons of the suspend (resume) failure. Alternatively, it may be
-possible to use a FireWire port for debugging with firescope
-(ftp://ftp.firstfloor.org/pub/ak/firescope/). On i386 it is also possible to
+In case that hibernation does not work on your system even in the minimal
+configuration and compiling more drivers as modules is not practical or some
+modules cannot be unloaded, you can use one of the more advanced debugging
+techniques to find the problem. First, if there is a serial port in your box,
+you can boot the kernel with the 'no_console_suspend' parameter and try to log
+kernel messages using the serial console. This may provide you with some
+information about the reasons of the suspend (resume) failure. Alternatively,
+it may be possible to use a FireWire port for debugging with firescope
+(ftp://ftp.firstfloor.org/pub/ak/firescope/). On x86 it is also possible to
use the PM_TRACE mechanism documented in Documentation/s2ram.txt .

2. Testing suspend to RAM (STR)
@@ -91,16 +180,25 @@ use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
To verify that the STR works, it is generally more convenient to use the s2ram
tool available from http://suspend.sf.net and documented at
http://en.opensuse.org/s2ram . However, before doing that it is recommended to
-carry out the procedure described in section 1.
-
-Assume you have resolved the problems with the STD and you have found some
-failing drivers. These drivers are also likely to fail during the STR or
-during the resume, so it is better to unload them every time before the STR
-transition. Now, you can follow the instructions at
-http://en.opensuse.org/s2ram to test the system, but if it does not work
-"out of the box", you may need to boot it with "init=/bin/bash" and test
-s2ram in the minimal configuration. In that case, you may be able to search
-for failing drivers by following the procedure analogous to the one described in
-1b). If you find some failing drivers, you will have to unload them every time
-before the STR transition (ie. before you run s2ram), and please report the
-problems with them.
+carry out STR testing using the facility described in section 1.
+
+Namely, after writing "freezer", "devices", "platform", "processors", or "core"
+into /sys/power/pm_test (available if the kernel is compiled with
+CONFIG_PM_DEBUG set) the suspend code will work in the test mode corresponding
+to given string. The STR test modes are defined in the same way as for
+hibernation, so please refer to Section 1 for more information about them. In
+particular, the "core" test allows you to test everything except for the actual
+invocation of the platform firmware in order to put the system into the sleep
+state.
+
+Among other things, the testing with the help of /sys/power/pm_test may allow
+you to identify drivers that fail to suspend or resume their devices. They
+should be unloaded every time before an STR transition.
+
+Next, you can follow the instructions at http://en.opensuse.org/s2ram to test
+the system, but if it does not work "out of the box", you may need to boot it
+with "init=/bin/bash" and test s2ram in the minimal configuration. In that
+case, you may be able to search for failing drivers by following the procedure
+analogous to the one described in section 1. If you find some failing drivers,
+you will have to unload them every time before an STR transition (ie. before
+you run s2ram), and please report the problems with them.
diff --git a/Documentation/power/drivers-testing.txt b/Documentation/power/drivers-testing.txt
index e4bdcae..7f7a737 100644
--- a/Documentation/power/drivers-testing.txt
+++ b/Documentation/power/drivers-testing.txt
@@ -6,9 +6,9 @@ Testing suspend and resume support in device drivers
Unfortunately, to effectively test the support for the system-wide suspend and
resume transitions in a driver, it is necessary to suspend and resume a fully
functional system with this driver loaded. Moreover, that should be done
-several times, preferably several times in a row, and separately for the suspend
-to disk (STD) and the suspend to RAM (STR) transitions, because each of these
-cases involves different ordering of operations and different interactions with
+several times, preferably several times in a row, and separately for hibernation
+(aka suspend to disk or STD) and suspend to RAM (STR), because each of these
+cases involves slightly different operations and different interactions with
the machine's BIOS.

Of course, for this purpose the test system has to be known to suspend and
@@ -22,20 +22,24 @@ for more information about the debugging of suspend/resume functionality.
Once you have resolved the suspend/resume-related problems with your test system
without the new driver, you are ready to test it:

-a) Build the driver as a module, load it and try the STD in the test mode (see:
-Documents/power/basic-pm-debugging.txt, 1a)).
+a) Build the driver as a module, load it and try the test modes of hibernation
+ (see: Documents/power/basic-pm-debugging.txt, 1).

-b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown"
-and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
+b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and
+ "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).

-c) Compile the driver directly into the kernel and try the STD in the test mode.
+c) Compile the driver directly into the kernel and try the test modes of
+ hibernation.

-d) Attempt to suspend to disk with the driver compiled directly into the kernel
-in the "reboot", "shutdown" and "platform" modes.
+d) Attempt to hibernate with the driver compiled directly into the kernel
+ in the "reboot", "shutdown" and "platform" modes.

-e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see:
-Documents/power/basic-pm-debugging.txt, 2). As far as the STR tests are
-concerned, it should not matter whether or not the driver is built as a module.
+e) Try the test modes of suspend (see: Documents/power/basic-pm-debugging.txt,
+ 2). [As far as the STR tests are concerned, it should not matter whether or
+ not the driver is built as a module.]
+
+f) Attempt to suspend to RAM using the s2ram tool with the driver loaded
+ (see: Documents/power/basic-pm-debugging.txt, 2).

Each of the above tests should be repeated several times and the STD tests
should be mixed with the STR tests. If any of them fails, the driver cannot be
--
1.5.4.rc5.16.gc0279

2008-02-01 04:49:45

by Len Brown

[permalink] [raw]
Subject: [PATCH 14/37] PM: Convert PM notifiers to out-of-line code

From: Alan Stern <[email protected]>

This patch (as1008b) converts the PM notifier routines from inline
calls to out-of-line code. It also prevents pm_chain_head from
being created when CONFIG_PM_SLEEP isn't enabled, and EXPORTs the
notifier registration and unregistration routines.

Signed-off-by: Alan Stern <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
include/linux/suspend.h | 13 ++-----------
kernel/power/main.c | 28 ++++++++++++++++++++++++++--
kernel/power/power.h | 12 ++++--------
3 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 40280df..51283e0 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -213,17 +213,8 @@ void save_processor_state(void);
void restore_processor_state(void);

/* kernel/power/main.c */
-extern struct blocking_notifier_head pm_chain_head;
-
-static inline int register_pm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&pm_chain_head, nb);
-}
-
-static inline int unregister_pm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&pm_chain_head, nb);
-}
+extern int register_pm_notifier(struct notifier_block *nb);
+extern int unregister_pm_notifier(struct notifier_block *nb);

#define pm_notifier(fn, pri) { \
static struct notifier_block fn##_nb = \
diff --git a/kernel/power/main.c b/kernel/power/main.c
index fc717b8..0a9f269 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -24,13 +24,37 @@

#include "power.h"

-BLOCKING_NOTIFIER_HEAD(pm_chain_head);
-
DEFINE_MUTEX(pm_mutex);

unsigned int pm_flags;
EXPORT_SYMBOL(pm_flags);

+#ifdef CONFIG_PM_SLEEP
+
+/* Routines for PM-transition notifications */
+
+static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+
+int register_pm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&pm_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(register_pm_notifier);
+
+int unregister_pm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&pm_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_pm_notifier);
+
+int pm_notifier_call_chain(unsigned long val)
+{
+ return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
+ == NOTIFY_BAD) ? -EINVAL : 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
#ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE;

diff --git a/kernel/power/power.h b/kernel/power/power.h
index f9f0d4d..a9732fd 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -172,14 +172,10 @@ static inline int suspend_devices_and_enter(suspend_state_t state)
}
#endif /* !CONFIG_SUSPEND */

-/* kernel/power/common.c */
-extern struct blocking_notifier_head pm_chain_head;
-
-static inline int pm_notifier_call_chain(unsigned long val)
-{
- return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
- == NOTIFY_BAD) ? -EINVAL : 0;
-}
+#ifdef CONFIG_PM_SLEEP
+/* kernel/power/main.c */
+extern int pm_notifier_call_chain(unsigned long val);
+#endif

#ifdef CONFIG_HIGHMEM
unsigned int count_highmem_pages(void);
--
1.5.4.rc5.16.gc0279

2008-02-01 04:50:22

by Len Brown

[permalink] [raw]
Subject: [PATCH 25/37] suspend: fix ia64 allmodconfig build

From: Rafael J. Wysocki <[email protected]>

kernel/power/main.c:488: error: ‘pm_test_attr’ undeclared here (not in a function)

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/main.c | 7 ++-----
1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index 5688168..050a607 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -53,10 +53,6 @@ int pm_notifier_call_chain(unsigned long val)
== NOTIFY_BAD) ? -EINVAL : 0;
}

-#endif /* CONFIG_PM_SLEEP */
-
-#ifdef CONFIG_SUSPEND
-
#ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE;

@@ -132,6 +128,7 @@ power_attr(pm_test);
static inline int suspend_test(int level) { return 0; }
#endif /* !CONFIG_PM_DEBUG */

+#endif /* CONFIG_PM_SLEEP */

#ifdef CONFIG_SUSPEND

@@ -495,7 +492,7 @@ static struct attribute * g[] = {
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
#endif
-#ifdef CONFIG_PM_DEBUG
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
&pm_test_attr.attr,
#endif
NULL,
--
1.5.4.rc5.16.gc0279

2008-02-01 04:50:57

by Len Brown

[permalink] [raw]
Subject: [PATCH 21/37] Hibernation: Update messages

From: Rafael J. Wysocki <[email protected]>

Make hibernation messages start with one common prefix "PM: " and use
the word "hibernation" in the messages as a synonym of "suspend to
disk".

Turn some KERN_INFO messages into debug ones.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/disk.c | 28 +++++++++++++++-------------
kernel/power/snapshot.c | 23 ++++++++++++-----------
kernel/power/swap.c | 31 +++++++++++++++++--------------
kernel/power/swsusp.c | 5 +++--
4 files changed, 47 insertions(+), 40 deletions(-)

diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 3e24a20..64e42ab 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -191,8 +191,8 @@ int create_image(int platform_mode)
*/
error = device_power_down(PMSG_FREEZE);
if (error) {
- printk(KERN_ERR "Some devices failed to power down, "
- KERN_ERR "aborting suspend\n");
+ printk(KERN_ERR "PM: Some devices failed to power down, "
+ "aborting hibernation\n");
goto Enable_irqs;
}

@@ -203,7 +203,8 @@ int create_image(int platform_mode)
save_processor_state();
error = swsusp_arch_suspend();
if (error)
- printk(KERN_ERR "Error %d while creating the image\n", error);
+ printk(KERN_ERR "PM: Error %d creating hibernation image\n",
+ error);
/* Restore control flow magically appears here */
restore_processor_state();
if (!in_suspend)
@@ -289,7 +290,7 @@ static int resume_target_kernel(void)
local_irq_disable();
error = device_power_down(PMSG_PRETHAW);
if (error) {
- printk(KERN_ERR "Some devices failed to power down, "
+ printk(KERN_ERR "PM: Some devices failed to power down, "
"aborting resume\n");
goto Enable_irqs;
}
@@ -438,7 +439,7 @@ static void power_down(void)
* Valid image is on the disk, if we continue we risk serious data
* corruption after resume.
*/
- printk(KERN_CRIT "Please power me down manually\n");
+ printk(KERN_CRIT "PM: Please power down manually\n");
while(1);
}

@@ -484,7 +485,7 @@ int hibernate(void)
if (error)
goto Exit;

- printk("Syncing filesystems ... ");
+ printk(KERN_INFO "PM: Syncing filesystems ... ");
sys_sync();
printk("done.\n");

@@ -560,10 +561,11 @@ static int software_resume(void)
return -ENOENT;
}
swsusp_resume_device = name_to_dev_t(resume_file);
- pr_debug("swsusp: Resume From Partition %s\n", resume_file);
+ pr_debug("PM: Resume from partition %s\n", resume_file);
} else {
- pr_debug("swsusp: Resume From Partition %d:%d\n",
- MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+ pr_debug("PM: Resume from partition %d:%d\n",
+ MAJOR(swsusp_resume_device),
+ MINOR(swsusp_resume_device));
}

if (noresume) {
@@ -575,7 +577,7 @@ static int software_resume(void)
return 0;
}

- pr_debug("PM: Checking swsusp image.\n");
+ pr_debug("PM: Checking hibernation image.\n");
error = swsusp_check();
if (error)
goto Unlock;
@@ -601,7 +603,7 @@ static int software_resume(void)
goto Done;
}

- pr_debug("PM: Reading swsusp image.\n");
+ pr_debug("PM: Reading hibernation image.\n");

error = swsusp_read(&flags);
if (!error)
@@ -728,7 +730,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
error = -EINVAL;

if (!error)
- pr_debug("PM: suspend-to-disk mode set to '%s'\n",
+ pr_debug("PM: Hibernation mode set to '%s'\n",
hibernation_modes[mode]);
mutex_unlock(&pm_mutex);
return error ? error : n;
@@ -760,7 +762,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
mutex_lock(&pm_mutex);
swsusp_resume_device = res;
mutex_unlock(&pm_mutex);
- printk("Attempting manual resume\n");
+ printk(KERN_INFO "PM: Starting manual resume from disk\n");
noresume = 0;
software_resume();
ret = n;
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 1ec3ecc..f6a5df9 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -635,7 +635,7 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
region->end_pfn = end_pfn;
list_add_tail(&region->list, &nosave_regions);
Report:
- printk("swsusp: Registered nosave memory region: %016lx - %016lx\n",
+ printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n",
start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
}

@@ -704,7 +704,7 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
list_for_each_entry(region, &nosave_regions, list) {
unsigned long pfn;

- printk("swsusp: Marking nosave pages: %016lx - %016lx\n",
+ pr_debug("PM: Marking nosave pages: %016lx - %016lx\n",
region->start_pfn << PAGE_SHIFT,
region->end_pfn << PAGE_SHIFT);

@@ -749,7 +749,7 @@ int create_basic_memory_bitmaps(void)
free_pages_map = bm2;
mark_nosave_pages(forbidden_pages_map);

- printk("swsusp: Basic memory bitmaps created\n");
+ pr_debug("PM: Basic memory bitmaps created\n");

return 0;

@@ -784,7 +784,7 @@ void free_basic_memory_bitmaps(void)
memory_bm_free(bm2, PG_UNSAFE_CLEAR);
kfree(bm2);

- printk("swsusp: Basic memory bitmaps freed\n");
+ pr_debug("PM: Basic memory bitmaps freed\n");
}

/**
@@ -1088,7 +1088,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
}

nr_pages += count_pages_for_highmem(nr_highmem);
- pr_debug("swsusp: Normal pages needed: %u + %u + %u, available pages: %u\n",
+ pr_debug("PM: Normal pages needed: %u + %u + %u, available pages: %u\n",
nr_pages, PAGES_FOR_IO, meta, free);

return free > nr_pages + PAGES_FOR_IO + meta;
@@ -1201,20 +1201,20 @@ asmlinkage int swsusp_save(void)
{
unsigned int nr_pages, nr_highmem;

- printk("swsusp: critical section: \n");
+ printk(KERN_INFO "PM: Creating hibernation image: \n");

drain_local_pages();
nr_pages = count_data_pages();
nr_highmem = count_highmem_pages();
- printk("swsusp: Need to copy %u pages\n", nr_pages + nr_highmem);
+ printk(KERN_INFO "PM: Need to copy %u pages\n", nr_pages + nr_highmem);

if (!enough_free_mem(nr_pages, nr_highmem)) {
- printk(KERN_ERR "swsusp: Not enough free memory\n");
+ printk(KERN_ERR "PM: Not enough free memory\n");
return -ENOMEM;
}

if (swsusp_alloc(&orig_bm, &copy_bm, nr_pages, nr_highmem)) {
- printk(KERN_ERR "swsusp: Memory allocation failed\n");
+ printk(KERN_ERR "PM: Memory allocation failed\n");
return -ENOMEM;
}

@@ -1234,7 +1234,8 @@ asmlinkage int swsusp_save(void)
nr_copy_pages = nr_pages;
nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);

- printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);
+ printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n",
+ nr_pages);

return 0;
}
@@ -1433,7 +1434,7 @@ static int check_header(struct swsusp_info *info)
if (!reason && info->num_physpages != num_physpages)
reason = "memory size";
if (reason) {
- printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
+ printk(KERN_ERR "PM: Image mismatch: %s\n", reason);
return -EPERM;
}
return 0;
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index ef41440..a0abf9a 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -71,7 +71,8 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
bio->bi_end_io = end_swap_bio_read;

if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
- printk("swsusp: ERROR: adding page to bio at %ld\n", page_off);
+ printk(KERN_ERR "PM: Adding page to bio failed at %ld\n",
+ page_off);
bio_put(bio);
return -EFAULT;
}
@@ -151,7 +152,7 @@ static int mark_swapfiles(sector_t start, unsigned int flags)
error = bio_write_page(swsusp_resume_block,
swsusp_header, NULL);
} else {
- printk(KERN_ERR "swsusp: Swap header not found!\n");
+ printk(KERN_ERR "PM: Swap header not found!\n");
error = -ENODEV;
}
return error;
@@ -323,7 +324,8 @@ static int save_image(struct swap_map_handle *handle,
struct timeval start;
struct timeval stop;

- printk("Saving image data pages (%u pages) ... ", nr_to_write);
+ printk(KERN_INFO "PM: Saving image data pages (%u pages) ... ",
+ nr_to_write);
m = nr_to_write / 100;
if (!m)
m = 1;
@@ -363,7 +365,7 @@ static int enough_swap(unsigned int nr_pages)
{
unsigned int free_swap = count_swap_pages(root_swap, 1);

- pr_debug("swsusp: free swap pages: %u\n", free_swap);
+ pr_debug("PM: Free swap pages: %u\n", free_swap);
return free_swap > nr_pages + PAGES_FOR_IO;
}

@@ -386,7 +388,7 @@ int swsusp_write(unsigned int flags)

error = swsusp_swap_check();
if (error) {
- printk(KERN_ERR "swsusp: Cannot find swap device, try "
+ printk(KERN_ERR "PM: Cannot find swap device, try "
"swapon -a.\n");
return error;
}
@@ -400,7 +402,7 @@ int swsusp_write(unsigned int flags)
}
header = (struct swsusp_info *)data_of(snapshot);
if (!enough_swap(header->pages)) {
- printk(KERN_ERR "swsusp: Not enough free swap\n");
+ printk(KERN_ERR "PM: Not enough free swap\n");
error = -ENOSPC;
goto out;
}
@@ -415,7 +417,7 @@ int swsusp_write(unsigned int flags)

if (!error) {
flush_swap_writer(&handle);
- printk("S");
+ printk(KERN_INFO "PM: S");
error = mark_swapfiles(start, flags);
printk("|\n");
}
@@ -505,7 +507,8 @@ static int load_image(struct swap_map_handle *handle,
int err2;
unsigned nr_pages;

- printk("Loading image data pages (%u pages) ... ", nr_to_read);
+ printk(KERN_INFO "PM: Loading image data pages (%u pages) ... ",
+ nr_to_read);
m = nr_to_read / 100;
if (!m)
m = 1;
@@ -556,7 +559,7 @@ int swsusp_read(unsigned int *flags_p)

*flags_p = swsusp_header->flags;
if (IS_ERR(resume_bdev)) {
- pr_debug("swsusp: block device not initialised\n");
+ pr_debug("PM: Image device not initialised\n");
return PTR_ERR(resume_bdev);
}

@@ -575,9 +578,9 @@ int swsusp_read(unsigned int *flags_p)
blkdev_put(resume_bdev);

if (!error)
- pr_debug("swsusp: Reading resume file was successful\n");
+ pr_debug("PM: Image successfully loaded\n");
else
- pr_debug("swsusp: Error %d resuming\n", error);
+ pr_debug("PM: Error %d resuming\n", error);
return error;
}

@@ -609,13 +612,13 @@ int swsusp_check(void)
if (error)
blkdev_put(resume_bdev);
else
- pr_debug("swsusp: Signature found, resuming\n");
+ pr_debug("PM: Signature found, resuming\n");
} else {
error = PTR_ERR(resume_bdev);
}

if (error)
- pr_debug("swsusp: Error %d check for resume file\n", error);
+ pr_debug("PM: Error %d checking image file\n", error);

return error;
}
@@ -627,7 +630,7 @@ int swsusp_check(void)
void swsusp_close(void)
{
if (IS_ERR(resume_bdev)) {
- pr_debug("swsusp: block device not initialised\n");
+ pr_debug("PM: Image device not initialised\n");
return;
}

diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index dc29a20..023ff2a 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -188,7 +188,8 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
centisecs = 1; /* avoid div-by-zero */
k = nr_pages * (PAGE_SIZE / 1024);
kps = (k * 100) / centisecs;
- printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k,
+ printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
+ msg, k,
centisecs / 100, centisecs % 100,
kps / 1000, (kps % 1000) / 10);
}
@@ -219,7 +220,7 @@ int swsusp_shrink_memory(void)
char *p = "-\\|/";
struct timeval start, stop;

- printk("Shrinking memory... ");
+ printk(KERN_INFO "PM: Shrinking memory... ");
do_gettimeofday(&start);
do {
long size, highmem_size;
--
1.5.4.rc5.16.gc0279

2008-02-01 04:51:28

by Len Brown

[permalink] [raw]
Subject: [PATCH 31/37] ACPI hibernation: Call _PTS before suspending devices

From: Rafael J. Wysocki <[email protected]>

The ACPI 1.0 specification wants us to put devices into low power
states after executing the _PTS global control method, while ACPI
2.0 and later want us to do that in the reverse order. The current
hibernation code follows ACPI 2.0 in that respect which may cause some
ACPI 1.0x systems to hang during hibernation (ref.
http://bugzilla.kernel.org/show_bug.cgi?id=9528).

Make the hibernation code execute _PTS before putting devices into
low power states (ie. in accordance with ACPI 1.0x) with the
possibility to override that using the 'acpi_new_pts_ordering' kernel
command line option.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/acpi/sleep/main.c | 36 +++++++++++++++++++++++++-----------
1 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 31e8e58..10db899 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -283,22 +283,34 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
#ifdef CONFIG_HIBERNATION
static int acpi_hibernation_begin(void)
{
+ int error;
+
acpi_target_sleep_state = ACPI_STATE_S4;
- return 0;
+ if (new_pts_ordering)
+ return 0;
+
+ error = acpi_sleep_prepare(ACPI_STATE_S4);
+ if (error)
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ else
+ acpi_sleep_finish_wake_up = true;
+
+ return error;
}

static int acpi_hibernation_prepare(void)
{
- int error;
-
- error = acpi_sleep_prepare(ACPI_STATE_S4);
- if (error)
- return error;
+ if (new_pts_ordering) {
+ int error = acpi_sleep_prepare(ACPI_STATE_S4);

- if (!ACPI_SUCCESS(acpi_hw_disable_all_gpes()))
- error = -EFAULT;
+ if (error) {
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ return error;
+ }
+ acpi_sleep_finish_wake_up = true;
+ }

- return error;
+ return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
}

static int acpi_hibernation_enter(void)
@@ -339,15 +351,17 @@ static void acpi_hibernation_finish(void)
acpi_set_firmware_waking_vector((acpi_physical_address) 0);

acpi_target_sleep_state = ACPI_STATE_S0;
+ acpi_sleep_finish_wake_up = false;
}

static void acpi_hibernation_end(void)
{
/*
* This is necessary in case acpi_hibernation_finish() is not called
- * during a failing transition to the sleep state.
+ * directly during a failing transition to the sleep state.
*/
- acpi_target_sleep_state = ACPI_STATE_S0;
+ if (acpi_sleep_finish_wake_up)
+ acpi_hibernation_finish();
}

static int acpi_hibernation_pre_restore(void)
--
1.5.4.rc5.16.gc0279

2008-02-01 04:51:51

by Len Brown

[permalink] [raw]
Subject: [PATCH 22/37] Hibernation: Clean up Kconfig (V2)

From: Johannes Berg <[email protected]>

This cleans up the hibernation Kconfig and removes the need to
declare centrally which architectures support hibernation. All
architectures that currently support hibernation are modified
accordingly.

Signed-off-by: Johannes Berg <[email protected]>
Acked-by: Paul Mackerras <[email protected]>
Cc: Pavel Machek <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
arch/powerpc/Kconfig | 14 ++++++++++++--
arch/x86/Kconfig | 4 ++++
kernel/power/Kconfig | 18 +++---------------
3 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 9c44af3..68f0cf7 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -151,9 +151,19 @@ config DEFAULT_UIMAGE
config REDBOOT
bool

-config PPC64_SWSUSP
+config HIBERNATE_32
bool
- depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
+ depends on (PPC_PMAC && !SMP) || BROKEN
+ default y
+
+config HIBERNATE_64
+ bool
+ depends on BROKEN || (PPC_PMAC64 && EXPERIMENTAL)
+ default y
+
+config ARCH_HIBERNATION_POSSIBLE
+ bool
+ depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
default y

config PPC_DCR_NATIVE
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 65b4491..9c511dd 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -109,6 +109,10 @@ config ARCH_SUPPORTS_OPROFILE

select HAVE_KVM

+config ARCH_HIBERNATION_POSSIBLE
+ def_bool y
+ depends on !SMP || !X86_VOYAGER
+
config ZONE_DMA32
bool
default X86_64
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 06a08f7..fd76d54 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -84,7 +84,8 @@ config PM_TRACE_RTC

config PM_SLEEP_SMP
bool
- depends on SUSPEND_SMP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
+ depends on SMP
+ depends on SUSPEND_SMP_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
depends on PM_SLEEP
select HOTPLUG_CPU
default y
@@ -118,22 +119,9 @@ config SUSPEND
powered and thus its contents are preserved, such as the
suspend-to-RAM state (i.e. the ACPI S3 state).

-config HIBERNATION_UP_POSSIBLE
- bool
- depends on X86 || PPC64_SWSUSP || PPC32
- depends on !SMP
- default y
-
-config HIBERNATION_SMP_POSSIBLE
- bool
- depends on (X86 && !X86_VOYAGER) || PPC64_SWSUSP
- depends on SMP
- default y
-
config HIBERNATION
bool "Hibernation (aka 'suspend to disk')"
- depends on PM && SWAP
- depends on HIBERNATION_UP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
+ depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
---help---
Enable the suspend to disk (STD) functionality, which is usually
called "hibernation" in user interfaces. STD checkpoints the
--
1.5.4.rc5.16.gc0279

2008-02-01 04:52:25

by Len Brown

[permalink] [raw]
Subject: [PATCH 28/37] ACPI: Separate disabling of GPEs from _PTS

From: Rafael J. Wysocki <[email protected]>

The preparation to enter an ACPI system sleep state is now tied to
the disabling of GPEs, but the GPEs should not be disabled before
suspending devices. Since on ACPI 1.0x systems the _PTS global
control method should be executed before suspending devices, we
need to disable GPEs separately.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/acpi/hardware/hwsleep.c | 4 ----
drivers/acpi/sleep/main.c | 17 +++++++++++++++--
2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 13c93a1..fd1c4ba 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -229,10 +229,6 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
"While executing method _SST"));
}

- /* Disable/Clear all GPEs */
-
- status = acpi_hw_disable_all_gpes();
-
return_ACPI_STATUS(status);
}

diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index fdd8139..198ff8a 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -91,10 +91,13 @@ static int acpi_pm_begin(suspend_state_t pm_state)

static int acpi_pm_prepare(void)
{
- int error = acpi_sleep_prepare(acpi_target_sleep_state);
+ int error;

+ error = acpi_sleep_prepare(acpi_target_sleep_state);
if (error)
acpi_target_sleep_state = ACPI_STATE_S0;
+ else if (!ACPI_SUCCESS(acpi_hw_disable_all_gpes()))
+ error = -EFAULT;

return error;
}
@@ -261,7 +264,16 @@ static int acpi_hibernation_start(void)

static int acpi_hibernation_prepare(void)
{
- return acpi_sleep_prepare(ACPI_STATE_S4);
+ int error;
+
+ error = acpi_sleep_prepare(ACPI_STATE_S4);
+ if (error)
+ return error;
+
+ if (!ACPI_SUCCESS(acpi_hw_disable_all_gpes()))
+ error = -EFAULT;
+
+ return error;
}

static int acpi_hibernation_enter(void)
@@ -426,6 +438,7 @@ static void acpi_power_off_prepare(void)
{
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
+ acpi_hw_disable_all_gpes();
}

static void acpi_power_off(void)
--
1.5.4.rc5.16.gc0279

2008-02-01 04:52:50

by Len Brown

[permalink] [raw]
Subject: [PATCH 30/37] Hibernation: Introduce begin() and end() callbacks

From: Rafael J. Wysocki <[email protected]>

Introduce global hibernation callback .end() and rename global
hibernation callback .start() to .begin(), in analogy with the
recent modifications of the global suspend callbacks.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/acpi/sleep/main.c | 14 ++++++++++++--
include/linux/suspend.h | 14 +++++++++-----
kernel/power/disk.c | 33 ++++++++++++++++++++++++---------
3 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index c37c4ea..31e8e58 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -281,7 +281,7 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
#endif /* CONFIG_SUSPEND */

#ifdef CONFIG_HIBERNATION
-static int acpi_hibernation_start(void)
+static int acpi_hibernation_begin(void)
{
acpi_target_sleep_state = ACPI_STATE_S4;
return 0;
@@ -341,6 +341,15 @@ static void acpi_hibernation_finish(void)
acpi_target_sleep_state = ACPI_STATE_S0;
}

+static void acpi_hibernation_end(void)
+{
+ /*
+ * This is necessary in case acpi_hibernation_finish() is not called
+ * during a failing transition to the sleep state.
+ */
+ acpi_target_sleep_state = ACPI_STATE_S0;
+}
+
static int acpi_hibernation_pre_restore(void)
{
acpi_status status;
@@ -356,7 +365,8 @@ static void acpi_hibernation_restore_cleanup(void)
}

static struct platform_hibernation_ops acpi_hibernation_ops = {
- .start = acpi_hibernation_start,
+ .begin = acpi_hibernation_begin,
+ .end = acpi_hibernation_end,
.pre_snapshot = acpi_hibernation_prepare,
.finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index a0b1dbb..646ce2d 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -136,14 +136,17 @@ extern void mark_free_pages(struct zone *zone);
/**
* struct platform_hibernation_ops - hibernation platform support
*
- * The methods in this structure allow a platform to override the default
- * mechanism of shutting down the machine during a hibernation transition.
+ * The methods in this structure allow a platform to carry out special
+ * operations required by it during a hibernation transition.
*
- * All three methods must be assigned.
+ * All the methods below must be implemented.
*
- * @start: Tell the platform driver that we're starting hibernation.
+ * @begin: Tell the platform driver that we're starting hibernation.
* Called right after shrinking memory and before freezing devices.
*
+ * @end: Called by the PM core right after resuming devices, to indicate to
+ * the platform that the system has returned to the working state.
+ *
* @pre_snapshot: Prepare the platform for creating the hibernation image.
* Called right after devices have been frozen and before the nonboot
* CPUs are disabled (runs with IRQs on).
@@ -178,7 +181,8 @@ extern void mark_free_pages(struct zone *zone);
* thawing devices (runs with IRQs on).
*/
struct platform_hibernation_ops {
- int (*start)(void);
+ int (*begin)(void);
+ void (*end)(void);
int (*pre_snapshot)(void);
void (*finish)(void);
int (*prepare)(void);
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 64e42ab..53c22d9 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -54,8 +54,8 @@ static struct platform_hibernation_ops *hibernation_ops;

void hibernation_set_ops(struct platform_hibernation_ops *ops)
{
- if (ops && !(ops->start && ops->pre_snapshot && ops->finish
- && ops->prepare && ops->enter && ops->pre_restore
+ if (ops && !(ops->begin && ops->end && ops->pre_snapshot
+ && ops->prepare && ops->finish && ops->enter && ops->pre_restore
&& ops->restore_cleanup)) {
WARN_ON(1);
return;
@@ -100,14 +100,25 @@ static int hibernation_test(int level) { return 0; }
#endif /* !CONFIG_PM_DEBUG */

/**
- * platform_start - tell the platform driver that we're starting
+ * platform_begin - tell the platform driver that we're starting
* hibernation
*/

-static int platform_start(int platform_mode)
+static int platform_begin(int platform_mode)
{
return (platform_mode && hibernation_ops) ?
- hibernation_ops->start() : 0;
+ hibernation_ops->begin() : 0;
+}
+
+/**
+ * platform_end - tell the platform driver that we've entered the
+ * working state
+ */
+
+static void platform_end(int platform_mode)
+{
+ if (platform_mode && hibernation_ops)
+ hibernation_ops->end();
}

/**
@@ -237,9 +248,9 @@ int hibernation_snapshot(int platform_mode)
if (error)
return error;

- error = platform_start(platform_mode);
+ error = platform_begin(platform_mode);
if (error)
- return error;
+ goto Close;

suspend_console();
error = device_suspend(PMSG_FREEZE);
@@ -272,6 +283,8 @@ int hibernation_snapshot(int platform_mode)
device_resume();
Resume_console:
resume_console();
+ Close:
+ platform_end(platform_mode);
return error;
}

@@ -373,9 +386,9 @@ int hibernation_platform_enter(void)
* hibernation_ops->finish() before saving the image, so we should let
* the firmware know that we're going to enter the sleep state after all
*/
- error = hibernation_ops->start();
+ error = hibernation_ops->begin();
if (error)
- return error;
+ goto Close;

suspend_console();
error = device_suspend(PMSG_SUSPEND);
@@ -409,6 +422,8 @@ int hibernation_platform_enter(void)
device_resume();
Resume_console:
resume_console();
+ Close:
+ hibernation_ops->end();
return error;
}

--
1.5.4.rc5.16.gc0279

2008-02-01 04:53:17

by Len Brown

[permalink] [raw]
Subject: [PATCH 32/37] ACPI: Print message before calling _PTS

From: Rafael J. Wysocki <[email protected]>

Make acpi_sleep_prepare() static and cause it to print a message
specifying the ACPI system sleep state to be entered (helpful for
debugging the suspend/hibernation code).

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/acpi/sleep/main.c | 4 +++-
drivers/acpi/sleep/sleep.h | 2 --
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 10db899..485de13 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -43,7 +43,7 @@ static int __init acpi_new_pts_ordering(char *str)
__setup("acpi_new_pts_ordering", acpi_new_pts_ordering);
#endif

-int acpi_sleep_prepare(u32 acpi_state)
+static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
/* do we have a wakeup address for S2 and S3? */
@@ -59,6 +59,8 @@ int acpi_sleep_prepare(u32 acpi_state)
ACPI_FLUSH_CPU_CACHE();
acpi_enable_wakeup_device_prep(acpi_state);
#endif
+ printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
+ acpi_state);
acpi_enter_sleep_state_prep(acpi_state);
return 0;
}
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
index a2ea125..cfaf8f5 100644
--- a/drivers/acpi/sleep/sleep.h
+++ b/drivers/acpi/sleep/sleep.h
@@ -5,5 +5,3 @@ extern int acpi_suspend (u32 state);
extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
extern void acpi_enable_wakeup_device(u8 sleep_state);
extern void acpi_disable_wakeup_device(u8 sleep_state);
-
-extern int acpi_sleep_prepare(u32 acpi_state);
--
1.5.4.rc5.16.gc0279

2008-02-01 04:53:37

by Len Brown

[permalink] [raw]
Subject: [PATCH 35/37] Suspend: Invoke suspend notifications after console switch

From: Johannes Berg <[email protected]>

In order to fix APM emulation it is necessary to enable apm-emulation
notifications for suspends triggered in various ways via the suspend
notifiers. However, this will cause the systems using APM emulation
to lock up between X being needed to switch away from the VT and X
already waiting for resume in the APM ioctl.

This patch moves the console switch (if enabled) before the suspend
notification (and after the resume notification) to avoid this issue.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/main.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index e47214c..6a6d5eb 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -175,12 +175,12 @@ static int suspend_prepare(void)
if (!suspend_ops || !suspend_ops->enter)
return -EPERM;

+ pm_prepare_console();
+
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
if (error)
goto Finish;

- pm_prepare_console();
-
if (suspend_freeze_processes()) {
error = -EAGAIN;
goto Thaw;
@@ -200,9 +200,9 @@ static int suspend_prepare(void)

Thaw:
suspend_thaw_processes();
- pm_restore_console();
Finish:
pm_notifier_call_chain(PM_POST_SUSPEND);
+ pm_restore_console();
return error;
}

@@ -309,8 +309,8 @@ int suspend_devices_and_enter(suspend_state_t state)
static void suspend_finish(void)
{
suspend_thaw_processes();
- pm_restore_console();
pm_notifier_call_chain(PM_POST_SUSPEND);
+ pm_restore_console();
}


--
1.5.4.rc5.16.gc0279

2008-02-01 04:53:54

by Len Brown

[permalink] [raw]
Subject: [PATCH 37/37] PM: Remove obsolete /sys/devices/.../power/state docs

From: David Brownell <[email protected]>

The /sys/devices/.../power/state files have been gone for a while
now, but I just noticed some documentation that still refers to
them. (Fortunately described as DEPRECATED and WILL REMOVE).

Time to remove that obsolete documentation too ...

Signed-off-by: David Brownell <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/devices.txt | 49 ---------------------------------------
1 files changed, 0 insertions(+), 49 deletions(-)

diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index d0e79d5..c53d263 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -502,52 +502,3 @@ If the CPU can have a "cpufreq" driver, there also may be opportunities
to shift to lower voltage settings and reduce the power cost of executing
a given number of instructions. (Without voltage adjustment, it's rare
for cpufreq to save much power; the cost-per-instruction must go down.)
-
-
-/sys/devices/.../power/state files
-==================================
-For now you can also test some of this functionality using sysfs.
-
- DEPRECATED: USE "power/state" ONLY FOR DRIVER TESTING, AND
- AVOID USING dev->power.power_state IN DRIVERS.
-
- THESE WILL BE REMOVED. IF THE "power/state" FILE GETS REPLACED,
- IT WILL BECOME SOMETHING COUPLED TO THE BUS OR DRIVER.
-
-In each device's directory, there is a 'power' directory, which contains
-at least a 'state' file. The value of this field is effectively boolean,
-PM_EVENT_ON or PM_EVENT_SUSPEND.
-
- * Reading from this file displays a value corresponding to
- the power.power_state.event field. All nonzero values are
- displayed as "2", corresponding to a low power state; zero
- is displayed as "0", corresponding to normal operation.
-
- * Writing to this file initiates a transition using the
- specified event code number; only '0', '2', and '3' are
- accepted (without a newline); '2' and '3' are both
- mapped to PM_EVENT_SUSPEND.
-
-On writes, the PM core relies on that recorded event code and the device/bus
-capabilities to determine whether it uses a partial suspend() or resume()
-sequence to change things so that the recorded event corresponds to the
-numeric parameter.
-
- - If the bus requires the irqs-disabled suspend_late()/resume_early()
- phases, writes fail because those operations are not supported here.
-
- - If the recorded value is the expected value, nothing is done.
-
- - If the recorded value is nonzero, the device is partially resumed,
- using the bus.resume() and/or class.resume() methods.
-
- - If the target value is nonzero, the device is partially suspended,
- using the class.suspend() and/or bus.suspend() methods and the
- PM_EVENT_SUSPEND message.
-
-Drivers have no way to tell whether their suspend() and resume() calls
-have come through the sysfs power/state file or as part of entering a
-system sleep state, except that when accessed through sysfs the normal
-parent/child sequencing rules are ignored. Drivers (such as bus, bridge,
-or hub drivers) which expose child devices may need to enforce those rules
-on their own.
--
1.5.4.rc5.16.gc0279

2008-02-01 04:54:32

by Len Brown

[permalink] [raw]
Subject: [PATCH 36/37] Hibernation: Invoke suspend notifications after console switch

From: Rafael J. Wysocki <[email protected]>

Following the recent change in the suspend code path, switch consoles before
calling PM notifiers during hibernation.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/disk.c | 17 +++++++----------
1 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 53c22d9..d09da08 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -458,20 +458,13 @@ static void power_down(void)
while(1);
}

-static void unprepare_processes(void)
-{
- thaw_processes();
- pm_restore_console();
-}
-
static int prepare_processes(void)
{
int error = 0;

- pm_prepare_console();
if (freeze_processes()) {
error = -EBUSY;
- unprepare_processes();
+ thaw_processes();
}
return error;
}
@@ -491,6 +484,7 @@ int hibernate(void)
goto Unlock;
}

+ pm_prepare_console();
error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
if (error)
goto Exit;
@@ -530,11 +524,12 @@ int hibernate(void)
swsusp_free();
}
Thaw:
- unprepare_processes();
+ thaw_processes();
Finish:
free_basic_memory_bitmaps();
Exit:
pm_notifier_call_chain(PM_POST_HIBERNATION);
+ pm_restore_console();
atomic_inc(&snapshot_device_available);
Unlock:
mutex_unlock(&pm_mutex);
@@ -603,6 +598,7 @@ static int software_resume(void)
goto Unlock;
}

+ pm_prepare_console();
error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
if (error)
goto Finish;
@@ -626,11 +622,12 @@ static int software_resume(void)

printk(KERN_ERR "PM: Restore failed, recovering.\n");
swsusp_free();
- unprepare_processes();
+ thaw_processes();
Done:
free_basic_memory_bitmaps();
Finish:
pm_notifier_call_chain(PM_POST_RESTORE);
+ pm_restore_console();
atomic_inc(&snapshot_device_available);
/* For success case, the suspend path will release the lock */
Unlock:
--
1.5.4.rc5.16.gc0279

2008-02-01 04:54:54

by Len Brown

[permalink] [raw]
Subject: [PATCH 17/37] Suspend: Fix comment in main.c

From: Rafael J. Wysocki <[email protected]>

Fix a comment in kernel/power/main.c so that it doesn't contain lines
longer that 80 characters.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/main.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index 7fb805d..d0cedaa 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -250,8 +250,8 @@ static int suspend_enter(suspend_state_t state)
}

/**
- * suspend_devices_and_enter - suspend devices and enter the desired system sleep
- * state.
+ * suspend_devices_and_enter - suspend devices and enter the desired system
+ * sleep state.
* @state: state to enter
*/
int suspend_devices_and_enter(suspend_state_t state)
--
1.5.4.rc5.16.gc0279

2008-02-01 04:55:32

by Len Brown

[permalink] [raw]
Subject: [PATCH 20/37] Suspend: Use common prefix in messages

From: Rafael J. Wysocki <[email protected]>

Make suspend messages start with one common prefix "PM: ".

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/main.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index d0cedaa..5688168 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -235,7 +235,7 @@ static int suspend_enter(suspend_state_t state)
BUG_ON(!irqs_disabled());

if ((error = device_power_down(PMSG_SUSPEND))) {
- printk(KERN_ERR "Some devices failed to power down\n");
+ printk(KERN_ERR "PM: Some devices failed to power down\n");
goto Done;
}

@@ -269,7 +269,7 @@ int suspend_devices_and_enter(suspend_state_t state)
suspend_console();
error = device_suspend(PMSG_SUSPEND);
if (error) {
- printk(KERN_ERR "Some devices failed to suspend\n");
+ printk(KERN_ERR "PM: Some devices failed to suspend\n");
goto Resume_console;
}

@@ -352,7 +352,7 @@ static int enter_state(suspend_state_t state)
if (!mutex_trylock(&pm_mutex))
return -EBUSY;

- printk("Syncing filesystems ... ");
+ printk(KERN_INFO "PM: Syncing filesystems ... ");
sys_sync();
printk("done.\n");

--
1.5.4.rc5.16.gc0279

2008-02-01 04:55:56

by Len Brown

[permalink] [raw]
Subject: [PATCH 29/37] ACPI suspend: Call _PTS before suspending devices

From: Rafael J. Wysocki <[email protected]>

The ACPI 1.0 specification wants us to put devices into low power
states after executing the _PTS global control method, while ACPI
2.0 and later want us to do that in the reverse order. The current
suspend code follows ACPI 2.0 in that respect which causes some
ACPI 1.0x systems to hang during suspend (ref.
http://bugzilla.kernel.org/show_bug.cgi?id=9528).

Make the suspend code execute _PTS before putting devices into low
power states (ie. in accordance with ACPI 1.0x) and provide a command
line option to override the default if need be.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/kernel-parameters.txt | 5 +++
drivers/acpi/sleep/main.c | 51 ++++++++++++++++++++++++++---------
2 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 92c40d1..cf38689 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -168,6 +168,11 @@ and is between 256 and 4096 characters. It is defined in the file
acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA
Format: <irq>,<irq>...

+ acpi_new_pts_ordering [HW,ACPI]
+ Enforce the ACPI 2.0 ordering of the _PTS control
+ method wrt putting devices into low power states
+ default: pre ACPI 2.0 ordering of _PTS
+
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT

acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 198ff8a..c37c4ea 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -26,6 +26,21 @@ u8 sleep_states[ACPI_S_STATE_COUNT];

#ifdef CONFIG_PM_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+static bool acpi_sleep_finish_wake_up;
+
+/*
+ * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we
+ * allow the user to request that behavior by using the 'acpi_new_pts_ordering'
+ * kernel command line option that causes the following variable to be set.
+ */
+static bool new_pts_ordering;
+
+static int __init acpi_new_pts_ordering(char *str)
+{
+ new_pts_ordering = true;
+ return 1;
+}
+__setup("acpi_new_pts_ordering", acpi_new_pts_ordering);
#endif

int acpi_sleep_prepare(u32 acpi_state)
@@ -74,6 +89,14 @@ static int acpi_pm_begin(suspend_state_t pm_state)

if (sleep_states[acpi_state]) {
acpi_target_sleep_state = acpi_state;
+ if (new_pts_ordering)
+ return 0;
+
+ error = acpi_sleep_prepare(acpi_state);
+ if (error)
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ else
+ acpi_sleep_finish_wake_up = true;
} else {
printk(KERN_ERR "ACPI does not support this state: %d\n",
pm_state);
@@ -91,15 +114,17 @@ static int acpi_pm_begin(suspend_state_t pm_state)

static int acpi_pm_prepare(void)
{
- int error;
+ if (new_pts_ordering) {
+ int error = acpi_sleep_prepare(acpi_target_sleep_state);

- error = acpi_sleep_prepare(acpi_target_sleep_state);
- if (error)
- acpi_target_sleep_state = ACPI_STATE_S0;
- else if (!ACPI_SUCCESS(acpi_hw_disable_all_gpes()))
- error = -EFAULT;
+ if (error) {
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ return error;
+ }
+ acpi_sleep_finish_wake_up = true;
+ }

- return error;
+ return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
}

/**
@@ -123,10 +148,8 @@ static int acpi_pm_enter(suspend_state_t pm_state)
if (acpi_state == ACPI_STATE_S3) {
int error = acpi_save_state_mem();

- if (error) {
- acpi_target_sleep_state = ACPI_STATE_S0;
+ if (error)
return error;
- }
}

local_irq_save(flags);
@@ -187,6 +210,7 @@ static void acpi_pm_finish(void)
acpi_set_firmware_waking_vector((acpi_physical_address) 0);

acpi_target_sleep_state = ACPI_STATE_S0;
+ acpi_sleep_finish_wake_up = false;

#ifdef CONFIG_X86
if (init_8259A_after_S1) {
@@ -203,10 +227,11 @@ static void acpi_pm_finish(void)
static void acpi_pm_end(void)
{
/*
- * This is necessary in case acpi_pm_finish() is not called during a
- * failing transition to a sleep state.
+ * This is necessary in case acpi_pm_finish() is not called directly
+ * during a failing transition to a sleep state.
*/
- acpi_target_sleep_state = ACPI_STATE_S0;
+ if (acpi_sleep_finish_wake_up)
+ acpi_pm_finish();
}

static int acpi_pm_state_valid(suspend_state_t pm_state)
--
1.5.4.rc5.16.gc0279

2008-02-01 04:56:35

by Len Brown

[permalink] [raw]
Subject: [PATCH 33/37] Suspend: Add config option to disable the freezer if architecture wants that

From: Johannes Berg <[email protected]>

This patch makes the freezer optional for suspend to allow the
system to work (or not work) like the original PMU suspend.

Signed-off-by: Johannes Berg <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
arch/powerpc/Kconfig | 4 ++++
kernel/power/Kconfig | 11 +++++++++++
kernel/power/main.c | 6 +++---
kernel/power/power.h | 22 ++++++++++++++++++++++
4 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 824140d..4a22c99 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -405,6 +405,10 @@ config CMDLINE
most cases you will need to specify the root device here.

if !44x || BROKEN
+config ARCH_WANTS_FREEZER_CONTROL
+ def_bool y
+ depends on ADB_PMU
+
source kernel/power/Kconfig
endif

diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index f8153fd..ef9b802 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -104,6 +104,17 @@ config SUSPEND
powered and thus its contents are preserved, such as the
suspend-to-RAM state (e.g. the ACPI S3 state).

+config SUSPEND_FREEZER
+ bool "Enable freezer for suspend to RAM/standby" \
+ if ARCH_WANTS_FREEZER_CONTROL || BROKEN
+ depends on SUSPEND
+ default y
+ help
+ This allows you to turn off the freezer for suspend. If this is
+ done, no tasks are frozen for suspend to RAM/standby.
+
+ Turning OFF this setting is NOT recommended! If in doubt, say Y.
+
config HIBERNATION
bool "Hibernation (aka 'suspend to disk')"
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
diff --git a/kernel/power/main.c b/kernel/power/main.c
index d9bba45..e47214c 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -181,7 +181,7 @@ static int suspend_prepare(void)

pm_prepare_console();

- if (freeze_processes()) {
+ if (suspend_freeze_processes()) {
error = -EAGAIN;
goto Thaw;
}
@@ -199,7 +199,7 @@ static int suspend_prepare(void)
return 0;

Thaw:
- thaw_processes();
+ suspend_thaw_processes();
pm_restore_console();
Finish:
pm_notifier_call_chain(PM_POST_SUSPEND);
@@ -308,7 +308,7 @@ int suspend_devices_and_enter(suspend_state_t state)
*/
static void suspend_finish(void)
{
- thaw_processes();
+ suspend_thaw_processes();
pm_restore_console();
pm_notifier_call_chain(PM_POST_SUSPEND);
}
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 8ec5499..700f44e 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -1,6 +1,7 @@
#include <linux/suspend.h>
#include <linux/suspend_ioctls.h>
#include <linux/utsname.h>
+#include <linux/freezer.h>

struct swsusp_info {
struct new_utsname uts;
@@ -203,3 +204,24 @@ enum {
#define TEST_MAX (__TEST_AFTER_LAST - 1)

extern int pm_test_level;
+
+#ifdef CONFIG_SUSPEND_FREEZER
+static inline int suspend_freeze_processes(void)
+{
+ return freeze_processes();
+}
+
+static inline void suspend_thaw_processes(void)
+{
+ thaw_processes();
+}
+#else
+static inline int suspend_freeze_processes(void)
+{
+ return 0;
+}
+
+static inline void suspend_thaw_processes(void)
+{
+}
+#endif
--
1.5.4.rc5.16.gc0279

2008-02-01 04:57:14

by Len Brown

[permalink] [raw]
Subject: [PATCH 34/37] Suspend: Clean up suspend_64.c

From: Borislav Petkov <[email protected]>

There's a freakishly long comment in suspend_64.c, shorten it.

Signed-off-by: Borislav Petkov <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
arch/x86/kernel/suspend_64.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/suspend_64.c b/arch/x86/kernel/suspend_64.c
index 0919951..7ac7130 100644
--- a/arch/x86/kernel/suspend_64.c
+++ b/arch/x86/kernel/suspend_64.c
@@ -140,7 +140,12 @@ static void fix_processor_context(void)
int cpu = smp_processor_id();
struct tss_struct *t = &per_cpu(init_tss, cpu);

- set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
+ /*
+ * This just modifies memory; should not be necessary. But... This
+ * is necessary, because 386 hardware has concept of busy TSS or some
+ * similar stupidity.
+ */
+ set_tss_desc(cpu, t);

get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;

@@ -160,7 +165,6 @@ static void fix_processor_context(void)
loaddebug(&current->thread, 6);
loaddebug(&current->thread, 7);
}
-
}

#ifdef CONFIG_HIBERNATION
--
1.5.4.rc5.16.gc0279

2008-02-01 04:57:33

by Len Brown

[permalink] [raw]
Subject: [PATCH 27/37] ACPI: Separate invocations of _GTS and _BFS from _PTS and _WAK

From: Rafael J. Wysocki <[email protected]>

The execution of ACPI global control methods _GTS and _BFS is
currently tied to the preparation to enter a sleep state and to the
leaving of the sleep state, respectively. However, these functions
are called before disabling the nonboot CPUs and after enabling
them, respectively (in fact, on ACPI 1.0x systems the first of them
ought to be called before suspending devices), while according to the
ACPI specification, _GTS is to be executed right prior to entering
the system sleep state and _BFS is to be executed right after the
platfor firmware has returned control to the OS on wake up.

Move the execution of _GTS and _BFS to the right places.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
drivers/acpi/hardware/hwsleep.c | 75 +++++++++++++++++++++++++++++---------
drivers/acpi/sleep/main.c | 7 ++++
include/acpi/acpixf.h | 2 +
3 files changed, 66 insertions(+), 18 deletions(-)

diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 81b2484..13c93a1 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -192,18 +192,13 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = sleep_state;

- /* Run the _PTS and _GTS methods */
+ /* Run the _PTS method */

status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
return_ACPI_STATUS(status);
}

- status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- return_ACPI_STATUS(status);
- }
-
/* Setup the argument to _SST */

switch (sleep_state) {
@@ -262,6 +257,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
struct acpi_bit_register_info *sleep_type_reg_info;
struct acpi_bit_register_info *sleep_enable_reg_info;
u32 in_value;
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
acpi_status status;

ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
@@ -307,6 +304,18 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
return_ACPI_STATUS(status);
}

+ /* Execute the _GTS method */
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = sleep_state;
+
+ status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ return_ACPI_STATUS(status);
+ }
+
/* Get current value of PM1A control */

status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
@@ -473,17 +482,18 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)

/*******************************************************************************
*
- * FUNCTION: acpi_leave_sleep_state
+ * FUNCTION: acpi_leave_sleep_state_prep
*
- * PARAMETERS: sleep_state - Which sleep state we just exited
+ * PARAMETERS: sleep_state - Which sleep state we are exiting
*
* RETURN: Status
*
- * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
- * Called with interrupts ENABLED.
+ * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
+ * sleep.
+ * Called with interrupts DISABLED.
*
******************************************************************************/
-acpi_status acpi_leave_sleep_state(u8 sleep_state)
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
{
struct acpi_object_list arg_list;
union acpi_object arg;
@@ -493,7 +503,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
u32 PM1Acontrol;
u32 PM1Bcontrol;

- ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+ ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);

/*
* Set SLP_TYPE and SLP_EN to state S0.
@@ -540,6 +550,41 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
}
}

+ /* Execute the _BFS method */
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = sleep_state;
+
+ status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_leave_sleep_state
+ *
+ * PARAMETERS: sleep_state - Which sleep state we just exited
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
+ * Called with interrupts ENABLED.
+ *
+ ******************************************************************************/
+acpi_status acpi_leave_sleep_state(u8 sleep_state)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+
/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */

acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
@@ -558,12 +603,6 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
}

- arg.integer.value = sleep_state;
- status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
- }
-
/*
* GPEs must be enabled before _WAK is called as GPEs
* might get fired there
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index e2e4e61..fdd8139 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -139,6 +139,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
break;
}

+ /* Reprogram control registers and execute _BFS */
+ acpi_leave_sleep_state_prep(acpi_state);
+
/* ACPI 3.0 specs (P62) says that it's the responsabilty
* of the OSPM to clear the status bit [ implying that the
* POWER_BUTTON event should not reach userspace ]
@@ -272,6 +275,8 @@ static int acpi_hibernation_enter(void)
acpi_enable_wakeup_device(ACPI_STATE_S4);
/* This shouldn't return. If it returns, we have a problem */
status = acpi_enter_sleep_state(ACPI_STATE_S4);
+ /* Reprogram control registers and execute _BFS */
+ acpi_leave_sleep_state_prep(ACPI_STATE_S4);
local_irq_restore(flags);

return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -284,6 +289,8 @@ static void acpi_hibernation_leave(void)
* enable it here.
*/
acpi_enable();
+ /* Reprogram control registers and execute _BFS */
+ acpi_leave_sleep_state_prep(ACPI_STATE_S4);
}

static void acpi_hibernation_finish(void)
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 9512f04..b729e64 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -335,6 +335,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state);

acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void);

+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
+
acpi_status acpi_leave_sleep_state(u8 sleep_state);

#endif /* __ACXFACE_H__ */
--
1.5.4.rc5.16.gc0279

2008-02-01 04:57:49

by Len Brown

[permalink] [raw]
Subject: [PATCH 15/37] Suspend: Fix compilation warning for CONFIG_SUSPEND unset

From: Rafael J. Wysocki <[email protected]>

Suspend: Make debug facility depend on CONFIG_SUSPEND

Make the new suspend debug facility code depend on CONFIG_SUSPEND,
as appropriate, to remove the compiler warning printed when CONFIG_PM is set
and CONFIG_SUSPEND is not set.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/main.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/kernel/power/main.c b/kernel/power/main.c
index 0a9f269..7fb805d 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -55,6 +55,8 @@ int pm_notifier_call_chain(unsigned long val)

#endif /* CONFIG_PM_SLEEP */

+#ifdef CONFIG_SUSPEND
+
#ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE;

--
1.5.4.rc5.16.gc0279

2008-02-01 04:58:18

by Len Brown

[permalink] [raw]
Subject: [PATCH 16/37] Hibernation: Move low level resume to disk.c

From: Rafael J. Wysocki <[email protected]>

Move the low level restore code to kernel/power/disk.c , since the
corresponding low level hibernation code is already there.

Make restore fail if device_power_down(PMSG_PRETHAW) returns an
error.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/disk.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
kernel/power/power.h | 1 -
kernel/power/swsusp.c | 35 -----------------------------------
3 files changed, 48 insertions(+), 37 deletions(-)

diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 0866b16..2a4bada 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -275,6 +275,53 @@ int hibernation_snapshot(int platform_mode)
}

/**
+ * resume_target_kernel - prepare devices that need to be suspended with
+ * interrupts off, restore the contents of highmem that have not been
+ * restored yet from the image and run the low level code that will restore
+ * the remaining contents of memory and switch to the just restored target
+ * kernel.
+ */
+
+static int resume_target_kernel(void)
+{
+ int error;
+
+ local_irq_disable();
+ error = device_power_down(PMSG_PRETHAW);
+ if (error) {
+ printk(KERN_ERR "Some devices failed to power down, "
+ "aborting resume\n");
+ goto Enable_irqs;
+ }
+ /* We'll ignore saved state, but this gets preempt count (etc) right */
+ save_processor_state();
+ error = restore_highmem();
+ if (!error) {
+ error = swsusp_arch_resume();
+ /*
+ * The code below is only ever reached in case of a failure.
+ * Otherwise execution continues at place where
+ * swsusp_arch_suspend() was called
+ */
+ BUG_ON(!error);
+ /* This call to restore_highmem() undos the previous one */
+ restore_highmem();
+ }
+ /*
+ * The only reason why swsusp_arch_resume() can fail is memory being
+ * very tight, so we have to free it as soon as we can to avoid
+ * subsequent failures
+ */
+ swsusp_free();
+ restore_processor_state();
+ touch_softlockup_watchdog();
+ device_power_up();
+ Enable_irqs:
+ local_irq_enable();
+ return error;
+}
+
+/**
* hibernation_restore - quiesce devices and restore the hibernation
* snapshot image. If successful, control returns in hibernation_snaphot()
* @platform_mode - if set, use the platform driver, if available, to
@@ -297,7 +344,7 @@ int hibernation_restore(int platform_mode)
if (!error) {
error = disable_nonboot_cpus();
if (!error)
- error = swsusp_resume();
+ error = resume_target_kernel();
enable_nonboot_cpus();
}
platform_restore_cleanup(platform_mode);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index a9732fd..8ec5499 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -152,7 +152,6 @@ extern int swsusp_swap_in_use(void);
extern int swsusp_check(void);
extern int swsusp_shrink_memory(void);
extern void swsusp_free(void);
-extern int swsusp_resume(void);
extern int swsusp_read(unsigned int *flags_p);
extern int swsusp_write(unsigned int flags);
extern void swsusp_close(void);
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 605c536..dc29a20 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -261,38 +261,3 @@ int swsusp_shrink_memory(void)

return 0;
}
-
-int swsusp_resume(void)
-{
- int error;
-
- local_irq_disable();
- /* NOTE: device_power_down() is just a suspend() with irqs off;
- * it has no special "power things down" semantics
- */
- if (device_power_down(PMSG_PRETHAW))
- printk(KERN_ERR "Some devices failed to power down, very bad\n");
- /* We'll ignore saved state, but this gets preempt count (etc) right */
- save_processor_state();
- error = restore_highmem();
- if (!error) {
- error = swsusp_arch_resume();
- /* The code below is only ever reached in case of a failure.
- * Otherwise execution continues at place where
- * swsusp_arch_suspend() was called
- */
- BUG_ON(!error);
- /* This call to restore_highmem() undos the previous one */
- restore_highmem();
- }
- /* The only reason why swsusp_arch_resume() can fail is memory being
- * very tight, so we have to free it as soon as we can to avoid
- * subsequent failures
- */
- swsusp_free();
- restore_processor_state();
- touch_softlockup_watchdog();
- device_power_up();
- local_irq_enable();
- return error;
-}
--
1.5.4.rc5.16.gc0279

2008-02-01 04:58:48

by Len Brown

[permalink] [raw]
Subject: [PATCH 26/37] Suspend: Introduce begin() and end() callbacks

From: Rafael J. Wysocki <[email protected]>

On ACPI systems the target state set by acpi_pm_set_target() is
reset by acpi_pm_finish(), but that need not be called if the
suspend fails.  All platforms that use the .set_target() global
suspend callback are affected by analogous issues.

For this reason, we need an additional global suspend callback that
will reset the target state regardless of whether or not the suspend
is successful.  Also, it is reasonable to rename the .set_target()
callback, since it will be used for a different purpose on ACPI
systems (due to ACPI 1.0x code ordering requirements).

Introduce the global suspend callback .end() to be executed at the
end of the suspend sequence and rename the .set_target() global
suspend callback to .begin().

Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
arch/arm/mach-at91/pm.c | 17 +++++++++++++----
arch/powerpc/platforms/52xx/lite5200_pm.c | 10 ++++++++--
drivers/acpi/sleep/main.c | 22 ++++++++++++++++++----
include/linux/suspend.h | 29 ++++++++++++++++++-----------
kernel/power/main.c | 9 ++++++---
5 files changed, 63 insertions(+), 24 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 4b120cc..a67defd 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -52,7 +52,7 @@ static suspend_state_t target_state;
/*
* Called after processes are frozen, but before we shutdown devices.
*/
-static int at91_pm_set_target(suspend_state_t state)
+static int at91_pm_begin(suspend_state_t state)
{
target_state = state;
return 0;
@@ -202,11 +202,20 @@ error:
return 0;
}

+/*
+ * Called right prior to thawing processes.
+ */
+static void at91_pm_end(void)
+{
+ target_state = PM_SUSPEND_ON;
+}
+

static struct platform_suspend_ops at91_pm_ops ={
- .valid = at91_pm_valid_state,
- .set_target = at91_pm_set_target,
- .enter = at91_pm_enter,
+ .valid = at91_pm_valid_state,
+ .begin = at91_pm_begin,
+ .enter = at91_pm_enter,
+ .end = at91_pm_end,
};

static int __init at91_pm_init(void)
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
index c0f13e8..41c7fd9 100644
--- a/arch/powerpc/platforms/52xx/lite5200_pm.c
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -31,7 +31,7 @@ static int lite5200_pm_valid(suspend_state_t state)
}
}

-static int lite5200_pm_set_target(suspend_state_t state)
+static int lite5200_pm_begin(suspend_state_t state)
{
if (lite5200_pm_valid(state)) {
lite5200_pm_target_state = state;
@@ -219,12 +219,18 @@ static void lite5200_pm_finish(void)
mpc52xx_pm_finish();
}

+static void lite5200_pm_end(void)
+{
+ lite5200_pm_target_state = PM_SUSPEND_ON;
+}
+
static struct platform_suspend_ops lite5200_pm_ops = {
.valid = lite5200_pm_valid,
- .set_target = lite5200_pm_set_target,
+ .begin = lite5200_pm_begin,
.prepare = lite5200_pm_prepare,
.enter = lite5200_pm_enter,
.finish = lite5200_pm_finish,
+ .end = lite5200_pm_end,
};

int __init lite5200_pm_init(void)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 96d23b3..e2e4e61 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -63,11 +63,11 @@ static u32 acpi_suspend_states[] = {
static int init_8259A_after_S1;

/**
- * acpi_pm_set_target - Set the target system sleep state to the state
+ * acpi_pm_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported.
*/

-static int acpi_pm_set_target(suspend_state_t pm_state)
+static int acpi_pm_begin(suspend_state_t pm_state)
{
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
@@ -164,7 +164,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
}

/**
- * acpi_pm_finish - Finish up suspend sequence.
+ * acpi_pm_finish - Instruct the platform to leave a sleep state.
*
* This is called after we wake back up (or if entering the sleep state
* failed).
@@ -190,6 +190,19 @@ static void acpi_pm_finish(void)
#endif
}

+/**
+ * acpi_pm_end - Finish up suspend sequence.
+ */
+
+static void acpi_pm_end(void)
+{
+ /*
+ * This is necessary in case acpi_pm_finish() is not called during a
+ * failing transition to a sleep state.
+ */
+ acpi_target_sleep_state = ACPI_STATE_S0;
+}
+
static int acpi_pm_state_valid(suspend_state_t pm_state)
{
u32 acpi_state;
@@ -208,10 +221,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)

static struct platform_suspend_ops acpi_pm_ops = {
.valid = acpi_pm_state_valid,
- .set_target = acpi_pm_set_target,
+ .begin = acpi_pm_begin,
.prepare = acpi_pm_prepare,
.enter = acpi_pm_enter,
.finish = acpi_pm_finish,
+ .end = acpi_pm_end,
};

/*
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 51283e0..a0b1dbb 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -38,18 +38,16 @@ typedef int __bitwise suspend_state_t;
* There is the %suspend_valid_only_mem function available that can be
* assigned to this if the platform only supports mem sleep.
*
- * @set_target: Tell the platform which system sleep state is going to be
- * entered.
- * @set_target() is executed right prior to suspending devices. The
- * information conveyed to the platform code by @set_target() should be
- * disregarded by the platform as soon as @finish() is executed and if
- * @prepare() fails. If @set_target() fails (ie. returns nonzero),
+ * @begin: Initialise a transition to given system sleep state.
+ * @begin() is executed right prior to suspending devices. The information
+ * conveyed to the platform code by @begin() should be disregarded by it as
+ * soon as @end() is executed. If @begin() fails (ie. returns nonzero),
* @prepare(), @enter() and @finish() will not be called by the PM core.
* This callback is optional. However, if it is implemented, the argument
- * passed to @enter() is meaningless and should be ignored.
+ * passed to @enter() is redundant and should be ignored.
*
* @prepare: Prepare the platform for entering the system sleep state indicated
- * by @set_target().
+ * by @begin().
* @prepare() is called right after devices have been suspended (ie. the
* appropriate .suspend() method has been executed for each device) and
* before the nonboot CPUs are disabled (it is executed with IRQs enabled).
@@ -57,8 +55,8 @@ typedef int __bitwise suspend_state_t;
* error code otherwise, in which case the system cannot enter the desired
* sleep state (@enter() and @finish() will not be called in that case).
*
- * @enter: Enter the system sleep state indicated by @set_target() or
- * represented by the argument if @set_target() is not implemented.
+ * @enter: Enter the system sleep state indicated by @begin() or represented by
+ * the argument if @begin() is not implemented.
* This callback is mandatory. It returns 0 on success or a negative
* error code otherwise, in which case the system cannot enter the desired
* sleep state.
@@ -69,13 +67,22 @@ typedef int __bitwise suspend_state_t;
* This callback is optional, but should be implemented by the platforms
* that implement @prepare(). If implemented, it is always called after
* @enter() (even if @enter() fails).
+ *
+ * @end: Called by the PM core right after resuming devices, to indicate to
+ * the platform that the system has returned to the working state or
+ * the transition to the sleep state has been aborted.
+ * This callback is optional, but should be implemented by the platforms
+ * that implement @begin(), but platforms implementing @begin() should
+ * also provide a @end() which cleans up transitions aborted before
+ * @enter().
*/
struct platform_suspend_ops {
int (*valid)(suspend_state_t state);
- int (*set_target)(suspend_state_t state);
+ int (*begin)(suspend_state_t state);
int (*prepare)(void);
int (*enter)(suspend_state_t state);
void (*finish)(void);
+ void (*end)(void);
};

#ifdef CONFIG_SUSPEND
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 050a607..d9bba45 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -258,10 +258,10 @@ int suspend_devices_and_enter(suspend_state_t state)
if (!suspend_ops)
return -ENOSYS;

- if (suspend_ops->set_target) {
- error = suspend_ops->set_target(state);
+ if (suspend_ops->begin) {
+ error = suspend_ops->begin(state);
if (error)
- return error;
+ goto Close;
}
suspend_console();
error = device_suspend(PMSG_SUSPEND);
@@ -294,6 +294,9 @@ int suspend_devices_and_enter(suspend_state_t state)
device_resume();
Resume_console:
resume_console();
+ Close:
+ if (suspend_ops->end)
+ suspend_ops->end();
return error;
}

--
1.5.4.rc5.16.gc0279

2008-02-01 04:59:25

by Len Brown

[permalink] [raw]
Subject: [PATCH 18/37] Hibernation: Fix comment in disk.c

From: Rafael J. Wysocki <[email protected]>

Fix a comment in kernel/power/disk.c so that it doesn't contain lines
longer that 80 characters.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
kernel/power/disk.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 2a4bada..3e24a20 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -568,8 +568,8 @@ static int software_resume(void)

if (noresume) {
/**
- * FIXME: If noresume is specified, we need to find the partition
- * and reset it back to normal swap space.
+ * FIXME: If noresume is specified, we need to find the
+ * partition and reset it back to normal swap space.
*/
mutex_unlock(&pm_mutex);
return 0;
--
1.5.4.rc5.16.gc0279

2008-02-01 04:59:49

by Len Brown

[permalink] [raw]
Subject: [PATCH 05/37] Hibernation: Introduce exportable suspend ioctls header (rev. 2)

From: Rafael J. Wysocki <[email protected]>

Move the definitions of hibernation ioctls to a separate header file in
include/linux, which can be exported to the user space.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/userland-swsusp.txt | 10 ++++----
include/linux/Kbuild | 1 +
include/linux/suspend_ioctls.h | 32 +++++++++++++++++++++++++++++++
kernel/power/power.h | 29 +---------------------------
4 files changed, 39 insertions(+), 33 deletions(-)
create mode 100644 include/linux/suspend_ioctls.h

diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index af52d53..7b99636 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -14,7 +14,7 @@ are going to develop your own suspend/resume utilities.

The interface consists of a character device providing the open(),
release(), read(), and write() operations as well as several ioctl()
-commands defined in kernel/power/power.h. The major and minor
+commands defined in include/linux/suspend_ioctls.h . The major and minor
numbers of the device are, respectively, 10 and 231, and they can
be read from /sys/class/misc/snapshot/dev.

@@ -70,10 +70,10 @@ SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated by
SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
units) from the beginning of the partition at which the swap header is
located (the last ioctl() argument should point to a struct
- resume_swap_area, as defined in kernel/power/power.h, containing the
- resume device specification and the offset); for swap partitions the
- offset is always 0, but it is different from zero for swap files (see
- Documentation/swsusp-and-swap-files.txt for details).
+ resume_swap_area, as defined in kernel/power/suspend_ioctls.h,
+ containing the resume device specification and the offset); for swap
+ partitions the offset is always 0, but it is different from zero for
+ swap files (see Documentation/swsusp-and-swap-files.txt for details).

SNAPSHOT_PLATFORM_SUPPORT - enable/disable the hibernation platform support,
depending on the argument value (enable, if the argument is nonzero)
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 85b2482..c0f9bb7 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -143,6 +143,7 @@ header-y += snmp.h
header-y += sockios.h
header-y += som.h
header-y += sound.h
+header-y += suspend_ioctls.h
header-y += taskstats.h
header-y += telephony.h
header-y += termios.h
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
new file mode 100644
index 0000000..2c6faec
--- /dev/null
+++ b/include/linux/suspend_ioctls.h
@@ -0,0 +1,32 @@
+#ifndef _LINUX_SUSPEND_IOCTLS_H
+#define _LINUX_SUSPEND_IOCTLS_H
+
+/*
+ * This structure is used to pass the values needed for the identification
+ * of the resume swap area from a user space to the kernel via the
+ * SNAPSHOT_SET_SWAP_AREA ioctl
+ */
+struct resume_swap_area {
+ loff_t offset;
+ u_int32_t dev;
+} __attribute__((packed));
+
+#define SNAPSHOT_IOC_MAGIC '3'
+#define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1)
+#define SNAPSHOT_UNFREEZE _IO(SNAPSHOT_IOC_MAGIC, 2)
+#define SNAPSHOT_ATOMIC_RESTORE _IO(SNAPSHOT_IOC_MAGIC, 4)
+#define SNAPSHOT_FREE _IO(SNAPSHOT_IOC_MAGIC, 5)
+#define SNAPSHOT_FREE_SWAP_PAGES _IO(SNAPSHOT_IOC_MAGIC, 9)
+#define SNAPSHOT_S2RAM _IO(SNAPSHOT_IOC_MAGIC, 11)
+#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
+ struct resume_swap_area)
+#define SNAPSHOT_GET_IMAGE_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
+#define SNAPSHOT_PLATFORM_SUPPORT _IO(SNAPSHOT_IOC_MAGIC, 15)
+#define SNAPSHOT_POWER_OFF _IO(SNAPSHOT_IOC_MAGIC, 16)
+#define SNAPSHOT_CREATE_IMAGE _IOW(SNAPSHOT_IOC_MAGIC, 17, int)
+#define SNAPSHOT_PREF_IMAGE_SIZE _IO(SNAPSHOT_IOC_MAGIC, 18)
+#define SNAPSHOT_AVAIL_SWAP_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 19, loff_t)
+#define SNAPSHOT_ALLOC_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 20, loff_t)
+#define SNAPSHOT_IOC_MAXNR 20
+
+#endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 0dd66fa..ef90605 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -1,4 +1,5 @@
#include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
#include <linux/utsname.h>

struct swsusp_info {
@@ -134,34 +135,6 @@ extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
extern void snapshot_write_finalize(struct snapshot_handle *handle);
extern int snapshot_image_loaded(struct snapshot_handle *handle);

-/*
- * This structure is used to pass the values needed for the identification
- * of the resume swap area from a user space to the kernel via the
- * SNAPSHOT_SET_SWAP_AREA ioctl
- */
-struct resume_swap_area {
- loff_t offset;
- u_int32_t dev;
-} __attribute__((packed));
-
-#define SNAPSHOT_IOC_MAGIC '3'
-#define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1)
-#define SNAPSHOT_UNFREEZE _IO(SNAPSHOT_IOC_MAGIC, 2)
-#define SNAPSHOT_ATOMIC_RESTORE _IO(SNAPSHOT_IOC_MAGIC, 4)
-#define SNAPSHOT_FREE _IO(SNAPSHOT_IOC_MAGIC, 5)
-#define SNAPSHOT_FREE_SWAP_PAGES _IO(SNAPSHOT_IOC_MAGIC, 9)
-#define SNAPSHOT_S2RAM _IO(SNAPSHOT_IOC_MAGIC, 11)
-#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
- struct resume_swap_area)
-#define SNAPSHOT_GET_IMAGE_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
-#define SNAPSHOT_PLATFORM_SUPPORT _IO(SNAPSHOT_IOC_MAGIC, 15)
-#define SNAPSHOT_POWER_OFF _IO(SNAPSHOT_IOC_MAGIC, 16)
-#define SNAPSHOT_CREATE_IMAGE _IOW(SNAPSHOT_IOC_MAGIC, 17, int)
-#define SNAPSHOT_PREF_IMAGE_SIZE _IO(SNAPSHOT_IOC_MAGIC, 18)
-#define SNAPSHOT_AVAIL_SWAP_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 19, loff_t)
-#define SNAPSHOT_ALLOC_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 20, loff_t)
-#define SNAPSHOT_IOC_MAXNR 20
-
/* If unset, the snapshot device cannot be open. */
extern atomic_t snapshot_device_available;

--
1.5.4.rc5.16.gc0279

2008-02-01 05:00:33

by Len Brown

[permalink] [raw]
Subject: [PATCH 04/37] Hibernation: Correct definitions of some ioctls (rev. 2)

From: Rafael J. Wysocki <[email protected]>

Three ioctl numbers belonging to the hibernation userland interface,
SNAPSHOT_ATOMIC_SNAPSHOT, SNAPSHOT_AVAIL_SWAP, SNAPSHOT_GET_SWAP_PAGE,
are defined in a wrong way (eg. not portable). Provide new ioctl numbers for
these ioctls and mark the existing ones as deprecated.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Signed-off-by: Len Brown <[email protected]>
---
Documentation/power/userland-swsusp.txt | 26 +++++++++++++-------------
kernel/power/power.h | 10 +++++-----
kernel/power/user.c | 18 ++++++++++++++++--
3 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index 0785500..af52d53 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -27,17 +27,17 @@ once at a time.
The ioctl() commands recognized by the device are:

SNAPSHOT_FREEZE - freeze user space processes (the current process is
- not frozen); this is required for SNAPSHOT_ATOMIC_SNAPSHOT
+ not frozen); this is required for SNAPSHOT_CREATE_IMAGE
and SNAPSHOT_ATOMIC_RESTORE to succeed

SNAPSHOT_UNFREEZE - thaw user space processes frozen by SNAPSHOT_FREEZE

-SNAPSHOT_ATOMIC_SNAPSHOT - create a snapshot of the system memory; the
+SNAPSHOT_CREATE_IMAGE - create a snapshot of the system memory; the
last argument of ioctl() should be a pointer to an int variable,
the value of which will indicate whether the call returned after
creating the snapshot (1) or after restoring the system memory state
from it (0) (after resume the system finds itself finishing the
- SNAPSHOT_ATOMIC_SNAPSHOT ioctl() again); after the snapshot
+ SNAPSHOT_CREATE_IMAGE ioctl() again); after the snapshot
has been created the read() operation can be used to transfer
it out of the kernel

@@ -49,23 +49,23 @@ SNAPSHOT_ATOMIC_RESTORE - restore the system memory state from the

SNAPSHOT_FREE - free memory allocated for the snapshot image

-SNAPSHOT_SET_IMAGE_SIZE - set the preferred maximum size of the image
+SNAPSHOT_PREF_IMAGE_SIZE - set the preferred maximum size of the image
(the kernel will do its best to ensure the image size will not exceed
this number, but if it turns out to be impossible, the kernel will
create the smallest image possible)

SNAPSHOT_GET_IMAGE_SIZE - return the actual size of the hibernation image

-SNAPSHOT_AVAIL_SWAP - return the amount of available swap in bytes (the last
- argument should be a pointer to an unsigned int variable that will
+SNAPSHOT_AVAIL_SWAP_SIZE - return the amount of available swap in bytes (the
+ last argument should be a pointer to an unsigned int variable that will
contain the result if the call is successful).

-SNAPSHOT_GET_SWAP_PAGE - allocate a swap page from the resume partition
+SNAPSHOT_ALLOC_SWAP_PAGE - allocate a swap page from the resume partition
(the last argument should be a pointer to a loff_t variable that
will contain the swap page offset if the call is successful)

-SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated with
- SNAPSHOT_GET_SWAP_PAGE
+SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated by
+ SNAPSHOT_ALLOC_SWAP_PAGE

SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
units) from the beginning of the partition at which the swap header is
@@ -102,7 +102,7 @@ The device's write() operation is used for uploading the system memory snapshot
into the kernel. It has the same limitations as the read() operation.

The release() operation frees all memory allocated for the snapshot image
-and all swap pages allocated with SNAPSHOT_GET_SWAP_PAGE (if any).
+and all swap pages allocated with SNAPSHOT_ALLOC_SWAP_PAGE (if any).
Thus it is not necessary to use either SNAPSHOT_FREE or
SNAPSHOT_FREE_SWAP_PAGES before closing the device (in fact it will also
unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are
@@ -113,7 +113,7 @@ snapshot image from/to the kernel will use a swap parition, called the resume
partition, or a swap file as storage space (if a swap file is used, the resume
partition is the partition that holds this file). However, this is not really
required, as they can use, for example, a special (blank) suspend partition or
-a file on a partition that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and
+a file on a partition that is unmounted before SNAPSHOT_CREATE_IMAGE and
mounted afterwards.

These utilities MUST NOT make any assumptions regarding the ordering of
@@ -135,7 +135,7 @@ means, such as checksums, to ensure the integrity of the snapshot image.
The suspending and resuming utilities MUST lock themselves in memory,
preferrably using mlockall(), before calling SNAPSHOT_FREEZE.

-The suspending utility MUST check the value stored by SNAPSHOT_ATOMIC_SNAPSHOT
+The suspending utility MUST check the value stored by SNAPSHOT_CREATE_IMAGE
in the memory location pointed to by the last argument of ioctl() and proceed
in accordance with it:
1. If the value is 1 (ie. the system memory snapshot has just been
@@ -149,7 +149,7 @@ in accordance with it:
image has been saved.
(b) The suspending utility SHOULD NOT attempt to perform any
file system operations (including reads) on the file systems
- that were mounted before SNAPSHOT_ATOMIC_SNAPSHOT has been
+ that were mounted before SNAPSHOT_CREATE_IMAGE has been
called. However, it MAY mount a file system that was not
mounted at that time and perform some operations on it (eg.
use it for saving the image).
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 8837ea3..0dd66fa 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -147,12 +147,8 @@ struct resume_swap_area {
#define SNAPSHOT_IOC_MAGIC '3'
#define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1)
#define SNAPSHOT_UNFREEZE _IO(SNAPSHOT_IOC_MAGIC, 2)
-#define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
#define SNAPSHOT_ATOMIC_RESTORE _IO(SNAPSHOT_IOC_MAGIC, 4)
#define SNAPSHOT_FREE _IO(SNAPSHOT_IOC_MAGIC, 5)
-#define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
-#define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
-#define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
#define SNAPSHOT_FREE_SWAP_PAGES _IO(SNAPSHOT_IOC_MAGIC, 9)
#define SNAPSHOT_S2RAM _IO(SNAPSHOT_IOC_MAGIC, 11)
#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
@@ -160,7 +156,11 @@ struct resume_swap_area {
#define SNAPSHOT_GET_IMAGE_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
#define SNAPSHOT_PLATFORM_SUPPORT _IO(SNAPSHOT_IOC_MAGIC, 15)
#define SNAPSHOT_POWER_OFF _IO(SNAPSHOT_IOC_MAGIC, 16)
-#define SNAPSHOT_IOC_MAXNR 16
+#define SNAPSHOT_CREATE_IMAGE _IOW(SNAPSHOT_IOC_MAGIC, 17, int)
+#define SNAPSHOT_PREF_IMAGE_SIZE _IO(SNAPSHOT_IOC_MAGIC, 18)
+#define SNAPSHOT_AVAIL_SWAP_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 19, loff_t)
+#define SNAPSHOT_ALLOC_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 20, loff_t)
+#define SNAPSHOT_IOC_MAXNR 20

/* If unset, the snapshot device cannot be open. */
extern atomic_t snapshot_device_available;
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 5e866e0..b902a7e 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -40,6 +40,16 @@
#define PMOPS_ENTER 2
#define PMOPS_FINISH 3

+/*
+ * NOTE: The following ioctl definitions are wrong and have been replaced with
+ * correct ones. They are only preserved here for compatibility with existing
+ * userland utilities and will be removed in the future.
+ */
+#define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
+#define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
+#define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
+#define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
+

#define SNAPSHOT_MINOR 231

@@ -191,6 +201,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
data->frozen = 0;
break;

+ case SNAPSHOT_CREATE_IMAGE:
case SNAPSHOT_ATOMIC_SNAPSHOT:
if (data->mode != O_RDONLY || !data->frozen || data->ready) {
error = -EPERM;
@@ -198,7 +209,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
}
error = hibernation_snapshot(data->platform_support);
if (!error)
- error = put_user(in_suspend, (unsigned int __user *)arg);
+ error = put_user(in_suspend, (int __user *)arg);
if (!error)
data->ready = 1;
break;
@@ -219,6 +230,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
data->ready = 0;
break;

+ case SNAPSHOT_PREF_IMAGE_SIZE:
case SNAPSHOT_SET_IMAGE_SIZE:
image_size = arg;
break;
@@ -233,12 +245,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = put_user(size, (loff_t __user *)arg);
break;

+ case SNAPSHOT_AVAIL_SWAP_SIZE:
case SNAPSHOT_AVAIL_SWAP:
size = count_swap_pages(data->swap, 1);
size <<= PAGE_SHIFT;
error = put_user(size, (loff_t __user *)arg);
break;

+ case SNAPSHOT_ALLOC_SWAP_PAGE:
case SNAPSHOT_GET_SWAP_PAGE:
if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
error = -ENODEV;
@@ -247,7 +261,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
offset = alloc_swapdev_block(data->swap);
if (offset) {
offset <<= PAGE_SHIFT;
- error = put_user(offset, (sector_t __user *)arg);
+ error = put_user(offset, (loff_t __user *)arg);
} else {
error = -ENOSPC;
}
--
1.5.4.rc5.16.gc0279

2008-02-01 05:48:51

by Harvey Harrison

[permalink] [raw]
Subject: [PATCH] feature-removal: Document suspend/hibernate deprecations

Let this appear as deprecated in 2.6.25, remove after three
releases (2.6.28).

Signed-off-by: Harvey Harrison <[email protected]>
---
Something like this should be included if you are deprecating
userspace functionality. I tried to come up with a useful
reason from your changelogs, but you should fill this in.

Documentation/feature-removal-schedule.txt | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 181bff0..cb005de 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -354,3 +354,28 @@ Why: The support code for the old firmware hurts code readability/maintainabilit
and slightly hurts runtime performance. Bugfixes for the old firmware
are not provided by Broadcom anymore.
Who: Michael Buesch <[email protected]>
+
+---------------------------
+
+What: SNAPSHOT_PMOPS ioctl
+When: 2.6.28
+Why: Badly designed interface, obsoleted by SNAPSHOT_PLATFORM_SUPPORT and
+ SNAPSHOT_POWER_OFF
+Who: Len Brown <[email protected]>
+
+---------------------------
+
+What: SNAPSHOT_SET_SWAP_FILE ioctl
+When: 2.6.28
+Why: Insert reason here
+Who: Len Brown <[email protected]>
+
+---------------------------
+
+What: SNAPSHOT_ATOMIC_SNAPSHOT, SNAPSHOT_AVAIL_SWAP, SNAPSHOT_GET_SWAP_PAGE ioctls
+When: 2.6.28
+Why: Defined in a non-portable manner, new numbers introduced, old numbers
+ deprecated.
+Who: Len Brown <[email protected]>
+
+---------------------------
--
1.5.4.rc4.1142.gf5a97


2008-02-01 09:06:29

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH 23/37] Suspend: Clean up Kconfig (V2)

On Feb 1, 2008 12:36 PM, Len Brown <[email protected]> wrote:
> From: Johannes Berg <[email protected]>
>
> This cleans up the suspend Kconfig and removes the need to
> declare centrally which architectures support suspend. All
> architectures that currently support suspend are modified
> accordingly.
>

Thanks, OK for Blackfin

Acked-by: Bryan Wu <[email protected]>

> Signed-off-by: Johannes Berg <[email protected]>
> Acked-by: Russell King <[email protected]>
> Acked-by: Paul Mackerras <[email protected]>
> Acked-by: Ralf Baechle <[email protected]>
> Acked-by: Paul Mundt <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Signed-off-by: Rafael J. Wysocki <[email protected]>
> Signed-off-by: Len Brown <[email protected]>
> ---
> arch/arm/Kconfig | 3 +++
> arch/blackfin/Kconfig | 4 ++++
> arch/frv/Kconfig | 5 +++++
> arch/mips/Kconfig | 4 ++++
> arch/powerpc/Kconfig | 4 ++++
> arch/sh/Kconfig | 4 ++++
> arch/x86/Kconfig | 4 ++++
> kernel/power/Kconfig | 21 +++------------------
> 8 files changed, 31 insertions(+), 18 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 77201d3..a00d8b9 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1035,6 +1035,9 @@ menu "Power management options"
>
> source "kernel/power/Kconfig"
>
> +config ARCH_SUSPEND_POSSIBLE
> + def_bool y
> +
> endmenu
>
> source "net/Kconfig"
> diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
> index fc7ca86..4802eb7 100644
> --- a/arch/blackfin/Kconfig
> +++ b/arch/blackfin/Kconfig
> @@ -898,6 +898,10 @@ endmenu
> menu "Power management options"
> source "kernel/power/Kconfig"
>
> +config ARCH_SUSPEND_POSSIBLE
> + def_bool y
> + depends on !SMP
> +
> choice
> prompt "Select PM Wakeup Event Source"
> default PM_WAKEUP_GPIO_BY_SIC_IWR
> diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
> index 43153e7..2e25b95 100644
> --- a/arch/frv/Kconfig
> +++ b/arch/frv/Kconfig
> @@ -357,6 +357,11 @@ source "drivers/pcmcia/Kconfig"
> # should probably wait a while.
>
> menu "Power management options"
> +
> +config ARCH_SUSPEND_POSSIBLE
> + def_bool y
> + depends on !SMP
> +
> source kernel/power/Kconfig
> endmenu
>
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 4fad0a3..e387f3a 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -2086,6 +2086,10 @@ endmenu
>
> menu "Power management options"
>
> +config ARCH_SUSPEND_POSSIBLE
> + def_bool y
> + depends on !SMP
> +
> source "kernel/power/Kconfig"
>
> endmenu
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 68f0cf7..824140d 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -166,6 +166,10 @@ config ARCH_HIBERNATION_POSSIBLE
> depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
> default y
>
> +config ARCH_SUSPEND_POSSIBLE
> + def_bool y
> + depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200
> +
> config PPC_DCR_NATIVE
> bool
> default n
> diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
> index 1cd9c8f..b30c4c3 100644
> --- a/arch/sh/Kconfig
> +++ b/arch/sh/Kconfig
> @@ -882,6 +882,10 @@ endmenu
> menu "Power management options (EXPERIMENTAL)"
> depends on EXPERIMENTAL && SYS_SUPPORTS_PM
>
> +config ARCH_SUSPEND_POSSIBLE
> + def_bool y
> + depends on !SMP
> +
> source kernel/power/Kconfig
>
> endmenu
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 9c511dd..340e81a 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -113,6 +113,10 @@ config ARCH_HIBERNATION_POSSIBLE
> def_bool y
> depends on !SMP || !X86_VOYAGER
>
> +config ARCH_SUSPEND_POSSIBLE
> + def_bool y
> + depends on !X86_VOYAGER
> +
> config ZONE_DMA32
> bool
> default X86_64
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index fd76d54..f8153fd 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -85,7 +85,7 @@ config PM_TRACE_RTC
> config PM_SLEEP_SMP
> bool
> depends on SMP
> - depends on SUSPEND_SMP_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
> + depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
> depends on PM_SLEEP
> select HOTPLUG_CPU
> default y
> @@ -95,29 +95,14 @@ config PM_SLEEP
> depends on SUSPEND || HIBERNATION
> default y
>
> -config SUSPEND_UP_POSSIBLE
> - bool
> - depends on (X86 && !X86_VOYAGER) || PPC || ARM || BLACKFIN || MIPS \
> - || SUPERH || FRV
> - depends on !SMP
> - default y
> -
> -config SUSPEND_SMP_POSSIBLE
> - bool
> - depends on (X86 && !X86_VOYAGER) \
> - || (PPC && (PPC_PSERIES || PPC_PMAC)) || ARM
> - depends on SMP
> - default y
> -
> config SUSPEND
> bool "Suspend to RAM and standby"
> - depends on PM
> - depends on SUSPEND_UP_POSSIBLE || SUSPEND_SMP_POSSIBLE
> + depends on PM && ARCH_SUSPEND_POSSIBLE
> default y
> ---help---
> Allow the system to enter sleep states in which main memory is
> powered and thus its contents are preserved, such as the
> - suspend-to-RAM state (i.e. the ACPI S3 state).
> + suspend-to-RAM state (e.g. the ACPI S3 state).
>
> config HIBERNATION
> bool "Hibernation (aka 'suspend to disk')"
> --
> 1.5.4.rc5.16.gc0279
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2008-02-01 10:56:37

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH] feature-removal: Document suspend/hibernate deprecations

On Friday, 1 of February 2008, Harvey Harrison wrote:
> Let this appear as deprecated in 2.6.25, remove after three
> releases (2.6.28).

Thanks, I'll post a more complete version of the patch later today.

> Signed-off-by: Harvey Harrison <[email protected]>
> ---
> Something like this should be included if you are deprecating
> userspace functionality. I tried to come up with a useful
> reason from your changelogs, but you should fill this in.
>
> Documentation/feature-removal-schedule.txt | 25 +++++++++++++++++++++++++
> 1 files changed, 25 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
> index 181bff0..cb005de 100644
> --- a/Documentation/feature-removal-schedule.txt
> +++ b/Documentation/feature-removal-schedule.txt
> @@ -354,3 +354,28 @@ Why: The support code for the old firmware hurts code readability/maintainabilit
> and slightly hurts runtime performance. Bugfixes for the old firmware
> are not provided by Broadcom anymore.
> Who: Michael Buesch <[email protected]>
> +
> +---------------------------
> +
> +What: SNAPSHOT_PMOPS ioctl
> +When: 2.6.28
> +Why: Badly designed interface, obsoleted by SNAPSHOT_PLATFORM_SUPPORT and
> + SNAPSHOT_POWER_OFF
> +Who: Len Brown <[email protected]>
> +
> +---------------------------
> +
> +What: SNAPSHOT_SET_SWAP_FILE ioctl
> +When: 2.6.28
> +Why: Insert reason here
> +Who: Len Brown <[email protected]>
> +
> +---------------------------
> +
> +What: SNAPSHOT_ATOMIC_SNAPSHOT, SNAPSHOT_AVAIL_SWAP, SNAPSHOT_GET_SWAP_PAGE ioctls
> +When: 2.6.28
> +Why: Defined in a non-portable manner, new numbers introduced, old numbers
> + deprecated.
> +Who: Len Brown <[email protected]>
> +
> +---------------------------

2008-02-04 14:59:51

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 23/37] Suspend: Clean up Kconfig (V2)

On Thu 2008-01-31 23:36:54, Len Brown wrote:
> From: Johannes Berg <[email protected]>
>
> This cleans up the suspend Kconfig and removes the need to
> declare centrally which architectures support suspend. All
> architectures that currently support suspend are modified
> accordingly.
>
> Signed-off-by: Johannes Berg <[email protected]>
> Acked-by: Russell King <[email protected]>
> Acked-by: Paul Mackerras <[email protected]>
> Acked-by: Ralf Baechle <[email protected]>
> Acked-by: Paul Mundt <[email protected]>
> Cc: Pavel Machek <[email protected]>

ACK.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html