Merge master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
[powerpc.git] / kernel / power / disk.c
index dee0ff4..0633137 100644 (file)
@@ -39,7 +39,13 @@ static inline int platform_prepare(void)
 {
        int error = 0;
 
-       if (pm_disk_mode == PM_DISK_PLATFORM) {
+       switch (pm_disk_mode) {
+       case PM_DISK_TEST:
+       case PM_DISK_TESTPROC:
+       case PM_DISK_SHUTDOWN:
+       case PM_DISK_REBOOT:
+               break;
+       default:
                if (pm_ops && pm_ops->prepare)
                        error = pm_ops->prepare(PM_SUSPEND_DISK);
        }
@@ -48,41 +54,48 @@ static inline int platform_prepare(void)
 
 /**
  *     power_down - Shut machine down for hibernate.
- *     @mode:          Suspend-to-disk mode
  *
- *     Use the platform driver, if configured so, and return gracefully if it
- *     fails.
- *     Otherwise, try to power off and reboot. If they fail, halt the machine,
- *     there ain't no turning back.
+ *     Use the platform driver, if configured so; otherwise try
+ *     to power off or reboot.
  */
 
-static void power_down(suspend_disk_method_t mode)
+static void power_down(void)
 {
-       disable_nonboot_cpus();
-       switch(mode) {
-       case PM_DISK_PLATFORM:
-               if (pm_ops && pm_ops->enter) {
-                       kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-                       pm_ops->enter(PM_SUSPEND_DISK);
-                       break;
-               }
+       switch (pm_disk_mode) {
+       case PM_DISK_TEST:
+       case PM_DISK_TESTPROC:
+               break;
        case PM_DISK_SHUTDOWN:
                kernel_power_off();
                break;
        case PM_DISK_REBOOT:
                kernel_restart(NULL);
                break;
+       default:
+               if (pm_ops && pm_ops->enter) {
+                       kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+                       pm_ops->enter(PM_SUSPEND_DISK);
+                       break;
+               }
        }
        kernel_halt();
-       /* Valid image is on the disk, if we continue we risk serious data corruption
-          after resume. */
+       /*
+        * 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");
        while(1);
 }
 
 static inline void platform_finish(void)
 {
-       if (pm_disk_mode == PM_DISK_PLATFORM) {
+       switch (pm_disk_mode) {
+       case PM_DISK_TEST:
+       case PM_DISK_TESTPROC:
+       case PM_DISK_SHUTDOWN:
+       case PM_DISK_REBOOT:
+               break;
+       default:
                if (pm_ops && pm_ops->finish)
                        pm_ops->finish(PM_SUSPEND_DISK);
        }
@@ -109,8 +122,6 @@ static int prepare_processes(void)
 /**
  *     pm_suspend_disk - The granpappy of hibernation power management.
  *
- *     If we're going through the firmware, then get it over with quickly.
- *
  *     If not, then call swsusp to do its thing, then figure out how
  *     to power down the system.
  */
@@ -119,15 +130,25 @@ int pm_suspend_disk(void)
 {
        int error;
 
+       /* The snapshot device should not be opened while we're running */
+       if (!atomic_add_unless(&snapshot_device_available, -1, 0))
+               return -EBUSY;
+
+       /* Allocate memory management structures */
+       error = create_basic_memory_bitmaps();
+       if (error)
+               goto Exit;
+
        error = prepare_processes();
        if (error)
-               return error;
+               goto Finish;
 
        if (pm_disk_mode == PM_DISK_TESTPROC) {
                printk("swsusp debug: Waiting for 5 seconds.\n");
                mdelay(5000);
                goto Thaw;
        }
+
        /* Free memory before shutting down devices. */
        error = swsusp_shrink_memory();
        if (error)
@@ -167,7 +188,7 @@ int pm_suspend_disk(void)
                pr_debug("PM: writing image.\n");
                error = swsusp_write();
                if (!error)
-                       power_down(pm_disk_mode);
+                       power_down();
                else {
                        swsusp_free();
                        goto Thaw;
@@ -185,6 +206,10 @@ int pm_suspend_disk(void)
        resume_console();
  Thaw:
        unprepare_processes();
+ Finish:
+       free_basic_memory_bitmaps();
+ Exit:
+       atomic_inc(&snapshot_device_available);
        return error;
 }
 
@@ -228,13 +253,21 @@ static int software_resume(void)
        }
 
        pr_debug("PM: Checking swsusp image.\n");
-
        error = swsusp_check();
        if (error)
-               goto Done;
+               goto Unlock;
 
-       pr_debug("PM: Preparing processes for restore.\n");
+       /* The snapshot device should not be opened while we're running */
+       if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+               error = -EBUSY;
+               goto Unlock;
+       }
 
+       error = create_basic_memory_bitmaps();
+       if (error)
+               goto Finish;
+
+       pr_debug("PM: Preparing processes for restore.\n");
        error = prepare_processes();
        if (error) {
                swsusp_close();
@@ -269,7 +302,11 @@ static int software_resume(void)
        printk(KERN_ERR "PM: Restore failed, recovering.\n");
        unprepare_processes();
  Done:
+       free_basic_memory_bitmaps();
+ Finish:
+       atomic_inc(&snapshot_device_available);
        /* For success case, the suspend path will release the lock */
+ Unlock:
        mutex_unlock(&pm_mutex);
        pr_debug("PM: Resume from disk failed.\n");
        return 0;
@@ -279,7 +316,6 @@ late_initcall(software_resume);
 
 
 static const char * const pm_disk_modes[] = {
-       [PM_DISK_FIRMWARE]      = "firmware",
        [PM_DISK_PLATFORM]      = "platform",
        [PM_DISK_SHUTDOWN]      = "shutdown",
        [PM_DISK_REBOOT]        = "reboot",
@@ -290,37 +326,62 @@ static const char * const pm_disk_modes[] = {
 /**
  *     disk - Control suspend-to-disk mode
  *
- *     Suspend-to-disk can be handled in several ways. The greatest
- *     distinction is who writes memory to disk - the firmware or the OS.
- *     If the firmware does it, we assume that it also handles suspending
- *     the system.
- *     If the OS does it, then we have three options for putting the system
- *     to sleep - using the platform driver (e.g. ACPI or other PM registers),
- *     powering off the system or rebooting the system (for testing).
+ *     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 pm_ops), powering off the system or rebooting the system
+ *     (for testing) as well as the two test modes.
  *
- *     The system will support either 'firmware' or 'platform', and that is
- *     known a priori (and encoded in pm_ops). But, the user may choose
- *     'shutdown' or 'reboot' as alternatives.
+ *     The system can support 'platform', and that is known a priori (and
+ *     encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot'
+ *     as alternatives, as well as the test modes 'test' and 'testproc'.
  *
  *     show() will display what the mode is currently set to.
  *     store() will accept one of
  *
- *     'firmware'
  *     'platform'
  *     'shutdown'
  *     'reboot'
+ *     'test'
+ *     'testproc'
  *
- *     It will only change to 'firmware' or 'platform' if the system
+ *     It will only change to 'platform' if the system
  *     supports it (as determined from pm_ops->pm_disk_mode).
  */
 
-static ssize_t disk_show(struct subsystem * subsys, char * buf)
+static ssize_t disk_show(struct kset *kset, char *buf)
 {
-       return sprintf(buf, "%s\n", pm_disk_modes[pm_disk_mode]);
+       int i;
+       char *start = buf;
+
+       for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
+               if (!pm_disk_modes[i])
+                       continue;
+               switch (i) {
+               case PM_DISK_SHUTDOWN:
+               case PM_DISK_REBOOT:
+               case PM_DISK_TEST:
+               case PM_DISK_TESTPROC:
+                       break;
+               default:
+                       if (pm_ops && pm_ops->enter &&
+                           (i == pm_ops->pm_disk_mode))
+                               break;
+                       /* not a valid mode, continue with loop */
+                       continue;
+               }
+               if (i == pm_disk_mode)
+                       buf += sprintf(buf, "[%s]", pm_disk_modes[i]);
+               else
+                       buf += sprintf(buf, "%s", pm_disk_modes[i]);
+               if (i+1 != PM_DISK_MAX)
+                       buf += sprintf(buf, " ");
+       }
+       buf += sprintf(buf, "\n");
+       return buf-start;
 }
 
 
-static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
+static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
 {
        int error = 0;
        int i;
@@ -332,17 +393,21 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
        len = p ? p - buf : n;
 
        mutex_lock(&pm_mutex);
-       for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) {
+       for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
                if (!strncmp(buf, pm_disk_modes[i], len)) {
                        mode = i;
                        break;
                }
        }
        if (mode) {
-               if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT ||
-                    mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) {
+               switch (mode) {
+               case PM_DISK_SHUTDOWN:
+               case PM_DISK_REBOOT:
+               case PM_DISK_TEST:
+               case PM_DISK_TESTPROC:
                        pm_disk_mode = mode;
-               } else {
+                       break;
+               default:
                        if (pm_ops && pm_ops->enter &&
                            (mode == pm_ops->pm_disk_mode))
                                pm_disk_mode = mode;
@@ -361,13 +426,13 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
 
 power_attr(disk);
 
-static ssize_t resume_show(struct subsystem * subsys, char *buf)
+static ssize_t resume_show(struct kset *kset, char *buf)
 {
        return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
                       MINOR(swsusp_resume_device));
 }
 
-static ssize_t resume_store(struct subsystem *subsys, const char *buf, size_t n)
+static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
 {
        unsigned int maj, min;
        dev_t res;
@@ -393,12 +458,12 @@ static ssize_t resume_store(struct subsystem *subsys, const char *buf, size_t n)
 
 power_attr(resume);
 
-static ssize_t image_size_show(struct subsystem * subsys, char *buf)
+static ssize_t image_size_show(struct kset *kset, char *buf)
 {
        return sprintf(buf, "%lu\n", image_size);
 }
 
-static ssize_t image_size_store(struct subsystem * subsys, const char * buf, size_t n)
+static ssize_t image_size_store(struct kset *kset, const char *buf, size_t n)
 {
        unsigned long size;
 
@@ -427,7 +492,7 @@ static struct attribute_group attr_group = {
 
 static int __init pm_disk_init(void)
 {
-       return sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+       return sysfs_create_group(&power_subsys.kobj, &attr_group);
 }
 
 core_initcall(pm_disk_init);