Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #define EXPORT_ACPI_INTERFACES
0011 
0012 #include <acpi/acpi.h>
0013 #include "accommon.h"
0014 
0015 #define _COMPONENT          ACPI_HARDWARE
0016 ACPI_MODULE_NAME("hwxfsleep")
0017 
0018 /* Local prototypes */
0019 #if (!ACPI_REDUCED_HARDWARE)
0020 static acpi_status
0021 acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
0022                    acpi_physical_address physical_address,
0023                    acpi_physical_address physical_address64);
0024 #endif
0025 
0026 /*
0027  * These functions are removed for the ACPI_REDUCED_HARDWARE case:
0028  *      acpi_set_firmware_waking_vector
0029  *      acpi_enter_sleep_state_s4bios
0030  */
0031 
0032 #if (!ACPI_REDUCED_HARDWARE)
0033 /*******************************************************************************
0034  *
0035  * FUNCTION:    acpi_hw_set_firmware_waking_vector
0036  *
0037  * PARAMETERS:  facs                - Pointer to FACS table
0038  *              physical_address    - 32-bit physical address of ACPI real mode
0039  *                                    entry point
0040  *              physical_address64  - 64-bit physical address of ACPI protected
0041  *                                    mode entry point
0042  *
0043  * RETURN:      Status
0044  *
0045  * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
0046  *
0047  ******************************************************************************/
0048 
0049 static acpi_status
0050 acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
0051                    acpi_physical_address physical_address,
0052                    acpi_physical_address physical_address64)
0053 {
0054     ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vector);
0055 
0056 
0057     /*
0058      * According to the ACPI specification 2.0c and later, the 64-bit
0059      * waking vector should be cleared and the 32-bit waking vector should
0060      * be used, unless we want the wake-up code to be called by the BIOS in
0061      * Protected Mode.  Some systems (for example HP dv5-1004nr) are known
0062      * to fail to resume if the 64-bit vector is used.
0063      */
0064 
0065     /* Set the 32-bit vector */
0066 
0067     facs->firmware_waking_vector = (u32)physical_address;
0068 
0069     if (facs->length > 32) {
0070         if (facs->version >= 1) {
0071 
0072             /* Set the 64-bit vector */
0073 
0074             facs->xfirmware_waking_vector = physical_address64;
0075         } else {
0076             /* Clear the 64-bit vector if it exists */
0077 
0078             facs->xfirmware_waking_vector = 0;
0079         }
0080     }
0081 
0082     return_ACPI_STATUS(AE_OK);
0083 }
0084 
0085 /*******************************************************************************
0086  *
0087  * FUNCTION:    acpi_set_firmware_waking_vector
0088  *
0089  * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
0090  *                                    entry point
0091  *              physical_address64  - 64-bit physical address of ACPI protected
0092  *                                    mode entry point
0093  *
0094  * RETURN:      Status
0095  *
0096  * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
0097  *
0098  ******************************************************************************/
0099 
0100 acpi_status
0101 acpi_set_firmware_waking_vector(acpi_physical_address physical_address,
0102                 acpi_physical_address physical_address64)
0103 {
0104 
0105     ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
0106 
0107     if (acpi_gbl_FACS) {
0108         (void)acpi_hw_set_firmware_waking_vector(acpi_gbl_FACS,
0109                              physical_address,
0110                              physical_address64);
0111     }
0112 
0113     return_ACPI_STATUS(AE_OK);
0114 }
0115 
0116 ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
0117 
0118 /*******************************************************************************
0119  *
0120  * FUNCTION:    acpi_enter_sleep_state_s4bios
0121  *
0122  * PARAMETERS:  None
0123  *
0124  * RETURN:      Status
0125  *
0126  * DESCRIPTION: Perform a S4 bios request.
0127  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
0128  *
0129  ******************************************************************************/
0130 acpi_status acpi_enter_sleep_state_s4bios(void)
0131 {
0132     u32 in_value;
0133     acpi_status status;
0134 
0135     ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
0136 
0137     /* Clear the wake status bit (PM1) */
0138 
0139     status =
0140         acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
0141     if (ACPI_FAILURE(status)) {
0142         return_ACPI_STATUS(status);
0143     }
0144 
0145     status = acpi_hw_clear_acpi_status();
0146     if (ACPI_FAILURE(status)) {
0147         return_ACPI_STATUS(status);
0148     }
0149 
0150     /*
0151      * 1) Disable all GPEs
0152      * 2) Enable all wakeup GPEs
0153      */
0154     status = acpi_hw_disable_all_gpes();
0155     if (ACPI_FAILURE(status)) {
0156         return_ACPI_STATUS(status);
0157     }
0158     acpi_gbl_system_awake_and_running = FALSE;
0159 
0160     status = acpi_hw_enable_all_wakeup_gpes();
0161     if (ACPI_FAILURE(status)) {
0162         return_ACPI_STATUS(status);
0163     }
0164 
0165     status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
0166                     (u32)acpi_gbl_FADT.s4_bios_request, 8);
0167     if (ACPI_FAILURE(status)) {
0168         return_ACPI_STATUS(status);
0169     }
0170 
0171     do {
0172         acpi_os_stall(ACPI_USEC_PER_MSEC);
0173         status =
0174             acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
0175         if (ACPI_FAILURE(status)) {
0176             return_ACPI_STATUS(status);
0177         }
0178 
0179     } while (!in_value);
0180 
0181     return_ACPI_STATUS(AE_OK);
0182 }
0183 
0184 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
0185 #endif              /* !ACPI_REDUCED_HARDWARE */
0186 
0187 /*******************************************************************************
0188  *
0189  * FUNCTION:    acpi_enter_sleep_state_prep
0190  *
0191  * PARAMETERS:  sleep_state         - Which sleep state to enter
0192  *
0193  * RETURN:      Status
0194  *
0195  * DESCRIPTION: Prepare to enter a system sleep state.
0196  *              This function must execute with interrupts enabled.
0197  *              We break sleeping into 2 stages so that OSPM can handle
0198  *              various OS-specific tasks between the two steps.
0199  *
0200  ******************************************************************************/
0201 
0202 acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
0203 {
0204     acpi_status status;
0205     struct acpi_object_list arg_list;
0206     union acpi_object arg;
0207     u32 sst_value;
0208 
0209     ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
0210 
0211     status = acpi_get_sleep_type_data(sleep_state,
0212                       &acpi_gbl_sleep_type_a,
0213                       &acpi_gbl_sleep_type_b);
0214     if (ACPI_FAILURE(status)) {
0215         return_ACPI_STATUS(status);
0216     }
0217 
0218     status = acpi_get_sleep_type_data(ACPI_STATE_S0,
0219                       &acpi_gbl_sleep_type_a_s0,
0220                       &acpi_gbl_sleep_type_b_s0);
0221     if (ACPI_FAILURE(status)) {
0222         acpi_gbl_sleep_type_a_s0 = ACPI_SLEEP_TYPE_INVALID;
0223     }
0224 
0225     /* Execute the _PTS method (Prepare To Sleep) */
0226 
0227     arg_list.count = 1;
0228     arg_list.pointer = &arg;
0229     arg.type = ACPI_TYPE_INTEGER;
0230     arg.integer.value = sleep_state;
0231 
0232     status =
0233         acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL);
0234     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
0235         return_ACPI_STATUS(status);
0236     }
0237 
0238     /* Setup the argument to the _SST method (System STatus) */
0239 
0240     switch (sleep_state) {
0241     case ACPI_STATE_S0:
0242 
0243         sst_value = ACPI_SST_WORKING;
0244         break;
0245 
0246     case ACPI_STATE_S1:
0247     case ACPI_STATE_S2:
0248     case ACPI_STATE_S3:
0249 
0250         sst_value = ACPI_SST_SLEEPING;
0251         break;
0252 
0253     case ACPI_STATE_S4:
0254 
0255         sst_value = ACPI_SST_SLEEP_CONTEXT;
0256         break;
0257 
0258     default:
0259 
0260         sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */
0261         break;
0262     }
0263 
0264     /*
0265      * Set the system indicators to show the desired sleep state.
0266      * _SST is an optional method (return no error if not found)
0267      */
0268     acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value);
0269     return_ACPI_STATUS(AE_OK);
0270 }
0271 
0272 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
0273 
0274 /*******************************************************************************
0275  *
0276  * FUNCTION:    acpi_enter_sleep_state
0277  *
0278  * PARAMETERS:  sleep_state         - Which sleep state to enter
0279  *
0280  * RETURN:      Status
0281  *
0282  * DESCRIPTION: Enter a system sleep state
0283  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
0284  *
0285  ******************************************************************************/
0286 acpi_status acpi_enter_sleep_state(u8 sleep_state)
0287 {
0288     acpi_status status;
0289 
0290     ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
0291 
0292     if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
0293         (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
0294         ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
0295                 acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
0296         return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
0297     }
0298 
0299 #if !ACPI_REDUCED_HARDWARE
0300     if (!acpi_gbl_reduced_hardware)
0301         status = acpi_hw_legacy_sleep(sleep_state);
0302     else
0303 #endif
0304         status = acpi_hw_extended_sleep(sleep_state);
0305     return_ACPI_STATUS(status);
0306 }
0307 
0308 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
0309 
0310 /*******************************************************************************
0311  *
0312  * FUNCTION:    acpi_leave_sleep_state_prep
0313  *
0314  * PARAMETERS:  sleep_state         - Which sleep state we are exiting
0315  *
0316  * RETURN:      Status
0317  *
0318  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
0319  *              sleep. Called with interrupts DISABLED.
0320  *              We break wake/resume into 2 stages so that OSPM can handle
0321  *              various OS-specific tasks between the two steps.
0322  *
0323  ******************************************************************************/
0324 acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
0325 {
0326     acpi_status status;
0327 
0328     ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
0329 
0330 #if !ACPI_REDUCED_HARDWARE
0331     if (!acpi_gbl_reduced_hardware)
0332         status = acpi_hw_legacy_wake_prep(sleep_state);
0333     else
0334 #endif
0335         status = acpi_hw_extended_wake_prep(sleep_state);
0336     return_ACPI_STATUS(status);
0337 }
0338 
0339 ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep)
0340 
0341 /*******************************************************************************
0342  *
0343  * FUNCTION:    acpi_leave_sleep_state
0344  *
0345  * PARAMETERS:  sleep_state         - Which sleep state we are exiting
0346  *
0347  * RETURN:      Status
0348  *
0349  * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
0350  *              Called with interrupts ENABLED.
0351  *
0352  ******************************************************************************/
0353 acpi_status acpi_leave_sleep_state(u8 sleep_state)
0354 {
0355     acpi_status status;
0356 
0357     ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
0358 
0359 #if !ACPI_REDUCED_HARDWARE
0360     if (!acpi_gbl_reduced_hardware)
0361         status = acpi_hw_legacy_wake(sleep_state);
0362     else
0363 #endif
0364         status = acpi_hw_extended_wake(sleep_state);
0365     return_ACPI_STATUS(status);
0366 }
0367 
0368 ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)