ACPI: S4: Use "platform" rather than "shutdown" mode by default
[safe/jmp/linux-2.6] / kernel / power / main.c
index 18d7d69..1210961 100644 (file)
@@ -15,7 +15,9 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/pm.h>
-
+#include <linux/console.h>
+#include <linux/cpu.h>
+#include <linux/resume-trace.h>
 
 #include "power.h"
 
@@ -24,8 +26,8 @@
 
 DECLARE_MUTEX(pm_sem);
 
-struct pm_ops * pm_ops = NULL;
-suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
+struct pm_ops *pm_ops;
+suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
 
 /**
  *     pm_set_ops - Set the global power method table. 
@@ -51,7 +53,7 @@ void pm_set_ops(struct pm_ops * ops)
 
 static int suspend_prepare(suspend_state_t state)
 {
-       int error = 0;
+       int error;
        unsigned int free_pages;
 
        if (!pm_ops || !pm_ops->enter)
@@ -59,12 +61,9 @@ static int suspend_prepare(suspend_state_t state)
 
        pm_prepare_console();
 
-       disable_nonboot_cpus();
-
-       if (num_online_cpus() != 1) {
-               error = -EPERM;
+       error = disable_nonboot_cpus();
+       if (error)
                goto Enable_cpu;
-       }
 
        if (freeze_processes()) {
                error = -EAGAIN;
@@ -86,6 +85,7 @@ static int suspend_prepare(suspend_state_t state)
                        goto Thaw;
        }
 
+       suspend_console();
        if ((error = device_suspend(PMSG_SUSPEND))) {
                printk(KERN_ERR "Some devices failed to suspend\n");
                goto Finish;
@@ -103,7 +103,7 @@ static int suspend_prepare(suspend_state_t state)
 }
 
 
-static int suspend_enter(suspend_state_t state)
+int suspend_enter(suspend_state_t state)
 {
        int error = 0;
        unsigned long flags;
@@ -133,17 +133,18 @@ static int suspend_enter(suspend_state_t state)
 static void suspend_finish(suspend_state_t state)
 {
        device_resume();
-       if (pm_ops && pm_ops->finish)
-               pm_ops->finish(state);
+       resume_console();
        thaw_processes();
        enable_nonboot_cpus();
+       if (pm_ops && pm_ops->finish)
+               pm_ops->finish(state);
        pm_restore_console();
 }
 
 
 
 
-static char *pm_states[PM_SUSPEND_MAX] = {
+static const char * const pm_states[PM_SUSPEND_MAX] = {
        [PM_SUSPEND_STANDBY]    = "standby",
        [PM_SUSPEND_MEM]        = "mem",
 #ifdef CONFIG_SOFTWARE_SUSPEND
@@ -151,6 +152,18 @@ static char *pm_states[PM_SUSPEND_MAX] = {
 #endif
 };
 
+static inline int valid_state(suspend_state_t state)
+{
+       /* Suspend-to-disk does not really need low-level support.
+        * It can work with reboot if needed. */
+       if (state == PM_SUSPEND_DISK)
+               return 1;
+
+       if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
+               return 0;
+       return 1;
+}
+
 
 /**
  *     enter_state - Do common work of entering low-power state.
@@ -167,7 +180,7 @@ static int enter_state(suspend_state_t state)
 {
        int error;
 
-       if (pm_ops->valid && !pm_ops->valid(state))
+       if (!valid_state(state))
                return -ENODEV;
        if (down_trylock(&pm_sem))
                return -EBUSY;
@@ -238,9 +251,8 @@ static ssize_t state_show(struct subsystem * subsys, char * buf)
        char * s = buf;
 
        for (i = 0; i < PM_SUSPEND_MAX; i++) {
-               if (pm_states[i] && pm_ops && (!pm_ops->valid
-                       ||(pm_ops->valid && pm_ops->valid(i))))
-                       s += sprintf(s,"%s ",pm_states[i]);
+               if (pm_states[i] && valid_state(i))
+                       s += sprintf(s,"%s ", pm_states[i]);
        }
        s += sprintf(s,"\n");
        return (s - buf);
@@ -249,7 +261,7 @@ static ssize_t state_show(struct subsystem * subsys, char * buf)
 static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
 {
        suspend_state_t state = PM_SUSPEND_STANDBY;
-       char ** s;
+       const char * const *s;
        char *p;
        int error;
        int len;
@@ -261,7 +273,7 @@ static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n
                if (*s && !strncmp(buf, *s, len))
                        break;
        }
-       if (*s)
+       if (state < PM_SUSPEND_MAX && *s)
                error = enter_state(state);
        else
                error = -EINVAL;
@@ -270,10 +282,39 @@ static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n
 
 power_attr(state);
 
+#ifdef CONFIG_PM_TRACE
+int pm_trace_enabled;
+
+static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
+{
+       return sprintf(buf, "%d\n", pm_trace_enabled);
+}
+
+static ssize_t
+pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
+{
+       int val;
+
+       if (sscanf(buf, "%d", &val) == 1) {
+               pm_trace_enabled = !!val;
+               return n;
+       }
+       return -EINVAL;
+}
+
+power_attr(pm_trace);
+
+static struct attribute * g[] = {
+       &state_attr.attr,
+       &pm_trace_attr.attr,
+       NULL,
+};
+#else
 static struct attribute * g[] = {
        &state_attr.attr,
        NULL,
 };
+#endif /* CONFIG_PM_TRACE */
 
 static struct attribute_group attr_group = {
        .attrs = g,