acpi: Suspend-to-idle support (s2idle)
Implement STYPE_SUSPEND_TO_IDLE sleep type added in c43473dc9b
("sys/power: Generic sleep types").
This is a prerequisite for the firmware to enter the S0ix states. When
suspending to idle, the system stays in an ACPI S0 state, but the CPUs
are idled and devices are suspended/resumed before and after this as
they would be when entering any other sleep type (except for AWAKE and
POWEROFF).
Factor out do_standby, do_sleep, and add a new do_idle function for
idling the CPU (a future patch will make this an idle loop and not just
a simple cpu_idle() call). In do_idle, SCIs (interrupt 9) are enabled to
allow wake events to break the CPU out of idle.
Record all the steps made instead of just the last one in slp_state,
which allows for more flexible unwinding (will be useful to not have to
goto breakout if the SPMC entry call fails when that is committed).
A lot of this borrows from Ben Widawsky's patch: D17675. The main
functional difference with that patch is that suspend-to-idle is a
wholly separate sleep type in this one as opposed to being an
alternative implementation for s2mem (S3).
Reviewed by: emaste, olce
Approved by: olce
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D48734
This commit is contained in:
+185
-93
@@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
#if defined(__i386__) || defined(__amd64__)
|
#if defined(__i386__) || defined(__amd64__)
|
||||||
#include <machine/clock.h>
|
#include <machine/clock.h>
|
||||||
|
#include <machine/intr_machdep.h>
|
||||||
#include <machine/pci_cfgreg.h>
|
#include <machine/pci_cfgreg.h>
|
||||||
#include <x86/cputypes.h>
|
#include <x86/cputypes.h>
|
||||||
#include <x86/x86_var.h>
|
#include <x86/x86_var.h>
|
||||||
@@ -679,15 +680,19 @@ acpi_attach(device_t dev)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Probe all supported ACPI sleep states. Awake (S0) is always supported.
|
* Probe all supported ACPI sleep states. Awake (S0) is always supported,
|
||||||
|
* and suspend-to-idle is always supported on x86 only (at the moment).
|
||||||
*/
|
*/
|
||||||
acpi_supported_sstates[ACPI_STATE_S0] = TRUE;
|
acpi_supported_sstates[ACPI_STATE_S0] = true;
|
||||||
acpi_supported_stypes[POWER_STYPE_AWAKE] = true;
|
acpi_supported_stypes[POWER_STYPE_AWAKE] = true;
|
||||||
|
#if defined(__i386__) || defined(__amd64__)
|
||||||
|
acpi_supported_stypes[POWER_STYPE_SUSPEND_TO_IDLE] = true;
|
||||||
|
#endif
|
||||||
for (state = ACPI_STATE_S1; state <= ACPI_STATE_S5; state++)
|
for (state = ACPI_STATE_S1; state <= ACPI_STATE_S5; state++)
|
||||||
if (ACPI_SUCCESS(AcpiEvaluateObject(ACPI_ROOT_OBJECT,
|
if (ACPI_SUCCESS(AcpiEvaluateObject(ACPI_ROOT_OBJECT,
|
||||||
__DECONST(char *, AcpiGbl_SleepStateNames[state]), NULL, NULL)) &&
|
__DECONST(char *, AcpiGbl_SleepStateNames[state]), NULL, NULL)) &&
|
||||||
ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) {
|
ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) {
|
||||||
acpi_supported_sstates[state] = TRUE;
|
acpi_supported_sstates[state] = true;
|
||||||
acpi_supported_stypes[acpi_sstate_to_stype(state)] = true;
|
acpi_supported_stypes[acpi_sstate_to_stype(state)] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,13 +710,24 @@ acpi_attach(device_t dev)
|
|||||||
else if (acpi_supported_sstates[ACPI_STATE_S2])
|
else if (acpi_supported_sstates[ACPI_STATE_S2])
|
||||||
sc->acpi_standby_sx = ACPI_STATE_S2;
|
sc->acpi_standby_sx = ACPI_STATE_S2;
|
||||||
|
|
||||||
/* Pick the first valid sleep type for the sleep button default. */
|
/*
|
||||||
|
* Pick the first valid sleep type for the sleep button default. If that
|
||||||
|
* type was hibernate and we support s2idle, set it to that. The sleep
|
||||||
|
* button prefers s2mem instead of s2idle at the moment as s2idle may not
|
||||||
|
* yet work reliably on all machines. In the future, we should set this to
|
||||||
|
* s2idle when ACPI_FADT_LOW_POWER_S0 is set.
|
||||||
|
*/
|
||||||
sc->acpi_sleep_button_stype = POWER_STYPE_UNKNOWN;
|
sc->acpi_sleep_button_stype = POWER_STYPE_UNKNOWN;
|
||||||
for (stype = POWER_STYPE_STANDBY; stype <= POWER_STYPE_HIBERNATE; stype++)
|
for (stype = POWER_STYPE_STANDBY; stype <= POWER_STYPE_HIBERNATE; stype++)
|
||||||
if (acpi_supported_stypes[stype]) {
|
if (acpi_supported_stypes[stype]) {
|
||||||
sc->acpi_sleep_button_stype = stype;
|
sc->acpi_sleep_button_stype = stype;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (sc->acpi_sleep_button_stype == POWER_STYPE_HIBERNATE ||
|
||||||
|
sc->acpi_sleep_button_stype == POWER_STYPE_UNKNOWN) {
|
||||||
|
if (acpi_supported_stypes[POWER_STYPE_SUSPEND_TO_IDLE])
|
||||||
|
sc->acpi_sleep_button_stype = POWER_STYPE_SUSPEND_TO_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
acpi_enable_fixed_events(sc);
|
acpi_enable_fixed_events(sc);
|
||||||
|
|
||||||
@@ -3315,7 +3331,8 @@ acpi_ReqSleepState(struct acpi_softc *sc, enum power_stype stype)
|
|||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
#else
|
#else
|
||||||
/* This platform does not support acpi suspend/resume. */
|
device_printf(sc->acpi_dev, "ACPI suspend not supported on this platform "
|
||||||
|
"(TODO suspend to idle should be, however)\n");
|
||||||
return (EOPNOTSUPP);
|
return (EOPNOTSUPP);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3330,13 +3347,13 @@ acpi_ReqSleepState(struct acpi_softc *sc, enum power_stype stype)
|
|||||||
int
|
int
|
||||||
acpi_AckSleepState(struct apm_clone_data *clone, int error)
|
acpi_AckSleepState(struct apm_clone_data *clone, int error)
|
||||||
{
|
{
|
||||||
|
struct acpi_softc *sc = clone->acpi_sc;
|
||||||
|
|
||||||
#if defined(__amd64__) || defined(__i386__)
|
#if defined(__amd64__) || defined(__i386__)
|
||||||
struct acpi_softc *sc;
|
|
||||||
int ret, sleeping;
|
int ret, sleeping;
|
||||||
|
|
||||||
/* If no pending sleep type, return an error. */
|
/* If no pending sleep type, return an error. */
|
||||||
ACPI_LOCK(acpi);
|
ACPI_LOCK(acpi);
|
||||||
sc = clone->acpi_sc;
|
|
||||||
if (sc->acpi_next_stype == POWER_STYPE_AWAKE) {
|
if (sc->acpi_next_stype == POWER_STYPE_AWAKE) {
|
||||||
ACPI_UNLOCK(acpi);
|
ACPI_UNLOCK(acpi);
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
@@ -3379,7 +3396,8 @@ acpi_AckSleepState(struct apm_clone_data *clone, int error)
|
|||||||
}
|
}
|
||||||
return (ret);
|
return (ret);
|
||||||
#else
|
#else
|
||||||
/* This platform does not support acpi suspend/resume. */
|
device_printf(sc->acpi_dev, "ACPI suspend not supported on this platform "
|
||||||
|
"(TODO suspend to idle should be, however)\n");
|
||||||
return (EOPNOTSUPP);
|
return (EOPNOTSUPP);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3418,27 +3436,133 @@ acpi_sleep_disable(struct acpi_softc *sc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum acpi_sleep_state {
|
enum acpi_sleep_state {
|
||||||
ACPI_SS_NONE,
|
ACPI_SS_NONE = 0,
|
||||||
ACPI_SS_GPE_SET,
|
ACPI_SS_GPE_SET = 1 << 0,
|
||||||
ACPI_SS_DEV_SUSPEND,
|
ACPI_SS_DEV_SUSPEND = 1 << 1,
|
||||||
ACPI_SS_SLP_PREP,
|
ACPI_SS_SLP_PREP = 1 << 2,
|
||||||
ACPI_SS_SLEPT,
|
ACPI_SS_SLEPT = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_standby(struct acpi_softc *sc, enum acpi_sleep_state *slp_state,
|
||||||
|
register_t rflags)
|
||||||
|
{
|
||||||
|
ACPI_STATUS status;
|
||||||
|
|
||||||
|
status = AcpiEnterSleepState(sc->acpi_standby_sx);
|
||||||
|
intr_restore(rflags);
|
||||||
|
AcpiLeaveSleepStatePrep(sc->acpi_standby_sx);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n",
|
||||||
|
AcpiFormatException(status));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*slp_state |= ACPI_SS_SLEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_sleep(struct acpi_softc *sc, enum acpi_sleep_state *slp_state,
|
||||||
|
register_t rflags, int state)
|
||||||
|
{
|
||||||
|
int sleep_result;
|
||||||
|
ACPI_EVENT_STATUS power_button_status;
|
||||||
|
|
||||||
|
MPASS(state == ACPI_STATE_S3 || state == ACPI_STATE_S4);
|
||||||
|
|
||||||
|
sleep_result = acpi_sleep_machdep(sc, state);
|
||||||
|
acpi_wakeup_machdep(sc, state, sleep_result, 0);
|
||||||
|
|
||||||
|
if (sleep_result == 1 && state == ACPI_STATE_S3) {
|
||||||
|
/*
|
||||||
|
* XXX According to ACPI specification SCI_EN bit should be restored
|
||||||
|
* by ACPI platform (BIOS, firmware) to its pre-sleep state.
|
||||||
|
* Unfortunately some BIOSes fail to do that and that leads to
|
||||||
|
* unexpected and serious consequences during wake up like a system
|
||||||
|
* getting stuck in SMI handlers.
|
||||||
|
* This hack is picked up from Linux, which claims that it follows
|
||||||
|
* Windows behavior.
|
||||||
|
*/
|
||||||
|
AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prevent misinterpretation of the wakeup by power button
|
||||||
|
* as a request for power off.
|
||||||
|
* Ideally we should post an appropriate wakeup event,
|
||||||
|
* perhaps using acpi_event_power_button_wake or alike.
|
||||||
|
*
|
||||||
|
* Clearing of power button status after wakeup is mandated
|
||||||
|
* by ACPI specification in section "Fixed Power Button".
|
||||||
|
*
|
||||||
|
* XXX As of ACPICA 20121114 AcpiGetEventStatus provides
|
||||||
|
* status as 0/1 corresponding to inactive/active despite
|
||||||
|
* its type being ACPI_EVENT_STATUS. In other words,
|
||||||
|
* we should not test for ACPI_EVENT_FLAG_SET for time being.
|
||||||
|
*/
|
||||||
|
if (ACPI_SUCCESS(AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON,
|
||||||
|
&power_button_status)) && power_button_status != 0) {
|
||||||
|
AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
|
||||||
|
device_printf(sc->acpi_dev, "cleared fixed power button status\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intr_restore(rflags);
|
||||||
|
|
||||||
|
/* call acpi_wakeup_machdep() again with interrupt enabled */
|
||||||
|
acpi_wakeup_machdep(sc, state, sleep_result, 1);
|
||||||
|
|
||||||
|
AcpiLeaveSleepStatePrep(state);
|
||||||
|
|
||||||
|
if (sleep_result == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Re-enable ACPI hardware on wakeup from sleep state 4. */
|
||||||
|
if (state == ACPI_STATE_S4)
|
||||||
|
AcpiEnable();
|
||||||
|
*slp_state |= ACPI_SS_SLEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__i386__) || defined(__amd64__)
|
||||||
|
static void
|
||||||
|
do_idle(struct acpi_softc *sc, enum acpi_sleep_state *slp_state,
|
||||||
|
register_t rflags)
|
||||||
|
{
|
||||||
|
|
||||||
|
intr_suspend();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The CPU will exit idle when interrupted, so we want to minimize the
|
||||||
|
* number of interrupts it can receive while idle. We do this by only
|
||||||
|
* allowing SCI (system control interrupt) interrupts, which are used by
|
||||||
|
* the ACPI firmware to send wake GPEs to the OS.
|
||||||
|
*
|
||||||
|
* XXX We might still receive other spurious non-wake GPEs from noisy
|
||||||
|
* devices that can't be disabled, so this will need to end up being a
|
||||||
|
* suspend-to-idle loop which, when breaking out of idle, will check the
|
||||||
|
* reason for the wakeup and immediately idle the CPU again if it was not a
|
||||||
|
* proper wake event.
|
||||||
|
*/
|
||||||
|
intr_enable_src(AcpiGbl_FADT.SciInterrupt);
|
||||||
|
|
||||||
|
cpu_idle(0);
|
||||||
|
|
||||||
|
intr_resume(false);
|
||||||
|
intr_restore(rflags);
|
||||||
|
*slp_state |= ACPI_SS_SLEPT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter the desired system sleep state.
|
* Enter the desired system sleep state.
|
||||||
*
|
*
|
||||||
* Currently we support S1-S5 but S4 is only S4BIOS
|
* Currently we support S1-S5 and suspend-to-idle, but S4 is only S4BIOS.
|
||||||
*/
|
*/
|
||||||
static ACPI_STATUS
|
static ACPI_STATUS
|
||||||
acpi_EnterSleepState(struct acpi_softc *sc, enum power_stype stype)
|
acpi_EnterSleepState(struct acpi_softc *sc, enum power_stype stype)
|
||||||
{
|
{
|
||||||
register_t intr;
|
register_t intr;
|
||||||
ACPI_STATUS status;
|
ACPI_STATUS status;
|
||||||
ACPI_EVENT_STATUS power_button_status;
|
|
||||||
enum acpi_sleep_state slp_state;
|
enum acpi_sleep_state slp_state;
|
||||||
int acpi_sstate;
|
int acpi_sstate;
|
||||||
int sleep_result;
|
|
||||||
|
|
||||||
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, stype);
|
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, stype);
|
||||||
|
|
||||||
@@ -3498,7 +3622,7 @@ acpi_EnterSleepState(struct acpi_softc *sc, enum power_stype stype)
|
|||||||
|
|
||||||
/* Enable any GPEs as appropriate and requested by the user. */
|
/* Enable any GPEs as appropriate and requested by the user. */
|
||||||
acpi_wake_prep_walk(sc, stype);
|
acpi_wake_prep_walk(sc, stype);
|
||||||
slp_state = ACPI_SS_GPE_SET;
|
slp_state |= ACPI_SS_GPE_SET;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Inform all devices that we are going to sleep. If at least one
|
* Inform all devices that we are going to sleep. If at least one
|
||||||
@@ -3509,113 +3633,81 @@ acpi_EnterSleepState(struct acpi_softc *sc, enum power_stype stype)
|
|||||||
* bus interface does not provide for this.
|
* bus interface does not provide for this.
|
||||||
*/
|
*/
|
||||||
if (DEVICE_SUSPEND(root_bus) != 0) {
|
if (DEVICE_SUSPEND(root_bus) != 0) {
|
||||||
device_printf(sc->acpi_dev, "device_suspend failed\n");
|
device_printf(sc->acpi_dev, "device_suspend failed\n");
|
||||||
goto backout;
|
goto backout;
|
||||||
}
|
}
|
||||||
slp_state = ACPI_SS_DEV_SUSPEND;
|
slp_state |= ACPI_SS_DEV_SUSPEND;
|
||||||
|
|
||||||
status = AcpiEnterSleepStatePrep(acpi_sstate);
|
if (stype != POWER_STYPE_SUSPEND_TO_IDLE) {
|
||||||
if (ACPI_FAILURE(status)) {
|
status = AcpiEnterSleepStatePrep(acpi_sstate);
|
||||||
device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
|
if (ACPI_FAILURE(status)) {
|
||||||
AcpiFormatException(status));
|
device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
|
||||||
goto backout;
|
AcpiFormatException(status));
|
||||||
|
goto backout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
slp_state = ACPI_SS_SLP_PREP;
|
slp_state |= ACPI_SS_SLP_PREP;
|
||||||
|
|
||||||
if (sc->acpi_sleep_delay > 0)
|
if (sc->acpi_sleep_delay > 0)
|
||||||
DELAY(sc->acpi_sleep_delay * 1000000);
|
DELAY(sc->acpi_sleep_delay * 1000000);
|
||||||
|
|
||||||
suspendclock();
|
suspendclock();
|
||||||
intr = intr_disable();
|
intr = intr_disable();
|
||||||
if (stype != POWER_STYPE_STANDBY) {
|
switch (stype) {
|
||||||
sleep_result = acpi_sleep_machdep(sc, acpi_sstate);
|
case POWER_STYPE_STANDBY:
|
||||||
acpi_wakeup_machdep(sc, acpi_sstate, sleep_result, 0);
|
do_standby(sc, &slp_state, intr);
|
||||||
|
break;
|
||||||
/*
|
case POWER_STYPE_SUSPEND_TO_MEM:
|
||||||
* XXX According to ACPI specification SCI_EN bit should be restored
|
case POWER_STYPE_HIBERNATE:
|
||||||
* by ACPI platform (BIOS, firmware) to its pre-sleep state.
|
do_sleep(sc, &slp_state, intr, acpi_sstate);
|
||||||
* Unfortunately some BIOSes fail to do that and that leads to
|
break;
|
||||||
* unexpected and serious consequences during wake up like a system
|
case POWER_STYPE_SUSPEND_TO_IDLE:
|
||||||
* getting stuck in SMI handlers.
|
#if defined(__i386__) || defined(__amd64__)
|
||||||
* This hack is picked up from Linux, which claims that it follows
|
do_idle(sc, &slp_state, intr);
|
||||||
* Windows behavior.
|
break;
|
||||||
*/
|
#endif
|
||||||
if (sleep_result == 1 && stype != POWER_STYPE_HIBERNATE)
|
case POWER_STYPE_AWAKE:
|
||||||
AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT);
|
case POWER_STYPE_POWEROFF:
|
||||||
|
case POWER_STYPE_COUNT:
|
||||||
if (sleep_result == 1 && stype == POWER_STYPE_SUSPEND_TO_MEM) {
|
case POWER_STYPE_UNKNOWN:
|
||||||
/*
|
__unreachable();
|
||||||
* Prevent mis-interpretation of the wakeup by power button
|
|
||||||
* as a request for power off.
|
|
||||||
* Ideally we should post an appropriate wakeup event,
|
|
||||||
* perhaps using acpi_event_power_button_wake or alike.
|
|
||||||
*
|
|
||||||
* Clearing of power button status after wakeup is mandated
|
|
||||||
* by ACPI specification in section "Fixed Power Button".
|
|
||||||
*
|
|
||||||
* XXX As of ACPICA 20121114 AcpiGetEventStatus provides
|
|
||||||
* status as 0/1 corressponding to inactive/active despite
|
|
||||||
* its type being ACPI_EVENT_STATUS. In other words,
|
|
||||||
* we should not test for ACPI_EVENT_FLAG_SET for time being.
|
|
||||||
*/
|
|
||||||
if (ACPI_SUCCESS(AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON,
|
|
||||||
&power_button_status)) && power_button_status != 0) {
|
|
||||||
AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
|
|
||||||
device_printf(sc->acpi_dev,
|
|
||||||
"cleared fixed power button status\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
intr_restore(intr);
|
|
||||||
|
|
||||||
/* call acpi_wakeup_machdep() again with interrupt enabled */
|
|
||||||
acpi_wakeup_machdep(sc, acpi_sstate, sleep_result, 1);
|
|
||||||
|
|
||||||
AcpiLeaveSleepStatePrep(acpi_sstate);
|
|
||||||
|
|
||||||
if (sleep_result == -1)
|
|
||||||
goto backout;
|
|
||||||
|
|
||||||
/* Re-enable ACPI hardware on wakeup from hibernate. */
|
|
||||||
if (stype == POWER_STYPE_HIBERNATE)
|
|
||||||
AcpiEnable();
|
|
||||||
} else {
|
|
||||||
status = AcpiEnterSleepState(acpi_sstate);
|
|
||||||
intr_restore(intr);
|
|
||||||
AcpiLeaveSleepStatePrep(acpi_sstate);
|
|
||||||
if (ACPI_FAILURE(status)) {
|
|
||||||
device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n",
|
|
||||||
AcpiFormatException(status));
|
|
||||||
goto backout;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
slp_state = ACPI_SS_SLEPT;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Back out state according to how far along we got in the suspend
|
* Back out state according to how far along we got in the suspend
|
||||||
* process. This handles both the error and success cases.
|
* process. This handles both the error and success cases.
|
||||||
*/
|
*/
|
||||||
backout:
|
backout:
|
||||||
if (slp_state >= ACPI_SS_SLP_PREP)
|
if ((slp_state & ACPI_SS_SLP_PREP) != 0) {
|
||||||
resumeclock();
|
resumeclock();
|
||||||
if (slp_state >= ACPI_SS_GPE_SET) {
|
slp_state &= ~ACPI_SS_SLP_PREP;
|
||||||
|
}
|
||||||
|
if ((slp_state & ACPI_SS_GPE_SET) != 0) {
|
||||||
acpi_wake_prep_walk(sc, stype);
|
acpi_wake_prep_walk(sc, stype);
|
||||||
sc->acpi_stype = POWER_STYPE_AWAKE;
|
sc->acpi_stype = POWER_STYPE_AWAKE;
|
||||||
|
slp_state &= ~ACPI_SS_GPE_SET;
|
||||||
}
|
}
|
||||||
if (slp_state >= ACPI_SS_DEV_SUSPEND)
|
if ((slp_state & ACPI_SS_DEV_SUSPEND) != 0) {
|
||||||
DEVICE_RESUME(root_bus);
|
DEVICE_RESUME(root_bus);
|
||||||
if (slp_state >= ACPI_SS_SLP_PREP)
|
slp_state &= ~ACPI_SS_DEV_SUSPEND;
|
||||||
|
}
|
||||||
|
if (stype != POWER_STYPE_SUSPEND_TO_IDLE && (slp_state & ACPI_SS_SLP_PREP) != 0) {
|
||||||
AcpiLeaveSleepState(acpi_sstate);
|
AcpiLeaveSleepState(acpi_sstate);
|
||||||
if (slp_state >= ACPI_SS_SLEPT) {
|
slp_state &= ~ACPI_SS_SLP_PREP;
|
||||||
|
}
|
||||||
|
if ((slp_state & ACPI_SS_SLEPT) != 0) {
|
||||||
#if defined(__i386__) || defined(__amd64__)
|
#if defined(__i386__) || defined(__amd64__)
|
||||||
/* NB: we are still using ACPI timecounter at this point. */
|
/* NB: we are still using ACPI timecounter at this point. */
|
||||||
resume_TSC();
|
resume_TSC();
|
||||||
#endif
|
#endif
|
||||||
acpi_resync_clock(sc);
|
acpi_resync_clock(sc);
|
||||||
acpi_enable_fixed_events(sc);
|
acpi_enable_fixed_events(sc);
|
||||||
|
slp_state &= ~ACPI_SS_SLEPT;
|
||||||
}
|
}
|
||||||
sc->acpi_next_stype = POWER_STYPE_AWAKE;
|
sc->acpi_next_stype = POWER_STYPE_AWAKE;
|
||||||
|
|
||||||
|
MPASS(slp_state == ACPI_SS_NONE);
|
||||||
|
|
||||||
bus_topo_unlock();
|
bus_topo_unlock();
|
||||||
|
|
||||||
#ifdef EARLY_AP_STARTUP
|
#ifdef EARLY_AP_STARTUP
|
||||||
|
|||||||
Reference in New Issue
Block a user