366 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#define EXPORT_ACPI_INTERFACES11 12#include <acpi/acpi.h>13#include "accommon.h"14 15#define _COMPONENT ACPI_HARDWARE16ACPI_MODULE_NAME("hwxfsleep")17 18/* Local prototypes */19static acpi_status20acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,21 acpi_physical_address physical_address,22 acpi_physical_address physical_address64);23 24/*******************************************************************************25 *26 * FUNCTION: acpi_hw_set_firmware_waking_vector27 *28 * PARAMETERS: facs - Pointer to FACS table29 * physical_address - 32-bit physical address of ACPI real mode30 * entry point31 * physical_address64 - 64-bit physical address of ACPI protected32 * mode entry point33 *34 * RETURN: Status35 *36 * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS37 *38 ******************************************************************************/39 40static acpi_status41acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,42 acpi_physical_address physical_address,43 acpi_physical_address physical_address64)44{45 ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vector);46 47 48 /*49 * According to the ACPI specification 2.0c and later, the 64-bit50 * waking vector should be cleared and the 32-bit waking vector should51 * be used, unless we want the wake-up code to be called by the BIOS in52 * Protected Mode. Some systems (for example HP dv5-1004nr) are known53 * to fail to resume if the 64-bit vector is used.54 */55 56 /* Set the 32-bit vector */57 58 facs->firmware_waking_vector = (u32)physical_address;59 60 if (facs->length > 32) {61 if (facs->version >= 1) {62 63 /* Set the 64-bit vector */64 65 facs->xfirmware_waking_vector = physical_address64;66 } else {67 /* Clear the 64-bit vector if it exists */68 69 facs->xfirmware_waking_vector = 0;70 }71 }72 73 return_ACPI_STATUS(AE_OK);74}75 76/*******************************************************************************77 *78 * FUNCTION: acpi_set_firmware_waking_vector79 *80 * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode81 * entry point82 * physical_address64 - 64-bit physical address of ACPI protected83 * mode entry point84 *85 * RETURN: Status86 *87 * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS88 *89 ******************************************************************************/90 91acpi_status92acpi_set_firmware_waking_vector(acpi_physical_address physical_address,93 acpi_physical_address physical_address64)94{95 96 ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);97 98 if (acpi_gbl_FACS) {99 (void)acpi_hw_set_firmware_waking_vector(acpi_gbl_FACS,100 physical_address,101 physical_address64);102 }103 104 return_ACPI_STATUS(AE_OK);105}106 107ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)108 109/*110 * These functions are removed for the ACPI_REDUCED_HARDWARE case:111 * acpi_enter_sleep_state_s4bios112 */113 114#if (!ACPI_REDUCED_HARDWARE)115/*******************************************************************************116 *117 * FUNCTION: acpi_enter_sleep_state_s4bios118 *119 * PARAMETERS: None120 *121 * RETURN: Status122 *123 * DESCRIPTION: Perform a S4 bios request.124 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED125 *126 ******************************************************************************/127acpi_status acpi_enter_sleep_state_s4bios(void)128{129 u32 in_value;130 acpi_status status;131 132 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);133 134 /* Clear the wake status bit (PM1) */135 136 status =137 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);138 if (ACPI_FAILURE(status)) {139 return_ACPI_STATUS(status);140 }141 142 status = acpi_hw_clear_acpi_status();143 if (ACPI_FAILURE(status)) {144 return_ACPI_STATUS(status);145 }146 147 /*148 * 1) Disable all GPEs149 * 2) Enable all wakeup GPEs150 */151 status = acpi_hw_disable_all_gpes();152 if (ACPI_FAILURE(status)) {153 return_ACPI_STATUS(status);154 }155 acpi_gbl_system_awake_and_running = FALSE;156 157 status = acpi_hw_enable_all_wakeup_gpes();158 if (ACPI_FAILURE(status)) {159 return_ACPI_STATUS(status);160 }161 162 status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,163 (u32)acpi_gbl_FADT.s4_bios_request, 8);164 if (ACPI_FAILURE(status)) {165 return_ACPI_STATUS(status);166 }167 168 do {169 acpi_os_stall(ACPI_USEC_PER_MSEC);170 status =171 acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);172 if (ACPI_FAILURE(status)) {173 return_ACPI_STATUS(status);174 }175 176 } while (!in_value);177 178 return_ACPI_STATUS(AE_OK);179}180 181ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)182#endif /* !ACPI_REDUCED_HARDWARE */183 184/*******************************************************************************185 *186 * FUNCTION: acpi_enter_sleep_state_prep187 *188 * PARAMETERS: sleep_state - Which sleep state to enter189 *190 * RETURN: Status191 *192 * DESCRIPTION: Prepare to enter a system sleep state.193 * This function must execute with interrupts enabled.194 * We break sleeping into 2 stages so that OSPM can handle195 * various OS-specific tasks between the two steps.196 *197 ******************************************************************************/198 199acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)200{201 acpi_status status;202 struct acpi_object_list arg_list;203 union acpi_object arg;204 u32 sst_value;205 206 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);207 208 status = acpi_get_sleep_type_data(sleep_state,209 &acpi_gbl_sleep_type_a,210 &acpi_gbl_sleep_type_b);211 if (ACPI_FAILURE(status)) {212 return_ACPI_STATUS(status);213 }214 215 status = acpi_get_sleep_type_data(ACPI_STATE_S0,216 &acpi_gbl_sleep_type_a_s0,217 &acpi_gbl_sleep_type_b_s0);218 if (ACPI_FAILURE(status)) {219 acpi_gbl_sleep_type_a_s0 = ACPI_SLEEP_TYPE_INVALID;220 }221 222 /* Execute the _PTS method (Prepare To Sleep) */223 224 arg_list.count = 1;225 arg_list.pointer = &arg;226 arg.type = ACPI_TYPE_INTEGER;227 arg.integer.value = sleep_state;228 229 status =230 acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL);231 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {232 return_ACPI_STATUS(status);233 }234 235 /* Setup the argument to the _SST method (System STatus) */236 237 switch (sleep_state) {238 case ACPI_STATE_S0:239 240 sst_value = ACPI_SST_WORKING;241 break;242 243 case ACPI_STATE_S1:244 case ACPI_STATE_S2:245 case ACPI_STATE_S3:246 247 sst_value = ACPI_SST_SLEEPING;248 break;249 250 case ACPI_STATE_S4:251 252 sst_value = ACPI_SST_SLEEP_CONTEXT;253 break;254 255 default:256 257 sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */258 break;259 }260 261 /*262 * Set the system indicators to show the desired sleep state.263 * _SST is an optional method (return no error if not found)264 */265 acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value);266 return_ACPI_STATUS(AE_OK);267}268 269ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)270 271/*******************************************************************************272 *273 * FUNCTION: acpi_enter_sleep_state274 *275 * PARAMETERS: sleep_state - Which sleep state to enter276 *277 * RETURN: Status278 *279 * DESCRIPTION: Enter a system sleep state280 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED281 *282 ******************************************************************************/283acpi_status acpi_enter_sleep_state(u8 sleep_state)284{285 acpi_status status;286 287 ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);288 289 if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||290 (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {291 ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",292 acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));293 return_ACPI_STATUS(AE_AML_OPERAND_VALUE);294 }295 296#if !ACPI_REDUCED_HARDWARE297 if (!acpi_gbl_reduced_hardware)298 status = acpi_hw_legacy_sleep(sleep_state);299 else300#endif301 status = acpi_hw_extended_sleep(sleep_state);302 return_ACPI_STATUS(status);303}304 305ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)306 307/*******************************************************************************308 *309 * FUNCTION: acpi_leave_sleep_state_prep310 *311 * PARAMETERS: sleep_state - Which sleep state we are exiting312 *313 * RETURN: Status314 *315 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a316 * sleep. Called with interrupts DISABLED.317 * We break wake/resume into 2 stages so that OSPM can handle318 * various OS-specific tasks between the two steps.319 *320 ******************************************************************************/321acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)322{323 acpi_status status;324 325 ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);326 327#if !ACPI_REDUCED_HARDWARE328 if (!acpi_gbl_reduced_hardware)329 status = acpi_hw_legacy_wake_prep(sleep_state);330 else331#endif332 status = acpi_hw_extended_wake_prep(sleep_state);333 return_ACPI_STATUS(status);334}335 336ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep)337 338/*******************************************************************************339 *340 * FUNCTION: acpi_leave_sleep_state341 *342 * PARAMETERS: sleep_state - Which sleep state we are exiting343 *344 * RETURN: Status345 *346 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep347 * Called with interrupts ENABLED.348 *349 ******************************************************************************/350acpi_status acpi_leave_sleep_state(u8 sleep_state)351{352 acpi_status status;353 354 ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);355 356#if !ACPI_REDUCED_HARDWARE357 if (!acpi_gbl_reduced_hardware)358 status = acpi_hw_legacy_wake(sleep_state);359 else360#endif361 status = acpi_hw_extended_wake(sleep_state);362 return_ACPI_STATUS(status);363}364 365ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)366