mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
PM: extend suspend_again mechanism to use partialresume
The old platform suspend_again callback overrides drivers' votes, such that if it implemented and returns false, then we do not call the partialresume handlers. When it doesn't exists or returns true, then we also query the registered drivers for consensus. When a device resumes from suspend, the suspend/resume code invokes partialresume to check to see if the set of wakeup interrupts all have matching handlers. If this is not the case, the PM subsystem can continue to resume as before. If all of the wakeup sources have matching handlers, then those are invoked in turn (and can block), and if all of them reach consensus that the reason for the wakeup can be ignored, they say so to the PM subsystem, which goes right back into suspend. Signed-off-by: Iliyan Malchev <malchev@google.com> Change-Id: Iaeb9ed78c4b5fb815c6e9c701233e703f481f962
This commit is contained in:
parent
4e0c8780cc
commit
953a4840dd
1 changed files with 61 additions and 3 deletions
|
@ -25,6 +25,8 @@
|
|||
#include <linux/suspend.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
#include <linux/partialresume.h>
|
||||
#include <trace/events/power.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
|
||||
|
@ -187,6 +189,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
|
|||
MAX_SUSPEND_ABORT_LEN);
|
||||
log_suspend_abort_reason(suspend_abort);
|
||||
}
|
||||
|
||||
start_logging_wakeup_reasons();
|
||||
syscore_resume();
|
||||
}
|
||||
|
||||
|
@ -209,6 +213,59 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
|
|||
return error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PARTIALRESUME
|
||||
static bool suspend_again(bool *drivers_resumed)
|
||||
{
|
||||
const struct list_head *irqs;
|
||||
struct list_head unfinished;
|
||||
|
||||
*drivers_resumed = false;
|
||||
|
||||
/* If a platform suspend_again handler is defined, when it decides to
|
||||
* not suspend again, this takes precedence over drivers. If a
|
||||
* platform's suspend_again callback returns true, then we proceed to
|
||||
* check the drivers as well.
|
||||
*/
|
||||
if (suspend_ops->suspend_again && !suspend_ops->suspend_again())
|
||||
return false;
|
||||
|
||||
/* TODO: resume only the drivers associated with the wakeup interrupts!
|
||||
*/
|
||||
dpm_resume_end(PMSG_RESUME);
|
||||
*drivers_resumed = true;
|
||||
|
||||
/* Thaw kernel threads opportunistically, to allow get_wakeup_reasons
|
||||
* to block while the wakeup interrupt list is being assembled. Calls
|
||||
* schedule() internally.
|
||||
*/
|
||||
thaw_kernel_threads();
|
||||
|
||||
/* Look for a match between the wakeup reasons and the registered
|
||||
* callbacks. Don't bother thawing the kernel threads if a match is
|
||||
* not found.
|
||||
*/
|
||||
irqs = get_wakeup_reasons(HZ, &unfinished);
|
||||
if (!suspend_again_match(irqs, &unfinished))
|
||||
return false;
|
||||
|
||||
if (suspend_again_consensus() &&
|
||||
!freeze_kernel_threads()) {
|
||||
clear_wakeup_reasons();
|
||||
dpm_suspend_start(PMSG_SUSPEND);
|
||||
*drivers_resumed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static __always_inline bool
|
||||
suspend_again(bool *drivers_resumed __attribute__((unused)))
|
||||
{
|
||||
return suspend_ops->suspend_again && suspend_ops->suspend_again();
|
||||
}
|
||||
#endif /* CONFIG_PARTIALRESUME */
|
||||
|
||||
/**
|
||||
* suspend_devices_and_enter - Suspend devices and enter system sleep state.
|
||||
* @state: System sleep state to enter.
|
||||
|
@ -217,6 +274,7 @@ int suspend_devices_and_enter(suspend_state_t state)
|
|||
{
|
||||
int error;
|
||||
bool wakeup = false;
|
||||
bool resumed = false;
|
||||
|
||||
if (!suspend_ops)
|
||||
return -ENOSYS;
|
||||
|
@ -241,12 +299,12 @@ int suspend_devices_and_enter(suspend_state_t state)
|
|||
|
||||
do {
|
||||
error = suspend_enter(state, &wakeup);
|
||||
} while (!error && !wakeup
|
||||
&& suspend_ops->suspend_again && suspend_ops->suspend_again());
|
||||
} while (!error && !wakeup && suspend_again(&resumed));
|
||||
|
||||
Resume_devices:
|
||||
suspend_test_start();
|
||||
dpm_resume_end(PMSG_RESUME);
|
||||
if (!resumed)
|
||||
dpm_resume_end(PMSG_RESUME);
|
||||
suspend_test_finish("resume devices");
|
||||
resume_console();
|
||||
Close:
|
||||
|
|
Loading…
Reference in a new issue