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