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/acpi.h> 47#include "accommon.h" 48 49#define _COMPONENT ACPI_HARDWARE 50ACPI_MODULE_NAME("hwxfsleep") 51 52/* Local prototypes */ 53#if (!ACPI_REDUCED_HARDWARE) 54static acpi_status 55acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, 56 acpi_physical_address physical_address, 57 acpi_physical_address physical_address64); 58#endif 59 60static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); 61 62/* 63 * Dispatch table used to efficiently branch to the various sleep 64 * functions. 65 */ 66#define ACPI_SLEEP_FUNCTION_ID 0 67#define ACPI_WAKE_PREP_FUNCTION_ID 1 68#define ACPI_WAKE_FUNCTION_ID 2 69 70/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ 71 72static struct acpi_sleep_functions acpi_sleep_dispatch[] = { 73 {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep), 74 acpi_hw_extended_sleep}, 75 {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep), 76 acpi_hw_extended_wake_prep}, 77 {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), acpi_hw_extended_wake} 78}; 79 80/* 81 * These functions are removed for the ACPI_REDUCED_HARDWARE case: 82 * acpi_set_firmware_waking_vectors 83 * acpi_set_firmware_waking_vector 84 * acpi_set_firmware_waking_vector64 85 * acpi_enter_sleep_state_s4bios 86 */ 87 88#if (!ACPI_REDUCED_HARDWARE) 89/******************************************************************************* 90 * 91 * FUNCTION: acpi_hw_set_firmware_waking_vectors 92 * 93 * PARAMETERS: facs - Pointer to FACS table 94 * physical_address - 32-bit physical address of ACPI real mode 95 * entry point. 96 * physical_address64 - 64-bit physical address of ACPI protected 97 * mode entry point. 98 * 99 * RETURN: Status 100 * 101 * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS 102 * 103 ******************************************************************************/ 104 105static acpi_status 106acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, 107 acpi_physical_address physical_address, 108 acpi_physical_address physical_address64) 109{ 110 ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vectors); 111 112 113 /* 114 * According to the ACPI specification 2.0c and later, the 64-bit 115 * waking vector should be cleared and the 32-bit waking vector should 116 * be used, unless we want the wake-up code to be called by the BIOS in 117 * Protected Mode. Some systems (for example HP dv5-1004nr) are known 118 * to fail to resume if the 64-bit vector is used. 119 */ 120 121 /* Set the 32-bit vector */ 122 123 facs->firmware_waking_vector = (u32)physical_address; 124 125 if (facs->length > 32) { 126 if (facs->version >= 1) { 127 128 /* Set the 64-bit vector */ 129 130 facs->xfirmware_waking_vector = physical_address64; 131 } else { 132 /* Clear the 64-bit vector if it exists */ 133 134 facs->xfirmware_waking_vector = 0; 135 } 136 } 137 138 return_ACPI_STATUS(AE_OK); 139} 140 141/******************************************************************************* 142 * 143 * FUNCTION: acpi_set_firmware_waking_vectors 144 * 145 * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode 146 * entry point. 147 * physical_address64 - 64-bit physical address of ACPI protected 148 * mode entry point. 149 * 150 * RETURN: Status 151 * 152 * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS 153 * 154 ******************************************************************************/ 155 156acpi_status 157acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, 158 acpi_physical_address physical_address64) 159{ 160 161 ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); 162 163 if (acpi_gbl_FACS) { 164 (void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_FACS, 165 physical_address, 166 physical_address64); 167 } 168 169 return_ACPI_STATUS(AE_OK); 170} 171 172ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vectors) 173 174/******************************************************************************* 175 * 176 * FUNCTION: acpi_set_firmware_waking_vector 177 * 178 * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode 179 * entry point. 180 * 181 * RETURN: Status 182 * 183 * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS 184 * 185 ******************************************************************************/ 186acpi_status acpi_set_firmware_waking_vector(u32 physical_address) 187{ 188 acpi_status status; 189 190 ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); 191 192 status = acpi_set_firmware_waking_vectors((acpi_physical_address) 193 physical_address, 0); 194 195 return_ACPI_STATUS(status); 196} 197 198ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) 199 200#if ACPI_MACHINE_WIDTH == 64 201/******************************************************************************* 202 * 203 * FUNCTION: acpi_set_firmware_waking_vector64 204 * 205 * PARAMETERS: physical_address - 64-bit physical address of ACPI protected 206 * mode entry point. 207 * 208 * RETURN: Status 209 * 210 * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if 211 * it exists in the table. This function is intended for use with 212 * 64-bit host operating systems. 213 * 214 ******************************************************************************/ 215acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) 216{ 217 acpi_status status; 218 219 ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); 220 221 status = acpi_set_firmware_waking_vectors(0, 222 (acpi_physical_address) 223 physical_address); 224 225 return_ACPI_STATUS(status); 226} 227 228ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) 229#endif 230/******************************************************************************* 231 * 232 * FUNCTION: acpi_enter_sleep_state_s4bios 233 * 234 * PARAMETERS: None 235 * 236 * RETURN: Status 237 * 238 * DESCRIPTION: Perform a S4 bios request. 239 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 240 * 241 ******************************************************************************/ 242acpi_status acpi_enter_sleep_state_s4bios(void) 243{ 244 u32 in_value; 245 acpi_status status; 246 247 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); 248 249 /* Clear the wake status bit (PM1) */ 250 251 status = 252 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 253 if (ACPI_FAILURE(status)) { 254 return_ACPI_STATUS(status); 255 } 256 257 status = acpi_hw_clear_acpi_status(); 258 if (ACPI_FAILURE(status)) { 259 return_ACPI_STATUS(status); 260 } 261 262 /* 263 * 1) Disable/Clear all GPEs 264 * 2) Enable all wakeup GPEs 265 */ 266 status = acpi_hw_disable_all_gpes(); 267 if (ACPI_FAILURE(status)) { 268 return_ACPI_STATUS(status); 269 } 270 acpi_gbl_system_awake_and_running = FALSE; 271 272 status = acpi_hw_enable_all_wakeup_gpes(); 273 if (ACPI_FAILURE(status)) { 274 return_ACPI_STATUS(status); 275 } 276 277 ACPI_FLUSH_CPU_CACHE(); 278 279 status = acpi_hw_write_port(acpi_gbl_FADT.smi_command, 280 (u32)acpi_gbl_FADT.s4_bios_request, 8); 281 282 do { 283 acpi_os_stall(ACPI_USEC_PER_MSEC); 284 status = 285 acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); 286 if (ACPI_FAILURE(status)) { 287 return_ACPI_STATUS(status); 288 } 289 } while (!in_value); 290 291 return_ACPI_STATUS(AE_OK); 292} 293 294ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) 295#endif /* !ACPI_REDUCED_HARDWARE */ 296/******************************************************************************* 297 * 298 * FUNCTION: acpi_hw_sleep_dispatch 299 * 300 * PARAMETERS: sleep_state - Which sleep state to enter/exit 301 * function_id - Sleep, wake_prep, or Wake 302 * 303 * RETURN: Status from the invoked sleep handling function. 304 * 305 * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling 306 * function. 307 * 308 ******************************************************************************/ 309static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) 310{ 311 acpi_status status; 312 struct acpi_sleep_functions *sleep_functions = 313 &acpi_sleep_dispatch[function_id]; 314 315#if (!ACPI_REDUCED_HARDWARE) 316 /* 317 * If the Hardware Reduced flag is set (from the FADT), we must 318 * use the extended sleep registers (FADT). Note: As per the ACPI 319 * specification, these extended registers are to be used for HW-reduced 320 * platforms only. They are not general-purpose replacements for the 321 * legacy PM register sleep support. 322 */ 323 if (acpi_gbl_reduced_hardware) { 324 status = sleep_functions->extended_function(sleep_state); 325 } else { 326 /* Legacy sleep */ 327 328 status = sleep_functions->legacy_function(sleep_state); 329 } 330 331 return (status); 332 333#else 334 /* 335 * For the case where reduced-hardware-only code is being generated, 336 * we know that only the extended sleep registers are available 337 */ 338 status = sleep_functions->extended_function(sleep_state); 339 return (status); 340 341#endif /* !ACPI_REDUCED_HARDWARE */ 342} 343 344/******************************************************************************* 345 * 346 * FUNCTION: acpi_enter_sleep_state_prep 347 * 348 * PARAMETERS: sleep_state - Which sleep state to enter 349 * 350 * RETURN: Status 351 * 352 * DESCRIPTION: Prepare to enter a system sleep state. 353 * This function must execute with interrupts enabled. 354 * We break sleeping into 2 stages so that OSPM can handle 355 * various OS-specific tasks between the two steps. 356 * 357 ******************************************************************************/ 358 359acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) 360{ 361 acpi_status status; 362 struct acpi_object_list arg_list; 363 union acpi_object arg; 364 u32 sst_value; 365 366 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep); 367 368 status = acpi_get_sleep_type_data(sleep_state, 369 &acpi_gbl_sleep_type_a, 370 &acpi_gbl_sleep_type_b); 371 if (ACPI_FAILURE(status)) { 372 return_ACPI_STATUS(status); 373 } 374 375 /* Execute the _PTS method (Prepare To Sleep) */ 376 377 arg_list.count = 1; 378 arg_list.pointer = &arg; 379 arg.type = ACPI_TYPE_INTEGER; 380 arg.integer.value = sleep_state; 381 382 status = 383 acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL); 384 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 385 return_ACPI_STATUS(status); 386 } 387 388 /* Setup the argument to the _SST method (System STatus) */ 389 390 switch (sleep_state) { 391 case ACPI_STATE_S0: 392 393 sst_value = ACPI_SST_WORKING; 394 break; 395 396 case ACPI_STATE_S1: 397 case ACPI_STATE_S2: 398 case ACPI_STATE_S3: 399 400 sst_value = ACPI_SST_SLEEPING; 401 break; 402 403 case ACPI_STATE_S4: 404 405 sst_value = ACPI_SST_SLEEP_CONTEXT; 406 break; 407 408 default: 409 410 sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */ 411 break; 412 } 413 414 /* 415 * Set the system indicators to show the desired sleep state. 416 * _SST is an optional method (return no error if not found) 417 */ 418 acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value); 419 return_ACPI_STATUS(AE_OK); 420} 421 422ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) 423 424/******************************************************************************* 425 * 426 * FUNCTION: acpi_enter_sleep_state 427 * 428 * PARAMETERS: sleep_state - Which sleep state to enter 429 * 430 * RETURN: Status 431 * 432 * DESCRIPTION: Enter a system sleep state 433 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 434 * 435 ******************************************************************************/ 436acpi_status acpi_enter_sleep_state(u8 sleep_state) 437{ 438 acpi_status status; 439 440 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); 441 442 if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || 443 (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { 444 ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", 445 acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b)); 446 return_ACPI_STATUS(AE_AML_OPERAND_VALUE); 447 } 448 449 status = acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); 450 return_ACPI_STATUS(status); 451} 452 453ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) 454 455/******************************************************************************* 456 * 457 * FUNCTION: acpi_leave_sleep_state_prep 458 * 459 * PARAMETERS: sleep_state - Which sleep state we are exiting 460 * 461 * RETURN: Status 462 * 463 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 464 * sleep. Called with interrupts DISABLED. 465 * We break wake/resume into 2 stages so that OSPM can handle 466 * various OS-specific tasks between the two steps. 467 * 468 ******************************************************************************/ 469acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) 470{ 471 acpi_status status; 472 473 ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); 474 475 status = 476 acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_PREP_FUNCTION_ID); 477 return_ACPI_STATUS(status); 478} 479 480ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep) 481 482/******************************************************************************* 483 * 484 * FUNCTION: acpi_leave_sleep_state 485 * 486 * PARAMETERS: sleep_state - Which sleep state we are exiting 487 * 488 * RETURN: Status 489 * 490 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 491 * Called with interrupts ENABLED. 492 * 493 ******************************************************************************/ 494acpi_status acpi_leave_sleep_state(u8 sleep_state) 495{ 496 acpi_status status; 497 498 ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); 499 500 status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID); 501 return_ACPI_STATUS(status); 502} 503 504ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state) 505