diff options
author | Andriy Gapon <avg@FreeBSD.org> | 2009-04-28 11:56:54 +0000 |
---|---|---|
committer | Andriy Gapon <avg@FreeBSD.org> | 2009-04-28 11:56:54 +0000 |
commit | 33c70d417ea93fb3dea40fbf9dd20336ccb6a6e1 (patch) | |
tree | 4ec34c6c43f15daa04b643a6c968d2341f3fad4b /sys/dev/acpica/acpi.c | |
parent | 7981aa2431ce1833d334dcd85a2694dee71145c8 (diff) | |
download | src-33c70d417ea93fb3dea40fbf9dd20336ccb6a6e1.tar.gz src-33c70d417ea93fb3dea40fbf9dd20336ccb6a6e1.zip |
acpi: do not run resume/backout code when entering S0/S5 states
This change adds (possibly redundant) early check for invalid
state input parameter (including S0). Handling of S5 request
is reduced to simply calling shutdown_nice(). As a result
control flow of acpi_EnterSleepState is somewhat simplified
and resume/backout half of the function is not executed
for S5 (soft poweroff) request and invalid state requests.
Note: it seems that shutdown_nice may act as nop when initproc
is already initialized (to grab pid of 1), but init process is in
"pre-natal" state.
Tested by: Fabian Keil <fk@fabiankeil.de>
Reviewed by: njl, jkim
Approved by: rpaulo
Notes
Notes:
svn path=/head/; revision=191627
Diffstat (limited to 'sys/dev/acpica/acpi.c')
-rw-r--r-- | sys/dev/acpica/acpi.c | 139 |
1 files changed, 66 insertions, 73 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 50b84a5b5bcd..d8626b435690 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -2482,6 +2482,18 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state) ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); + if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5) + return_ACPI_STATUS (AE_BAD_PARAMETER); + + if (state == ACPI_STATE_S5) { + /* + * Shut down cleanly and power off. This will call us back through the + * shutdown handlers. + */ + shutdown_nice(RB_POWEROFF); + return_ACPI_STATUS (AE_OK); + } + /* Re-entry once we're suspending is not allowed. */ status = acpi_sleep_disable(sc); if (ACPI_FAILURE(status)) { @@ -2502,92 +2514,74 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state) mtx_lock(&Giant); slp_state = ACPI_SS_NONE; - switch (state) { - case ACPI_STATE_S1: - case ACPI_STATE_S2: - case ACPI_STATE_S3: - case ACPI_STATE_S4: - status = AcpiGetSleepTypeData(state, &TypeA, &TypeB); - if (status == AE_NOT_FOUND) { - device_printf(sc->acpi_dev, - "Sleep state S%d not supported by BIOS\n", state); - break; - } else if (ACPI_FAILURE(status)) { - device_printf(sc->acpi_dev, "AcpiGetSleepTypeData failed - %s\n", - AcpiFormatException(status)); - break; - } + status = AcpiGetSleepTypeData(state, &TypeA, &TypeB); + if (status == AE_NOT_FOUND) { + device_printf(sc->acpi_dev, + "Sleep state S%d not supported by BIOS\n", state); + goto backout; + } else if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiGetSleepTypeData failed - %s\n", + AcpiFormatException(status)); + goto backout; + } - sc->acpi_sstate = state; + sc->acpi_sstate = state; - /* Enable any GPEs as appropriate and requested by the user. */ - acpi_wake_prep_walk(state); - slp_state = ACPI_SS_GPE_SET; + /* Enable any GPEs as appropriate and requested by the user. */ + acpi_wake_prep_walk(state); + slp_state = ACPI_SS_GPE_SET; - /* - * Inform all devices that we are going to sleep. If at least one - * device fails, DEVICE_SUSPEND() automatically resumes the tree. - * - * XXX Note that a better two-pass approach with a 'veto' pass - * followed by a "real thing" pass would be better, but the current - * bus interface does not provide for this. - */ - if (DEVICE_SUSPEND(root_bus) != 0) { - device_printf(sc->acpi_dev, "device_suspend failed\n"); - break; - } - slp_state = ACPI_SS_DEV_SUSPEND; + /* + * Inform all devices that we are going to sleep. If at least one + * device fails, DEVICE_SUSPEND() automatically resumes the tree. + * + * XXX Note that a better two-pass approach with a 'veto' pass + * followed by a "real thing" pass would be better, but the current + * bus interface does not provide for this. + */ + if (DEVICE_SUSPEND(root_bus) != 0) { + device_printf(sc->acpi_dev, "device_suspend failed\n"); + goto backout; + } + slp_state = ACPI_SS_DEV_SUSPEND; - /* If testing device suspend only, back out of everything here. */ - if (acpi_susp_bounce) - break; + /* If testing device suspend only, back out of everything here. */ + if (acpi_susp_bounce) + goto backout; - status = AcpiEnterSleepStatePrep(state); - if (ACPI_FAILURE(status)) { - device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", - AcpiFormatException(status)); - break; - } - slp_state = ACPI_SS_SLP_PREP; + status = AcpiEnterSleepStatePrep(state); + if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", + AcpiFormatException(status)); + goto backout; + } + slp_state = ACPI_SS_SLP_PREP; - if (sc->acpi_sleep_delay > 0) - DELAY(sc->acpi_sleep_delay * 1000000); + if (sc->acpi_sleep_delay > 0) + DELAY(sc->acpi_sleep_delay * 1000000); - if (state != ACPI_STATE_S1) { - acpi_sleep_machdep(sc, state); + if (state != ACPI_STATE_S1) { + acpi_sleep_machdep(sc, state); - /* Re-enable ACPI hardware on wakeup from sleep state 4. */ - if (state == ACPI_STATE_S4) - AcpiEnable(); - } else { - ACPI_DISABLE_IRQS(); - status = AcpiEnterSleepState(state); - if (ACPI_FAILURE(status)) { - device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", - AcpiFormatException(status)); - break; - } + /* Re-enable ACPI hardware on wakeup from sleep state 4. */ + if (state == ACPI_STATE_S4) + AcpiEnable(); + } else { + ACPI_DISABLE_IRQS(); + status = AcpiEnterSleepState(state); + if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", + AcpiFormatException(status)); + goto backout; } - slp_state = ACPI_SS_SLEPT; - break; - case ACPI_STATE_S5: - /* - * Shut down cleanly and power off. This will call us back through the - * shutdown handlers. - */ - shutdown_nice(RB_POWEROFF); - status = AE_OK; - break; - case ACPI_STATE_S0: - default: - status = AE_BAD_PARAMETER; - break; } + slp_state = ACPI_SS_SLEPT; /* * Back out state according to how far along we got in the suspend * process. This handles both the error and success cases. */ +backout: sc->acpi_next_sstate = 0; if (slp_state >= ACPI_SS_GPE_SET) { acpi_wake_prep_walk(state); @@ -2609,8 +2603,7 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state) #endif /* Allow another sleep request after a while. */ - if (state != ACPI_STATE_S5) - timeout(acpi_sleep_enable, sc, hz * ACPI_MINIMUM_AWAKETIME); + timeout(acpi_sleep_enable, sc, hz * ACPI_MINIMUM_AWAKETIME); /* Run /etc/rc.resume after we are back. */ if (devctl_process_running()) |