Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[sfrench/cifs-2.6.git] / kernel / power / main.c
index e1c4131204698fd891af0b8046406ae4fd0ff76a..f6dda685e7e2b06bd0eb27631dd84dbf33e8c0ef 100644 (file)
@@ -30,7 +30,7 @@
 DEFINE_MUTEX(pm_mutex);
 
 struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
+suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
 
 /**
  *     pm_set_ops - Set the global power method table. 
@@ -41,9 +41,26 @@ void pm_set_ops(struct pm_ops * ops)
 {
        mutex_lock(&pm_mutex);
        pm_ops = ops;
+       if (ops && ops->pm_disk_mode != PM_DISK_INVALID) {
+               pm_disk_mode = ops->pm_disk_mode;
+       } else
+               pm_disk_mode = PM_DISK_SHUTDOWN;
        mutex_unlock(&pm_mutex);
 }
 
+/**
+ * pm_valid_only_mem - generic memory-only valid callback
+ *
+ * pm_ops drivers that implement mem suspend only and only need
+ * to check for that in their .valid callback can use this instead
+ * of rolling their own .valid callback.
+ */
+int pm_valid_only_mem(suspend_state_t state)
+{
+       return state == PM_SUSPEND_MEM;
+}
+
+
 static inline void pm_finish(suspend_state_t state)
 {
        if (pm_ops->finish)
@@ -111,13 +128,24 @@ static int suspend_prepare(suspend_state_t state)
        return error;
 }
 
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
+{
+       local_irq_disable();
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
+{
+       local_irq_enable();
+}
 
 int suspend_enter(suspend_state_t state)
 {
        int error = 0;
-       unsigned long flags;
 
-       local_irq_save(flags);
+       arch_suspend_disable_irqs();
+       BUG_ON(!irqs_disabled());
 
        if ((error = device_power_down(PMSG_SUSPEND))) {
                printk(KERN_ERR "Some devices failed to power down\n");
@@ -126,7 +154,8 @@ int suspend_enter(suspend_state_t state)
        error = pm_ops->enter(state);
        device_power_up();
  Done:
-       local_irq_restore(flags);
+       arch_suspend_enable_irqs();
+       BUG_ON(irqs_disabled());
        return error;
 }
 
@@ -155,19 +184,26 @@ static void suspend_finish(suspend_state_t state)
 static const char * const pm_states[PM_SUSPEND_MAX] = {
        [PM_SUSPEND_STANDBY]    = "standby",
        [PM_SUSPEND_MEM]        = "mem",
-#ifdef CONFIG_SOFTWARE_SUSPEND
        [PM_SUSPEND_DISK]       = "disk",
-#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. */
+        * It can work with shutdown/reboot if needed. If it isn't
+        * configured, then it cannot be supported.
+        */
        if (state == PM_SUSPEND_DISK)
+#ifdef CONFIG_SOFTWARE_SUSPEND
                return 1;
+#else
+               return 0;
+#endif
 
-       if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
+       /* all other states need lowlevel support and need to be
+        * valid to the lowlevel implementation, no valid callback
+        * implies that none are valid. */
+       if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
                return 0;
        return 1;
 }
@@ -212,15 +248,6 @@ static int enter_state(suspend_state_t state)
        return error;
 }
 
-/*
- * This is main interface to the outside world. It needs to be
- * called from process context.
- */
-int software_suspend(void)
-{
-       return enter_state(PM_SUSPEND_DISK);
-}
-
 
 /**
  *     pm_suspend - Externally visible function for suspending system.
@@ -253,7 +280,7 @@ decl_subsys(power,NULL,NULL);
  *     proper enumerated value, and initiates a suspend transition.
  */
 
-static ssize_t state_show(struct subsystem * subsys, char * buf)
+static ssize_t state_show(struct kset *kset, char *buf)
 {
        int i;
        char * s = buf;
@@ -266,7 +293,7 @@ static ssize_t state_show(struct subsystem * subsys, char * buf)
        return (s - buf);
 }
 
-static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
+static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
 {
        suspend_state_t state = PM_SUSPEND_STANDBY;
        const char * const *s;
@@ -293,13 +320,13 @@ power_attr(state);
 #ifdef CONFIG_PM_TRACE
 int pm_trace_enabled;
 
-static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
+static ssize_t pm_trace_show(struct kset *kset, 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)
+pm_trace_store(struct kset *kset, const char *buf, size_t n)
 {
        int val;
 
@@ -333,7 +360,7 @@ static int __init pm_init(void)
 {
        int error = subsystem_register(&power_subsys);
        if (!error)
-               error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+               error = sysfs_create_group(&power_subsys.kobj,&attr_group);
        return error;
 }