Home | History | Annotate | Line # | Download | only in hardware
hwxfsleep.c revision 1.5
      1 /******************************************************************************
      2  *
      3  * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2015, 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  *                                    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  *                                    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 Hardware Reduced flag is set, there is no FACS */
    173 
    174     if (AcpiGbl_ReducedHardware)
    175     {
    176         return_ACPI_STATUS (AE_OK);
    177     }
    178 
    179     if (AcpiGbl_Facs32)
    180     {
    181         (void) AcpiHwSetFirmwareWakingVector (AcpiGbl_Facs32,
    182                     PhysicalAddress, PhysicalAddress64);
    183     }
    184     if (AcpiGbl_Facs64)
    185     {
    186         (void) AcpiHwSetFirmwareWakingVector (AcpiGbl_Facs64,
    187                     PhysicalAddress, PhysicalAddress64);
    188     }
    189 
    190     return_ACPI_STATUS (AE_OK);
    191 }
    192 
    193 ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)
    194 
    195 
    196 /*******************************************************************************
    197  *
    198  * FUNCTION:    AcpiEnterSleepStateS4bios
    199  *
    200  * PARAMETERS:  None
    201  *
    202  * RETURN:      Status
    203  *
    204  * DESCRIPTION: Perform a S4 bios request.
    205  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
    206  *
    207  ******************************************************************************/
    208 
    209 ACPI_STATUS
    210 AcpiEnterSleepStateS4bios (
    211     void)
    212 {
    213     UINT32                  InValue;
    214     ACPI_STATUS             Status;
    215 
    216 
    217     ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios);
    218 
    219 
    220     /* Clear the wake status bit (PM1) */
    221 
    222     Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
    223     if (ACPI_FAILURE (Status))
    224     {
    225         return_ACPI_STATUS (Status);
    226     }
    227 
    228     Status = AcpiHwClearAcpiStatus ();
    229     if (ACPI_FAILURE (Status))
    230     {
    231         return_ACPI_STATUS (Status);
    232     }
    233 
    234     /*
    235      * 1) Disable/Clear all GPEs
    236      * 2) Enable all wakeup GPEs
    237      */
    238     Status = AcpiHwDisableAllGpes ();
    239     if (ACPI_FAILURE (Status))
    240     {
    241         return_ACPI_STATUS (Status);
    242     }
    243     AcpiGbl_SystemAwakeAndRunning = FALSE;
    244 
    245     Status = AcpiHwEnableAllWakeupGpes ();
    246     if (ACPI_FAILURE (Status))
    247     {
    248         return_ACPI_STATUS (Status);
    249     }
    250 
    251     ACPI_FLUSH_CPU_CACHE ();
    252 
    253     Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand,
    254                 (UINT32) AcpiGbl_FADT.S4BiosRequest, 8);
    255 
    256     do {
    257         AcpiOsStall (ACPI_USEC_PER_MSEC);
    258         Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
    259         if (ACPI_FAILURE (Status))
    260         {
    261             return_ACPI_STATUS (Status);
    262         }
    263     } while (!InValue);
    264 
    265     return_ACPI_STATUS (AE_OK);
    266 }
    267 
    268 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios)
    269 
    270 #endif /* !ACPI_REDUCED_HARDWARE */
    271 
    272 
    273 /*******************************************************************************
    274  *
    275  * FUNCTION:    AcpiHwSleepDispatch
    276  *
    277  * PARAMETERS:  SleepState          - Which sleep state to enter/exit
    278  *              FunctionId          - Sleep, WakePrep, or Wake
    279  *
    280  * RETURN:      Status from the invoked sleep handling function.
    281  *
    282  * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling
    283  *              function.
    284  *
    285  ******************************************************************************/
    286 
    287 static ACPI_STATUS
    288 AcpiHwSleepDispatch (
    289     UINT8                   SleepState,
    290     UINT32                  FunctionId)
    291 {
    292     ACPI_STATUS             Status;
    293     ACPI_SLEEP_FUNCTIONS    *SleepFunctions = &AcpiSleepDispatch[FunctionId];
    294 
    295 
    296 #if (!ACPI_REDUCED_HARDWARE)
    297     /*
    298      * If the Hardware Reduced flag is set (from the FADT), we must
    299      * use the extended sleep registers (FADT). Note: As per the ACPI
    300      * specification, these extended registers are to be used for HW-reduced
    301      * platforms only. They are not general-purpose replacements for the
    302      * legacy PM register sleep support.
    303      */
    304     if (AcpiGbl_ReducedHardware)
    305     {
    306         Status = SleepFunctions->ExtendedFunction (SleepState);
    307     }
    308     else
    309     {
    310         /* Legacy sleep */
    311 
    312         Status = SleepFunctions->LegacyFunction (SleepState);
    313     }
    314 
    315     return (Status);
    316 
    317 #else
    318     /*
    319      * For the case where reduced-hardware-only code is being generated,
    320      * we know that only the extended sleep registers are available
    321      */
    322     Status = SleepFunctions->ExtendedFunction (SleepState);
    323     return (Status);
    324 
    325 #endif /* !ACPI_REDUCED_HARDWARE */
    326 }
    327 
    328 
    329 /*******************************************************************************
    330  *
    331  * FUNCTION:    AcpiEnterSleepStatePrep
    332  *
    333  * PARAMETERS:  SleepState          - Which sleep state to enter
    334  *
    335  * RETURN:      Status
    336  *
    337  * DESCRIPTION: Prepare to enter a system sleep state.
    338  *              This function must execute with interrupts enabled.
    339  *              We break sleeping into 2 stages so that OSPM can handle
    340  *              various OS-specific tasks between the two steps.
    341  *
    342  ******************************************************************************/
    343 
    344 ACPI_STATUS
    345 AcpiEnterSleepStatePrep (
    346     UINT8                   SleepState)
    347 {
    348     ACPI_STATUS             Status;
    349     ACPI_OBJECT_LIST        ArgList;
    350     ACPI_OBJECT             Arg;
    351     UINT32                  SstValue;
    352 
    353 
    354     ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep);
    355 
    356 
    357     Status = AcpiGetSleepTypeData (SleepState,
    358                     &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
    359     if (ACPI_FAILURE (Status))
    360     {
    361         return_ACPI_STATUS (Status);
    362     }
    363 
    364     /* Execute the _PTS method (Prepare To Sleep) */
    365 
    366     ArgList.Count = 1;
    367     ArgList.Pointer = &Arg;
    368     Arg.Type = ACPI_TYPE_INTEGER;
    369     Arg.Integer.Value = SleepState;
    370 
    371     Status = AcpiEvaluateObject (NULL, METHOD_PATHNAME__PTS, &ArgList, NULL);
    372     if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
    373     {
    374         return_ACPI_STATUS (Status);
    375     }
    376 
    377     /* Setup the argument to the _SST method (System STatus) */
    378 
    379     switch (SleepState)
    380     {
    381     case ACPI_STATE_S0:
    382 
    383         SstValue = ACPI_SST_WORKING;
    384         break;
    385 
    386     case ACPI_STATE_S1:
    387     case ACPI_STATE_S2:
    388     case ACPI_STATE_S3:
    389 
    390         SstValue = ACPI_SST_SLEEPING;
    391         break;
    392 
    393     case ACPI_STATE_S4:
    394 
    395         SstValue = ACPI_SST_SLEEP_CONTEXT;
    396         break;
    397 
    398     default:
    399 
    400         SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */
    401         break;
    402     }
    403 
    404     /*
    405      * Set the system indicators to show the desired sleep state.
    406      * _SST is an optional method (return no error if not found)
    407      */
    408     AcpiHwExecuteSleepMethod (__UNCONST(METHOD_PATHNAME__SST), SstValue);
    409     return_ACPI_STATUS (AE_OK);
    410 }
    411 
    412 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep)
    413 
    414 
    415 /*******************************************************************************
    416  *
    417  * FUNCTION:    AcpiEnterSleepState
    418  *
    419  * PARAMETERS:  SleepState          - Which sleep state to enter
    420  *
    421  * RETURN:      Status
    422  *
    423  * DESCRIPTION: Enter a system sleep state
    424  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
    425  *
    426  ******************************************************************************/
    427 
    428 ACPI_STATUS
    429 AcpiEnterSleepState (
    430     UINT8                   SleepState)
    431 {
    432     ACPI_STATUS             Status;
    433 
    434 
    435     ACPI_FUNCTION_TRACE (AcpiEnterSleepState);
    436 
    437 
    438     if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) ||
    439         (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX))
    440     {
    441         ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
    442             AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB));
    443         return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
    444     }
    445 
    446     Status = AcpiHwSleepDispatch (SleepState, ACPI_SLEEP_FUNCTION_ID);
    447     return_ACPI_STATUS (Status);
    448 }
    449 
    450 ACPI_EXPORT_SYMBOL (AcpiEnterSleepState)
    451 
    452 
    453 /*******************************************************************************
    454  *
    455  * FUNCTION:    AcpiLeaveSleepStatePrep
    456  *
    457  * PARAMETERS:  SleepState          - Which sleep state we are exiting
    458  *
    459  * RETURN:      Status
    460  *
    461  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
    462  *              sleep. Called with interrupts DISABLED.
    463  *              We break wake/resume into 2 stages so that OSPM can handle
    464  *              various OS-specific tasks between the two steps.
    465  *
    466  ******************************************************************************/
    467 
    468 ACPI_STATUS
    469 AcpiLeaveSleepStatePrep (
    470     UINT8                   SleepState)
    471 {
    472     ACPI_STATUS             Status;
    473 
    474 
    475     ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep);
    476 
    477 
    478     Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_PREP_FUNCTION_ID);
    479     return_ACPI_STATUS (Status);
    480 }
    481 
    482 ACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep)
    483 
    484 
    485 /*******************************************************************************
    486  *
    487  * FUNCTION:    AcpiLeaveSleepState
    488  *
    489  * PARAMETERS:  SleepState          - Which sleep state we are exiting
    490  *
    491  * RETURN:      Status
    492  *
    493  * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
    494  *              Called with interrupts ENABLED.
    495  *
    496  ******************************************************************************/
    497 
    498 ACPI_STATUS
    499 AcpiLeaveSleepState (
    500     UINT8                   SleepState)
    501 {
    502     ACPI_STATUS             Status;
    503 
    504 
    505     ACPI_FUNCTION_TRACE (AcpiLeaveSleepState);
    506 
    507 
    508     Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_FUNCTION_ID);
    509     return_ACPI_STATUS (Status);
    510 }
    511 
    512 ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState)
    513