1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #define EXPORT_ACPI_INTERFACES |
11 | |
12 | #include <acpi/acpi.h> |
13 | #include "accommon.h" |
14 | |
15 | #define _COMPONENT ACPI_HARDWARE |
16 | ACPI_MODULE_NAME("hwxfsleep" ) |
17 | |
18 | /* Local prototypes */ |
19 | #if (!ACPI_REDUCED_HARDWARE) |
20 | static acpi_status |
21 | acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs, |
22 | acpi_physical_address physical_address, |
23 | acpi_physical_address physical_address64); |
24 | #endif |
25 | |
26 | /* |
27 | * These functions are removed for the ACPI_REDUCED_HARDWARE case: |
28 | * acpi_set_firmware_waking_vector |
29 | * acpi_enter_sleep_state_s4bios |
30 | */ |
31 | |
32 | #if (!ACPI_REDUCED_HARDWARE) |
33 | /******************************************************************************* |
34 | * |
35 | * FUNCTION: acpi_hw_set_firmware_waking_vector |
36 | * |
37 | * PARAMETERS: facs - Pointer to FACS table |
38 | * physical_address - 32-bit physical address of ACPI real mode |
39 | * entry point |
40 | * physical_address64 - 64-bit physical address of ACPI protected |
41 | * mode entry point |
42 | * |
43 | * RETURN: Status |
44 | * |
45 | * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS |
46 | * |
47 | ******************************************************************************/ |
48 | |
49 | static acpi_status |
50 | acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs, |
51 | acpi_physical_address physical_address, |
52 | acpi_physical_address physical_address64) |
53 | { |
54 | ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vector); |
55 | |
56 | |
57 | /* |
58 | * According to the ACPI specification 2.0c and later, the 64-bit |
59 | * waking vector should be cleared and the 32-bit waking vector should |
60 | * be used, unless we want the wake-up code to be called by the BIOS in |
61 | * Protected Mode. Some systems (for example HP dv5-1004nr) are known |
62 | * to fail to resume if the 64-bit vector is used. |
63 | */ |
64 | |
65 | /* Set the 32-bit vector */ |
66 | |
67 | facs->firmware_waking_vector = (u32)physical_address; |
68 | |
69 | if (facs->length > 32) { |
70 | if (facs->version >= 1) { |
71 | |
72 | /* Set the 64-bit vector */ |
73 | |
74 | facs->xfirmware_waking_vector = physical_address64; |
75 | } else { |
76 | /* Clear the 64-bit vector if it exists */ |
77 | |
78 | facs->xfirmware_waking_vector = 0; |
79 | } |
80 | } |
81 | |
82 | return_ACPI_STATUS(AE_OK); |
83 | } |
84 | |
85 | /******************************************************************************* |
86 | * |
87 | * FUNCTION: acpi_set_firmware_waking_vector |
88 | * |
89 | * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode |
90 | * entry point |
91 | * physical_address64 - 64-bit physical address of ACPI protected |
92 | * mode entry point |
93 | * |
94 | * RETURN: Status |
95 | * |
96 | * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS |
97 | * |
98 | ******************************************************************************/ |
99 | |
100 | acpi_status |
101 | acpi_set_firmware_waking_vector(acpi_physical_address physical_address, |
102 | acpi_physical_address physical_address64) |
103 | { |
104 | |
105 | ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); |
106 | |
107 | if (acpi_gbl_FACS) { |
108 | (void)acpi_hw_set_firmware_waking_vector(acpi_gbl_FACS, |
109 | physical_address, |
110 | physical_address64); |
111 | } |
112 | |
113 | return_ACPI_STATUS(AE_OK); |
114 | } |
115 | |
116 | ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) |
117 | |
118 | /******************************************************************************* |
119 | * |
120 | * FUNCTION: acpi_enter_sleep_state_s4bios |
121 | * |
122 | * PARAMETERS: None |
123 | * |
124 | * RETURN: Status |
125 | * |
126 | * DESCRIPTION: Perform a S4 bios request. |
127 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
128 | * |
129 | ******************************************************************************/ |
130 | acpi_status acpi_enter_sleep_state_s4bios(void) |
131 | { |
132 | u32 in_value; |
133 | acpi_status status; |
134 | |
135 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); |
136 | |
137 | /* Clear the wake status bit (PM1) */ |
138 | |
139 | status = |
140 | acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); |
141 | if (ACPI_FAILURE(status)) { |
142 | return_ACPI_STATUS(status); |
143 | } |
144 | |
145 | status = acpi_hw_clear_acpi_status(); |
146 | if (ACPI_FAILURE(status)) { |
147 | return_ACPI_STATUS(status); |
148 | } |
149 | |
150 | /* |
151 | * 1) Disable all GPEs |
152 | * 2) Enable all wakeup GPEs |
153 | */ |
154 | status = acpi_hw_disable_all_gpes(); |
155 | if (ACPI_FAILURE(status)) { |
156 | return_ACPI_STATUS(status); |
157 | } |
158 | acpi_gbl_system_awake_and_running = FALSE; |
159 | |
160 | status = acpi_hw_enable_all_wakeup_gpes(); |
161 | if (ACPI_FAILURE(status)) { |
162 | return_ACPI_STATUS(status); |
163 | } |
164 | |
165 | status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, |
166 | (u32)acpi_gbl_FADT.s4_bios_request, 8); |
167 | if (ACPI_FAILURE(status)) { |
168 | return_ACPI_STATUS(status); |
169 | } |
170 | |
171 | do { |
172 | acpi_os_stall(ACPI_USEC_PER_MSEC); |
173 | status = |
174 | acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); |
175 | if (ACPI_FAILURE(status)) { |
176 | return_ACPI_STATUS(status); |
177 | } |
178 | |
179 | } while (!in_value); |
180 | |
181 | return_ACPI_STATUS(AE_OK); |
182 | } |
183 | |
184 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) |
185 | #endif /* !ACPI_REDUCED_HARDWARE */ |
186 | |
187 | /******************************************************************************* |
188 | * |
189 | * FUNCTION: acpi_enter_sleep_state_prep |
190 | * |
191 | * PARAMETERS: sleep_state - Which sleep state to enter |
192 | * |
193 | * RETURN: Status |
194 | * |
195 | * DESCRIPTION: Prepare to enter a system sleep state. |
196 | * This function must execute with interrupts enabled. |
197 | * We break sleeping into 2 stages so that OSPM can handle |
198 | * various OS-specific tasks between the two steps. |
199 | * |
200 | ******************************************************************************/ |
201 | |
202 | acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) |
203 | { |
204 | acpi_status status; |
205 | struct acpi_object_list arg_list; |
206 | union acpi_object arg; |
207 | u32 sst_value; |
208 | |
209 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep); |
210 | |
211 | status = acpi_get_sleep_type_data(sleep_state, |
212 | slp_typ_a: &acpi_gbl_sleep_type_a, |
213 | slp_typ_b: &acpi_gbl_sleep_type_b); |
214 | if (ACPI_FAILURE(status)) { |
215 | return_ACPI_STATUS(status); |
216 | } |
217 | |
218 | status = acpi_get_sleep_type_data(ACPI_STATE_S0, |
219 | slp_typ_a: &acpi_gbl_sleep_type_a_s0, |
220 | slp_typ_b: &acpi_gbl_sleep_type_b_s0); |
221 | if (ACPI_FAILURE(status)) { |
222 | acpi_gbl_sleep_type_a_s0 = ACPI_SLEEP_TYPE_INVALID; |
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 = |
233 | acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, parameter_objects: &arg_list, NULL); |
234 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
235 | return_ACPI_STATUS(status); |
236 | } |
237 | |
238 | /* Setup the argument to the _SST method (System STatus) */ |
239 | |
240 | switch (sleep_state) { |
241 | case ACPI_STATE_S0: |
242 | |
243 | sst_value = ACPI_SST_WORKING; |
244 | break; |
245 | |
246 | case ACPI_STATE_S1: |
247 | case ACPI_STATE_S2: |
248 | case ACPI_STATE_S3: |
249 | |
250 | sst_value = ACPI_SST_SLEEPING; |
251 | break; |
252 | |
253 | case ACPI_STATE_S4: |
254 | |
255 | sst_value = ACPI_SST_SLEEP_CONTEXT; |
256 | break; |
257 | |
258 | default: |
259 | |
260 | sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */ |
261 | break; |
262 | } |
263 | |
264 | /* |
265 | * Set the system indicators to show the desired sleep state. |
266 | * _SST is an optional method (return no error if not found) |
267 | */ |
268 | acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, integer_argument: sst_value); |
269 | return_ACPI_STATUS(AE_OK); |
270 | } |
271 | |
272 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) |
273 | |
274 | /******************************************************************************* |
275 | * |
276 | * FUNCTION: acpi_enter_sleep_state |
277 | * |
278 | * PARAMETERS: sleep_state - Which sleep state to enter |
279 | * |
280 | * RETURN: Status |
281 | * |
282 | * DESCRIPTION: Enter a system sleep state |
283 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
284 | * |
285 | ******************************************************************************/ |
286 | acpi_status acpi_enter_sleep_state(u8 sleep_state) |
287 | { |
288 | acpi_status status; |
289 | |
290 | ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); |
291 | |
292 | if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || |
293 | (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { |
294 | ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X" , |
295 | acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b)); |
296 | return_ACPI_STATUS(AE_AML_OPERAND_VALUE); |
297 | } |
298 | |
299 | #if !ACPI_REDUCED_HARDWARE |
300 | if (!acpi_gbl_reduced_hardware) |
301 | status = acpi_hw_legacy_sleep(sleep_state); |
302 | else |
303 | #endif |
304 | status = acpi_hw_extended_sleep(sleep_state); |
305 | return_ACPI_STATUS(status); |
306 | } |
307 | |
308 | ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) |
309 | |
310 | /******************************************************************************* |
311 | * |
312 | * FUNCTION: acpi_leave_sleep_state_prep |
313 | * |
314 | * PARAMETERS: sleep_state - Which sleep state we are exiting |
315 | * |
316 | * RETURN: Status |
317 | * |
318 | * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a |
319 | * sleep. Called with interrupts DISABLED. |
320 | * We break wake/resume into 2 stages so that OSPM can handle |
321 | * various OS-specific tasks between the two steps. |
322 | * |
323 | ******************************************************************************/ |
324 | acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) |
325 | { |
326 | acpi_status status; |
327 | |
328 | ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); |
329 | |
330 | #if !ACPI_REDUCED_HARDWARE |
331 | if (!acpi_gbl_reduced_hardware) |
332 | status = acpi_hw_legacy_wake_prep(sleep_state); |
333 | else |
334 | #endif |
335 | status = acpi_hw_extended_wake_prep(sleep_state); |
336 | return_ACPI_STATUS(status); |
337 | } |
338 | |
339 | ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep) |
340 | |
341 | /******************************************************************************* |
342 | * |
343 | * FUNCTION: acpi_leave_sleep_state |
344 | * |
345 | * PARAMETERS: sleep_state - Which sleep state we are exiting |
346 | * |
347 | * RETURN: Status |
348 | * |
349 | * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep |
350 | * Called with interrupts ENABLED. |
351 | * |
352 | ******************************************************************************/ |
353 | acpi_status acpi_leave_sleep_state(u8 sleep_state) |
354 | { |
355 | acpi_status status; |
356 | |
357 | ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); |
358 | |
359 | #if !ACPI_REDUCED_HARDWARE |
360 | if (!acpi_gbl_reduced_hardware) |
361 | status = acpi_hw_legacy_wake(sleep_state); |
362 | else |
363 | #endif |
364 | status = acpi_hw_extended_wake(sleep_state); |
365 | return_ACPI_STATUS(status); |
366 | } |
367 | |
368 | ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state) |
369 | |