aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/suspend.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/suspend.c')
-rw-r--r--kernel/power/suspend.c109
1 files changed, 76 insertions, 33 deletions
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 155721f7f909..963e6d0f050b 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -31,13 +31,14 @@
31 31
32#include "power.h" 32#include "power.h"
33 33
34const char *const pm_states[PM_SUSPEND_MAX] = { 34struct pm_sleep_state pm_states[PM_SUSPEND_MAX] = {
35 [PM_SUSPEND_FREEZE] = "freeze", 35 [PM_SUSPEND_FREEZE] = { .label = "freeze", .state = PM_SUSPEND_FREEZE },
36 [PM_SUSPEND_STANDBY] = "standby", 36 [PM_SUSPEND_STANDBY] = { .label = "standby", },
37 [PM_SUSPEND_MEM] = "mem", 37 [PM_SUSPEND_MEM] = { .label = "mem", },
38}; 38};
39 39
40static const struct platform_suspend_ops *suspend_ops; 40static const struct platform_suspend_ops *suspend_ops;
41static const struct platform_freeze_ops *freeze_ops;
41 42
42static bool need_suspend_ops(suspend_state_t state) 43static bool need_suspend_ops(suspend_state_t state)
43{ 44{
@@ -47,6 +48,13 @@ static bool need_suspend_ops(suspend_state_t state)
47static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head); 48static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
48static bool suspend_freeze_wake; 49static bool suspend_freeze_wake;
49 50
51void freeze_set_ops(const struct platform_freeze_ops *ops)
52{
53 lock_system_sleep();
54 freeze_ops = ops;
55 unlock_system_sleep();
56}
57
50static void freeze_begin(void) 58static void freeze_begin(void)
51{ 59{
52 suspend_freeze_wake = false; 60 suspend_freeze_wake = false;
@@ -68,42 +76,62 @@ void freeze_wake(void)
68} 76}
69EXPORT_SYMBOL_GPL(freeze_wake); 77EXPORT_SYMBOL_GPL(freeze_wake);
70 78
79static bool valid_state(suspend_state_t state)
80{
81 /*
82 * PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level
83 * support and need to be valid to the low level
84 * implementation, no valid callback implies that none are valid.
85 */
86 return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
87}
88
89/*
90 * If this is set, the "mem" label always corresponds to the deepest sleep state
91 * available, the "standby" label corresponds to the second deepest sleep state
92 * available (if any), and the "freeze" label corresponds to the remaining
93 * available sleep state (if there is one).
94 */
95static bool relative_states;
96
97static int __init sleep_states_setup(char *str)
98{
99 relative_states = !strncmp(str, "1", 1);
100 if (relative_states) {
101 pm_states[PM_SUSPEND_MEM].state = PM_SUSPEND_FREEZE;
102 pm_states[PM_SUSPEND_FREEZE].state = 0;
103 }
104 return 1;
105}
106
107__setup("relative_sleep_states=", sleep_states_setup);
108
71/** 109/**
72 * suspend_set_ops - Set the global suspend method table. 110 * suspend_set_ops - Set the global suspend method table.
73 * @ops: Suspend operations to use. 111 * @ops: Suspend operations to use.
74 */ 112 */
75void suspend_set_ops(const struct platform_suspend_ops *ops) 113void suspend_set_ops(const struct platform_suspend_ops *ops)
76{ 114{
115 suspend_state_t i;
116 int j = PM_SUSPEND_MAX - 1;
117
77 lock_system_sleep(); 118 lock_system_sleep();
119
78 suspend_ops = ops; 120 suspend_ops = ops;
121 for (i = PM_SUSPEND_MEM; i >= PM_SUSPEND_STANDBY; i--)
122 if (valid_state(i))
123 pm_states[j--].state = i;
124 else if (!relative_states)
125 pm_states[j--].state = 0;
126
127 pm_states[j--].state = PM_SUSPEND_FREEZE;
128 while (j >= PM_SUSPEND_MIN)
129 pm_states[j--].state = 0;
130
79 unlock_system_sleep(); 131 unlock_system_sleep();
80} 132}
81EXPORT_SYMBOL_GPL(suspend_set_ops); 133EXPORT_SYMBOL_GPL(suspend_set_ops);
82 134
83bool valid_state(suspend_state_t state)
84{
85 if (state == PM_SUSPEND_FREEZE) {
86#ifdef CONFIG_PM_DEBUG
87 if (pm_test_level != TEST_NONE &&
88 pm_test_level != TEST_FREEZER &&
89 pm_test_level != TEST_DEVICES &&
90 pm_test_level != TEST_PLATFORM) {
91 printk(KERN_WARNING "Unsupported pm_test mode for "
92 "freeze state, please choose "
93 "none/freezer/devices/platform.\n");
94 return false;
95 }
96#endif
97 return true;
98 }
99 /*
100 * PM_SUSPEND_STANDBY and PM_SUSPEND_MEMORY states need lowlevel
101 * support and need to be valid to the lowlevel
102 * implementation, no valid callback implies that none are valid.
103 */
104 return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
105}
106
107/** 135/**
108 * suspend_valid_only_mem - Generic memory-only valid callback. 136 * suspend_valid_only_mem - Generic memory-only valid callback.
109 * 137 *
@@ -271,6 +299,10 @@ int suspend_devices_and_enter(suspend_state_t state)
271 error = suspend_ops->begin(state); 299 error = suspend_ops->begin(state);
272 if (error) 300 if (error)
273 goto Close; 301 goto Close;
302 } else if (state == PM_SUSPEND_FREEZE && freeze_ops->begin) {
303 error = freeze_ops->begin();
304 if (error)
305 goto Close;
274 } 306 }
275 suspend_console(); 307 suspend_console();
276 suspend_test_start(); 308 suspend_test_start();
@@ -296,6 +328,9 @@ int suspend_devices_and_enter(suspend_state_t state)
296 Close: 328 Close:
297 if (need_suspend_ops(state) && suspend_ops->end) 329 if (need_suspend_ops(state) && suspend_ops->end)
298 suspend_ops->end(); 330 suspend_ops->end();
331 else if (state == PM_SUSPEND_FREEZE && freeze_ops->end)
332 freeze_ops->end();
333
299 trace_machine_suspend(PWR_EVENT_EXIT); 334 trace_machine_suspend(PWR_EVENT_EXIT);
300 return error; 335 return error;
301 336
@@ -330,9 +365,17 @@ static int enter_state(suspend_state_t state)
330{ 365{
331 int error; 366 int error;
332 367
333 if (!valid_state(state)) 368 if (state == PM_SUSPEND_FREEZE) {
334 return -ENODEV; 369#ifdef CONFIG_PM_DEBUG
335 370 if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {
371 pr_warning("PM: Unsupported test mode for freeze state,"
372 "please choose none/freezer/devices/platform.\n");
373 return -EAGAIN;
374 }
375#endif
376 } else if (!valid_state(state)) {
377 return -EINVAL;
378 }
336 if (!mutex_trylock(&pm_mutex)) 379 if (!mutex_trylock(&pm_mutex))
337 return -EBUSY; 380 return -EBUSY;
338 381
@@ -343,7 +386,7 @@ static int enter_state(suspend_state_t state)
343 sys_sync(); 386 sys_sync();
344 printk("done.\n"); 387 printk("done.\n");
345 388
346 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 389 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state].label);
347 error = suspend_prepare(state); 390 error = suspend_prepare(state);
348 if (error) 391 if (error)
349 goto Unlock; 392 goto Unlock;
@@ -351,7 +394,7 @@ static int enter_state(suspend_state_t state)
351 if (suspend_test(TEST_FREEZER)) 394 if (suspend_test(TEST_FREEZER))
352 goto Finish; 395 goto Finish;
353 396
354 pr_debug("PM: Entering %s sleep\n", pm_states[state]); 397 pr_debug("PM: Entering %s sleep\n", pm_states[state].label);
355 pm_restrict_gfp_mask(); 398 pm_restrict_gfp_mask();
356 error = suspend_devices_and_enter(state); 399 error = suspend_devices_and_enter(state);
357 pm_restore_gfp_mask(); 400 pm_restore_gfp_mask();