hwsleep.c revision 229989
1 2/****************************************************************************** 3 * 4 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface 5 * 6 *****************************************************************************/ 7 8/* 9 * Copyright (C) 2000 - 2012, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45#include <contrib/dev/acpica/include/acpi.h> 46#include <contrib/dev/acpica/include/accommon.h> 47 48#define _COMPONENT ACPI_HARDWARE 49 ACPI_MODULE_NAME ("hwsleep") 50 51 52/******************************************************************************* 53 * 54 * FUNCTION: AcpiSetFirmwareWakingVector 55 * 56 * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode 57 * entry point. 58 * 59 * RETURN: Status 60 * 61 * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS 62 * 63 ******************************************************************************/ 64 65ACPI_STATUS 66AcpiSetFirmwareWakingVector ( 67 UINT32 PhysicalAddress) 68{ 69 ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector); 70 71 72 /* Set the 32-bit vector */ 73 74 AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress; 75 76 /* Clear the 64-bit vector if it exists */ 77 78 if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1)) 79 { 80 AcpiGbl_FACS->XFirmwareWakingVector = 0; 81 } 82 83 return_ACPI_STATUS (AE_OK); 84} 85 86ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector) 87 88 89#if ACPI_MACHINE_WIDTH == 64 90/******************************************************************************* 91 * 92 * FUNCTION: AcpiSetFirmwareWakingVector64 93 * 94 * PARAMETERS: PhysicalAddress - 64-bit physical address of ACPI protected 95 * mode entry point. 96 * 97 * RETURN: Status 98 * 99 * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if 100 * it exists in the table. This function is intended for use with 101 * 64-bit host operating systems. 102 * 103 ******************************************************************************/ 104 105ACPI_STATUS 106AcpiSetFirmwareWakingVector64 ( 107 UINT64 PhysicalAddress) 108{ 109 ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64); 110 111 112 /* Determine if the 64-bit vector actually exists */ 113 114 if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1)) 115 { 116 return_ACPI_STATUS (AE_NOT_EXIST); 117 } 118 119 /* Clear 32-bit vector, set the 64-bit X_ vector */ 120 121 AcpiGbl_FACS->FirmwareWakingVector = 0; 122 AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress; 123 return_ACPI_STATUS (AE_OK); 124} 125 126ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64) 127#endif 128 129/******************************************************************************* 130 * 131 * FUNCTION: AcpiEnterSleepStatePrep 132 * 133 * PARAMETERS: SleepState - Which sleep state to enter 134 * 135 * RETURN: Status 136 * 137 * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231) 138 * This function must execute with interrupts enabled. 139 * We break sleeping into 2 stages so that OSPM can handle 140 * various OS-specific tasks between the two steps. 141 * 142 ******************************************************************************/ 143 144ACPI_STATUS 145AcpiEnterSleepStatePrep ( 146 UINT8 SleepState) 147{ 148 ACPI_STATUS Status; 149 ACPI_OBJECT_LIST ArgList; 150 ACPI_OBJECT Arg; 151 152 153 ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep); 154 155 156 /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */ 157 158 Status = AcpiGetSleepTypeData (SleepState, 159 &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 160 if (ACPI_FAILURE (Status)) 161 { 162 return_ACPI_STATUS (Status); 163 } 164 165 /* Execute the _PTS method (Prepare To Sleep) */ 166 167 ArgList.Count = 1; 168 ArgList.Pointer = &Arg; 169 Arg.Type = ACPI_TYPE_INTEGER; 170 Arg.Integer.Value = SleepState; 171 172 Status = AcpiEvaluateObject (NULL, METHOD_NAME__PTS, &ArgList, NULL); 173 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 174 { 175 return_ACPI_STATUS (Status); 176 } 177 178 /* Setup the argument to the _SST method (System STatus) */ 179 180 switch (SleepState) 181 { 182 case ACPI_STATE_S0: 183 Arg.Integer.Value = ACPI_SST_WORKING; 184 break; 185 186 case ACPI_STATE_S1: 187 case ACPI_STATE_S2: 188 case ACPI_STATE_S3: 189 Arg.Integer.Value = ACPI_SST_SLEEPING; 190 break; 191 192 case ACPI_STATE_S4: 193 Arg.Integer.Value = ACPI_SST_SLEEP_CONTEXT; 194 break; 195 196 default: 197 Arg.Integer.Value = ACPI_SST_INDICATOR_OFF; /* Default is off */ 198 break; 199 } 200 201 /* 202 * Set the system indicators to show the desired sleep state. 203 * _SST is an optional method (return no error if not found) 204 */ 205 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 206 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 207 { 208 ACPI_EXCEPTION ((AE_INFO, Status, "While executing method _SST")); 209 } 210 211 return_ACPI_STATUS (AE_OK); 212} 213 214ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep) 215 216 217/******************************************************************************* 218 * 219 * FUNCTION: AcpiEnterSleepState 220 * 221 * PARAMETERS: SleepState - Which sleep state to enter 222 * 223 * RETURN: Status 224 * 225 * DESCRIPTION: Enter a system sleep state 226 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 227 * 228 ******************************************************************************/ 229 230ACPI_STATUS 231AcpiEnterSleepState ( 232 UINT8 SleepState) 233{ 234 UINT32 Pm1aControl; 235 UINT32 Pm1bControl; 236 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 237 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 238 UINT32 InValue; 239 ACPI_OBJECT_LIST ArgList; 240 ACPI_OBJECT Arg; 241 UINT32 Retry; 242 ACPI_STATUS Status; 243 244 245 ACPI_FUNCTION_TRACE (AcpiEnterSleepState); 246 247 248 if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) || 249 (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX)) 250 { 251 ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", 252 AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB)); 253 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 254 } 255 256 SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 257 SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 258 259 /* Clear wake status */ 260 261 Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 262 if (ACPI_FAILURE (Status)) 263 { 264 return_ACPI_STATUS (Status); 265 } 266 267 /* Clear all fixed and general purpose status bits */ 268 269 Status = AcpiHwClearAcpiStatus (); 270 if (ACPI_FAILURE (Status)) 271 { 272 return_ACPI_STATUS (Status); 273 } 274 275 if (SleepState != ACPI_STATE_S5) 276 { 277 /* 278 * Disable BM arbitration. This feature is contained within an 279 * optional register (PM2 Control), so ignore a BAD_ADDRESS 280 * exception. 281 */ 282 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1); 283 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 284 { 285 return_ACPI_STATUS (Status); 286 } 287 } 288 289 /* 290 * 1) Disable/Clear all GPEs 291 * 2) Enable all wakeup GPEs 292 */ 293 Status = AcpiHwDisableAllGpes (); 294 if (ACPI_FAILURE (Status)) 295 { 296 return_ACPI_STATUS (Status); 297 } 298 AcpiGbl_SystemAwakeAndRunning = FALSE; 299 300 Status = AcpiHwEnableAllWakeupGpes (); 301 if (ACPI_FAILURE (Status)) 302 { 303 return_ACPI_STATUS (Status); 304 } 305 306 /* Execute the _GTS method (Going To Sleep) */ 307 308 ArgList.Count = 1; 309 ArgList.Pointer = &Arg; 310 Arg.Type = ACPI_TYPE_INTEGER; 311 Arg.Integer.Value = SleepState; 312 313 Status = AcpiEvaluateObject (NULL, METHOD_NAME__GTS, &ArgList, NULL); 314 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 315 { 316 return_ACPI_STATUS (Status); 317 } 318 319 /* Get current value of PM1A control */ 320 321 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 322 &Pm1aControl); 323 if (ACPI_FAILURE (Status)) 324 { 325 return_ACPI_STATUS (Status); 326 } 327 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 328 "Entering sleep state [S%u]\n", SleepState)); 329 330 /* Clear the SLP_EN and SLP_TYP fields */ 331 332 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 333 SleepEnableRegInfo->AccessBitMask); 334 Pm1bControl = Pm1aControl; 335 336 /* Insert the SLP_TYP bits */ 337 338 Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 339 Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 340 341 /* 342 * We split the writes of SLP_TYP and SLP_EN to workaround 343 * poorly implemented hardware. 344 */ 345 346 /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 347 348 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 349 if (ACPI_FAILURE (Status)) 350 { 351 return_ACPI_STATUS (Status); 352 } 353 354 /* Insert the sleep enable (SLP_EN) bit */ 355 356 Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 357 Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 358 359 /* Flush caches, as per ACPI specification */ 360 361 ACPI_FLUSH_CPU_CACHE (); 362 363 /* Write #2: Write both SLP_TYP + SLP_EN */ 364 365 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 366 if (ACPI_FAILURE (Status)) 367 { 368 return_ACPI_STATUS (Status); 369 } 370 371 if (SleepState > ACPI_STATE_S3) 372 { 373 /* 374 * We wanted to sleep > S3, but it didn't happen (by virtue of the 375 * fact that we are still executing!) 376 * 377 * Wait ten seconds, then try again. This is to get S4/S5 to work on 378 * all machines. 379 * 380 * We wait so long to allow chipsets that poll this reg very slowly 381 * to still read the right value. Ideally, this block would go 382 * away entirely. 383 */ 384 AcpiOsStall (10000000); 385 386 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 387 SleepEnableRegInfo->AccessBitMask); 388 if (ACPI_FAILURE (Status)) 389 { 390 return_ACPI_STATUS (Status); 391 } 392 } 393 394 /* Wait until we enter sleep state */ 395 396 Retry = 1000; 397 do 398 { 399 Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 400 if (ACPI_FAILURE (Status)) 401 { 402 return_ACPI_STATUS (Status); 403 } 404 405 if (AcpiGbl_EnableInterpreterSlack) 406 { 407 /* 408 * Some BIOSs don't set WAK_STS at all. Give up waiting after 409 * 1000 retries if it still isn't set. 410 */ 411 if (Retry-- == 0) 412 { 413 break; 414 } 415 } 416 417 /* Spin until we wake */ 418 419 } while (!InValue); 420 421 return_ACPI_STATUS (AE_OK); 422} 423 424ACPI_EXPORT_SYMBOL (AcpiEnterSleepState) 425 426 427/******************************************************************************* 428 * 429 * FUNCTION: AcpiEnterSleepStateS4bios 430 * 431 * PARAMETERS: None 432 * 433 * RETURN: Status 434 * 435 * DESCRIPTION: Perform a S4 bios request. 436 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 437 * 438 ******************************************************************************/ 439 440ACPI_STATUS 441AcpiEnterSleepStateS4bios ( 442 void) 443{ 444 UINT32 InValue; 445 ACPI_STATUS Status; 446 447 448 ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios); 449 450 451 /* Clear the wake status bit (PM1) */ 452 453 Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 454 if (ACPI_FAILURE (Status)) 455 { 456 return_ACPI_STATUS (Status); 457 } 458 459 Status = AcpiHwClearAcpiStatus (); 460 if (ACPI_FAILURE (Status)) 461 { 462 return_ACPI_STATUS (Status); 463 } 464 465 /* 466 * 1) Disable/Clear all GPEs 467 * 2) Enable all wakeup GPEs 468 */ 469 Status = AcpiHwDisableAllGpes (); 470 if (ACPI_FAILURE (Status)) 471 { 472 return_ACPI_STATUS (Status); 473 } 474 AcpiGbl_SystemAwakeAndRunning = FALSE; 475 476 Status = AcpiHwEnableAllWakeupGpes (); 477 if (ACPI_FAILURE (Status)) 478 { 479 return_ACPI_STATUS (Status); 480 } 481 482 ACPI_FLUSH_CPU_CACHE (); 483 484 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, 485 (UINT32) AcpiGbl_FADT.S4BiosRequest, 8); 486 487 do { 488 AcpiOsStall(1000); 489 Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 490 if (ACPI_FAILURE (Status)) 491 { 492 return_ACPI_STATUS (Status); 493 } 494 } while (!InValue); 495 496 return_ACPI_STATUS (AE_OK); 497} 498 499ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios) 500 501 502/******************************************************************************* 503 * 504 * FUNCTION: AcpiLeaveSleepState 505 * 506 * PARAMETERS: SleepState - Which sleep state we just exited 507 * 508 * RETURN: Status 509 * 510 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 511 * Called with interrupts ENABLED. 512 * 513 ******************************************************************************/ 514 515ACPI_STATUS 516AcpiLeaveSleepState ( 517 UINT8 SleepState) 518{ 519 ACPI_OBJECT_LIST ArgList; 520 ACPI_OBJECT Arg; 521 ACPI_STATUS Status; 522 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 523 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 524 UINT32 Pm1aControl; 525 UINT32 Pm1bControl; 526 527 528 ACPI_FUNCTION_TRACE (AcpiLeaveSleepState); 529 530 531 /* 532 * Set SLP_TYPE and SLP_EN to state S0. 533 * This is unclear from the ACPI Spec, but it is required 534 * by some machines. 535 */ 536 Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 537 &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 538 if (ACPI_SUCCESS (Status)) 539 { 540 SleepTypeRegInfo = 541 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 542 SleepEnableRegInfo = 543 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 544 545 /* Get current value of PM1A control */ 546 547 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 548 &Pm1aControl); 549 if (ACPI_SUCCESS (Status)) 550 { 551 /* Clear the SLP_EN and SLP_TYP fields */ 552 553 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 554 SleepEnableRegInfo->AccessBitMask); 555 Pm1bControl = Pm1aControl; 556 557 /* Insert the SLP_TYP bits */ 558 559 Pm1aControl |= (AcpiGbl_SleepTypeA << 560 SleepTypeRegInfo->BitPosition); 561 Pm1bControl |= (AcpiGbl_SleepTypeB << 562 SleepTypeRegInfo->BitPosition); 563 564 /* Write the control registers and ignore any errors */ 565 566 (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 567 } 568 } 569 570 /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 571 572 AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 573 574 /* Setup parameter object */ 575 576 ArgList.Count = 1; 577 ArgList.Pointer = &Arg; 578 Arg.Type = ACPI_TYPE_INTEGER; 579 580 /* Ignore any errors from these methods */ 581 582 Arg.Integer.Value = ACPI_SST_WAKING; 583 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 584 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 585 { 586 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST")); 587 } 588 589 Arg.Integer.Value = SleepState; 590 Status = AcpiEvaluateObject (NULL, METHOD_NAME__BFS, &ArgList, NULL); 591 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 592 { 593 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _BFS")); 594 } 595 596 Status = AcpiEvaluateObject (NULL, METHOD_NAME__WAK, &ArgList, NULL); 597 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 598 { 599 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _WAK")); 600 } 601 /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ 602 603 /* 604 * Restore the GPEs: 605 * 1) Disable/Clear all GPEs 606 * 2) Enable all runtime GPEs 607 */ 608 Status = AcpiHwDisableAllGpes (); 609 if (ACPI_FAILURE (Status)) 610 { 611 return_ACPI_STATUS (Status); 612 } 613 AcpiGbl_SystemAwakeAndRunning = TRUE; 614 615 Status = AcpiHwEnableAllRuntimeGpes (); 616 if (ACPI_FAILURE (Status)) 617 { 618 return_ACPI_STATUS (Status); 619 } 620 621 /* Enable power button */ 622 623 (void) AcpiWriteBitRegister( 624 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 625 ACPI_ENABLE_EVENT); 626 627 (void) AcpiWriteBitRegister( 628 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 629 ACPI_CLEAR_STATUS); 630 631 /* 632 * Enable BM arbitration. This feature is contained within an 633 * optional register (PM2 Control), so ignore a BAD_ADDRESS 634 * exception. 635 */ 636 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0); 637 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 638 { 639 return_ACPI_STATUS (Status); 640 } 641 642 Arg.Integer.Value = ACPI_SST_WORKING; 643 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 644 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 645 { 646 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST")); 647 } 648 649 return_ACPI_STATUS (Status); 650} 651 652ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState) 653 654