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