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