acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags) { struct acpi_bit_register_info *sleep_type_reg_info; struct acpi_bit_register_info *sleep_enable_reg_info; u32 pm1a_control; u32 pm1b_control; u32 in_value; acpi_status status; ACPI_FUNCTION_TRACE(hw_legacy_sleep); sleep_type_reg_info = acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE); sleep_enable_reg_info = acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE); status = acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } status = acpi_hw_clear_acpi_status(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (sleep_state != ACPI_STATE_S5) { status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) { return_ACPI_STATUS(status); } } status = acpi_hw_disable_all_gpes(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } acpi_gbl_system_awake_and_running = FALSE; status = acpi_hw_enable_all_wakeup_gpes(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (flags & ACPI_EXECUTE_GTS) { acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state); } status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &pm1a_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Entering sleep state [S%u]\n", sleep_state)); pm1a_control &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask); pm1b_control = pm1a_control; pm1a_control |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position); pm1b_control |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position); status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } pm1a_control |= sleep_enable_reg_info->access_bit_mask; pm1b_control |= sleep_enable_reg_info->access_bit_mask; ACPI_FLUSH_CPU_CACHE(); status = acpi_os_prepare_sleep(sleep_state, pm1a_control, pm1b_control); if (ACPI_SKIP(status)) return_ACPI_STATUS(AE_OK); if (ACPI_FAILURE(status)) return_ACPI_STATUS(status); status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (sleep_state > ACPI_STATE_S3) { acpi_os_stall(10000000); status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL, sleep_enable_reg_info-> access_bit_mask); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } do { status = acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } while (!in_value); return_ACPI_STATUS(AE_OK); }
/******************************************************************************* * * FUNCTION: acpi_hw_legacy_sleep * * PARAMETERS: sleep_state - Which sleep state to enter * * RETURN: Status * * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) { struct acpi_bit_register_info *sleep_type_reg_info; struct acpi_bit_register_info *sleep_enable_reg_info; u32 pm1a_control; u32 pm1b_control; u32 in_value; acpi_status status; ACPI_FUNCTION_TRACE(hw_legacy_sleep); sleep_type_reg_info = acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE); sleep_enable_reg_info = acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE); /* Clear wake status */ status = acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Clear all fixed and general purpose status bits */ status = acpi_hw_clear_acpi_status(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ status = acpi_hw_disable_all_gpes(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } acpi_gbl_system_awake_and_running = FALSE; status = acpi_hw_enable_all_wakeup_gpes(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Get current value of PM1A control */ status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &pm1a_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Entering sleep state [S%u]\n", sleep_state)); /* Clear the SLP_EN and SLP_TYP fields */ pm1a_control &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask); pm1b_control = pm1a_control; /* Insert the SLP_TYP bits */ pm1a_control |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position); pm1b_control |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position); /* * We split the writes of SLP_TYP and SLP_EN to workaround * poorly implemented hardware. */ /* Write #1: write the SLP_TYP data to the PM1 Control registers */ status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Insert the sleep enable (SLP_EN) bit */ pm1a_control |= sleep_enable_reg_info->access_bit_mask; pm1b_control |= sleep_enable_reg_info->access_bit_mask; /* Flush caches, as per ACPI specification */ ACPI_FLUSH_CPU_CACHE(); status = acpi_os_prepare_sleep(sleep_state, pm1a_control, pm1b_control); if (ACPI_SKIP(status)) return_ACPI_STATUS(AE_OK); if (ACPI_FAILURE(status)) return_ACPI_STATUS(status); /* Write #2: Write both SLP_TYP + SLP_EN */ status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (sleep_state > ACPI_STATE_S3) { /* * We wanted to sleep > S3, but it didn't happen (by virtue of the * fact that we are still executing!) * * Wait ten seconds, then try again. This is to get S4/S5 to work on * all machines. * * We wait so long to allow chipsets that poll this reg very slowly * to still read the right value. Ideally, this block would go * away entirely. */ acpi_os_stall(10000000); status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL, sleep_enable_reg_info-> access_bit_mask); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } /* Wait for transition back to Working State */ do { status = acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } while (!in_value); return_ACPI_STATUS(AE_OK); }
acpi_status acpi_hw_extended_sleep(u8 sleep_state) { acpi_status status; u8 sleep_type_value; u64 sleep_status; ACPI_FUNCTION_TRACE(hw_extended_sleep); /* Extended sleep registers must be valid */ if (!acpi_gbl_FADT.sleep_control.address || !acpi_gbl_FADT.sleep_status.address) { return_ACPI_STATUS(AE_NOT_EXIST); } /* Clear wake status (WAK_STS) */ status = acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } acpi_gbl_system_awake_and_running = FALSE; /* Flush caches, as per ACPI specification */ ACPI_FLUSH_CPU_CACHE(); status = acpi_os_prepare_extended_sleep(sleep_state, acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b); if (ACPI_SKIP(status)) return_ACPI_STATUS(AE_OK); if (ACPI_FAILURE(status)) return_ACPI_STATUS(status); /* * Set the SLP_TYP and SLP_EN bits. * * Note: We only use the first value returned by the \_Sx method * (acpi_gbl_sleep_type_a) - As per ACPI specification. */ ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Entering sleep state [S%u]\n", sleep_state)); sleep_type_value = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & ACPI_X_SLEEP_TYPE_MASK); status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), &acpi_gbl_FADT.sleep_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Wait for transition back to Working State */ do { status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS)); return_ACPI_STATUS(AE_OK); }