forked from Minki/linux
cpuidle: PSCI: Improve support for suspend-to-RAM for PSCI OSI mode
When PSCI OSI mode is supported the syscore flag is set for the CPU devices that becomes attached to their PM domains (genpds). In the suspend-to-idle case, we call dev_pm_genpd_suspend|resume() to allow genpd to properly manage the power-off/on operations (pick an idlestate and manage the on/off notifications). For suspend-to-ram, dev_pm_genpd_suspend|resume() is currently not being called, which causes a problem that the genpd on/off notifiers do not get sent as expected. This prevents the platform-specific operations from being executed, typically needed just before/after the boot CPU is being turned off/on. To deal with this problem, let's register a syscore ops for cpuidle-psci when PSCI OSI mode is being used and call dev_pm_genpd_suspend|resume() from them. In this way, genpd regains control of the PM domain topology and then sends the on/off notifications when it's appropriate. Reported-by: Maulik Shah <quic_mkshah@quicinc.com> Suggested-by: Maulik Shah <quic_mkshah@quicinc.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Maulik Shah <quic_mkshah@quicinc.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
13966517d4
commit
171b66e2e2
@ -23,6 +23,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include <asm/cpuidle.h>
|
||||
|
||||
@ -131,6 +132,49 @@ static int psci_idle_cpuhp_down(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psci_idle_syscore_switch(bool suspend)
|
||||
{
|
||||
bool cleared = false;
|
||||
struct device *dev;
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
dev = per_cpu_ptr(&psci_cpuidle_data, cpu)->dev;
|
||||
|
||||
if (dev && suspend) {
|
||||
dev_pm_genpd_suspend(dev);
|
||||
} else if (dev) {
|
||||
dev_pm_genpd_resume(dev);
|
||||
|
||||
/* Account for userspace having offlined a CPU. */
|
||||
if (pm_runtime_status_suspended(dev))
|
||||
pm_runtime_set_active(dev);
|
||||
|
||||
/* Clear domain state to re-start fresh. */
|
||||
if (!cleared) {
|
||||
psci_set_domain_state(0);
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int psci_idle_syscore_suspend(void)
|
||||
{
|
||||
psci_idle_syscore_switch(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psci_idle_syscore_resume(void)
|
||||
{
|
||||
psci_idle_syscore_switch(false);
|
||||
}
|
||||
|
||||
static struct syscore_ops psci_idle_syscore_ops = {
|
||||
.suspend = psci_idle_syscore_suspend,
|
||||
.resume = psci_idle_syscore_resume,
|
||||
};
|
||||
|
||||
static void psci_idle_init_cpuhp(void)
|
||||
{
|
||||
int err;
|
||||
@ -138,6 +182,8 @@ static void psci_idle_init_cpuhp(void)
|
||||
if (!psci_cpuidle_use_cpuhp)
|
||||
return;
|
||||
|
||||
register_syscore_ops(&psci_idle_syscore_ops);
|
||||
|
||||
err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING,
|
||||
"cpuidle/psci:online",
|
||||
psci_idle_cpuhp_up,
|
||||
|
Loading…
Reference in New Issue
Block a user