1 /****************************************************************************** 2 * 3 * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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)