Home | History | Annotate | Line # | Download | only in hardware
hwxfsleep.c revision 1.9
      1 /******************************************************************************
      2  *
      3  * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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_STRUCT_INIT (legacy_function,
     80                        ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacySleep)),
     81      ACPI_STRUCT_INIT (extended_function,
     82                        AcpiHwExtendedSleep) },
     83     {ACPI_STRUCT_INIT (legacy_function,
     84                        ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWakePrep)),
     85      ACPI_STRUCT_INIT (extended_function,
     86                        AcpiHwExtendedWakePrep) },
     87     {ACPI_STRUCT_INIT (legacy_function,
     88                        ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWake)),
     89      ACPI_STRUCT_INIT (extended_function,
     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/Clear 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 
    253     do {
    254         AcpiOsStall (ACPI_USEC_PER_MSEC);
    255         Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
    256         if (ACPI_FAILURE (Status))
    257         {
    258             return_ACPI_STATUS (Status);
    259         }
    260 
    261     } while (!InValue);
    262 
    263     return_ACPI_STATUS (AE_OK);
    264 }
    265 
    266 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios)
    267 
    268 #endif /* !ACPI_REDUCED_HARDWARE */
    269 
    270 
    271 /*******************************************************************************
    272  *
    273  * FUNCTION:    AcpiHwSleepDispatch
    274  *
    275  * PARAMETERS:  SleepState          - Which sleep state to enter/exit
    276  *              FunctionId          - Sleep, WakePrep, or Wake
    277  *
    278  * RETURN:      Status from the invoked sleep handling function.
    279  *
    280  * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling
    281  *              function.
    282  *
    283  ******************************************************************************/
    284 
    285 static ACPI_STATUS
    286 AcpiHwSleepDispatch (
    287     UINT8                   SleepState,
    288     UINT32                  FunctionId)
    289 {
    290     ACPI_STATUS             Status;
    291     ACPI_SLEEP_FUNCTIONS    *SleepFunctions = &AcpiSleepDispatch[FunctionId];
    292 
    293 
    294 #if (!ACPI_REDUCED_HARDWARE)
    295     /*
    296      * If the Hardware Reduced flag is set (from the FADT), we must
    297      * use the extended sleep registers (FADT). Note: As per the ACPI
    298      * specification, these extended registers are to be used for HW-reduced
    299      * platforms only. They are not general-purpose replacements for the
    300      * legacy PM register sleep support.
    301      */
    302     if (AcpiGbl_ReducedHardware)
    303     {
    304         Status = SleepFunctions->ExtendedFunction (SleepState);
    305     }
    306     else
    307     {
    308         /* Legacy sleep */
    309 
    310         Status = SleepFunctions->LegacyFunction (SleepState);
    311     }
    312 
    313     return (Status);
    314 
    315 #else
    316     /*
    317      * For the case where reduced-hardware-only code is being generated,
    318      * we know that only the extended sleep registers are available
    319      */
    320     Status = SleepFunctions->ExtendedFunction (SleepState);
    321     return (Status);
    322 
    323 #endif /* !ACPI_REDUCED_HARDWARE */
    324 }
    325 
    326 
    327 /*******************************************************************************
    328  *
    329  * FUNCTION:    AcpiEnterSleepStatePrep
    330  *
    331  * PARAMETERS:  SleepState          - Which sleep state to enter
    332  *
    333  * RETURN:      Status
    334  *
    335  * DESCRIPTION: Prepare to enter a system sleep state.
    336  *              This function must execute with interrupts enabled.
    337  *              We break sleeping into 2 stages so that OSPM can handle
    338  *              various OS-specific tasks between the two steps.
    339  *
    340  ******************************************************************************/
    341 
    342 ACPI_STATUS
    343 AcpiEnterSleepStatePrep (
    344     UINT8                   SleepState)
    345 {
    346     ACPI_STATUS             Status;
    347     ACPI_OBJECT_LIST        ArgList;
    348     ACPI_OBJECT             Arg;
    349     UINT32                  SstValue;
    350 
    351 
    352     ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep);
    353 
    354 
    355     Status = AcpiGetSleepTypeData (SleepState,
    356         &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
    357     if (ACPI_FAILURE (Status))
    358     {
    359         return_ACPI_STATUS (Status);
    360     }
    361 
    362     /* Execute the _PTS method (Prepare To Sleep) */
    363 
    364     ArgList.Count = 1;
    365     ArgList.Pointer = &Arg;
    366     Arg.Type = ACPI_TYPE_INTEGER;
    367     Arg.Integer.Value = SleepState;
    368 
    369     Status = AcpiEvaluateObject (NULL, METHOD_PATHNAME__PTS, &ArgList, NULL);
    370     if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
    371     {
    372         return_ACPI_STATUS (Status);
    373     }
    374 
    375     /* Setup the argument to the _SST method (System STatus) */
    376 
    377     switch (SleepState)
    378     {
    379     case ACPI_STATE_S0:
    380 
    381         SstValue = ACPI_SST_WORKING;
    382         break;
    383 
    384     case ACPI_STATE_S1:
    385     case ACPI_STATE_S2:
    386     case ACPI_STATE_S3:
    387 
    388         SstValue = ACPI_SST_SLEEPING;
    389         break;
    390 
    391     case ACPI_STATE_S4:
    392 
    393         SstValue = ACPI_SST_SLEEP_CONTEXT;
    394         break;
    395 
    396     default:
    397 
    398         SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */
    399         break;
    400     }
    401 
    402     /*
    403      * Set the system indicators to show the desired sleep state.
    404      * _SST is an optional method (return no error if not found)
    405      */
    406     AcpiHwExecuteSleepMethod (__UNCONST(METHOD_PATHNAME__SST), SstValue);
    407     return_ACPI_STATUS (AE_OK);
    408 }
    409 
    410 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep)
    411 
    412 
    413 /*******************************************************************************
    414  *
    415  * FUNCTION:    AcpiEnterSleepState
    416  *
    417  * PARAMETERS:  SleepState          - Which sleep state to enter
    418  *
    419  * RETURN:      Status
    420  *
    421  * DESCRIPTION: Enter a system sleep state
    422  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
    423  *
    424  ******************************************************************************/
    425 
    426 ACPI_STATUS
    427 AcpiEnterSleepState (
    428     UINT8                   SleepState)
    429 {
    430     ACPI_STATUS             Status;
    431 
    432 
    433     ACPI_FUNCTION_TRACE (AcpiEnterSleepState);
    434 
    435 
    436     if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) ||
    437         (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX))
    438     {
    439         ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
    440             AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB));
    441         return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
    442     }
    443 
    444     Status = AcpiHwSleepDispatch (SleepState, ACPI_SLEEP_FUNCTION_ID);
    445     return_ACPI_STATUS (Status);
    446 }
    447 
    448 ACPI_EXPORT_SYMBOL (AcpiEnterSleepState)
    449 
    450 
    451 /*******************************************************************************
    452  *
    453  * FUNCTION:    AcpiLeaveSleepStatePrep
    454  *
    455  * PARAMETERS:  SleepState          - Which sleep state we are exiting
    456  *
    457  * RETURN:      Status
    458  *
    459  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
    460  *              sleep. Called with interrupts DISABLED.
    461  *              We break wake/resume into 2 stages so that OSPM can handle
    462  *              various OS-specific tasks between the two steps.
    463  *
    464  ******************************************************************************/
    465 
    466 ACPI_STATUS
    467 AcpiLeaveSleepStatePrep (
    468     UINT8                   SleepState)
    469 {
    470     ACPI_STATUS             Status;
    471 
    472 
    473     ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep);
    474 
    475 
    476     Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_PREP_FUNCTION_ID);
    477     return_ACPI_STATUS (Status);
    478 }
    479 
    480 ACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep)
    481 
    482 
    483 /*******************************************************************************
    484  *
    485  * FUNCTION:    AcpiLeaveSleepState
    486  *
    487  * PARAMETERS:  SleepState          - Which sleep state we are exiting
    488  *
    489  * RETURN:      Status
    490  *
    491  * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
    492  *              Called with interrupts ENABLED.
    493  *
    494  ******************************************************************************/
    495 
    496 ACPI_STATUS
    497 AcpiLeaveSleepState (
    498     UINT8                   SleepState)
    499 {
    500     ACPI_STATUS             Status;
    501 
    502 
    503     ACPI_FUNCTION_TRACE (AcpiLeaveSleepState);
    504 
    505 
    506     Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_FUNCTION_ID);
    507     return_ACPI_STATUS (Status);
    508 }
    509 
    510 ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState)
    511