aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2007-07-19 04:47:38 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:42 -0400
commit6c961dfb7c903cfd1cd71b506863894038fd704f (patch)
tree32890d6ef2cf735243d804778a5b62951aed4ef5 /kernel/power
parentccd4b65aef4be2278543fde5b999e55a4d694fd8 (diff)
PM: Reduce code duplication between main.c and user.c
The SNAPSHOT_S2RAM ioctl code is outdated and it should not duplicate the suspend code in kernel/power/main.c. Fix that. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Cc: Nigel Cunningham <nigel@nigel.suspend2.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/main.c99
-rw-r--r--kernel/power/power.h3
-rw-r--r--kernel/power/user.c38
3 files changed, 62 insertions, 78 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 72static int suspend_prepare(void)
75static 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 */
151int suspend_enter(suspend_state_t state) 129int 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 */
153int 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 195static void suspend_finish(void)
179static 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
220static int enter_state(suspend_state_t state) 231static 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;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 01c2275b15b2..5f24c786f8ec 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -170,7 +170,6 @@ extern int swsusp_resume(void);
170extern int swsusp_read(unsigned int *flags_p); 170extern int swsusp_read(unsigned int *flags_p);
171extern int swsusp_write(unsigned int flags); 171extern int swsusp_write(unsigned int flags);
172extern void swsusp_close(void); 172extern void swsusp_close(void);
173extern int suspend_enter(suspend_state_t state);
174 173
175struct timeval; 174struct timeval;
176/* kernel/power/swsusp.c */ 175/* kernel/power/swsusp.c */
@@ -178,6 +177,8 @@ extern void swsusp_show_speed(struct timeval *, struct timeval *,
178 unsigned int, char *); 177 unsigned int, char *);
179 178
180/* kernel/power/main.c */ 179/* kernel/power/main.c */
180extern int suspend_enter(suspend_state_t state);
181extern int suspend_devices_and_enter(suspend_state_t state);
181extern struct blocking_notifier_head pm_chain_head; 182extern struct blocking_notifier_head pm_chain_head;
182 183
183static inline int pm_notifier_call_chain(unsigned long val) 184static inline int pm_notifier_call_chain(unsigned long val)
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 7f19afe01b48..bd0723a7df3f 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -255,47 +255,19 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
255 break; 255 break;
256 256
257 case SNAPSHOT_S2RAM: 257 case SNAPSHOT_S2RAM:
258 if (!pm_ops) {
259 error = -ENOSYS;
260 break;
261 }
262
263 if (!data->frozen) { 258 if (!data->frozen) {
264 error = -EPERM; 259 error = -EPERM;
265 break; 260 break;
266 } 261 }
267
268 if (!mutex_trylock(&pm_mutex)) { 262 if (!mutex_trylock(&pm_mutex)) {
269 error = -EBUSY; 263 error = -EBUSY;
270 break; 264 break;
271 } 265 }
272 266 /*
273 if (pm_ops->prepare) { 267 * Tasks are frozen and the notifiers have been called with
274 error = pm_ops->prepare(PM_SUSPEND_MEM); 268 * PM_HIBERNATION_PREPARE
275 if (error) 269 */
276 goto OutS3; 270 error = suspend_devices_and_enter(PM_SUSPEND_MEM);
277 }
278
279 /* Put devices to sleep */
280 suspend_console();
281 error = device_suspend(PMSG_SUSPEND);
282 if (error) {
283 printk(KERN_ERR "Failed to suspend some devices.\n");
284 } else {
285 error = disable_nonboot_cpus();
286 if (!error) {
287 /* Enter S3, system is already frozen */
288 suspend_enter(PM_SUSPEND_MEM);
289 enable_nonboot_cpus();
290 }
291 /* Wake up devices */
292 device_resume();
293 }
294 resume_console();
295 if (pm_ops->finish)
296 pm_ops->finish(PM_SUSPEND_MEM);
297
298 OutS3:
299 mutex_unlock(&pm_mutex); 271 mutex_unlock(&pm_mutex);
300 break; 272 break;
301 273