diff options
author | Bob Moore <robert.moore@intel.com> | 2012-02-14 02:00:53 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-03-22 01:44:34 -0400 |
commit | 2feec47d4c5f80b05f1650f5a24865718978eea4 (patch) | |
tree | 71fc838990113004d07186997efd83875af3a3d8 /drivers/acpi/acpica/hwsleep.c | |
parent | 384fe875efdc99f367a58920acb89c63f7465479 (diff) |
ACPICA: ACPI 5: Support for new FADT SleepStatus, SleepControl registers
Adds sleep and wake support for systems with these registers.
One new file, hwxfsleep.c
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/hwsleep.c')
-rw-r--r-- | drivers/acpi/acpica/hwsleep.c | 566 |
1 files changed, 298 insertions, 268 deletions
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 3c4a922a9fc2..59a2a6b897d4 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c | |||
@@ -1,7 +1,6 @@ | |||
1 | |||
2 | /****************************************************************************** | 1 | /****************************************************************************** |
3 | * | 2 | * |
4 | * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface | 3 | * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support Functions |
5 | * | 4 | * |
6 | *****************************************************************************/ | 5 | *****************************************************************************/ |
7 | 6 | ||
@@ -44,212 +43,183 @@ | |||
44 | 43 | ||
45 | #include <acpi/acpi.h> | 44 | #include <acpi/acpi.h> |
46 | #include "accommon.h" | 45 | #include "accommon.h" |
47 | #include "actables.h" | ||
48 | #include <linux/tboot.h> | 46 | #include <linux/tboot.h> |
49 | #include <linux/module.h> | 47 | #include <linux/module.h> |
50 | 48 | ||
51 | #define _COMPONENT ACPI_HARDWARE | 49 | #define _COMPONENT ACPI_HARDWARE |
52 | ACPI_MODULE_NAME("hwsleep") | 50 | ACPI_MODULE_NAME("hwsleep") |
53 | 51 | ||
52 | /* Local prototypes */ | ||
53 | static void acpi_hw_execute_GTS(u8 sleep_state); | ||
54 | |||
55 | static void acpi_hw_execute_BFS(u8 sleep_state); | ||
56 | |||
57 | static void acpi_hw_execute_WAK(u8 sleep_state); | ||
58 | |||
59 | static unsigned int gts, bfs; | ||
60 | module_param(gts, uint, 0644); | ||
61 | module_param(bfs, uint, 0644); | ||
62 | MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); | ||
63 | MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); | ||
64 | |||
54 | /******************************************************************************* | 65 | /******************************************************************************* |
55 | * | 66 | * |
56 | * FUNCTION: acpi_set_firmware_waking_vector | 67 | * FUNCTION: acpi_hw_execute_GTS |
57 | * | 68 | * |
58 | * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode | 69 | * PARAMETERS: sleep_state - Sleep state that will be entered |
59 | * entry point. | ||
60 | * | 70 | * |
61 | * RETURN: Status | 71 | * RETURN: None |
62 | * | 72 | * |
63 | * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS | 73 | * DESCRIPTION: Execute the optional _GTS method (Going To Sleep) |
64 | * | 74 | * |
65 | ******************************************************************************/ | 75 | ******************************************************************************/ |
66 | acpi_status | ||
67 | acpi_set_firmware_waking_vector(u32 physical_address) | ||
68 | { | ||
69 | ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); | ||
70 | |||
71 | 76 | ||
72 | /* | 77 | static void acpi_hw_execute_GTS(u8 sleep_state) |
73 | * According to the ACPI specification 2.0c and later, the 64-bit | 78 | { |
74 | * waking vector should be cleared and the 32-bit waking vector should | 79 | struct acpi_object_list arg_list; |
75 | * be used, unless we want the wake-up code to be called by the BIOS in | 80 | union acpi_object arg; |
76 | * Protected Mode. Some systems (for example HP dv5-1004nr) are known | 81 | acpi_status status; |
77 | * to fail to resume if the 64-bit vector is used. | ||
78 | */ | ||
79 | 82 | ||
80 | /* Set the 32-bit vector */ | 83 | if (!gts) |
84 | return; | ||
81 | 85 | ||
82 | acpi_gbl_FACS->firmware_waking_vector = physical_address; | 86 | /* One argument, sleep_state */ |
83 | 87 | ||
84 | /* Clear the 64-bit vector if it exists */ | 88 | arg_list.count = 1; |
89 | arg_list.pointer = &arg; | ||
90 | arg.type = ACPI_TYPE_INTEGER; | ||
91 | arg.integer.value = sleep_state; | ||
85 | 92 | ||
86 | if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) { | 93 | status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL); |
87 | acpi_gbl_FACS->xfirmware_waking_vector = 0; | 94 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
95 | ACPI_EXCEPTION((AE_INFO, status, | ||
96 | "While executing method _GTS")); | ||
88 | } | 97 | } |
89 | |||
90 | return_ACPI_STATUS(AE_OK); | ||
91 | } | 98 | } |
92 | 99 | ||
93 | ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) | ||
94 | |||
95 | #if ACPI_MACHINE_WIDTH == 64 | ||
96 | /******************************************************************************* | 100 | /******************************************************************************* |
97 | * | 101 | * |
98 | * FUNCTION: acpi_set_firmware_waking_vector64 | 102 | * FUNCTION: acpi_hw_execute_BFS |
99 | * | 103 | * |
100 | * PARAMETERS: physical_address - 64-bit physical address of ACPI protected | 104 | * PARAMETERS: sleep_state - Which sleep state we just exited |
101 | * mode entry point. | ||
102 | * | 105 | * |
103 | * RETURN: Status | 106 | * RETURN: None |
104 | * | 107 | * |
105 | * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if | 108 | * DESCRIPTION: Execute the optional _BFS method (Back From Sleep) |
106 | * it exists in the table. This function is intended for use with | ||
107 | * 64-bit host operating systems. | ||
108 | * | 109 | * |
109 | ******************************************************************************/ | 110 | ******************************************************************************/ |
110 | acpi_status | ||
111 | acpi_set_firmware_waking_vector64(u64 physical_address) | ||
112 | { | ||
113 | ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); | ||
114 | |||
115 | 111 | ||
116 | /* Determine if the 64-bit vector actually exists */ | 112 | static void acpi_hw_execute_BFS(u8 sleep_state) |
113 | { | ||
114 | struct acpi_object_list arg_list; | ||
115 | union acpi_object arg; | ||
116 | acpi_status status; | ||
117 | 117 | ||
118 | if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { | 118 | if (!bfs) |
119 | return_ACPI_STATUS(AE_NOT_EXIST); | 119 | return; |
120 | } | ||
121 | 120 | ||
122 | /* Clear 32-bit vector, set the 64-bit X_ vector */ | 121 | /* One argument, sleep_state */ |
123 | 122 | ||
124 | acpi_gbl_FACS->firmware_waking_vector = 0; | 123 | arg_list.count = 1; |
125 | acpi_gbl_FACS->xfirmware_waking_vector = physical_address; | 124 | arg_list.pointer = &arg; |
125 | arg.type = ACPI_TYPE_INTEGER; | ||
126 | arg.integer.value = sleep_state; | ||
126 | 127 | ||
127 | return_ACPI_STATUS(AE_OK); | 128 | status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL); |
129 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
130 | ACPI_EXCEPTION((AE_INFO, status, | ||
131 | "While executing method _BFS")); | ||
132 | } | ||
128 | } | 133 | } |
129 | 134 | ||
130 | ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) | ||
131 | #endif | ||
132 | |||
133 | /******************************************************************************* | 135 | /******************************************************************************* |
134 | * | 136 | * |
135 | * FUNCTION: acpi_enter_sleep_state_prep | 137 | * FUNCTION: acpi_hw_execute_WAK |
136 | * | 138 | * |
137 | * PARAMETERS: sleep_state - Which sleep state to enter | 139 | * PARAMETERS: sleep_state - Which sleep state we just exited |
138 | * | 140 | * |
139 | * RETURN: Status | 141 | * RETURN: None |
140 | * | 142 | * |
141 | * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231) | 143 | * DESCRIPTION: Execute the _WAK method (System Wake) |
142 | * This function must execute with interrupts enabled. | ||
143 | * We break sleeping into 2 stages so that OSPM can handle | ||
144 | * various OS-specific tasks between the two steps. | ||
145 | * | 144 | * |
146 | ******************************************************************************/ | 145 | ******************************************************************************/ |
147 | acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) | 146 | |
147 | static void acpi_hw_execute_WAK(u8 sleep_state) | ||
148 | { | 148 | { |
149 | acpi_status status; | ||
150 | struct acpi_object_list arg_list; | 149 | struct acpi_object_list arg_list; |
151 | union acpi_object arg; | 150 | union acpi_object arg; |
151 | acpi_status status; | ||
152 | 152 | ||
153 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep); | 153 | /* One argument, sleep_state */ |
154 | |||
155 | /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */ | ||
156 | |||
157 | status = acpi_get_sleep_type_data(sleep_state, | ||
158 | &acpi_gbl_sleep_type_a, | ||
159 | &acpi_gbl_sleep_type_b); | ||
160 | if (ACPI_FAILURE(status)) { | ||
161 | return_ACPI_STATUS(status); | ||
162 | } | ||
163 | |||
164 | /* Setup parameter object */ | ||
165 | 154 | ||
166 | arg_list.count = 1; | 155 | arg_list.count = 1; |
167 | arg_list.pointer = &arg; | 156 | arg_list.pointer = &arg; |
168 | |||
169 | arg.type = ACPI_TYPE_INTEGER; | 157 | arg.type = ACPI_TYPE_INTEGER; |
170 | arg.integer.value = sleep_state; | 158 | arg.integer.value = sleep_state; |
171 | 159 | ||
172 | /* Run the _PTS method */ | 160 | status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL); |
173 | |||
174 | status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL); | ||
175 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 161 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
176 | return_ACPI_STATUS(status); | 162 | ACPI_EXCEPTION((AE_INFO, status, |
163 | "While executing method _WAK")); | ||
177 | } | 164 | } |
165 | /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ | ||
166 | } | ||
178 | 167 | ||
179 | /* Setup the argument to _SST */ | 168 | /******************************************************************************* |
180 | 169 | * | |
181 | switch (sleep_state) { | 170 | * FUNCTION: acpi_hw_execute_SST |
182 | case ACPI_STATE_S0: | 171 | * |
183 | arg.integer.value = ACPI_SST_WORKING; | 172 | * PARAMETERS: indicator_id - Value to be passed to the _SST method |
184 | break; | 173 | * |
174 | * RETURN: None | ||
175 | * | ||
176 | * DESCRIPTION: Execute the optional _SST method (System Status) | ||
177 | * | ||
178 | ******************************************************************************/ | ||
185 | 179 | ||
186 | case ACPI_STATE_S1: | 180 | void acpi_hw_execute_SST(u32 indicator_id) |
187 | case ACPI_STATE_S2: | 181 | { |
188 | case ACPI_STATE_S3: | 182 | struct acpi_object_list arg_list; |
189 | arg.integer.value = ACPI_SST_SLEEPING; | 183 | union acpi_object arg; |
190 | break; | 184 | acpi_status status; |
191 | 185 | ||
192 | case ACPI_STATE_S4: | 186 | /* One argument, status indicator ID */ |
193 | arg.integer.value = ACPI_SST_SLEEP_CONTEXT; | ||
194 | break; | ||
195 | 187 | ||
196 | default: | 188 | arg_list.count = 1; |
197 | arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is off */ | 189 | arg_list.pointer = &arg; |
198 | break; | 190 | arg.type = ACPI_TYPE_INTEGER; |
199 | } | ||
200 | 191 | ||
201 | /* | 192 | arg.integer.value = indicator_id; |
202 | * Set the system indicators to show the desired sleep state. | ||
203 | * _SST is an optional method (return no error if not found) | ||
204 | */ | ||
205 | status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL); | 193 | status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL); |
206 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 194 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
207 | ACPI_EXCEPTION((AE_INFO, status, | 195 | ACPI_EXCEPTION((AE_INFO, status, |
208 | "While executing method _SST")); | 196 | "While executing method _SST")); |
209 | } | 197 | } |
210 | |||
211 | return_ACPI_STATUS(AE_OK); | ||
212 | } | 198 | } |
213 | 199 | ||
214 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) | ||
215 | |||
216 | static unsigned int gts, bfs; | ||
217 | module_param(gts, uint, 0644); | ||
218 | module_param(bfs, uint, 0644); | ||
219 | MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); | ||
220 | MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); | ||
221 | |||
222 | /******************************************************************************* | 200 | /******************************************************************************* |
223 | * | 201 | * |
224 | * FUNCTION: acpi_enter_sleep_state | 202 | * FUNCTION: acpi_hw_legacy_sleep |
225 | * | 203 | * |
226 | * PARAMETERS: sleep_state - Which sleep state to enter | 204 | * PARAMETERS: sleep_state - Which sleep state to enter |
227 | * | 205 | * |
228 | * RETURN: Status | 206 | * RETURN: Status |
229 | * | 207 | * |
230 | * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231) | 208 | * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers |
231 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | 209 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
232 | * | 210 | * |
233 | ******************************************************************************/ | 211 | ******************************************************************************/ |
234 | acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) | 212 | |
213 | acpi_status acpi_hw_legacy_sleep(u8 sleep_state) | ||
235 | { | 214 | { |
236 | u32 pm1a_control; | ||
237 | u32 pm1b_control; | ||
238 | struct acpi_bit_register_info *sleep_type_reg_info; | 215 | struct acpi_bit_register_info *sleep_type_reg_info; |
239 | struct acpi_bit_register_info *sleep_enable_reg_info; | 216 | struct acpi_bit_register_info *sleep_enable_reg_info; |
217 | u32 pm1a_control; | ||
218 | u32 pm1b_control; | ||
240 | u32 in_value; | 219 | u32 in_value; |
241 | struct acpi_object_list arg_list; | ||
242 | union acpi_object arg; | ||
243 | acpi_status status; | 220 | acpi_status status; |
244 | 221 | ||
245 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); | 222 | ACPI_FUNCTION_TRACE(hw_legacy_sleep); |
246 | |||
247 | if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || | ||
248 | (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { | ||
249 | ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", | ||
250 | acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b)); | ||
251 | return_ACPI_STATUS(AE_AML_OPERAND_VALUE); | ||
252 | } | ||
253 | 223 | ||
254 | sleep_type_reg_info = | 224 | sleep_type_reg_info = |
255 | acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE); | 225 | acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE); |
@@ -271,6 +241,18 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) | |||
271 | return_ACPI_STATUS(status); | 241 | return_ACPI_STATUS(status); |
272 | } | 242 | } |
273 | 243 | ||
244 | if (sleep_state != ACPI_STATE_S5) { | ||
245 | /* | ||
246 | * Disable BM arbitration. This feature is contained within an | ||
247 | * optional register (PM2 Control), so ignore a BAD_ADDRESS | ||
248 | * exception. | ||
249 | */ | ||
250 | status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); | ||
251 | if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) { | ||
252 | return_ACPI_STATUS(status); | ||
253 | } | ||
254 | } | ||
255 | |||
274 | /* | 256 | /* |
275 | * 1) Disable/Clear all GPEs | 257 | * 1) Disable/Clear all GPEs |
276 | * 2) Enable all wakeup GPEs | 258 | * 2) Enable all wakeup GPEs |
@@ -286,19 +268,9 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) | |||
286 | return_ACPI_STATUS(status); | 268 | return_ACPI_STATUS(status); |
287 | } | 269 | } |
288 | 270 | ||
289 | if (gts) { | 271 | /* Execute the _GTS method (Going To Sleep) */ |
290 | /* Execute the _GTS method */ | ||
291 | 272 | ||
292 | arg_list.count = 1; | 273 | acpi_hw_execute_GTS(sleep_state); |
293 | arg_list.pointer = &arg; | ||
294 | arg.type = ACPI_TYPE_INTEGER; | ||
295 | arg.integer.value = sleep_state; | ||
296 | |||
297 | status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL); | ||
298 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
299 | return_ACPI_STATUS(status); | ||
300 | } | ||
301 | } | ||
302 | 274 | ||
303 | /* Get current value of PM1A control */ | 275 | /* Get current value of PM1A control */ |
304 | 276 | ||
@@ -375,114 +347,43 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) | |||
375 | } | 347 | } |
376 | } | 348 | } |
377 | 349 | ||
378 | /* Wait until we enter sleep state */ | 350 | /* Wait for transition back to Working State */ |
379 | |||
380 | do { | ||
381 | status = acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, | ||
382 | &in_value); | ||
383 | if (ACPI_FAILURE(status)) { | ||
384 | return_ACPI_STATUS(status); | ||
385 | } | ||
386 | |||
387 | /* Spin until we wake */ | ||
388 | |||
389 | } while (!in_value); | ||
390 | |||
391 | return_ACPI_STATUS(AE_OK); | ||
392 | } | ||
393 | |||
394 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) | ||
395 | |||
396 | /******************************************************************************* | ||
397 | * | ||
398 | * FUNCTION: acpi_enter_sleep_state_s4bios | ||
399 | * | ||
400 | * PARAMETERS: None | ||
401 | * | ||
402 | * RETURN: Status | ||
403 | * | ||
404 | * DESCRIPTION: Perform a S4 bios request. | ||
405 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | ||
406 | * | ||
407 | ******************************************************************************/ | ||
408 | acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) | ||
409 | { | ||
410 | u32 in_value; | ||
411 | acpi_status status; | ||
412 | |||
413 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); | ||
414 | |||
415 | /* Clear the wake status bit (PM1) */ | ||
416 | |||
417 | status = | ||
418 | acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); | ||
419 | if (ACPI_FAILURE(status)) { | ||
420 | return_ACPI_STATUS(status); | ||
421 | } | ||
422 | |||
423 | status = acpi_hw_clear_acpi_status(); | ||
424 | if (ACPI_FAILURE(status)) { | ||
425 | return_ACPI_STATUS(status); | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * 1) Disable/Clear all GPEs | ||
430 | * 2) Enable all wakeup GPEs | ||
431 | */ | ||
432 | status = acpi_hw_disable_all_gpes(); | ||
433 | if (ACPI_FAILURE(status)) { | ||
434 | return_ACPI_STATUS(status); | ||
435 | } | ||
436 | acpi_gbl_system_awake_and_running = FALSE; | ||
437 | |||
438 | status = acpi_hw_enable_all_wakeup_gpes(); | ||
439 | if (ACPI_FAILURE(status)) { | ||
440 | return_ACPI_STATUS(status); | ||
441 | } | ||
442 | |||
443 | ACPI_FLUSH_CPU_CACHE(); | ||
444 | |||
445 | status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, | ||
446 | (u32) acpi_gbl_FADT.S4bios_request, 8); | ||
447 | 351 | ||
448 | do { | 352 | do { |
449 | acpi_os_stall(1000); | ||
450 | status = | 353 | status = |
451 | acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); | 354 | acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); |
452 | if (ACPI_FAILURE(status)) { | 355 | if (ACPI_FAILURE(status)) { |
453 | return_ACPI_STATUS(status); | 356 | return_ACPI_STATUS(status); |
454 | } | 357 | } |
358 | |||
455 | } while (!in_value); | 359 | } while (!in_value); |
456 | 360 | ||
457 | return_ACPI_STATUS(AE_OK); | 361 | return_ACPI_STATUS(AE_OK); |
458 | } | 362 | } |
459 | 363 | ||
460 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) | ||
461 | |||
462 | /******************************************************************************* | 364 | /******************************************************************************* |
463 | * | 365 | * |
464 | * FUNCTION: acpi_leave_sleep_state_prep | 366 | * FUNCTION: acpi_hw_legacy_wake_prep |
465 | * | 367 | * |
466 | * PARAMETERS: sleep_state - Which sleep state we are exiting | 368 | * PARAMETERS: sleep_state - Which sleep state we just exited |
467 | * | 369 | * |
468 | * RETURN: Status | 370 | * RETURN: Status |
469 | * | 371 | * |
470 | * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a | 372 | * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a |
471 | * sleep. | 373 | * sleep. |
472 | * Called with interrupts DISABLED. | 374 | * Called with interrupts ENABLED. |
473 | * | 375 | * |
474 | ******************************************************************************/ | 376 | ******************************************************************************/ |
475 | acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) | 377 | |
378 | acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state) | ||
476 | { | 379 | { |
477 | struct acpi_object_list arg_list; | ||
478 | union acpi_object arg; | ||
479 | acpi_status status; | 380 | acpi_status status; |
480 | struct acpi_bit_register_info *sleep_type_reg_info; | 381 | struct acpi_bit_register_info *sleep_type_reg_info; |
481 | struct acpi_bit_register_info *sleep_enable_reg_info; | 382 | struct acpi_bit_register_info *sleep_enable_reg_info; |
482 | u32 pm1a_control; | 383 | u32 pm1a_control; |
483 | u32 pm1b_control; | 384 | u32 pm1b_control; |
484 | 385 | ||
485 | ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); | 386 | ACPI_FUNCTION_TRACE(hw_legacy_wake_prep); |
486 | 387 | ||
487 | /* | 388 | /* |
488 | * Set SLP_TYPE and SLP_EN to state S0. | 389 | * Set SLP_TYPE and SLP_EN to state S0. |
@@ -525,25 +426,13 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) | |||
525 | } | 426 | } |
526 | } | 427 | } |
527 | 428 | ||
528 | if (bfs) { | 429 | acpi_hw_execute_BFS(sleep_state); |
529 | /* Execute the _BFS method */ | ||
530 | |||
531 | arg_list.count = 1; | ||
532 | arg_list.pointer = &arg; | ||
533 | arg.type = ACPI_TYPE_INTEGER; | ||
534 | arg.integer.value = sleep_state; | ||
535 | |||
536 | status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL); | ||
537 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
538 | ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS")); | ||
539 | } | ||
540 | } | ||
541 | return_ACPI_STATUS(status); | 430 | return_ACPI_STATUS(status); |
542 | } | 431 | } |
543 | 432 | ||
544 | /******************************************************************************* | 433 | /******************************************************************************* |
545 | * | 434 | * |
546 | * FUNCTION: acpi_leave_sleep_state | 435 | * FUNCTION: acpi_hw_legacy_wake |
547 | * | 436 | * |
548 | * PARAMETERS: sleep_state - Which sleep state we just exited | 437 | * PARAMETERS: sleep_state - Which sleep state we just exited |
549 | * | 438 | * |
@@ -553,31 +442,17 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) | |||
553 | * Called with interrupts ENABLED. | 442 | * Called with interrupts ENABLED. |
554 | * | 443 | * |
555 | ******************************************************************************/ | 444 | ******************************************************************************/ |
556 | acpi_status acpi_leave_sleep_state(u8 sleep_state) | 445 | |
446 | acpi_status acpi_hw_legacy_wake(u8 sleep_state) | ||
557 | { | 447 | { |
558 | struct acpi_object_list arg_list; | ||
559 | union acpi_object arg; | ||
560 | acpi_status status; | 448 | acpi_status status; |
561 | 449 | ||
562 | ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); | 450 | ACPI_FUNCTION_TRACE(hw_legacy_wake); |
563 | 451 | ||
564 | /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ | 452 | /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ |
565 | 453 | ||
566 | acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; | 454 | acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; |
567 | 455 | acpi_hw_execute_SST(ACPI_SST_WAKING); | |
568 | /* Setup parameter object */ | ||
569 | |||
570 | arg_list.count = 1; | ||
571 | arg_list.pointer = &arg; | ||
572 | arg.type = ACPI_TYPE_INTEGER; | ||
573 | |||
574 | /* Ignore any errors from these methods */ | ||
575 | |||
576 | arg.integer.value = ACPI_SST_WAKING; | ||
577 | status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL); | ||
578 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
579 | ACPI_EXCEPTION((AE_INFO, status, "During Method _SST")); | ||
580 | } | ||
581 | 456 | ||
582 | /* | 457 | /* |
583 | * GPEs must be enabled before _WAK is called as GPEs | 458 | * GPEs must be enabled before _WAK is called as GPEs |
@@ -591,46 +466,201 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) | |||
591 | if (ACPI_FAILURE(status)) { | 466 | if (ACPI_FAILURE(status)) { |
592 | return_ACPI_STATUS(status); | 467 | return_ACPI_STATUS(status); |
593 | } | 468 | } |
469 | |||
594 | status = acpi_hw_enable_all_runtime_gpes(); | 470 | status = acpi_hw_enable_all_runtime_gpes(); |
595 | if (ACPI_FAILURE(status)) { | 471 | if (ACPI_FAILURE(status)) { |
596 | return_ACPI_STATUS(status); | 472 | return_ACPI_STATUS(status); |
597 | } | 473 | } |
598 | 474 | ||
599 | arg.integer.value = sleep_state; | 475 | /* |
600 | status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL); | 476 | * Now we can execute _WAK, etc. Some machines require that the GPEs |
601 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 477 | * are enabled before the wake methods are executed. |
602 | ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK")); | 478 | */ |
603 | } | 479 | acpi_hw_execute_WAK(sleep_state); |
604 | /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ | ||
605 | 480 | ||
606 | /* | 481 | /* |
607 | * Some BIOSes assume that WAK_STS will be cleared on resume and use | 482 | * Some BIOS code assumes that WAK_STS will be cleared on resume |
608 | * it to determine whether the system is rebooting or resuming. Clear | 483 | * and use it to determine whether the system is rebooting or |
609 | * it for compatibility. | 484 | * resuming. Clear WAK_STS for compatibility. |
610 | */ | 485 | */ |
611 | acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1); | 486 | acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1); |
612 | |||
613 | acpi_gbl_system_awake_and_running = TRUE; | 487 | acpi_gbl_system_awake_and_running = TRUE; |
614 | 488 | ||
615 | /* Enable power button */ | 489 | /* Enable power button */ |
616 | 490 | ||
617 | (void) | 491 | (void) |
618 | acpi_write_bit_register(acpi_gbl_fixed_event_info | 492 | acpi_write_bit_register(acpi_gbl_fixed_event_info |
619 | [ACPI_EVENT_POWER_BUTTON]. | 493 | [ACPI_EVENT_POWER_BUTTON]. |
620 | enable_register_id, ACPI_ENABLE_EVENT); | 494 | enable_register_id, ACPI_ENABLE_EVENT); |
621 | 495 | ||
622 | (void) | 496 | (void) |
623 | acpi_write_bit_register(acpi_gbl_fixed_event_info | 497 | acpi_write_bit_register(acpi_gbl_fixed_event_info |
624 | [ACPI_EVENT_POWER_BUTTON]. | 498 | [ACPI_EVENT_POWER_BUTTON]. |
625 | status_register_id, ACPI_CLEAR_STATUS); | 499 | status_register_id, ACPI_CLEAR_STATUS); |
626 | 500 | ||
627 | arg.integer.value = ACPI_SST_WORKING; | 501 | /* |
628 | status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL); | 502 | * Enable BM arbitration. This feature is contained within an |
629 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 503 | * optional register (PM2 Control), so ignore a BAD_ADDRESS |
630 | ACPI_EXCEPTION((AE_INFO, status, "During Method _SST")); | 504 | * exception. |
505 | */ | ||
506 | status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); | ||
507 | if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) { | ||
508 | return_ACPI_STATUS(status); | ||
631 | } | 509 | } |
632 | 510 | ||
511 | acpi_hw_execute_SST(ACPI_SST_WORKING); | ||
633 | return_ACPI_STATUS(status); | 512 | return_ACPI_STATUS(status); |
634 | } | 513 | } |
635 | 514 | ||
636 | ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state) | 515 | |
516 | /******************************************************************************* | ||
517 | * | ||
518 | * FUNCTION: acpi_hw_extended_sleep | ||
519 | * | ||
520 | * PARAMETERS: sleep_state - Which sleep state to enter | ||
521 | * | ||
522 | * RETURN: Status | ||
523 | * | ||
524 | * DESCRIPTION: Enter a system sleep state via the extended FADT sleep | ||
525 | * registers (V5 FADT). | ||
526 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | ||
527 | * | ||
528 | ******************************************************************************/ | ||
529 | |||
530 | acpi_status acpi_hw_extended_sleep(u8 sleep_state) | ||
531 | { | ||
532 | acpi_status status; | ||
533 | u8 sleep_type_value; | ||
534 | u64 sleep_status; | ||
535 | |||
536 | ACPI_FUNCTION_TRACE(hw_extended_sleep); | ||
537 | |||
538 | /* Extended sleep registers must be valid */ | ||
539 | |||
540 | if (!acpi_gbl_FADT.sleep_control.address || | ||
541 | !acpi_gbl_FADT.sleep_status.address) { | ||
542 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
543 | } | ||
544 | |||
545 | /* Clear wake status (WAK_STS) */ | ||
546 | |||
547 | status = acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status); | ||
548 | if (ACPI_FAILURE(status)) { | ||
549 | return_ACPI_STATUS(status); | ||
550 | } | ||
551 | |||
552 | acpi_gbl_system_awake_and_running = FALSE; | ||
553 | |||
554 | /* Execute the _GTS method (Going To Sleep) */ | ||
555 | |||
556 | acpi_hw_execute_GTS(sleep_state); | ||
557 | |||
558 | /* Flush caches, as per ACPI specification */ | ||
559 | |||
560 | ACPI_FLUSH_CPU_CACHE(); | ||
561 | |||
562 | /* | ||
563 | * Set the SLP_TYP and SLP_EN bits. | ||
564 | * | ||
565 | * Note: We only use the first value returned by the \_Sx method | ||
566 | * (acpi_gbl_sleep_type_a) - As per ACPI specification. | ||
567 | */ | ||
568 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, | ||
569 | "Entering sleep state [S%u]\n", sleep_state)); | ||
570 | |||
571 | sleep_type_value = | ||
572 | ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & | ||
573 | ACPI_X_SLEEP_TYPE_MASK); | ||
574 | |||
575 | status = acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE), | ||
576 | &acpi_gbl_FADT.sleep_control); | ||
577 | if (ACPI_FAILURE(status)) { | ||
578 | return_ACPI_STATUS(status); | ||
579 | } | ||
580 | |||
581 | /* Wait for transition back to Working State */ | ||
582 | |||
583 | do { | ||
584 | status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status); | ||
585 | if (ACPI_FAILURE(status)) { | ||
586 | return_ACPI_STATUS(status); | ||
587 | } | ||
588 | |||
589 | } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS)); | ||
590 | |||
591 | return_ACPI_STATUS(AE_OK); | ||
592 | } | ||
593 | |||
594 | /******************************************************************************* | ||
595 | * | ||
596 | * FUNCTION: acpi_hw_extended_wake_prep | ||
597 | * | ||
598 | * PARAMETERS: sleep_state - Which sleep state we just exited | ||
599 | * | ||
600 | * RETURN: Status | ||
601 | * | ||
602 | * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after | ||
603 | * a sleep. Called with interrupts ENABLED. | ||
604 | * | ||
605 | ******************************************************************************/ | ||
606 | |||
607 | acpi_status acpi_hw_extended_wake_prep(u8 sleep_state) | ||
608 | { | ||
609 | acpi_status status; | ||
610 | u8 sleep_type_value; | ||
611 | |||
612 | ACPI_FUNCTION_TRACE(hw_extended_wake_prep); | ||
613 | |||
614 | status = acpi_get_sleep_type_data(ACPI_STATE_S0, | ||
615 | &acpi_gbl_sleep_type_a, | ||
616 | &acpi_gbl_sleep_type_b); | ||
617 | if (ACPI_SUCCESS(status)) { | ||
618 | sleep_type_value = | ||
619 | ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & | ||
620 | ACPI_X_SLEEP_TYPE_MASK); | ||
621 | |||
622 | (void)acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE), | ||
623 | &acpi_gbl_FADT.sleep_control); | ||
624 | } | ||
625 | |||
626 | acpi_hw_execute_BFS(sleep_state); | ||
627 | return_ACPI_STATUS(AE_OK); | ||
628 | } | ||
629 | |||
630 | /******************************************************************************* | ||
631 | * | ||
632 | * FUNCTION: acpi_hw_extended_wake | ||
633 | * | ||
634 | * PARAMETERS: sleep_state - Which sleep state we just exited | ||
635 | * | ||
636 | * RETURN: Status | ||
637 | * | ||
638 | * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep | ||
639 | * Called with interrupts ENABLED. | ||
640 | * | ||
641 | ******************************************************************************/ | ||
642 | |||
643 | acpi_status acpi_hw_extended_wake(u8 sleep_state) | ||
644 | { | ||
645 | ACPI_FUNCTION_TRACE(hw_extended_wake); | ||
646 | |||
647 | /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ | ||
648 | |||
649 | acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; | ||
650 | |||
651 | /* Execute the wake methods */ | ||
652 | |||
653 | acpi_hw_execute_SST(ACPI_SST_WAKING); | ||
654 | acpi_hw_execute_WAK(sleep_state); | ||
655 | |||
656 | /* | ||
657 | * Some BIOS code assumes that WAK_STS will be cleared on resume | ||
658 | * and use it to determine whether the system is rebooting or | ||
659 | * resuming. Clear WAK_STS for compatibility. | ||
660 | */ | ||
661 | (void)acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status); | ||
662 | acpi_gbl_system_awake_and_running = TRUE; | ||
663 | |||
664 | acpi_hw_execute_SST(ACPI_SST_WORKING); | ||
665 | return_ACPI_STATUS(AE_OK); | ||
666 | } | ||