run resume code only for S1-S4 states
Andriy Gapon
avg at freebsd.org
Fri Apr 17 09:31:17 PDT 2009
An updated version of the patch, the only difference is: do-while(0) is gone,
breaks are replaces with gotos, indentation is reduced.
Per Nate's request I am calling for people with SMP systems to test if powering
off via power button still works with this change. It's desirable to test power
off at least two times to increase a chance of non-BSP CPU being used.
--
Andriy Gapon
-------------- next part --------------
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 50b84a5..6477125 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -2482,6 +2482,9 @@ 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);
+
/* Re-entry once we're suspending is not allowed. */
status = acpi_sleep_disable(sc);
if (ACPI_FAILURE(status)) {
@@ -2489,6 +2492,15 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state)
return (status);
}
+ 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);
+ }
+
#ifdef SMP
thread_lock(curthread);
sched_bind(curthread, 0);
@@ -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())
More information about the freebsd-acpi
mailing list