aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sleep
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 22:29:57 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 22:29:57 -0500
commit687fcdf741e4a268c2c7bac8b3734de761bb9719 (patch)
tree82603cd0f892b13d4252cc525ecaec99bb86c0cd /drivers/acpi/sleep
parent215e871aaa3d94540121a3809d80d0c5e5686e4f (diff)
parenta6eb84bc1e069e1d285167e09035ed6c27978feb (diff)
Merge branch 'suspend' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'suspend' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (38 commits) suspend: cleanup reference to swsusp_pg_dir[] PM: Remove obsolete /sys/devices/.../power/state docs Hibernation: Invoke suspend notifications after console switch Suspend: Invoke suspend notifications after console switch Suspend: Clean up suspend_64.c Suspend: Add config option to disable the freezer if architecture wants that ACPI: Print message before calling _PTS ACPI hibernation: Call _PTS before suspending devices Hibernation: Introduce begin() and end() callbacks ACPI suspend: Call _PTS before suspending devices ACPI: Separate disabling of GPEs from _PTS ACPI: Separate invocations of _GTS and _BFS from _PTS and _WAK Suspend: Introduce begin() and end() callbacks suspend: fix ia64 allmodconfig build ACPI: clear GPE earily in resume to avoid warning Suspend: Clean up Kconfig (V2) Hibernation: Clean up Kconfig (V2) Hibernation: Update messages Suspend: Use common prefix in messages Hibernation: Remove unnecessary variable declaration ...
Diffstat (limited to 'drivers/acpi/sleep')
-rw-r--r--drivers/acpi/sleep/main.c129
-rw-r--r--drivers/acpi/sleep/sleep.h2
2 files changed, 108 insertions, 23 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 2c0b6630f8ba..485de1347075 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -26,9 +26,24 @@ u8 sleep_states[ACPI_S_STATE_COUNT];
26 26
27#ifdef CONFIG_PM_SLEEP 27#ifdef CONFIG_PM_SLEEP
28static u32 acpi_target_sleep_state = ACPI_STATE_S0; 28static u32 acpi_target_sleep_state = ACPI_STATE_S0;
29static bool acpi_sleep_finish_wake_up;
30
31/*
32 * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we
33 * allow the user to request that behavior by using the 'acpi_new_pts_ordering'
34 * kernel command line option that causes the following variable to be set.
35 */
36static bool new_pts_ordering;
37
38static int __init acpi_new_pts_ordering(char *str)
39{
40 new_pts_ordering = true;
41 return 1;
42}
43__setup("acpi_new_pts_ordering", acpi_new_pts_ordering);
29#endif 44#endif
30 45
31int acpi_sleep_prepare(u32 acpi_state) 46static int acpi_sleep_prepare(u32 acpi_state)
32{ 47{
33#ifdef CONFIG_ACPI_SLEEP 48#ifdef CONFIG_ACPI_SLEEP
34 /* do we have a wakeup address for S2 and S3? */ 49 /* do we have a wakeup address for S2 and S3? */
@@ -44,6 +59,8 @@ int acpi_sleep_prepare(u32 acpi_state)
44 ACPI_FLUSH_CPU_CACHE(); 59 ACPI_FLUSH_CPU_CACHE();
45 acpi_enable_wakeup_device_prep(acpi_state); 60 acpi_enable_wakeup_device_prep(acpi_state);
46#endif 61#endif
62 printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
63 acpi_state);
47 acpi_enter_sleep_state_prep(acpi_state); 64 acpi_enter_sleep_state_prep(acpi_state);
48 return 0; 65 return 0;
49} 66}
@@ -63,17 +80,25 @@ static u32 acpi_suspend_states[] = {
63static int init_8259A_after_S1; 80static int init_8259A_after_S1;
64 81
65/** 82/**
66 * acpi_pm_set_target - Set the target system sleep state to the state 83 * acpi_pm_begin - Set the target system sleep state to the state
67 * associated with given @pm_state, if supported. 84 * associated with given @pm_state, if supported.
68 */ 85 */
69 86
70static int acpi_pm_set_target(suspend_state_t pm_state) 87static int acpi_pm_begin(suspend_state_t pm_state)
71{ 88{
72 u32 acpi_state = acpi_suspend_states[pm_state]; 89 u32 acpi_state = acpi_suspend_states[pm_state];
73 int error = 0; 90 int error = 0;
74 91
75 if (sleep_states[acpi_state]) { 92 if (sleep_states[acpi_state]) {
76 acpi_target_sleep_state = acpi_state; 93 acpi_target_sleep_state = acpi_state;
94 if (new_pts_ordering)
95 return 0;
96
97 error = acpi_sleep_prepare(acpi_state);
98 if (error)
99 acpi_target_sleep_state = ACPI_STATE_S0;
100 else
101 acpi_sleep_finish_wake_up = true;
77 } else { 102 } else {
78 printk(KERN_ERR "ACPI does not support this state: %d\n", 103 printk(KERN_ERR "ACPI does not support this state: %d\n",
79 pm_state); 104 pm_state);
@@ -91,12 +116,17 @@ static int acpi_pm_set_target(suspend_state_t pm_state)
91 116
92static int acpi_pm_prepare(void) 117static int acpi_pm_prepare(void)
93{ 118{
94 int error = acpi_sleep_prepare(acpi_target_sleep_state); 119 if (new_pts_ordering) {
120 int error = acpi_sleep_prepare(acpi_target_sleep_state);
95 121
96 if (error) 122 if (error) {
97 acpi_target_sleep_state = ACPI_STATE_S0; 123 acpi_target_sleep_state = ACPI_STATE_S0;
124 return error;
125 }
126 acpi_sleep_finish_wake_up = true;
127 }
98 128
99 return error; 129 return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
100} 130}
101 131
102/** 132/**
@@ -120,10 +150,8 @@ static int acpi_pm_enter(suspend_state_t pm_state)
120 if (acpi_state == ACPI_STATE_S3) { 150 if (acpi_state == ACPI_STATE_S3) {
121 int error = acpi_save_state_mem(); 151 int error = acpi_save_state_mem();
122 152
123 if (error) { 153 if (error)
124 acpi_target_sleep_state = ACPI_STATE_S0;
125 return error; 154 return error;
126 }
127 } 155 }
128 156
129 local_irq_save(flags); 157 local_irq_save(flags);
@@ -139,6 +167,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
139 break; 167 break;
140 } 168 }
141 169
170 /* Reprogram control registers and execute _BFS */
171 acpi_leave_sleep_state_prep(acpi_state);
172
142 /* ACPI 3.0 specs (P62) says that it's the responsabilty 173 /* ACPI 3.0 specs (P62) says that it's the responsabilty
143 * of the OSPM to clear the status bit [ implying that the 174 * of the OSPM to clear the status bit [ implying that the
144 * POWER_BUTTON event should not reach userspace ] 175 * POWER_BUTTON event should not reach userspace ]
@@ -146,6 +177,13 @@ static int acpi_pm_enter(suspend_state_t pm_state)
146 if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) 177 if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
147 acpi_clear_event(ACPI_EVENT_POWER_BUTTON); 178 acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
148 179
180 /*
181 * Disable and clear GPE status before interrupt is enabled. Some GPEs
182 * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
183 * acpi_leave_sleep_state will reenable specific GPEs later
184 */
185 acpi_hw_disable_all_gpes();
186
149 local_irq_restore(flags); 187 local_irq_restore(flags);
150 printk(KERN_DEBUG "Back to C!\n"); 188 printk(KERN_DEBUG "Back to C!\n");
151 189
@@ -157,7 +195,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
157} 195}
158 196
159/** 197/**
160 * acpi_pm_finish - Finish up suspend sequence. 198 * acpi_pm_finish - Instruct the platform to leave a sleep state.
161 * 199 *
162 * This is called after we wake back up (or if entering the sleep state 200 * This is called after we wake back up (or if entering the sleep state
163 * failed). 201 * failed).
@@ -174,6 +212,7 @@ static void acpi_pm_finish(void)
174 acpi_set_firmware_waking_vector((acpi_physical_address) 0); 212 acpi_set_firmware_waking_vector((acpi_physical_address) 0);
175 213
176 acpi_target_sleep_state = ACPI_STATE_S0; 214 acpi_target_sleep_state = ACPI_STATE_S0;
215 acpi_sleep_finish_wake_up = false;
177 216
178#ifdef CONFIG_X86 217#ifdef CONFIG_X86
179 if (init_8259A_after_S1) { 218 if (init_8259A_after_S1) {
@@ -183,6 +222,20 @@ static void acpi_pm_finish(void)
183#endif 222#endif
184} 223}
185 224
225/**
226 * acpi_pm_end - Finish up suspend sequence.
227 */
228
229static void acpi_pm_end(void)
230{
231 /*
232 * This is necessary in case acpi_pm_finish() is not called directly
233 * during a failing transition to a sleep state.
234 */
235 if (acpi_sleep_finish_wake_up)
236 acpi_pm_finish();
237}
238
186static int acpi_pm_state_valid(suspend_state_t pm_state) 239static int acpi_pm_state_valid(suspend_state_t pm_state)
187{ 240{
188 u32 acpi_state; 241 u32 acpi_state;
@@ -201,10 +254,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
201 254
202static struct platform_suspend_ops acpi_pm_ops = { 255static struct platform_suspend_ops acpi_pm_ops = {
203 .valid = acpi_pm_state_valid, 256 .valid = acpi_pm_state_valid,
204 .set_target = acpi_pm_set_target, 257 .begin = acpi_pm_begin,
205 .prepare = acpi_pm_prepare, 258 .prepare = acpi_pm_prepare,
206 .enter = acpi_pm_enter, 259 .enter = acpi_pm_enter,
207 .finish = acpi_pm_finish, 260 .finish = acpi_pm_finish,
261 .end = acpi_pm_end,
208}; 262};
209 263
210/* 264/*
@@ -229,15 +283,36 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
229#endif /* CONFIG_SUSPEND */ 283#endif /* CONFIG_SUSPEND */
230 284
231#ifdef CONFIG_HIBERNATION 285#ifdef CONFIG_HIBERNATION
232static int acpi_hibernation_start(void) 286static int acpi_hibernation_begin(void)
233{ 287{
288 int error;
289
234 acpi_target_sleep_state = ACPI_STATE_S4; 290 acpi_target_sleep_state = ACPI_STATE_S4;
235 return 0; 291 if (new_pts_ordering)
292 return 0;
293
294 error = acpi_sleep_prepare(ACPI_STATE_S4);
295 if (error)
296 acpi_target_sleep_state = ACPI_STATE_S0;
297 else
298 acpi_sleep_finish_wake_up = true;
299
300 return error;
236} 301}
237 302
238static int acpi_hibernation_prepare(void) 303static int acpi_hibernation_prepare(void)
239{ 304{
240 return acpi_sleep_prepare(ACPI_STATE_S4); 305 if (new_pts_ordering) {
306 int error = acpi_sleep_prepare(ACPI_STATE_S4);
307
308 if (error) {
309 acpi_target_sleep_state = ACPI_STATE_S0;
310 return error;
311 }
312 acpi_sleep_finish_wake_up = true;
313 }
314
315 return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
241} 316}
242 317
243static int acpi_hibernation_enter(void) 318static int acpi_hibernation_enter(void)
@@ -251,6 +326,8 @@ static int acpi_hibernation_enter(void)
251 acpi_enable_wakeup_device(ACPI_STATE_S4); 326 acpi_enable_wakeup_device(ACPI_STATE_S4);
252 /* This shouldn't return. If it returns, we have a problem */ 327 /* This shouldn't return. If it returns, we have a problem */
253 status = acpi_enter_sleep_state(ACPI_STATE_S4); 328 status = acpi_enter_sleep_state(ACPI_STATE_S4);
329 /* Reprogram control registers and execute _BFS */
330 acpi_leave_sleep_state_prep(ACPI_STATE_S4);
254 local_irq_restore(flags); 331 local_irq_restore(flags);
255 332
256 return ACPI_SUCCESS(status) ? 0 : -EFAULT; 333 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -263,15 +340,12 @@ static void acpi_hibernation_leave(void)
263 * enable it here. 340 * enable it here.
264 */ 341 */
265 acpi_enable(); 342 acpi_enable();
343 /* Reprogram control registers and execute _BFS */
344 acpi_leave_sleep_state_prep(ACPI_STATE_S4);
266} 345}
267 346
268static void acpi_hibernation_finish(void) 347static void acpi_hibernation_finish(void)
269{ 348{
270 /*
271 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
272 * enable it here.
273 */
274 acpi_enable();
275 acpi_disable_wakeup_device(ACPI_STATE_S4); 349 acpi_disable_wakeup_device(ACPI_STATE_S4);
276 acpi_leave_sleep_state(ACPI_STATE_S4); 350 acpi_leave_sleep_state(ACPI_STATE_S4);
277 351
@@ -279,6 +353,17 @@ static void acpi_hibernation_finish(void)
279 acpi_set_firmware_waking_vector((acpi_physical_address) 0); 353 acpi_set_firmware_waking_vector((acpi_physical_address) 0);
280 354
281 acpi_target_sleep_state = ACPI_STATE_S0; 355 acpi_target_sleep_state = ACPI_STATE_S0;
356 acpi_sleep_finish_wake_up = false;
357}
358
359static void acpi_hibernation_end(void)
360{
361 /*
362 * This is necessary in case acpi_hibernation_finish() is not called
363 * directly during a failing transition to the sleep state.
364 */
365 if (acpi_sleep_finish_wake_up)
366 acpi_hibernation_finish();
282} 367}
283 368
284static int acpi_hibernation_pre_restore(void) 369static int acpi_hibernation_pre_restore(void)
@@ -296,7 +381,8 @@ static void acpi_hibernation_restore_cleanup(void)
296} 381}
297 382
298static struct platform_hibernation_ops acpi_hibernation_ops = { 383static struct platform_hibernation_ops acpi_hibernation_ops = {
299 .start = acpi_hibernation_start, 384 .begin = acpi_hibernation_begin,
385 .end = acpi_hibernation_end,
300 .pre_snapshot = acpi_hibernation_prepare, 386 .pre_snapshot = acpi_hibernation_prepare,
301 .finish = acpi_hibernation_finish, 387 .finish = acpi_hibernation_finish,
302 .prepare = acpi_hibernation_prepare, 388 .prepare = acpi_hibernation_prepare,
@@ -403,6 +489,7 @@ static void acpi_power_off_prepare(void)
403{ 489{
404 /* Prepare to power off the system */ 490 /* Prepare to power off the system */
405 acpi_sleep_prepare(ACPI_STATE_S5); 491 acpi_sleep_prepare(ACPI_STATE_S5);
492 acpi_hw_disable_all_gpes();
406} 493}
407 494
408static void acpi_power_off(void) 495static void acpi_power_off(void)
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
index a2ea125ae2d0..cfaf8f5b0a14 100644
--- a/drivers/acpi/sleep/sleep.h
+++ b/drivers/acpi/sleep/sleep.h
@@ -5,5 +5,3 @@ extern int acpi_suspend (u32 state);
5extern void acpi_enable_wakeup_device_prep(u8 sleep_state); 5extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
6extern void acpi_enable_wakeup_device(u8 sleep_state); 6extern void acpi_enable_wakeup_device(u8 sleep_state);
7extern void acpi_disable_wakeup_device(u8 sleep_state); 7extern void acpi_disable_wakeup_device(u8 sleep_state);
8
9extern int acpi_sleep_prepare(u32 acpi_state);