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