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