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