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