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