diff options
Diffstat (limited to 'kernel/power/main.c')
-rw-r--r-- | kernel/power/main.c | 99 |
1 files changed, 55 insertions, 44 deletions
diff --git a/kernel/power/main.c b/kernel/power/main.c index 4d26ad394fb3..32147b57c3bf 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -65,14 +65,11 @@ static inline void pm_finish(suspend_state_t state) | |||
65 | 65 | ||
66 | /** | 66 | /** |
67 | * suspend_prepare - Do prep work before entering low-power state. | 67 | * suspend_prepare - Do prep work before entering low-power state. |
68 | * @state: State we're entering. | ||
69 | * | 68 | * |
70 | * This is common code that is called for each state that we're | 69 | * This is common code that is called for each state that we're entering. |
71 | * entering. Allocate a console, stop all processes, then make sure | 70 | * Run suspend notifiers, allocate a console and stop all processes. |
72 | * the platform can enter the requested state. | ||
73 | */ | 71 | */ |
74 | 72 | static int suspend_prepare(void) | |
75 | static int suspend_prepare(suspend_state_t state) | ||
76 | { | 73 | { |
77 | int error; | 74 | int error; |
78 | unsigned int free_pages; | 75 | unsigned int free_pages; |
@@ -91,43 +88,18 @@ static int suspend_prepare(suspend_state_t state) | |||
91 | goto Thaw; | 88 | goto Thaw; |
92 | } | 89 | } |
93 | 90 | ||
94 | if ((free_pages = global_page_state(NR_FREE_PAGES)) | 91 | free_pages = global_page_state(NR_FREE_PAGES); |
95 | < FREE_PAGE_NUMBER) { | 92 | if (free_pages < FREE_PAGE_NUMBER) { |
96 | pr_debug("PM: free some memory\n"); | 93 | pr_debug("PM: free some memory\n"); |
97 | shrink_all_memory(FREE_PAGE_NUMBER - free_pages); | 94 | shrink_all_memory(FREE_PAGE_NUMBER - free_pages); |
98 | if (nr_free_pages() < FREE_PAGE_NUMBER) { | 95 | if (nr_free_pages() < FREE_PAGE_NUMBER) { |
99 | error = -ENOMEM; | 96 | error = -ENOMEM; |
100 | printk(KERN_ERR "PM: No enough memory\n"); | 97 | printk(KERN_ERR "PM: No enough memory\n"); |
101 | goto Thaw; | ||
102 | } | 98 | } |
103 | } | 99 | } |
104 | |||
105 | if (pm_ops->set_target) { | ||
106 | error = pm_ops->set_target(state); | ||
107 | if (error) | ||
108 | goto Thaw; | ||
109 | } | ||
110 | suspend_console(); | ||
111 | error = device_suspend(PMSG_SUSPEND); | ||
112 | if (error) { | ||
113 | printk(KERN_ERR "Some devices failed to suspend\n"); | ||
114 | goto Resume_console; | ||
115 | } | ||
116 | if (pm_ops->prepare) { | ||
117 | if ((error = pm_ops->prepare(state))) | ||
118 | goto Resume_devices; | ||
119 | } | ||
120 | |||
121 | error = disable_nonboot_cpus(); | ||
122 | if (!error) | 100 | if (!error) |
123 | return 0; | 101 | return 0; |
124 | 102 | ||
125 | enable_nonboot_cpus(); | ||
126 | pm_finish(state); | ||
127 | Resume_devices: | ||
128 | device_resume(); | ||
129 | Resume_console: | ||
130 | resume_console(); | ||
131 | Thaw: | 103 | Thaw: |
132 | thaw_processes(); | 104 | thaw_processes(); |
133 | pm_restore_console(); | 105 | pm_restore_console(); |
@@ -148,6 +120,12 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) | |||
148 | local_irq_enable(); | 120 | local_irq_enable(); |
149 | } | 121 | } |
150 | 122 | ||
123 | /** | ||
124 | * suspend_enter - enter the desired system sleep state. | ||
125 | * @state: state to enter | ||
126 | * | ||
127 | * This function should be called after devices have been suspended. | ||
128 | */ | ||
151 | int suspend_enter(suspend_state_t state) | 129 | int suspend_enter(suspend_state_t state) |
152 | { | 130 | { |
153 | int error = 0; | 131 | int error = 0; |
@@ -167,21 +145,55 @@ int suspend_enter(suspend_state_t state) | |||
167 | return error; | 145 | return error; |
168 | } | 146 | } |
169 | 147 | ||
148 | /** | ||
149 | * suspend_devices_and_enter - suspend devices and enter the desired system sleep | ||
150 | * state. | ||
151 | * @state: state to enter | ||
152 | */ | ||
153 | int suspend_devices_and_enter(suspend_state_t state) | ||
154 | { | ||
155 | int error; | ||
156 | |||
157 | if (!pm_ops) | ||
158 | return -ENOSYS; | ||
159 | |||
160 | if (pm_ops->set_target) { | ||
161 | error = pm_ops->set_target(state); | ||
162 | if (error) | ||
163 | return error; | ||
164 | } | ||
165 | suspend_console(); | ||
166 | error = device_suspend(PMSG_SUSPEND); | ||
167 | if (error) { | ||
168 | printk(KERN_ERR "Some devices failed to suspend\n"); | ||
169 | goto Resume_console; | ||
170 | } | ||
171 | if (pm_ops->prepare) { | ||
172 | error = pm_ops->prepare(state); | ||
173 | if (error) | ||
174 | goto Resume_devices; | ||
175 | } | ||
176 | error = disable_nonboot_cpus(); | ||
177 | if (!error) | ||
178 | suspend_enter(state); | ||
179 | |||
180 | enable_nonboot_cpus(); | ||
181 | pm_finish(state); | ||
182 | Resume_devices: | ||
183 | device_resume(); | ||
184 | Resume_console: | ||
185 | resume_console(); | ||
186 | return error; | ||
187 | } | ||
170 | 188 | ||
171 | /** | 189 | /** |
172 | * suspend_finish - Do final work before exiting suspend sequence. | 190 | * suspend_finish - Do final work before exiting suspend sequence. |
173 | * @state: State we're coming out of. | ||
174 | * | 191 | * |
175 | * Call platform code to clean up, restart processes, and free the | 192 | * Call platform code to clean up, restart processes, and free the |
176 | * console that we've allocated. This is not called for suspend-to-disk. | 193 | * console that we've allocated. This is not called for suspend-to-disk. |
177 | */ | 194 | */ |
178 | 195 | static void suspend_finish(void) | |
179 | static void suspend_finish(suspend_state_t state) | ||
180 | { | 196 | { |
181 | enable_nonboot_cpus(); | ||
182 | pm_finish(state); | ||
183 | device_resume(); | ||
184 | resume_console(); | ||
185 | thaw_processes(); | 197 | thaw_processes(); |
186 | pm_restore_console(); | 198 | pm_restore_console(); |
187 | pm_notifier_call_chain(PM_POST_SUSPEND); | 199 | pm_notifier_call_chain(PM_POST_SUSPEND); |
@@ -216,7 +228,6 @@ static inline int valid_state(suspend_state_t state) | |||
216 | * Then, do the setup for suspend, enter the state, and cleaup (after | 228 | * Then, do the setup for suspend, enter the state, and cleaup (after |
217 | * we've woken up). | 229 | * we've woken up). |
218 | */ | 230 | */ |
219 | |||
220 | static int enter_state(suspend_state_t state) | 231 | static int enter_state(suspend_state_t state) |
221 | { | 232 | { |
222 | int error; | 233 | int error; |
@@ -227,14 +238,14 @@ static int enter_state(suspend_state_t state) | |||
227 | return -EBUSY; | 238 | return -EBUSY; |
228 | 239 | ||
229 | pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); | 240 | pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); |
230 | if ((error = suspend_prepare(state))) | 241 | if ((error = suspend_prepare())) |
231 | goto Unlock; | 242 | goto Unlock; |
232 | 243 | ||
233 | pr_debug("PM: Entering %s sleep\n", pm_states[state]); | 244 | pr_debug("PM: Entering %s sleep\n", pm_states[state]); |
234 | error = suspend_enter(state); | 245 | error = suspend_devices_and_enter(state); |
235 | 246 | ||
236 | pr_debug("PM: Finishing wakeup.\n"); | 247 | pr_debug("PM: Finishing wakeup.\n"); |
237 | suspend_finish(state); | 248 | suspend_finish(); |
238 | Unlock: | 249 | Unlock: |
239 | mutex_unlock(&pm_mutex); | 250 | mutex_unlock(&pm_mutex); |
240 | return error; | 251 | return error; |