Commit c697eece authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Len Brown

Suspend: Introduce begin() and end() callbacks

On ACPI systems the target state set by acpi_pm_set_target() is
reset by acpi_pm_finish(), but that need not be called if the
suspend fails.  All platforms that use the .set_target() global
suspend callback are affected by analogous issues.

For this reason, we need an additional global suspend callback that
will reset the target state regardless of whether or not the suspend
is successful.  Also, it is reasonable to rename the .set_target()
callback, since it will be used for a different purpose on ACPI
systems (due to ACPI 1.0x code ordering requirements).

Introduce the global suspend callback .end() to be executed at the
end of the suspend sequence and rename the .set_target() global
suspend callback to .begin().
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 7671b8ae
...@@ -52,7 +52,7 @@ static suspend_state_t target_state; ...@@ -52,7 +52,7 @@ static suspend_state_t target_state;
/* /*
* Called after processes are frozen, but before we shutdown devices. * Called after processes are frozen, but before we shutdown devices.
*/ */
static int at91_pm_set_target(suspend_state_t state) static int at91_pm_begin(suspend_state_t state)
{ {
target_state = state; target_state = state;
return 0; return 0;
...@@ -202,11 +202,20 @@ static int at91_pm_enter(suspend_state_t state) ...@@ -202,11 +202,20 @@ static int at91_pm_enter(suspend_state_t state)
return 0; return 0;
} }
/*
* Called right prior to thawing processes.
*/
static void at91_pm_end(void)
{
target_state = PM_SUSPEND_ON;
}
static struct platform_suspend_ops at91_pm_ops ={ static struct platform_suspend_ops at91_pm_ops ={
.valid = at91_pm_valid_state, .valid = at91_pm_valid_state,
.set_target = at91_pm_set_target, .begin = at91_pm_begin,
.enter = at91_pm_enter, .enter = at91_pm_enter,
.end = at91_pm_end,
}; };
static int __init at91_pm_init(void) static int __init at91_pm_init(void)
......
...@@ -31,7 +31,7 @@ static int lite5200_pm_valid(suspend_state_t state) ...@@ -31,7 +31,7 @@ static int lite5200_pm_valid(suspend_state_t state)
} }
} }
static int lite5200_pm_set_target(suspend_state_t state) static int lite5200_pm_begin(suspend_state_t state)
{ {
if (lite5200_pm_valid(state)) { if (lite5200_pm_valid(state)) {
lite5200_pm_target_state = state; lite5200_pm_target_state = state;
...@@ -219,12 +219,18 @@ static void lite5200_pm_finish(void) ...@@ -219,12 +219,18 @@ static void lite5200_pm_finish(void)
mpc52xx_pm_finish(); mpc52xx_pm_finish();
} }
static void lite5200_pm_end(void)
{
lite5200_pm_target_state = PM_SUSPEND_ON;
}
static struct platform_suspend_ops lite5200_pm_ops = { static struct platform_suspend_ops lite5200_pm_ops = {
.valid = lite5200_pm_valid, .valid = lite5200_pm_valid,
.set_target = lite5200_pm_set_target, .begin = lite5200_pm_begin,
.prepare = lite5200_pm_prepare, .prepare = lite5200_pm_prepare,
.enter = lite5200_pm_enter, .enter = lite5200_pm_enter,
.finish = lite5200_pm_finish, .finish = lite5200_pm_finish,
.end = lite5200_pm_end,
}; };
int __init lite5200_pm_init(void) int __init lite5200_pm_init(void)
......
...@@ -63,11 +63,11 @@ static u32 acpi_suspend_states[] = { ...@@ -63,11 +63,11 @@ static u32 acpi_suspend_states[] = {
static int init_8259A_after_S1; static int init_8259A_after_S1;
/** /**
* acpi_pm_set_target - Set the target system sleep state to the state * acpi_pm_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported. * associated with given @pm_state, if supported.
*/ */
static int acpi_pm_set_target(suspend_state_t pm_state) static int acpi_pm_begin(suspend_state_t pm_state)
{ {
u32 acpi_state = acpi_suspend_states[pm_state]; u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0; int error = 0;
...@@ -164,7 +164,7 @@ static int acpi_pm_enter(suspend_state_t pm_state) ...@@ -164,7 +164,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
} }
/** /**
* acpi_pm_finish - Finish up suspend sequence. * acpi_pm_finish - Instruct the platform to leave a sleep state.
* *
* This is called after we wake back up (or if entering the sleep state * This is called after we wake back up (or if entering the sleep state
* failed). * failed).
...@@ -190,6 +190,19 @@ static void acpi_pm_finish(void) ...@@ -190,6 +190,19 @@ static void acpi_pm_finish(void)
#endif #endif
} }
/**
* acpi_pm_end - Finish up suspend sequence.
*/
static void acpi_pm_end(void)
{
/*
* This is necessary in case acpi_pm_finish() is not called during a
* failing transition to a sleep state.
*/
acpi_target_sleep_state = ACPI_STATE_S0;
}
static int acpi_pm_state_valid(suspend_state_t pm_state) static int acpi_pm_state_valid(suspend_state_t pm_state)
{ {
u32 acpi_state; u32 acpi_state;
...@@ -208,10 +221,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state) ...@@ -208,10 +221,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
static struct platform_suspend_ops acpi_pm_ops = { static struct platform_suspend_ops acpi_pm_ops = {
.valid = acpi_pm_state_valid, .valid = acpi_pm_state_valid,
.set_target = acpi_pm_set_target, .begin = acpi_pm_begin,
.prepare = acpi_pm_prepare, .prepare = acpi_pm_prepare,
.enter = acpi_pm_enter, .enter = acpi_pm_enter,
.finish = acpi_pm_finish, .finish = acpi_pm_finish,
.end = acpi_pm_end,
}; };
/* /*
......
...@@ -38,18 +38,16 @@ typedef int __bitwise suspend_state_t; ...@@ -38,18 +38,16 @@ typedef int __bitwise suspend_state_t;
* There is the %suspend_valid_only_mem function available that can be * There is the %suspend_valid_only_mem function available that can be
* assigned to this if the platform only supports mem sleep. * assigned to this if the platform only supports mem sleep.
* *
* @set_target: Tell the platform which system sleep state is going to be * @begin: Initialise a transition to given system sleep state.
* entered. * @begin() is executed right prior to suspending devices. The information
* @set_target() is executed right prior to suspending devices. The * conveyed to the platform code by @begin() should be disregarded by it as
* information conveyed to the platform code by @set_target() should be * soon as @end() is executed. If @begin() fails (ie. returns nonzero),
* disregarded by the platform as soon as @finish() is executed and if
* @prepare() fails. If @set_target() fails (ie. returns nonzero),
* @prepare(), @enter() and @finish() will not be called by the PM core. * @prepare(), @enter() and @finish() will not be called by the PM core.
* This callback is optional. However, if it is implemented, the argument * This callback is optional. However, if it is implemented, the argument
* passed to @enter() is meaningless and should be ignored. * passed to @enter() is redundant and should be ignored.
* *
* @prepare: Prepare the platform for entering the system sleep state indicated * @prepare: Prepare the platform for entering the system sleep state indicated
* by @set_target(). * by @begin().
* @prepare() is called right after devices have been suspended (ie. the * @prepare() is called right after devices have been suspended (ie. the
* appropriate .suspend() method has been executed for each device) and * appropriate .suspend() method has been executed for each device) and
* before the nonboot CPUs are disabled (it is executed with IRQs enabled). * before the nonboot CPUs are disabled (it is executed with IRQs enabled).
...@@ -57,8 +55,8 @@ typedef int __bitwise suspend_state_t; ...@@ -57,8 +55,8 @@ typedef int __bitwise suspend_state_t;
* error code otherwise, in which case the system cannot enter the desired * error code otherwise, in which case the system cannot enter the desired
* sleep state (@enter() and @finish() will not be called in that case). * sleep state (@enter() and @finish() will not be called in that case).
* *
* @enter: Enter the system sleep state indicated by @set_target() or * @enter: Enter the system sleep state indicated by @begin() or represented by
* represented by the argument if @set_target() is not implemented. * the argument if @begin() is not implemented.
* This callback is mandatory. It returns 0 on success or a negative * This callback is mandatory. It returns 0 on success or a negative
* error code otherwise, in which case the system cannot enter the desired * error code otherwise, in which case the system cannot enter the desired
* sleep state. * sleep state.
...@@ -69,13 +67,22 @@ typedef int __bitwise suspend_state_t; ...@@ -69,13 +67,22 @@ typedef int __bitwise suspend_state_t;
* This callback is optional, but should be implemented by the platforms * This callback is optional, but should be implemented by the platforms
* that implement @prepare(). If implemented, it is always called after * that implement @prepare(). If implemented, it is always called after
* @enter() (even if @enter() fails). * @enter() (even if @enter() fails).
*
* @end: Called by the PM core right after resuming devices, to indicate to
* the platform that the system has returned to the working state or
* the transition to the sleep state has been aborted.
* This callback is optional, but should be implemented by the platforms
* that implement @begin(), but platforms implementing @begin() should
* also provide a @end() which cleans up transitions aborted before
* @enter().
*/ */
struct platform_suspend_ops { struct platform_suspend_ops {
int (*valid)(suspend_state_t state); int (*valid)(suspend_state_t state);
int (*set_target)(suspend_state_t state); int (*begin)(suspend_state_t state);
int (*prepare)(void); int (*prepare)(void);
int (*enter)(suspend_state_t state); int (*enter)(suspend_state_t state);
void (*finish)(void); void (*finish)(void);
void (*end)(void);
}; };
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
......
...@@ -258,10 +258,10 @@ int suspend_devices_and_enter(suspend_state_t state) ...@@ -258,10 +258,10 @@ int suspend_devices_and_enter(suspend_state_t state)
if (!suspend_ops) if (!suspend_ops)
return -ENOSYS; return -ENOSYS;
if (suspend_ops->set_target) { if (suspend_ops->begin) {
error = suspend_ops->set_target(state); error = suspend_ops->begin(state);
if (error) if (error)
return error; goto Close;
} }
suspend_console(); suspend_console();
error = device_suspend(PMSG_SUSPEND); error = device_suspend(PMSG_SUSPEND);
...@@ -294,6 +294,9 @@ int suspend_devices_and_enter(suspend_state_t state) ...@@ -294,6 +294,9 @@ int suspend_devices_and_enter(suspend_state_t state)
device_resume(); device_resume();
Resume_console: Resume_console:
resume_console(); resume_console();
Close:
if (suspend_ops->end)
suspend_ops->end();
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment