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