diff options
| author | Rafael J. Wysocki <rjw@sisk.pl> | 2006-11-03 01:07:19 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-11-03 15:27:58 -0500 |
| commit | b918f6e62cd46774f9fc0a3fbba6bd10ad85ee14 (patch) | |
| tree | d73dc0e8823c8445d84701cc3d527e0e34494a32 | |
| parent | 90d53909443b3986569b38ef145f09ea2359af75 (diff) | |
[PATCH] swsusp: debugging
Add a swsusp debugging mode. This does everything that's needed for a suspend
except for actually suspending. So we can look in the log messages and work
out a) what code is being slow and b) which drivers are misbehaving.
(1)
# echo testproc > /sys/power/disk
# echo disk > /sys/power/state
This should turn off the non-boot CPU, freeze all processes, wait for 5
seconds and then thaw the processes and the CPU.
(2)
# echo test > /sys/power/disk
# echo disk > /sys/power/state
This should turn off the non-boot CPU, freeze all processes, shrink
memory, suspend all devices, wait for 5 seconds, resume the devices etc.
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Stefan Seyfried <seife@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | Documentation/ABI/testing/sysfs-power | 17 | ||||
| -rw-r--r-- | Documentation/power/interface.txt | 13 | ||||
| -rw-r--r-- | include/linux/pm.h | 4 | ||||
| -rw-r--r-- | kernel/power/disk.c | 37 |
4 files changed, 60 insertions, 11 deletions
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index d882f8093871..dcff4d0623ad 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power | |||
| @@ -21,7 +21,7 @@ Description: | |||
| 21 | these states. | 21 | these states. |
| 22 | 22 | ||
| 23 | What: /sys/power/disk | 23 | What: /sys/power/disk |
| 24 | Date: August 2006 | 24 | Date: September 2006 |
| 25 | Contact: Rafael J. Wysocki <rjw@sisk.pl> | 25 | Contact: Rafael J. Wysocki <rjw@sisk.pl> |
| 26 | Description: | 26 | Description: |
| 27 | The /sys/power/disk file controls the operating mode of the | 27 | The /sys/power/disk file controls the operating mode of the |
| @@ -39,6 +39,19 @@ Description: | |||
| 39 | 'reboot' - the memory image will be saved by the kernel and | 39 | 'reboot' - the memory image will be saved by the kernel and |
| 40 | the system will be rebooted. | 40 | the system will be rebooted. |
| 41 | 41 | ||
| 42 | Additionally, /sys/power/disk can be used to turn on one of the | ||
| 43 | two testing modes of the suspend-to-disk mechanism: 'testproc' | ||
| 44 | or 'test'. If the suspend-to-disk mechanism is in the | ||
| 45 | 'testproc' mode, writing 'disk' to /sys/power/state will cause | ||
| 46 | the kernel to disable nonboot CPUs and freeze tasks, wait for 5 | ||
| 47 | seconds, unfreeze tasks and enable nonboot CPUs. If it is in | ||
| 48 | the 'test' mode, writing 'disk' to /sys/power/state will cause | ||
| 49 | the kernel to disable nonboot CPUs and freeze tasks, shrink | ||
| 50 | memory, suspend devices, wait for 5 seconds, resume devices, | ||
| 51 | unfreeze tasks and enable nonboot CPUs. Then, we are able to | ||
| 52 | look in the log messages and work out, for example, which code | ||
| 53 | is being slow and which device drivers are misbehaving. | ||
| 54 | |||
| 42 | The suspend-to-disk method may be chosen by writing to this | 55 | The suspend-to-disk method may be chosen by writing to this |
| 43 | file one of the accepted strings: | 56 | file one of the accepted strings: |
| 44 | 57 | ||
| @@ -46,6 +59,8 @@ Description: | |||
| 46 | 'platform' | 59 | 'platform' |
| 47 | 'shutdown' | 60 | 'shutdown' |
| 48 | 'reboot' | 61 | 'reboot' |
| 62 | 'testproc' | ||
| 63 | 'test' | ||
| 49 | 64 | ||
| 50 | It will only change to 'firmware' or 'platform' if the system | 65 | It will only change to 'firmware' or 'platform' if the system |
| 51 | supports that. | 66 | supports that. |
diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt index a66bec222b16..74311d7e0f3c 100644 --- a/Documentation/power/interface.txt +++ b/Documentation/power/interface.txt | |||
| @@ -30,6 +30,17 @@ testing). The system will support either 'firmware' or 'platform', and | |||
| 30 | that is known a priori. But, the user may choose 'shutdown' or | 30 | that is known a priori. But, the user may choose 'shutdown' or |
| 31 | 'reboot' as alternatives. | 31 | 'reboot' as alternatives. |
| 32 | 32 | ||
| 33 | Additionally, /sys/power/disk can be used to turn on one of the two testing | ||
| 34 | modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the | ||
| 35 | suspend-to-disk mechanism is in the 'testproc' mode, writing 'disk' to | ||
| 36 | /sys/power/state will cause the kernel to disable nonboot CPUs and freeze | ||
| 37 | tasks, wait for 5 seconds, unfreeze tasks and enable nonboot CPUs. If it is | ||
| 38 | in the 'test' mode, writing 'disk' to /sys/power/state will cause the kernel | ||
| 39 | to disable nonboot CPUs and freeze tasks, shrink memory, suspend devices, wait | ||
| 40 | for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then, | ||
| 41 | we are able to look in the log messages and work out, for example, which code | ||
| 42 | is being slow and which device drivers are misbehaving. | ||
| 43 | |||
| 33 | Reading from this file will display what the mode is currently set | 44 | Reading from this file will display what the mode is currently set |
| 34 | to. Writing to this file will accept one of | 45 | to. Writing to this file will accept one of |
| 35 | 46 | ||
| @@ -37,6 +48,8 @@ to. Writing to this file will accept one of | |||
| 37 | 'platform' | 48 | 'platform' |
| 38 | 'shutdown' | 49 | 'shutdown' |
| 39 | 'reboot' | 50 | 'reboot' |
| 51 | 'testproc' | ||
| 52 | 'test' | ||
| 40 | 53 | ||
| 41 | It will only change to 'firmware' or 'platform' if the system supports | 54 | It will only change to 'firmware' or 'platform' if the system supports |
| 42 | it. | 55 | it. |
diff --git a/include/linux/pm.h b/include/linux/pm.h index 6b27e07aef19..070394e846d0 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
| @@ -116,7 +116,9 @@ typedef int __bitwise suspend_disk_method_t; | |||
| 116 | #define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2) | 116 | #define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2) |
| 117 | #define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3) | 117 | #define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3) |
| 118 | #define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4) | 118 | #define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4) |
| 119 | #define PM_DISK_MAX ((__force suspend_disk_method_t) 5) | 119 | #define PM_DISK_TEST ((__force suspend_disk_method_t) 5) |
| 120 | #define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6) | ||
| 121 | #define PM_DISK_MAX ((__force suspend_disk_method_t) 7) | ||
| 120 | 122 | ||
| 121 | struct pm_ops { | 123 | struct pm_ops { |
| 122 | suspend_disk_method_t pm_disk_mode; | 124 | suspend_disk_method_t pm_disk_mode; |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index d3a158a60312..b1fb7866b0b3 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
| @@ -71,7 +71,7 @@ static inline void platform_finish(void) | |||
| 71 | 71 | ||
| 72 | static int prepare_processes(void) | 72 | static int prepare_processes(void) |
| 73 | { | 73 | { |
| 74 | int error; | 74 | int error = 0; |
| 75 | 75 | ||
| 76 | pm_prepare_console(); | 76 | pm_prepare_console(); |
| 77 | 77 | ||
| @@ -84,6 +84,12 @@ static int prepare_processes(void) | |||
| 84 | goto thaw; | 84 | goto thaw; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | if (pm_disk_mode == PM_DISK_TESTPROC) { | ||
| 88 | printk("swsusp debug: Waiting for 5 seconds.\n"); | ||
| 89 | mdelay(5000); | ||
| 90 | goto thaw; | ||
| 91 | } | ||
| 92 | |||
| 87 | /* Free memory before shutting down devices. */ | 93 | /* Free memory before shutting down devices. */ |
| 88 | if (!(error = swsusp_shrink_memory())) | 94 | if (!(error = swsusp_shrink_memory())) |
| 89 | return 0; | 95 | return 0; |
| @@ -120,13 +126,21 @@ int pm_suspend_disk(void) | |||
| 120 | if (error) | 126 | if (error) |
| 121 | return error; | 127 | return error; |
| 122 | 128 | ||
| 129 | if (pm_disk_mode == PM_DISK_TESTPROC) | ||
| 130 | goto Thaw; | ||
| 131 | |||
| 123 | suspend_console(); | 132 | suspend_console(); |
| 124 | error = device_suspend(PMSG_FREEZE); | 133 | error = device_suspend(PMSG_FREEZE); |
| 125 | if (error) { | 134 | if (error) { |
| 126 | resume_console(); | 135 | resume_console(); |
| 127 | printk("Some devices failed to suspend\n"); | 136 | printk("Some devices failed to suspend\n"); |
| 128 | unprepare_processes(); | 137 | goto Thaw; |
| 129 | return error; | 138 | } |
| 139 | |||
| 140 | if (pm_disk_mode == PM_DISK_TEST) { | ||
| 141 | printk("swsusp debug: Waiting for 5 seconds.\n"); | ||
| 142 | mdelay(5000); | ||
| 143 | goto Done; | ||
| 130 | } | 144 | } |
| 131 | 145 | ||
| 132 | pr_debug("PM: snapshotting memory.\n"); | 146 | pr_debug("PM: snapshotting memory.\n"); |
| @@ -143,16 +157,17 @@ int pm_suspend_disk(void) | |||
| 143 | power_down(pm_disk_mode); | 157 | power_down(pm_disk_mode); |
| 144 | else { | 158 | else { |
| 145 | swsusp_free(); | 159 | swsusp_free(); |
| 146 | unprepare_processes(); | 160 | goto Thaw; |
| 147 | return error; | ||
| 148 | } | 161 | } |
| 149 | } else | 162 | } else { |
| 150 | pr_debug("PM: Image restored successfully.\n"); | 163 | pr_debug("PM: Image restored successfully.\n"); |
| 164 | } | ||
| 151 | 165 | ||
| 152 | swsusp_free(); | 166 | swsusp_free(); |
| 153 | Done: | 167 | Done: |
| 154 | device_resume(); | 168 | device_resume(); |
| 155 | resume_console(); | 169 | resume_console(); |
| 170 | Thaw: | ||
| 156 | unprepare_processes(); | 171 | unprepare_processes(); |
| 157 | return error; | 172 | return error; |
| 158 | } | 173 | } |
| @@ -249,6 +264,8 @@ static const char * const pm_disk_modes[] = { | |||
| 249 | [PM_DISK_PLATFORM] = "platform", | 264 | [PM_DISK_PLATFORM] = "platform", |
| 250 | [PM_DISK_SHUTDOWN] = "shutdown", | 265 | [PM_DISK_SHUTDOWN] = "shutdown", |
| 251 | [PM_DISK_REBOOT] = "reboot", | 266 | [PM_DISK_REBOOT] = "reboot", |
| 267 | [PM_DISK_TEST] = "test", | ||
| 268 | [PM_DISK_TESTPROC] = "testproc", | ||
| 252 | }; | 269 | }; |
| 253 | 270 | ||
| 254 | /** | 271 | /** |
| @@ -303,17 +320,19 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n) | |||
| 303 | } | 320 | } |
| 304 | } | 321 | } |
| 305 | if (mode) { | 322 | if (mode) { |
| 306 | if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT) | 323 | if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT || |
| 324 | mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) { | ||
| 307 | pm_disk_mode = mode; | 325 | pm_disk_mode = mode; |
| 308 | else { | 326 | } else { |
| 309 | if (pm_ops && pm_ops->enter && | 327 | if (pm_ops && pm_ops->enter && |
| 310 | (mode == pm_ops->pm_disk_mode)) | 328 | (mode == pm_ops->pm_disk_mode)) |
| 311 | pm_disk_mode = mode; | 329 | pm_disk_mode = mode; |
| 312 | else | 330 | else |
| 313 | error = -EINVAL; | 331 | error = -EINVAL; |
| 314 | } | 332 | } |
| 315 | } else | 333 | } else { |
| 316 | error = -EINVAL; | 334 | error = -EINVAL; |
| 335 | } | ||
| 317 | 336 | ||
| 318 | pr_debug("PM: suspend-to-disk mode set to '%s'\n", | 337 | pr_debug("PM: suspend-to-disk mode set to '%s'\n", |
| 319 | pm_disk_modes[mode]); | 338 | pm_disk_modes[mode]); |
