1 | /****************************************************************************** |
2 | * |
3 | * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, 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 | #define EXPORT_ACPI_INTERFACES |
45 | |
46 | #include "acpi.h" |
47 | #include "accommon.h" |
48 | |
49 | #define _COMPONENT ACPI_HARDWARE |
50 | ACPI_MODULE_NAME ("hwxfsleep" ) |
51 | |
52 | /* Local prototypes */ |
53 | |
54 | #if (!ACPI_REDUCED_HARDWARE) |
55 | static ACPI_STATUS |
56 | AcpiHwSetFirmwareWakingVector ( |
57 | ACPI_TABLE_FACS *Facs, |
58 | ACPI_PHYSICAL_ADDRESS PhysicalAddress, |
59 | ACPI_PHYSICAL_ADDRESS PhysicalAddress64); |
60 | #endif |
61 | |
62 | static ACPI_STATUS |
63 | AcpiHwSleepDispatch ( |
64 | UINT8 SleepState, |
65 | UINT32 FunctionId); |
66 | |
67 | /* |
68 | * Dispatch table used to efficiently branch to the various sleep |
69 | * functions. |
70 | */ |
71 | #define ACPI_SLEEP_FUNCTION_ID 0 |
72 | #define ACPI_WAKE_PREP_FUNCTION_ID 1 |
73 | #define ACPI_WAKE_FUNCTION_ID 2 |
74 | |
75 | /* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ |
76 | |
77 | static ACPI_SLEEP_FUNCTIONS AcpiSleepDispatch[] = |
78 | { |
79 | {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacySleep), AcpiHwExtendedSleep}, |
80 | {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWakePrep), AcpiHwExtendedWakePrep}, |
81 | {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWake), AcpiHwExtendedWake} |
82 | }; |
83 | |
84 | |
85 | /* |
86 | * These functions are removed for the ACPI_REDUCED_HARDWARE case: |
87 | * AcpiSetFirmwareWakingVector |
88 | * AcpiEnterSleepStateS4bios |
89 | */ |
90 | |
91 | #if (!ACPI_REDUCED_HARDWARE) |
92 | /******************************************************************************* |
93 | * |
94 | * FUNCTION: AcpiHwSetFirmwareWakingVector |
95 | * |
96 | * PARAMETERS: Facs - Pointer to FACS table |
97 | * PhysicalAddress - 32-bit physical address of ACPI real mode |
98 | * entry point |
99 | * PhysicalAddress64 - 64-bit physical address of ACPI protected |
100 | * mode entry point |
101 | * |
102 | * RETURN: Status |
103 | * |
104 | * DESCRIPTION: Sets the FirmwareWakingVector fields of the FACS |
105 | * |
106 | ******************************************************************************/ |
107 | |
108 | static ACPI_STATUS |
109 | AcpiHwSetFirmwareWakingVector ( |
110 | ACPI_TABLE_FACS *Facs, |
111 | ACPI_PHYSICAL_ADDRESS PhysicalAddress, |
112 | ACPI_PHYSICAL_ADDRESS PhysicalAddress64) |
113 | { |
114 | ACPI_FUNCTION_TRACE (AcpiHwSetFirmwareWakingVector); |
115 | |
116 | |
117 | /* |
118 | * According to the ACPI specification 2.0c and later, the 64-bit |
119 | * waking vector should be cleared and the 32-bit waking vector should |
120 | * be used, unless we want the wake-up code to be called by the BIOS in |
121 | * Protected Mode. Some systems (for example HP dv5-1004nr) are known |
122 | * to fail to resume if the 64-bit vector is used. |
123 | */ |
124 | |
125 | /* Set the 32-bit vector */ |
126 | |
127 | Facs->FirmwareWakingVector = (UINT32) PhysicalAddress; |
128 | |
129 | if (Facs->Length > 32) |
130 | { |
131 | if (Facs->Version >= 1) |
132 | { |
133 | /* Set the 64-bit vector */ |
134 | |
135 | Facs->XFirmwareWakingVector = PhysicalAddress64; |
136 | } |
137 | else |
138 | { |
139 | /* Clear the 64-bit vector if it exists */ |
140 | |
141 | Facs->XFirmwareWakingVector = 0; |
142 | } |
143 | } |
144 | |
145 | return_ACPI_STATUS (AE_OK); |
146 | } |
147 | |
148 | |
149 | /******************************************************************************* |
150 | * |
151 | * FUNCTION: AcpiSetFirmwareWakingVector |
152 | * |
153 | * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode |
154 | * entry point |
155 | * PhysicalAddress64 - 64-bit physical address of ACPI protected |
156 | * mode entry point |
157 | * |
158 | * RETURN: Status |
159 | * |
160 | * DESCRIPTION: Sets the FirmwareWakingVector fields of the FACS |
161 | * |
162 | ******************************************************************************/ |
163 | |
164 | ACPI_STATUS |
165 | AcpiSetFirmwareWakingVector ( |
166 | ACPI_PHYSICAL_ADDRESS PhysicalAddress, |
167 | ACPI_PHYSICAL_ADDRESS PhysicalAddress64) |
168 | { |
169 | |
170 | ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector); |
171 | |
172 | if (AcpiGbl_FACS) |
173 | { |
174 | (void) AcpiHwSetFirmwareWakingVector (AcpiGbl_FACS, |
175 | PhysicalAddress, PhysicalAddress64); |
176 | } |
177 | |
178 | return_ACPI_STATUS (AE_OK); |
179 | } |
180 | |
181 | ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector) |
182 | |
183 | |
184 | /******************************************************************************* |
185 | * |
186 | * FUNCTION: AcpiEnterSleepStateS4bios |
187 | * |
188 | * PARAMETERS: None |
189 | * |
190 | * RETURN: Status |
191 | * |
192 | * DESCRIPTION: Perform a S4 bios request. |
193 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
194 | * |
195 | ******************************************************************************/ |
196 | |
197 | ACPI_STATUS |
198 | AcpiEnterSleepStateS4bios ( |
199 | void) |
200 | { |
201 | UINT32 InValue; |
202 | ACPI_STATUS Status; |
203 | |
204 | |
205 | ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios); |
206 | |
207 | |
208 | /* Clear the wake status bit (PM1) */ |
209 | |
210 | Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); |
211 | if (ACPI_FAILURE (Status)) |
212 | { |
213 | return_ACPI_STATUS (Status); |
214 | } |
215 | |
216 | Status = AcpiHwClearAcpiStatus (); |
217 | if (ACPI_FAILURE (Status)) |
218 | { |
219 | return_ACPI_STATUS (Status); |
220 | } |
221 | |
222 | /* |
223 | * 1) Disable/Clear all GPEs |
224 | * 2) Enable all wakeup GPEs |
225 | */ |
226 | Status = AcpiHwDisableAllGpes (); |
227 | if (ACPI_FAILURE (Status)) |
228 | { |
229 | return_ACPI_STATUS (Status); |
230 | } |
231 | AcpiGbl_SystemAwakeAndRunning = FALSE; |
232 | |
233 | Status = AcpiHwEnableAllWakeupGpes (); |
234 | if (ACPI_FAILURE (Status)) |
235 | { |
236 | return_ACPI_STATUS (Status); |
237 | } |
238 | |
239 | ACPI_FLUSH_CPU_CACHE (); |
240 | |
241 | Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, |
242 | (UINT32) AcpiGbl_FADT.S4BiosRequest, 8); |
243 | |
244 | do { |
245 | AcpiOsStall (ACPI_USEC_PER_MSEC); |
246 | Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); |
247 | if (ACPI_FAILURE (Status)) |
248 | { |
249 | return_ACPI_STATUS (Status); |
250 | } |
251 | |
252 | } while (!InValue); |
253 | |
254 | return_ACPI_STATUS (AE_OK); |
255 | } |
256 | |
257 | ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios) |
258 | |
259 | #endif /* !ACPI_REDUCED_HARDWARE */ |
260 | |
261 | |
262 | /******************************************************************************* |
263 | * |
264 | * FUNCTION: AcpiHwSleepDispatch |
265 | * |
266 | * PARAMETERS: SleepState - Which sleep state to enter/exit |
267 | * FunctionId - Sleep, WakePrep, or Wake |
268 | * |
269 | * RETURN: Status from the invoked sleep handling function. |
270 | * |
271 | * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling |
272 | * function. |
273 | * |
274 | ******************************************************************************/ |
275 | |
276 | static ACPI_STATUS |
277 | AcpiHwSleepDispatch ( |
278 | UINT8 SleepState, |
279 | UINT32 FunctionId) |
280 | { |
281 | ACPI_STATUS Status; |
282 | ACPI_SLEEP_FUNCTIONS *SleepFunctions = &AcpiSleepDispatch[FunctionId]; |
283 | |
284 | |
285 | #if (!ACPI_REDUCED_HARDWARE) |
286 | /* |
287 | * If the Hardware Reduced flag is set (from the FADT), we must |
288 | * use the extended sleep registers (FADT). Note: As per the ACPI |
289 | * specification, these extended registers are to be used for HW-reduced |
290 | * platforms only. They are not general-purpose replacements for the |
291 | * legacy PM register sleep support. |
292 | */ |
293 | if (AcpiGbl_ReducedHardware) |
294 | { |
295 | Status = SleepFunctions->ExtendedFunction (SleepState); |
296 | } |
297 | else |
298 | { |
299 | /* Legacy sleep */ |
300 | |
301 | Status = SleepFunctions->LegacyFunction (SleepState); |
302 | } |
303 | |
304 | return (Status); |
305 | |
306 | #else |
307 | /* |
308 | * For the case where reduced-hardware-only code is being generated, |
309 | * we know that only the extended sleep registers are available |
310 | */ |
311 | Status = SleepFunctions->ExtendedFunction (SleepState); |
312 | return (Status); |
313 | |
314 | #endif /* !ACPI_REDUCED_HARDWARE */ |
315 | } |
316 | |
317 | |
318 | /******************************************************************************* |
319 | * |
320 | * FUNCTION: AcpiEnterSleepStatePrep |
321 | * |
322 | * PARAMETERS: SleepState - Which sleep state to enter |
323 | * |
324 | * RETURN: Status |
325 | * |
326 | * DESCRIPTION: Prepare to enter a system sleep state. |
327 | * This function must execute with interrupts enabled. |
328 | * We break sleeping into 2 stages so that OSPM can handle |
329 | * various OS-specific tasks between the two steps. |
330 | * |
331 | ******************************************************************************/ |
332 | |
333 | ACPI_STATUS |
334 | AcpiEnterSleepStatePrep ( |
335 | UINT8 SleepState) |
336 | { |
337 | ACPI_STATUS Status; |
338 | ACPI_OBJECT_LIST ArgList; |
339 | ACPI_OBJECT Arg; |
340 | UINT32 SstValue; |
341 | |
342 | |
343 | ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep); |
344 | |
345 | |
346 | Status = AcpiGetSleepTypeData (SleepState, |
347 | &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); |
348 | if (ACPI_FAILURE (Status)) |
349 | { |
350 | return_ACPI_STATUS (Status); |
351 | } |
352 | |
353 | /* Execute the _PTS method (Prepare To Sleep) */ |
354 | |
355 | ArgList.Count = 1; |
356 | ArgList.Pointer = &Arg; |
357 | Arg.Type = ACPI_TYPE_INTEGER; |
358 | Arg.Integer.Value = SleepState; |
359 | |
360 | Status = AcpiEvaluateObject (NULL, METHOD_PATHNAME__PTS, &ArgList, NULL); |
361 | if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) |
362 | { |
363 | return_ACPI_STATUS (Status); |
364 | } |
365 | |
366 | /* Setup the argument to the _SST method (System STatus) */ |
367 | |
368 | switch (SleepState) |
369 | { |
370 | case ACPI_STATE_S0: |
371 | |
372 | SstValue = ACPI_SST_WORKING; |
373 | break; |
374 | |
375 | case ACPI_STATE_S1: |
376 | case ACPI_STATE_S2: |
377 | case ACPI_STATE_S3: |
378 | |
379 | SstValue = ACPI_SST_SLEEPING; |
380 | break; |
381 | |
382 | case ACPI_STATE_S4: |
383 | |
384 | SstValue = ACPI_SST_SLEEP_CONTEXT; |
385 | break; |
386 | |
387 | default: |
388 | |
389 | SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */ |
390 | break; |
391 | } |
392 | |
393 | /* |
394 | * Set the system indicators to show the desired sleep state. |
395 | * _SST is an optional method (return no error if not found) |
396 | */ |
397 | AcpiHwExecuteSleepMethod (__UNCONST(METHOD_PATHNAME__SST), SstValue); |
398 | return_ACPI_STATUS (AE_OK); |
399 | } |
400 | |
401 | ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep) |
402 | |
403 | |
404 | /******************************************************************************* |
405 | * |
406 | * FUNCTION: AcpiEnterSleepState |
407 | * |
408 | * PARAMETERS: SleepState - Which sleep state to enter |
409 | * |
410 | * RETURN: Status |
411 | * |
412 | * DESCRIPTION: Enter a system sleep state |
413 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
414 | * |
415 | ******************************************************************************/ |
416 | |
417 | ACPI_STATUS |
418 | AcpiEnterSleepState ( |
419 | UINT8 SleepState) |
420 | { |
421 | ACPI_STATUS Status; |
422 | |
423 | |
424 | ACPI_FUNCTION_TRACE (AcpiEnterSleepState); |
425 | |
426 | |
427 | if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) || |
428 | (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX)) |
429 | { |
430 | ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X" , |
431 | AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB)); |
432 | return_ACPI_STATUS (AE_AML_OPERAND_VALUE); |
433 | } |
434 | |
435 | Status = AcpiHwSleepDispatch (SleepState, ACPI_SLEEP_FUNCTION_ID); |
436 | return_ACPI_STATUS (Status); |
437 | } |
438 | |
439 | ACPI_EXPORT_SYMBOL (AcpiEnterSleepState) |
440 | |
441 | |
442 | /******************************************************************************* |
443 | * |
444 | * FUNCTION: AcpiLeaveSleepStatePrep |
445 | * |
446 | * PARAMETERS: SleepState - Which sleep state we are exiting |
447 | * |
448 | * RETURN: Status |
449 | * |
450 | * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a |
451 | * sleep. Called with interrupts DISABLED. |
452 | * We break wake/resume into 2 stages so that OSPM can handle |
453 | * various OS-specific tasks between the two steps. |
454 | * |
455 | ******************************************************************************/ |
456 | |
457 | ACPI_STATUS |
458 | AcpiLeaveSleepStatePrep ( |
459 | UINT8 SleepState) |
460 | { |
461 | ACPI_STATUS Status; |
462 | |
463 | |
464 | ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep); |
465 | |
466 | |
467 | Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_PREP_FUNCTION_ID); |
468 | return_ACPI_STATUS (Status); |
469 | } |
470 | |
471 | ACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep) |
472 | |
473 | |
474 | /******************************************************************************* |
475 | * |
476 | * FUNCTION: AcpiLeaveSleepState |
477 | * |
478 | * PARAMETERS: SleepState - Which sleep state we are exiting |
479 | * |
480 | * RETURN: Status |
481 | * |
482 | * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep |
483 | * Called with interrupts ENABLED. |
484 | * |
485 | ******************************************************************************/ |
486 | |
487 | ACPI_STATUS |
488 | AcpiLeaveSleepState ( |
489 | UINT8 SleepState) |
490 | { |
491 | ACPI_STATUS Status; |
492 | |
493 | |
494 | ACPI_FUNCTION_TRACE (AcpiLeaveSleepState); |
495 | |
496 | |
497 | Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_FUNCTION_ID); |
498 | return_ACPI_STATUS (Status); |
499 | } |
500 | |
501 | ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState) |
502 | |