1 /****************************************************************************** 2 * 3 * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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 #include <acpi/acpi.h> 45 #include "accommon.h" 46 #include <linux/module.h> 47 48 #define _COMPONENT ACPI_HARDWARE 49 ACPI_MODULE_NAME("hwxfsleep") 50 51 /* Local prototypes */ 52 static acpi_status 53 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 65 static 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 94 acpi_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 120 ACPI_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 ******************************************************************************/ 137 acpi_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 155 ACPI_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 ******************************************************************************/ 170 acpi_status asmlinkage 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(1000); 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 222 ACPI_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 ******************************************************************************/ 237 static acpi_status 238 acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) 239 { 240 acpi_status status; 241 struct acpi_sleep_functions *sleep_functions = 242 &acpi_sleep_dispatch[function_id]; 243 244 #if (!ACPI_REDUCED_HARDWARE) 245 246 /* 247 * If the Hardware Reduced flag is set (from the FADT), we must 248 * use the extended sleep registers 249 */ 250 if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) { 251 status = sleep_functions->extended_function(sleep_state); 252 } else { 253 /* Legacy sleep */ 254 255 status = sleep_functions->legacy_function(sleep_state); 256 } 257 258 return (status); 259 260 #else 261 /* 262 * For the case where reduced-hardware-only code is being generated, 263 * we know that only the extended sleep registers are available 264 */ 265 status = sleep_functions->extended_function(sleep_state); 266 return (status); 267 268 #endif /* !ACPI_REDUCED_HARDWARE */ 269 } 270 271 /******************************************************************************* 272 * 273 * FUNCTION: acpi_enter_sleep_state_prep 274 * 275 * PARAMETERS: sleep_state - Which sleep state to enter 276 * 277 * RETURN: Status 278 * 279 * DESCRIPTION: Prepare to enter a system sleep state. 280 * This function must execute with interrupts enabled. 281 * We break sleeping into 2 stages so that OSPM can handle 282 * various OS-specific tasks between the two steps. 283 * 284 ******************************************************************************/ 285 286 acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) 287 { 288 acpi_status status; 289 struct acpi_object_list arg_list; 290 union acpi_object arg; 291 u32 sst_value; 292 293 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep); 294 295 status = acpi_get_sleep_type_data(sleep_state, 296 &acpi_gbl_sleep_type_a, 297 &acpi_gbl_sleep_type_b); 298 if (ACPI_FAILURE(status)) { 299 return_ACPI_STATUS(status); 300 } 301 302 /* Execute the _PTS method (Prepare To Sleep) */ 303 304 arg_list.count = 1; 305 arg_list.pointer = &arg; 306 arg.type = ACPI_TYPE_INTEGER; 307 arg.integer.value = sleep_state; 308 309 status = 310 acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL); 311 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 312 return_ACPI_STATUS(status); 313 } 314 315 /* Setup the argument to the _SST method (System STatus) */ 316 317 switch (sleep_state) { 318 case ACPI_STATE_S0: 319 sst_value = ACPI_SST_WORKING; 320 break; 321 322 case ACPI_STATE_S1: 323 case ACPI_STATE_S2: 324 case ACPI_STATE_S3: 325 sst_value = ACPI_SST_SLEEPING; 326 break; 327 328 case ACPI_STATE_S4: 329 sst_value = ACPI_SST_SLEEP_CONTEXT; 330 break; 331 332 default: 333 sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */ 334 break; 335 } 336 337 /* 338 * Set the system indicators to show the desired sleep state. 339 * _SST is an optional method (return no error if not found) 340 */ 341 acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value); 342 return_ACPI_STATUS(AE_OK); 343 } 344 345 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) 346 347 /******************************************************************************* 348 * 349 * FUNCTION: acpi_enter_sleep_state 350 * 351 * PARAMETERS: sleep_state - Which sleep state to enter 352 * 353 * RETURN: Status 354 * 355 * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231) 356 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 357 * 358 ******************************************************************************/ 359 acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) 360 { 361 acpi_status status; 362 363 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); 364 365 if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || 366 (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { 367 ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", 368 acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b)); 369 return_ACPI_STATUS(AE_AML_OPERAND_VALUE); 370 } 371 372 status = 373 acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); 374 return_ACPI_STATUS(status); 375 } 376 377 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) 378 379 /******************************************************************************* 380 * 381 * FUNCTION: acpi_leave_sleep_state_prep 382 * 383 * PARAMETERS: sleep_state - Which sleep state we are exiting 384 * flags - ACPI_EXECUTE_BFS to run optional method 385 * 386 * RETURN: Status 387 * 388 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 389 * sleep. 390 * Called with interrupts DISABLED. 391 * 392 ******************************************************************************/ 393 acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) 394 { 395 acpi_status status; 396 397 ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); 398 399 status = 400 acpi_hw_sleep_dispatch(sleep_state, 401 ACPI_WAKE_PREP_FUNCTION_ID); 402 return_ACPI_STATUS(status); 403 } 404 405 ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep) 406 407 /******************************************************************************* 408 * 409 * FUNCTION: acpi_leave_sleep_state 410 * 411 * PARAMETERS: sleep_state - Which sleep state we are exiting 412 * 413 * RETURN: Status 414 * 415 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 416 * Called with interrupts ENABLED. 417 * 418 ******************************************************************************/ 419 acpi_status acpi_leave_sleep_state(u8 sleep_state) 420 { 421 acpi_status status; 422 423 ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); 424 425 status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID); 426 return_ACPI_STATUS(status); 427 } 428 429 ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state) 430