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