Commit f23a5e14 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
  PM: Fix PM QOS's user mode interface to work with ASCII input
  PM / Hibernate: Update kerneldoc comments in hibernate.c
  PM / Hibernate: Remove arch_prepare_suspend()
  PM / Hibernate: Update some comments in core hibernate code
parents d24c2af4 0775a60a
/* suspend.h: suspension stuff
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _ASM_SUSPEND_H
#define _ASM_SUSPEND_H
static inline int arch_prepare_suspend(void)
{
return 0;
}
#endif /* _ASM_SUSPEND_H */
#ifndef __ASM_SUSPEND_H #ifndef __ASM_SUSPEND_H
#define __ASM_SUSPEND_H #define __ASM_SUSPEND_H
static inline int arch_prepare_suspend(void) { return 0; }
/* References to section boundaries */ /* References to section boundaries */
extern const void __nosave_begin, __nosave_end; extern const void __nosave_begin, __nosave_end;
......
#ifndef __ASM_POWERPC_SUSPEND_H
#define __ASM_POWERPC_SUSPEND_H
static inline int arch_prepare_suspend(void) { return 0; }
#endif /* __ASM_POWERPC_SUSPEND_H */
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/suspend.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/current.h> #include <asm/current.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
......
#ifndef __ASM_S390_SUSPEND_H
#define __ASM_S390_SUSPEND_H
static inline int arch_prepare_suspend(void)
{
return 0;
}
#endif
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/notifier.h> #include <linux/notifier.h>
static inline int arch_prepare_suspend(void) { return 0; }
#include <asm/ptrace.h> #include <asm/ptrace.h>
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#define __UNICORE_SUSPEND_H__ #define __UNICORE_SUSPEND_H__
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
static inline int arch_prepare_suspend(void) { return 0; }
#include <asm/ptrace.h> #include <asm/ptrace.h>
......
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/i387.h> #include <asm/i387.h>
static inline int arch_prepare_suspend(void) { return 0; }
/* image of the saved processor state */ /* image of the saved processor state */
struct saved_context { struct saved_context {
u16 es, fs, gs, ss; u16 es, fs, gs, ss;
......
...@@ -9,11 +9,6 @@ ...@@ -9,11 +9,6 @@
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/i387.h> #include <asm/i387.h>
static inline int arch_prepare_suspend(void)
{
return 0;
}
/* /*
* Image of the saved processor state, used by the low level ACPI suspend to * Image of the saved processor state, used by the low level ACPI suspend to
* RAM code and by the low level hibernation code. * RAM code and by the low level hibernation code.
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -404,24 +405,36 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, ...@@ -404,24 +405,36 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos) size_t count, loff_t *f_pos)
{ {
s32 value; s32 value;
int x;
char ascii_value[11];
struct pm_qos_request_list *pm_qos_req; struct pm_qos_request_list *pm_qos_req;
if (count == sizeof(s32)) { if (count == sizeof(s32)) {
if (copy_from_user(&value, buf, sizeof(s32))) if (copy_from_user(&value, buf, sizeof(s32)))
return -EFAULT; return -EFAULT;
} else if (count == 11) { /* len('0x12345678/0') */ } else if (count <= 11) { /* ASCII perhaps? */
if (copy_from_user(ascii_value, buf, 11)) char ascii_value[11];
unsigned long int ulval;
int ret;
if (copy_from_user(ascii_value, buf, count))
return -EFAULT; return -EFAULT;
if (strlen(ascii_value) != 10)
if (count > 10) {
if (ascii_value[10] == '\n')
ascii_value[10] = '\0';
else
return -EINVAL; return -EINVAL;
x = sscanf(ascii_value, "%x", &value); } else {
if (x != 1) ascii_value[count] = '\0';
}
ret = strict_strtoul(ascii_value, 16, &ulval);
if (ret) {
pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
return -EINVAL; return -EINVAL;
pr_debug("%s, %d, 0x%x\n", ascii_value, x, value); }
} else value = (s32)lower_32_bits(ulval);
} else {
return -EINVAL; return -EINVAL;
}
pm_qos_req = filp->private_data; pm_qos_req = filp->private_data;
pm_qos_update_request(pm_qos_req, value); pm_qos_update_request(pm_qos_req, value);
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <scsi/scsi_scan.h> #include <scsi/scsi_scan.h>
#include <asm/suspend.h>
#include "power.h" #include "power.h"
...@@ -55,10 +54,9 @@ static int hibernation_mode = HIBERNATION_SHUTDOWN; ...@@ -55,10 +54,9 @@ static int hibernation_mode = HIBERNATION_SHUTDOWN;
static const struct platform_hibernation_ops *hibernation_ops; static const struct platform_hibernation_ops *hibernation_ops;
/** /**
* hibernation_set_ops - set the global hibernate operations * hibernation_set_ops - Set the global hibernate operations.
* @ops: the hibernation operations to use in subsequent hibernation transitions * @ops: Hibernation operations to use in subsequent hibernation transitions.
*/ */
void hibernation_set_ops(const struct platform_hibernation_ops *ops) void hibernation_set_ops(const struct platform_hibernation_ops *ops)
{ {
if (ops && !(ops->begin && ops->end && ops->pre_snapshot if (ops && !(ops->begin && ops->end && ops->pre_snapshot
...@@ -115,10 +113,9 @@ static int hibernation_test(int level) { return 0; } ...@@ -115,10 +113,9 @@ static int hibernation_test(int level) { return 0; }
#endif /* !CONFIG_PM_DEBUG */ #endif /* !CONFIG_PM_DEBUG */
/** /**
* platform_begin - tell the platform driver that we're starting * platform_begin - Call platform to start hibernation.
* hibernation * @platform_mode: Whether or not to use the platform driver.
*/ */
static int platform_begin(int platform_mode) static int platform_begin(int platform_mode)
{ {
return (platform_mode && hibernation_ops) ? return (platform_mode && hibernation_ops) ?
...@@ -126,10 +123,9 @@ static int platform_begin(int platform_mode) ...@@ -126,10 +123,9 @@ static int platform_begin(int platform_mode)
} }
/** /**
* platform_end - tell the platform driver that we've entered the * platform_end - Call platform to finish transition to the working state.
* working state * @platform_mode: Whether or not to use the platform driver.
*/ */
static void platform_end(int platform_mode) static void platform_end(int platform_mode)
{ {
if (platform_mode && hibernation_ops) if (platform_mode && hibernation_ops)
...@@ -137,8 +133,11 @@ static void platform_end(int platform_mode) ...@@ -137,8 +133,11 @@ static void platform_end(int platform_mode)
} }
/** /**
* platform_pre_snapshot - prepare the machine for hibernation using the * platform_pre_snapshot - Call platform to prepare the machine for hibernation.
* platform driver if so configured and return an error code if it fails * @platform_mode: Whether or not to use the platform driver.
*
* Use the platform driver to prepare the system for creating a hibernate image,
* if so configured, and return an error code if that fails.
*/ */
static int platform_pre_snapshot(int platform_mode) static int platform_pre_snapshot(int platform_mode)
...@@ -148,10 +147,14 @@ static int platform_pre_snapshot(int platform_mode) ...@@ -148,10 +147,14 @@ static int platform_pre_snapshot(int platform_mode)
} }
/** /**
* platform_leave - prepare the machine for switching to the normal mode * platform_leave - Call platform to prepare a transition to the working state.
* of operation using the platform driver (called with interrupts disabled) * @platform_mode: Whether or not to use the platform driver.
*
* Use the platform driver prepare to prepare the machine for switching to the
* normal mode of operation.
*
* This routine is called on one CPU with interrupts disabled.
*/ */
static void platform_leave(int platform_mode) static void platform_leave(int platform_mode)
{ {
if (platform_mode && hibernation_ops) if (platform_mode && hibernation_ops)
...@@ -159,10 +162,14 @@ static void platform_leave(int platform_mode) ...@@ -159,10 +162,14 @@ static void platform_leave(int platform_mode)
} }
/** /**
* platform_finish - switch the machine to the normal mode of operation * platform_finish - Call platform to switch the system to the working state.
* using the platform driver (must be called after platform_prepare()) * @platform_mode: Whether or not to use the platform driver.
*
* Use the platform driver to switch the machine to the normal mode of
* operation.
*
* This routine must be called after platform_prepare().
*/ */
static void platform_finish(int platform_mode) static void platform_finish(int platform_mode)
{ {
if (platform_mode && hibernation_ops) if (platform_mode && hibernation_ops)
...@@ -170,11 +177,15 @@ static void platform_finish(int platform_mode) ...@@ -170,11 +177,15 @@ static void platform_finish(int platform_mode)
} }
/** /**
* platform_pre_restore - prepare the platform for the restoration from a * platform_pre_restore - Prepare for hibernate image restoration.
* hibernation image. If the restore fails after this function has been * @platform_mode: Whether or not to use the platform driver.
* called, platform_restore_cleanup() must be called. *
* Use the platform driver to prepare the system for resume from a hibernation
* image.
*
* If the restore fails after this function has been called,
* platform_restore_cleanup() must be called.
*/ */
static int platform_pre_restore(int platform_mode) static int platform_pre_restore(int platform_mode)
{ {
return (platform_mode && hibernation_ops) ? return (platform_mode && hibernation_ops) ?
...@@ -182,12 +193,16 @@ static int platform_pre_restore(int platform_mode) ...@@ -182,12 +193,16 @@ static int platform_pre_restore(int platform_mode)
} }
/** /**
* platform_restore_cleanup - switch the platform to the normal mode of * platform_restore_cleanup - Switch to the working state after failing restore.
* operation after a failing restore. If platform_pre_restore() has been * @platform_mode: Whether or not to use the platform driver.
* called before the failing restore, this function must be called too, *
* regardless of the result of platform_pre_restore(). * Use the platform driver to switch the system to the normal mode of operation
* after a failing restore.
*
* If platform_pre_restore() has been called before the failing restore, this
* function must be called too, regardless of the result of
* platform_pre_restore().
*/ */
static void platform_restore_cleanup(int platform_mode) static void platform_restore_cleanup(int platform_mode)
{ {
if (platform_mode && hibernation_ops) if (platform_mode && hibernation_ops)
...@@ -195,10 +210,9 @@ static void platform_restore_cleanup(int platform_mode) ...@@ -195,10 +210,9 @@ static void platform_restore_cleanup(int platform_mode)
} }
/** /**
* platform_recover - recover the platform from a failure to suspend * platform_recover - Recover from a failure to suspend devices.
* devices. * @platform_mode: Whether or not to use the platform driver.
*/ */
static void platform_recover(int platform_mode) static void platform_recover(int platform_mode)
{ {
if (platform_mode && hibernation_ops && hibernation_ops->recover) if (platform_mode && hibernation_ops && hibernation_ops->recover)
...@@ -206,13 +220,12 @@ static void platform_recover(int platform_mode) ...@@ -206,13 +220,12 @@ static void platform_recover(int platform_mode)
} }
/** /**
* swsusp_show_speed - print the time elapsed between two events. * swsusp_show_speed - Print time elapsed between two events during hibernation.
* @start: Starting event. * @start: Starting event.
* @stop: Final event. * @stop: Final event.
* @nr_pages - number of pages processed between @start and @stop * @nr_pages: Number of memory pages processed between @start and @stop.
* @msg - introductory message to print * @msg: Additional diagnostic message to print.
*/ */
void swsusp_show_speed(struct timeval *start, struct timeval *stop, void swsusp_show_speed(struct timeval *start, struct timeval *stop,
unsigned nr_pages, char *msg) unsigned nr_pages, char *msg)
{ {
...@@ -235,25 +248,18 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop, ...@@ -235,25 +248,18 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
} }
/** /**
* create_image - freeze devices that need to be frozen with interrupts * create_image - Create a hibernation image.
* off, create the hibernation image and thaw those devices. Control * @platform_mode: Whether or not to use the platform driver.
* reappears in this routine after a restore. *
* Execute device drivers' .freeze_noirq() callbacks, create a hibernation image
* and execute the drivers' .thaw_noirq() callbacks.
*
* Control reappears in this routine after the subsequent restore.
*/ */
static int create_image(int platform_mode) static int create_image(int platform_mode)
{ {
int error; int error;
error = arch_prepare_suspend();
if (error)
return error;
/* At this point, dpm_suspend_start() has been called, but *not*
* dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() now.
* Otherwise, drivers for some devices (e.g. interrupt controllers)
* become desynchronized with the actual state of the hardware
* at resume time, and evil weirdness ensues.
*/
error = dpm_suspend_noirq(PMSG_FREEZE); error = dpm_suspend_noirq(PMSG_FREEZE);
if (error) { if (error) {
printk(KERN_ERR "PM: Some devices failed to power down, " printk(KERN_ERR "PM: Some devices failed to power down, "
...@@ -297,9 +303,6 @@ static int create_image(int platform_mode) ...@@ -297,9 +303,6 @@ static int create_image(int platform_mode)
Power_up: Power_up:
syscore_resume(); syscore_resume();
/* NOTE: dpm_resume_noirq() is just a resume() for devices
* that suspended with irqs off ... no overall powerup.
*/
Enable_irqs: Enable_irqs:
local_irq_enable(); local_irq_enable();
...@@ -317,14 +320,11 @@ static int create_image(int platform_mode) ...@@ -317,14 +320,11 @@ static int create_image(int platform_mode)
} }
/** /**
* hibernation_snapshot - quiesce devices and create the hibernation * hibernation_snapshot - Quiesce devices and create a hibernation image.
* snapshot image. * @platform_mode: If set, use platform driver to prepare for the transition.
* @platform_mode - if set, use the platform driver, if available, to
* prepare the platform firmware for the power transition.
* *
* Must be called with pm_mutex held * This routine must be called with pm_mutex held.
*/ */
int hibernation_snapshot(int platform_mode) int hibernation_snapshot(int platform_mode)
{ {
pm_message_t msg = PMSG_RECOVER; pm_message_t msg = PMSG_RECOVER;
...@@ -384,13 +384,14 @@ int hibernation_snapshot(int platform_mode) ...@@ -384,13 +384,14 @@ int hibernation_snapshot(int platform_mode)
} }
/** /**
* resume_target_kernel - prepare devices that need to be suspended with * resume_target_kernel - Restore system state from a hibernation image.
* interrupts off, restore the contents of highmem that have not been * @platform_mode: Whether or not to use the platform driver.
* 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 * Execute device drivers' .freeze_noirq() callbacks, restore the contents of
* kernel. * 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(bool platform_mode) static int resume_target_kernel(bool platform_mode)
{ {
int error; int error;
...@@ -416,24 +417,26 @@ static int resume_target_kernel(bool platform_mode) ...@@ -416,24 +417,26 @@ static int resume_target_kernel(bool platform_mode)
if (error) if (error)
goto Enable_irqs; goto Enable_irqs;
/* We'll ignore saved state, but this gets preempt count (etc) right */
save_processor_state(); save_processor_state();
error = restore_highmem(); error = restore_highmem();
if (!error) { if (!error) {
error = swsusp_arch_resume(); error = swsusp_arch_resume();
/* /*
* The code below is only ever reached in case of a failure. * The code below is only ever reached in case of a failure.
* Otherwise execution continues at place where * Otherwise, execution continues at the place where
* swsusp_arch_suspend() was called * swsusp_arch_suspend() was called.
*/ */
BUG_ON(!error); BUG_ON(!error);
/* This call to restore_highmem() undos the previous one */ /*
* This call to restore_highmem() reverts the changes made by
* the previous one.
*/
restore_highmem(); restore_highmem();
} }
/* /*
* The only reason why swsusp_arch_resume() can fail is memory being * 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 * very tight, so we have to free it as soon as we can to avoid
* subsequent failures * subsequent failures.
*/ */
swsusp_free(); swsusp_free();
restore_processor_state(); restore_processor_state();
...@@ -456,14 +459,12 @@ static int resume_target_kernel(bool platform_mode) ...@@ -456,14 +459,12 @@ static int resume_target_kernel(bool platform_mode)
} }
/** /**
* hibernation_restore - quiesce devices and restore the hibernation * hibernation_restore - Quiesce devices and restore from a hibernation image.
* snapshot image. If successful, control returns in hibernation_snaphot() * @platform_mode: If set, use platform driver to prepare for the transition.
* @platform_mode - if set, use the platform driver, if available, to
* prepare the platform firmware for the transition.
* *
* Must be called with pm_mutex held * This routine must be called with pm_mutex held. If it is successful, control
* reappears in the restored target kernel in hibernation_snaphot().
*/ */
int hibernation_restore(int platform_mode) int hibernation_restore(int platform_mode)
{ {
int error; int error;
...@@ -483,10 +484,8 @@ int hibernation_restore(int platform_mode) ...@@ -483,10 +484,8 @@ int hibernation_restore(int platform_mode)
} }
/** /**
* hibernation_platform_enter - enter the hibernation state using the * hibernation_platform_enter - Power off the system using the platform driver.
* platform driver (if available)
*/ */
int hibernation_platform_enter(void) int hibernation_platform_enter(void)
{ {
int error; int error;
...@@ -559,10 +558,10 @@ int hibernation_platform_enter(void) ...@@ -559,10 +558,10 @@ int hibernation_platform_enter(void)
/** /**
* power_down - Shut the machine down for hibernation. * power_down - Shut the machine down for hibernation.
* *
* Use the platform driver, if configured so; otherwise try * Use the platform driver, if configured, to put the system into the sleep
* to power off or reboot. * state corresponding to hibernation, or try to power it off or reboot,
* depending on the value of hibernation_mode.
*/ */
static void power_down(void) static void power_down(void)
{ {
switch (hibernation_mode) { switch (hibernation_mode) {
...@@ -599,9 +598,8 @@ static int prepare_processes(void) ...@@ -599,9 +598,8 @@ static int prepare_processes(void)
} }
/** /**
* hibernate - The granpappy of the built-in hibernation management * hibernate - Carry out system hibernation, including saving the image.
*/ */
int hibernate(void) int hibernate(void)
{ {
int error; int error;
...@@ -679,17 +677,20 @@ int hibernate(void) ...@@ -679,17 +677,20 @@ int hibernate(void)
/** /**
* software_resume - Resume from a saved image. * software_resume - Resume from a saved hibernation image.
* *
* Called as a late_initcall (so all devices are discovered and * This routine is called as a late initcall, when all devices have been
* initialized), we call swsusp to see if we have a saved image or not. * discovered and initialized already.
* If so, we quiesce devices, the restore the saved image. We will
* return above (in hibernate() ) if everything goes well.
* Otherwise, we fail gracefully and return to the normally
* scheduled program.
* *
* The image reading code is called to see if there is a hibernation image
* available for reading. If that is the case, devices are quiesced and the
* contents of memory is restored from the saved image.
*
* If this is successful, control reappears in the restored target kernel in
* hibernation_snaphot() which returns to hibernate(). Otherwise, the routine
* attempts to recover gracefully and make the kernel return to the normal mode
* of operation.
*/ */
static int software_resume(void) static int software_resume(void)
{ {
int error; int error;
...@@ -819,21 +820,17 @@ static const char * const hibernation_modes[] = { ...@@ -819,21 +820,17 @@ static const char * const hibernation_modes[] = {
[HIBERNATION_TESTPROC] = "testproc", [HIBERNATION_TESTPROC] = "testproc",
}; };
/** /*
* disk - Control hibernation mode * /sys/power/disk - Control hibernation mode.
*
* Suspend-to-disk can be handled in several ways. We have a few options
* for putting the system to sleep - using the platform driver (e.g. ACPI
* or other hibernation_ops), powering off the system or rebooting the
* system (for testing) as well as the two test modes.
* *
* The system can support 'platform', and that is known a priori (and * Hibernation can be handled in several ways. There are a few different ways
* encoded by the presence of hibernation_ops). However, the user may * to put the system into the sleep state: using the platform driver (e.g. ACPI
* choose 'shutdown' or 'reboot' as alternatives, as well as one fo the * or other hibernation_ops), powering it off or rebooting it (for testing
* test modes, 'test' or 'testproc'. * mostly), or using one of the two available test modes.
* *
* show() will display what the mode is currently set to. * The sysfs file /sys/power/disk provides an interface for selecting the
* store() will accept one of * hibernation mode to use. Reading from this file causes the available modes
* to be printed. There are 5 modes that can be supported:
* *
* 'platform' * 'platform'
* 'shutdown' * 'shutdown'
...@@ -841,8 +838,14 @@ static const char * const hibernation_modes[] = { ...@@ -841,8 +838,14 @@ static const char * const hibernation_modes[] = {
* 'test' * 'test'
* 'testproc' * 'testproc'
* *
* It will only change to 'platform' if the system * If a platform hibernation driver is in use, 'platform' will be supported
* supports it (as determined by having hibernation_ops). * and will be used by default. Otherwise, 'shutdown' will be used by default.
* The selected option (i.e. the one corresponding to the current value of
* hibernation_mode) is enclosed by a square bracket.
*
* To select a given hibernation mode it is necessary to write the mode's
* string representation (as returned by reading from /sys/power/disk) back
* into /sys/power/disk.
*/ */
static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
...@@ -875,7 +878,6 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, ...@@ -875,7 +878,6 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
return buf-start; return buf-start;
} }
static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n) const char *buf, size_t n)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment