hwxfsleep.c revision 238381
155682Smarkm/******************************************************************************
2233294Sstas *
355682Smarkm * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
455682Smarkm *
5233294Sstas *****************************************************************************/
655682Smarkm
755682Smarkm/*
855682Smarkm * Copyright (C) 2000 - 2012, Intel Corp.
9233294Sstas * All rights reserved.
1055682Smarkm *
1155682Smarkm * Redistribution and use in source and binary forms, with or without
12233294Sstas * modification, are permitted provided that the following conditions
1355682Smarkm * are met:
1455682Smarkm * 1. Redistributions of source code must retain the above copyright
1555682Smarkm *    notice, this list of conditions, and the following disclaimer,
16233294Sstas *    without modification.
1755682Smarkm * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1855682Smarkm *    substantially similar to the "NO WARRANTY" disclaimer below
1955682Smarkm *    ("Disclaimer") and any redistribution must be conditioned upon
20233294Sstas *    including a substantially similar Disclaimer requirement for further
2155682Smarkm *    binary redistribution.
2255682Smarkm * 3. Neither the names of the above-listed copyright holders nor the names
2355682Smarkm *    of any contributors may be used to endorse or promote products derived
2455682Smarkm *    from this software without specific prior written permission.
2555682Smarkm *
2655682Smarkm * Alternatively, this software may be distributed under the terms of the
2755682Smarkm * GNU General Public License ("GPL") version 2 as published by the Free
2855682Smarkm * Software Foundation.
2955682Smarkm *
3055682Smarkm * NO WARRANTY
3155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3255682Smarkm * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3355682Smarkm * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3455682Smarkm * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3555682Smarkm * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39233294Sstas * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4055682Smarkm * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4155682Smarkm * POSSIBILITY OF SUCH DAMAGES.
4255682Smarkm */
4355682Smarkm
4455682Smarkm#include <contrib/dev/acpica/include/acpi.h>
4555682Smarkm#include <contrib/dev/acpica/include/accommon.h>
4655682Smarkm
4755682Smarkm#define _COMPONENT          ACPI_HARDWARE
4855682Smarkm        ACPI_MODULE_NAME    ("hwxfsleep")
4955682Smarkm
50/* Local prototypes */
51
52static ACPI_STATUS
53AcpiHwSleepDispatch (
54    UINT8                   SleepState,
55    UINT8                   Flags,
56    UINT32                  FunctionId);
57
58/*
59 * Dispatch table used to efficiently branch to the various sleep
60 * functions.
61 */
62#define ACPI_SLEEP_FUNCTION_ID          0
63#define ACPI_WAKE_PREP_FUNCTION_ID      1
64#define ACPI_WAKE_FUNCTION_ID           2
65
66/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */
67
68static ACPI_SLEEP_FUNCTIONS         AcpiSleepDispatch[] =
69{
70    {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacySleep),    AcpiHwExtendedSleep},
71    {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWakePrep), AcpiHwExtendedWakePrep},
72    {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWake),     AcpiHwExtendedWake}
73};
74
75
76/*
77 * These functions are removed for the ACPI_REDUCED_HARDWARE case:
78 *      AcpiSetFirmwareWakingVector
79 *      AcpiSetFirmwareWakingVector64
80 *      AcpiEnterSleepStateS4bios
81 */
82
83#if (!ACPI_REDUCED_HARDWARE)
84/*******************************************************************************
85 *
86 * FUNCTION:    AcpiSetFirmwareWakingVector
87 *
88 * PARAMETERS:  PhysicalAddress     - 32-bit physical address of ACPI real mode
89 *                                    entry point.
90 *
91 * RETURN:      Status
92 *
93 * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS
94 *
95 ******************************************************************************/
96
97ACPI_STATUS
98AcpiSetFirmwareWakingVector (
99    UINT32                  PhysicalAddress)
100{
101    ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector);
102
103
104    /*
105     * According to the ACPI specification 2.0c and later, the 64-bit
106     * waking vector should be cleared and the 32-bit waking vector should
107     * be used, unless we want the wake-up code to be called by the BIOS in
108     * Protected Mode. Some systems (for example HP dv5-1004nr) are known
109     * to fail to resume if the 64-bit vector is used.
110     */
111
112    /* Set the 32-bit vector */
113
114    AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress;
115
116    /* Clear the 64-bit vector if it exists */
117
118    if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1))
119    {
120        AcpiGbl_FACS->XFirmwareWakingVector = 0;
121    }
122
123    return_ACPI_STATUS (AE_OK);
124}
125
126ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)
127
128
129#if ACPI_MACHINE_WIDTH == 64
130/*******************************************************************************
131 *
132 * FUNCTION:    AcpiSetFirmwareWakingVector64
133 *
134 * PARAMETERS:  PhysicalAddress     - 64-bit physical address of ACPI protected
135 *                                    mode entry point.
136 *
137 * RETURN:      Status
138 *
139 * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if
140 *              it exists in the table. This function is intended for use with
141 *              64-bit host operating systems.
142 *
143 ******************************************************************************/
144
145ACPI_STATUS
146AcpiSetFirmwareWakingVector64 (
147    UINT64                  PhysicalAddress)
148{
149    ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64);
150
151
152    /* Determine if the 64-bit vector actually exists */
153
154    if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1))
155    {
156        return_ACPI_STATUS (AE_NOT_EXIST);
157    }
158
159    /* Clear 32-bit vector, set the 64-bit X_ vector */
160
161    AcpiGbl_FACS->FirmwareWakingVector = 0;
162    AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress;
163    return_ACPI_STATUS (AE_OK);
164}
165
166ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64)
167#endif
168
169
170/*******************************************************************************
171 *
172 * FUNCTION:    AcpiEnterSleepStateS4bios
173 *
174 * PARAMETERS:  None
175 *
176 * RETURN:      Status
177 *
178 * DESCRIPTION: Perform a S4 bios request.
179 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
180 *
181 ******************************************************************************/
182
183ACPI_STATUS
184AcpiEnterSleepStateS4bios (
185    void)
186{
187    UINT32                  InValue;
188    ACPI_STATUS             Status;
189
190
191    ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios);
192
193
194    /* Clear the wake status bit (PM1) */
195
196    Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
197    if (ACPI_FAILURE (Status))
198    {
199        return_ACPI_STATUS (Status);
200    }
201
202    Status = AcpiHwClearAcpiStatus ();
203    if (ACPI_FAILURE (Status))
204    {
205        return_ACPI_STATUS (Status);
206    }
207
208    /*
209     * 1) Disable/Clear all GPEs
210     * 2) Enable all wakeup GPEs
211     */
212    Status = AcpiHwDisableAllGpes ();
213    if (ACPI_FAILURE (Status))
214    {
215        return_ACPI_STATUS (Status);
216    }
217    AcpiGbl_SystemAwakeAndRunning = FALSE;
218
219    Status = AcpiHwEnableAllWakeupGpes ();
220    if (ACPI_FAILURE (Status))
221    {
222        return_ACPI_STATUS (Status);
223    }
224
225    ACPI_FLUSH_CPU_CACHE ();
226
227    Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand,
228                (UINT32) AcpiGbl_FADT.S4BiosRequest, 8);
229
230    do {
231        AcpiOsStall(1000);
232        Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
233        if (ACPI_FAILURE (Status))
234        {
235            return_ACPI_STATUS (Status);
236        }
237    } while (!InValue);
238
239    return_ACPI_STATUS (AE_OK);
240}
241
242ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios)
243
244#endif /* !ACPI_REDUCED_HARDWARE */
245
246
247/*******************************************************************************
248 *
249 * FUNCTION:    AcpiHwSleepDispatch
250 *
251 * PARAMETERS:  SleepState          - Which sleep state to enter/exit
252 *              FunctionId          - Sleep, WakePrep, or Wake
253 *
254 * RETURN:      Status from the invoked sleep handling function.
255 *
256 * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling
257 *              function.
258 *
259 ******************************************************************************/
260
261static ACPI_STATUS
262AcpiHwSleepDispatch (
263    UINT8                   SleepState,
264    UINT8                   Flags,
265    UINT32                  FunctionId)
266{
267    ACPI_STATUS             Status;
268    ACPI_SLEEP_FUNCTIONS    *SleepFunctions = &AcpiSleepDispatch[FunctionId];
269
270
271#if (!ACPI_REDUCED_HARDWARE)
272
273    /*
274     * If the Hardware Reduced flag is set (from the FADT), we must
275     * use the extended sleep registers
276     */
277    if (AcpiGbl_ReducedHardware ||
278        AcpiGbl_FADT.SleepControl.Address)
279    {
280        Status = SleepFunctions->ExtendedFunction (SleepState, Flags);
281    }
282    else
283    {
284        /* Legacy sleep */
285
286        Status = SleepFunctions->LegacyFunction (SleepState, Flags);
287    }
288
289    return (Status);
290
291#else
292    /*
293     * For the case where reduced-hardware-only code is being generated,
294     * we know that only the extended sleep registers are available
295     */
296    Status = SleepFunctions->ExtendedFunction (SleepState, Flags);
297    return (Status);
298
299#endif /* !ACPI_REDUCED_HARDWARE */
300}
301
302
303/*******************************************************************************
304 *
305 * FUNCTION:    AcpiEnterSleepStatePrep
306 *
307 * PARAMETERS:  SleepState          - Which sleep state to enter
308 *
309 * RETURN:      Status
310 *
311 * DESCRIPTION: Prepare to enter a system sleep state.
312 *              This function must execute with interrupts enabled.
313 *              We break sleeping into 2 stages so that OSPM can handle
314 *              various OS-specific tasks between the two steps.
315 *
316 ******************************************************************************/
317
318ACPI_STATUS
319AcpiEnterSleepStatePrep (
320    UINT8                   SleepState)
321{
322    ACPI_STATUS             Status;
323    ACPI_OBJECT_LIST        ArgList;
324    ACPI_OBJECT             Arg;
325    UINT32                  SstValue;
326
327
328    ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep);
329
330
331    Status = AcpiGetSleepTypeData (SleepState,
332                    &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
333    if (ACPI_FAILURE (Status))
334    {
335        return_ACPI_STATUS (Status);
336    }
337
338    /* Execute the _PTS method (Prepare To Sleep) */
339
340    ArgList.Count = 1;
341    ArgList.Pointer = &Arg;
342    Arg.Type = ACPI_TYPE_INTEGER;
343    Arg.Integer.Value = SleepState;
344
345    Status = AcpiEvaluateObject (NULL, METHOD_PATHNAME__PTS, &ArgList, NULL);
346    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
347    {
348        return_ACPI_STATUS (Status);
349    }
350
351    /* Setup the argument to the _SST method (System STatus) */
352
353    switch (SleepState)
354    {
355    case ACPI_STATE_S0:
356        SstValue = ACPI_SST_WORKING;
357        break;
358
359    case ACPI_STATE_S1:
360    case ACPI_STATE_S2:
361    case ACPI_STATE_S3:
362        SstValue = ACPI_SST_SLEEPING;
363        break;
364
365    case ACPI_STATE_S4:
366        SstValue = ACPI_SST_SLEEP_CONTEXT;
367        break;
368
369    default:
370        SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */
371        break;
372    }
373
374    /*
375     * Set the system indicators to show the desired sleep state.
376     * _SST is an optional method (return no error if not found)
377     */
378    AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, SstValue);
379    return_ACPI_STATUS (AE_OK);
380}
381
382ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep)
383
384
385/*******************************************************************************
386 *
387 * FUNCTION:    AcpiEnterSleepState
388 *
389 * PARAMETERS:  SleepState          - Which sleep state to enter
390 *              Flags               - ACPI_EXECUTE_GTS to run optional method
391 *
392 * RETURN:      Status
393 *
394 * DESCRIPTION: Enter a system sleep state
395 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
396 *
397 ******************************************************************************/
398
399ACPI_STATUS
400AcpiEnterSleepState (
401    UINT8                   SleepState,
402    UINT8                   Flags)
403{
404    ACPI_STATUS             Status;
405
406
407    ACPI_FUNCTION_TRACE (AcpiEnterSleepState);
408
409
410    if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) ||
411        (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX))
412    {
413        ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
414            AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB));
415        return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
416    }
417
418    Status = AcpiHwSleepDispatch (SleepState, Flags, ACPI_SLEEP_FUNCTION_ID);
419    return_ACPI_STATUS (Status);
420}
421
422ACPI_EXPORT_SYMBOL (AcpiEnterSleepState)
423
424
425/*******************************************************************************
426 *
427 * FUNCTION:    AcpiLeaveSleepStatePrep
428 *
429 * PARAMETERS:  SleepState          - Which sleep state we are exiting
430 *              Flags               - ACPI_EXECUTE_BFS to run optional method
431 *
432 * RETURN:      Status
433 *
434 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
435 *              sleep. Called with interrupts DISABLED.
436 *              We break wake/resume into 2 stages so that OSPM can handle
437 *              various OS-specific tasks between the two steps.
438 *
439 ******************************************************************************/
440
441ACPI_STATUS
442AcpiLeaveSleepStatePrep (
443    UINT8                   SleepState,
444    UINT8                   Flags)
445{
446    ACPI_STATUS             Status;
447
448
449    ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep);
450
451
452    Status = AcpiHwSleepDispatch (SleepState, Flags, ACPI_WAKE_PREP_FUNCTION_ID);
453    return_ACPI_STATUS (Status);
454}
455
456ACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep)
457
458
459/*******************************************************************************
460 *
461 * FUNCTION:    AcpiLeaveSleepState
462 *
463 * PARAMETERS:  SleepState          - Which sleep state we are exiting
464 *
465 * RETURN:      Status
466 *
467 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
468 *              Called with interrupts ENABLED.
469 *
470 ******************************************************************************/
471
472ACPI_STATUS
473AcpiLeaveSleepState (
474    UINT8                   SleepState)
475{
476    ACPI_STATUS             Status;
477
478
479    ACPI_FUNCTION_TRACE (AcpiLeaveSleepState);
480
481
482    Status = AcpiHwSleepDispatch (SleepState, 0, ACPI_WAKE_FUNCTION_ID);
483    return_ACPI_STATUS (Status);
484}
485
486ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState)
487