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 | |
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')
-rw-r--r-- | drivers/acpi/acpica/Makefile | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/achware.h | 17 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwsleep.c | 566 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwxfsleep.c | 377 |
4 files changed, 694 insertions, 269 deletions
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 0ca208b6dcf0..da5518063ef7 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile | |||
@@ -73,7 +73,8 @@ acpi-y += \ | |||
73 | hwregs.o \ | 73 | hwregs.o \ |
74 | hwsleep.o \ | 74 | hwsleep.o \ |
75 | hwvalid.o \ | 75 | hwvalid.o \ |
76 | hwxface.o | 76 | hwxface.o \ |
77 | hwxfsleep.o | ||
77 | 78 | ||
78 | acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o | 79 | acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o |
79 | 80 | ||
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 677793e938f5..087f7106412d 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h | |||
@@ -81,6 +81,23 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value); | |||
81 | acpi_status acpi_hw_clear_acpi_status(void); | 81 | acpi_status acpi_hw_clear_acpi_status(void); |
82 | 82 | ||
83 | /* | 83 | /* |
84 | * hwsleep - sleep/wake support | ||
85 | */ | ||
86 | void acpi_hw_execute_SST(u32 value); | ||
87 | |||
88 | acpi_status acpi_hw_extended_sleep(u8 sleep_state); | ||
89 | |||
90 | acpi_status acpi_hw_legacy_sleep(u8 sleep_state); | ||
91 | |||
92 | acpi_status acpi_hw_extended_wake_prep(u8 sleep_state); | ||
93 | |||
94 | acpi_status acpi_hw_extended_wake(u8 sleep_state); | ||
95 | |||
96 | acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state); | ||
97 | |||
98 | acpi_status acpi_hw_legacy_wake(u8 sleep_state); | ||
99 | |||
100 | /* | ||
84 | * hwvalid - Port I/O with validation | 101 | * hwvalid - Port I/O with validation |
85 | */ | 102 | */ |
86 | acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width); | 103 | acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width); |
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 | } | ||
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c new file mode 100644 index 000000000000..29c0fd3810b0 --- /dev/null +++ b/drivers/acpi/acpica/hwxfsleep.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2012, Intel Corp. | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions, and the following disclaimer, | ||
16 | * without modification. | ||
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
18 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
19 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
20 | * including a substantially similar Disclaimer requirement for further | ||
21 | * binary redistribution. | ||
22 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
23 | * of any contributors may be used to endorse or promote products derived | ||
24 | * from this software without specific prior written permission. | ||
25 | * | ||
26 | * Alternatively, this software may be distributed under the terms of the | ||
27 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
28 | * Software Foundation. | ||
29 | * | ||
30 | * NO WARRANTY | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGES. | ||
42 | */ | ||
43 | |||
44 | #include <acpi/acpi.h> | ||
45 | #include "accommon.h" | ||
46 | #include <linux/module.h> | ||
47 | |||
48 | #define _COMPONENT ACPI_HARDWARE | ||
49 | ACPI_MODULE_NAME("hwxfsleep") | ||
50 | |||
51 | /******************************************************************************* | ||
52 | * | ||
53 | * FUNCTION: acpi_set_firmware_waking_vector | ||
54 | * | ||
55 | * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode | ||
56 | * entry point. | ||
57 | * | ||
58 | * RETURN: Status | ||
59 | * | ||
60 | * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS | ||
61 | * | ||
62 | ******************************************************************************/ | ||
63 | acpi_status acpi_set_firmware_waking_vector(u32 physical_address) | ||
64 | { | ||
65 | ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); | ||
66 | |||
67 | |||
68 | /* | ||
69 | * According to the ACPI specification 2.0c and later, the 64-bit | ||
70 | * waking vector should be cleared and the 32-bit waking vector should | ||
71 | * be used, unless we want the wake-up code to be called by the BIOS in | ||
72 | * Protected Mode. Some systems (for example HP dv5-1004nr) are known | ||
73 | * to fail to resume if the 64-bit vector is used. | ||
74 | */ | ||
75 | |||
76 | /* Set the 32-bit vector */ | ||
77 | |||
78 | acpi_gbl_FACS->firmware_waking_vector = physical_address; | ||
79 | |||
80 | /* Clear the 64-bit vector if it exists */ | ||
81 | |||
82 | if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) { | ||
83 | acpi_gbl_FACS->xfirmware_waking_vector = 0; | ||
84 | } | ||
85 | |||
86 | return_ACPI_STATUS(AE_OK); | ||
87 | } | ||
88 | |||
89 | ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) | ||
90 | |||
91 | #if ACPI_MACHINE_WIDTH == 64 | ||
92 | /******************************************************************************* | ||
93 | * | ||
94 | * FUNCTION: acpi_set_firmware_waking_vector64 | ||
95 | * | ||
96 | * PARAMETERS: physical_address - 64-bit physical address of ACPI protected | ||
97 | * mode entry point. | ||
98 | * | ||
99 | * RETURN: Status | ||
100 | * | ||
101 | * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if | ||
102 | * it exists in the table. This function is intended for use with | ||
103 | * 64-bit host operating systems. | ||
104 | * | ||
105 | ******************************************************************************/ | ||
106 | acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) | ||
107 | { | ||
108 | ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); | ||
109 | |||
110 | |||
111 | /* Determine if the 64-bit vector actually exists */ | ||
112 | |||
113 | if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { | ||
114 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
115 | } | ||
116 | |||
117 | /* Clear 32-bit vector, set the 64-bit X_ vector */ | ||
118 | |||
119 | acpi_gbl_FACS->firmware_waking_vector = 0; | ||
120 | acpi_gbl_FACS->xfirmware_waking_vector = physical_address; | ||
121 | return_ACPI_STATUS(AE_OK); | ||
122 | } | ||
123 | |||
124 | ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) | ||
125 | #endif | ||
126 | |||
127 | /******************************************************************************* | ||
128 | * | ||
129 | * FUNCTION: acpi_enter_sleep_state_s4bios | ||
130 | * | ||
131 | * PARAMETERS: None | ||
132 | * | ||
133 | * RETURN: Status | ||
134 | * | ||
135 | * DESCRIPTION: Perform a S4 bios request. | ||
136 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | ||
137 | * | ||
138 | ******************************************************************************/ | ||
139 | acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) | ||
140 | { | ||
141 | u32 in_value; | ||
142 | acpi_status status; | ||
143 | |||
144 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); | ||
145 | |||
146 | /* Clear the wake status bit (PM1) */ | ||
147 | |||
148 | status = | ||
149 | acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); | ||
150 | if (ACPI_FAILURE(status)) { | ||
151 | return_ACPI_STATUS(status); | ||
152 | } | ||
153 | |||
154 | status = acpi_hw_clear_acpi_status(); | ||
155 | if (ACPI_FAILURE(status)) { | ||
156 | return_ACPI_STATUS(status); | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * 1) Disable/Clear all GPEs | ||
161 | * 2) Enable all wakeup GPEs | ||
162 | */ | ||
163 | status = acpi_hw_disable_all_gpes(); | ||
164 | if (ACPI_FAILURE(status)) { | ||
165 | return_ACPI_STATUS(status); | ||
166 | } | ||
167 | acpi_gbl_system_awake_and_running = FALSE; | ||
168 | |||
169 | status = acpi_hw_enable_all_wakeup_gpes(); | ||
170 | if (ACPI_FAILURE(status)) { | ||
171 | return_ACPI_STATUS(status); | ||
172 | } | ||
173 | |||
174 | ACPI_FLUSH_CPU_CACHE(); | ||
175 | |||
176 | status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, | ||
177 | (u32)acpi_gbl_FADT.S4bios_request, 8); | ||
178 | |||
179 | do { | ||
180 | acpi_os_stall(1000); | ||
181 | status = | ||
182 | acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); | ||
183 | if (ACPI_FAILURE(status)) { | ||
184 | return_ACPI_STATUS(status); | ||
185 | } | ||
186 | } while (!in_value); | ||
187 | |||
188 | return_ACPI_STATUS(AE_OK); | ||
189 | } | ||
190 | |||
191 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) | ||
192 | |||
193 | /******************************************************************************* | ||
194 | * | ||
195 | * FUNCTION: acpi_enter_sleep_state_prep | ||
196 | * | ||
197 | * PARAMETERS: sleep_state - Which sleep state to enter | ||
198 | * | ||
199 | * RETURN: Status | ||
200 | * | ||
201 | * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231) | ||
202 | * This function must execute with interrupts enabled. | ||
203 | * We break sleeping into 2 stages so that OSPM can handle | ||
204 | * various OS-specific tasks between the two steps. | ||
205 | * | ||
206 | ******************************************************************************/ | ||
207 | acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) | ||
208 | { | ||
209 | acpi_status status; | ||
210 | struct acpi_object_list arg_list; | ||
211 | union acpi_object arg; | ||
212 | u32 sst_value; | ||
213 | |||
214 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep); | ||
215 | |||
216 | /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */ | ||
217 | |||
218 | status = acpi_get_sleep_type_data(sleep_state, | ||
219 | &acpi_gbl_sleep_type_a, | ||
220 | &acpi_gbl_sleep_type_b); | ||
221 | if (ACPI_FAILURE(status)) { | ||
222 | return_ACPI_STATUS(status); | ||
223 | } | ||
224 | |||
225 | /* Execute the _PTS method (Prepare To Sleep) */ | ||
226 | |||
227 | arg_list.count = 1; | ||
228 | arg_list.pointer = &arg; | ||
229 | arg.type = ACPI_TYPE_INTEGER; | ||
230 | arg.integer.value = sleep_state; | ||
231 | |||
232 | status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL); | ||
233 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
234 | return_ACPI_STATUS(status); | ||
235 | } | ||
236 | |||
237 | /* Setup the argument to the _SST method (System STatus) */ | ||
238 | |||
239 | switch (sleep_state) { | ||
240 | case ACPI_STATE_S0: | ||
241 | sst_value = ACPI_SST_WORKING; | ||
242 | break; | ||
243 | |||
244 | case ACPI_STATE_S1: | ||
245 | case ACPI_STATE_S2: | ||
246 | case ACPI_STATE_S3: | ||
247 | sst_value = ACPI_SST_SLEEPING; | ||
248 | break; | ||
249 | |||
250 | case ACPI_STATE_S4: | ||
251 | sst_value = ACPI_SST_SLEEP_CONTEXT; | ||
252 | break; | ||
253 | |||
254 | default: | ||
255 | sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */ | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Set the system indicators to show the desired sleep state. | ||
261 | * _SST is an optional method (return no error if not found) | ||
262 | */ | ||
263 | acpi_hw_execute_SST(sst_value); | ||
264 | return_ACPI_STATUS(AE_OK); | ||
265 | } | ||
266 | |||
267 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) | ||
268 | |||
269 | /******************************************************************************* | ||
270 | * | ||
271 | * FUNCTION: acpi_enter_sleep_state | ||
272 | * | ||
273 | * PARAMETERS: sleep_state - Which sleep state to enter | ||
274 | * | ||
275 | * RETURN: Status | ||
276 | * | ||
277 | * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231) | ||
278 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | ||
279 | * | ||
280 | ******************************************************************************/ | ||
281 | acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) | ||
282 | { | ||
283 | acpi_status status; | ||
284 | |||
285 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); | ||
286 | |||
287 | if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || | ||
288 | (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { | ||
289 | ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", | ||
290 | acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b)); | ||
291 | return_ACPI_STATUS(AE_AML_OPERAND_VALUE); | ||
292 | } | ||
293 | |||
294 | /* If Hardware Reduced flag is set, must use the extended sleep registers */ | ||
295 | |||
296 | if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) { | ||
297 | status = acpi_hw_extended_sleep(sleep_state); | ||
298 | } else { | ||
299 | /* Legacy sleep */ | ||
300 | |||
301 | status = acpi_hw_legacy_sleep(sleep_state); | ||
302 | } | ||
303 | |||
304 | return_ACPI_STATUS(status); | ||
305 | } | ||
306 | |||
307 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) | ||
308 | |||
309 | /******************************************************************************* | ||
310 | * | ||
311 | * FUNCTION: acpi_leave_sleep_state_prep | ||
312 | * | ||
313 | * PARAMETERS: sleep_state - Which sleep state we are exiting | ||
314 | * | ||
315 | * RETURN: Status | ||
316 | * | ||
317 | * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a | ||
318 | * sleep. | ||
319 | * Called with interrupts DISABLED. | ||
320 | * | ||
321 | ******************************************************************************/ | ||
322 | acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) | ||
323 | { | ||
324 | acpi_status status; | ||
325 | |||
326 | ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); | ||
327 | |||
328 | |||
329 | /* If Hardware Reduced flag is set, must use the extended sleep registers */ | ||
330 | |||
331 | if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) { | ||
332 | status = acpi_hw_extended_wake_prep(sleep_state); | ||
333 | } else { | ||
334 | /* Legacy sleep */ | ||
335 | |||
336 | status = acpi_hw_legacy_wake_prep(sleep_state); | ||
337 | } | ||
338 | |||
339 | |||
340 | return_ACPI_STATUS(status); | ||
341 | } | ||
342 | |||
343 | ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep) | ||
344 | |||
345 | /******************************************************************************* | ||
346 | * | ||
347 | * FUNCTION: acpi_leave_sleep_state | ||
348 | * | ||
349 | * PARAMETERS: sleep_state - Which sleep state we just exited | ||
350 | * | ||
351 | * RETURN: Status | ||
352 | * | ||
353 | * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep | ||
354 | * Called with interrupts ENABLED. | ||
355 | * | ||
356 | ******************************************************************************/ | ||
357 | acpi_status acpi_leave_sleep_state(u8 sleep_state) | ||
358 | { | ||
359 | acpi_status status; | ||
360 | |||
361 | ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); | ||
362 | |||
363 | |||
364 | /* If Hardware Reduced flag is set, must use the extended sleep registers */ | ||
365 | |||
366 | if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) { | ||
367 | status = acpi_hw_extended_wake(sleep_state); | ||
368 | } else { | ||
369 | /* Legacy sleep */ | ||
370 | |||
371 | status = acpi_hw_legacy_wake(sleep_state); | ||
372 | } | ||
373 | |||
374 | return_ACPI_STATUS(status); | ||
375 | } | ||
376 | |||
377 | ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state) | ||