@@ -41,6 +41,11 @@
* are used to save any global context for affected blocks, and must be called
* after all the CPUs in the power domain have been notified of the low power
* state.
+ *
+ * CPU system notifications apply to all CPUs within the system. They are used
+ * for operations that must only happen on suspend and have an ordering
+ * requirement with the other CPU PM notifications. Must be called after all
+ * CPUs and clusters in the system have been notified of the low power state.
*/
/*
@@ -64,6 +69,15 @@ enum cpu_pm_event {
/* A cpu power domain is exiting a low power state */
CPU_CLUSTER_PM_EXIT,
+
+ /* A cpu power domain is entering a system low power state (suspend) */
+ CPU_SYSTEM_PM_ENTER,
+
+ /* A cpu power domain failed to enter a system low power state */
+ CPU_SYSTEM_PM_ENTER_FAILED,
+
+ /* A cpu power domain is exiting a system low power state */
+ CPU_SYSTEM_PM_EXIT,
};
#ifdef CONFIG_CPU_PM
@@ -72,6 +72,22 @@ int cpu_pm_unregister_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
+static int cpu_pm_notify_enter(enum cpu_pm_event enter, enum cpu_pm_event fail)
+{
+ int nr_calls;
+ int ret = 0;
+
+ ret = cpu_pm_notify(enter, -1, &nr_calls);
+ if (ret)
+ /*
+ * Inform listeners (nr_calls - 1) about failure to enter CPU PM
+ * state <enter> who were notified earlier to prepare for it.
+ */
+ cpu_pm_notify(fail, nr_calls - 1, NULL);
+
+ return ret;
+}
+
/**
* cpu_pm_enter - CPU low power entry notifier
*
@@ -89,18 +105,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
*/
int cpu_pm_enter(void)
{
- int nr_calls;
- int ret = 0;
-
- ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
- if (ret)
- /*
- * Inform listeners (nr_calls - 1) about failure of CPU PM
- * PM entry who are notified earlier to prepare for it.
- */
- cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
-
- return ret;
+ return cpu_pm_notify_enter(CPU_PM_ENTER, CPU_PM_ENTER_FAILED);
}
EXPORT_SYMBOL_GPL(cpu_pm_enter);
@@ -140,18 +145,8 @@ EXPORT_SYMBOL_GPL(cpu_pm_exit);
*/
int cpu_cluster_pm_enter(void)
{
- int nr_calls;
- int ret = 0;
-
- ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
- if (ret)
- /*
- * Inform listeners (nr_calls - 1) about failure of CPU cluster
- * PM entry who are notified earlier to prepare for it.
- */
- cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
-
- return ret;
+ return cpu_pm_notify_enter(CPU_CLUSTER_PM_ENTER,
+ CPU_CLUSTER_PM_ENTER_FAILED);
}
EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
@@ -176,6 +171,27 @@ int cpu_cluster_pm_exit(void)
}
EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
+/*
+ * Notifies listeners that the system is entering suspend. Called after
+ * cpu_cluster_pm_enter() and only within the syscore suspend callback,
+ * cpu_pm_suspend.
+ */
+static int cpu_system_pm_enter(void)
+{
+ return cpu_pm_notify_enter(CPU_SYSTEM_PM_ENTER,
+ CPU_SYSTEM_PM_ENTER_FAILED);
+}
+
+/*
+ * Notifies listeners that the system is leaving suspend. Called before
+ * cpu_cluster_pm_exit() and only within the syscore resume callback,
+ * cpu_pm_resume.
+ */
+static int cpu_system_pm_exit(void)
+{
+ return cpu_pm_notify(CPU_SYSTEM_PM_EXIT, -1, NULL);
+}
+
#ifdef CONFIG_PM
static int cpu_pm_suspend(void)
{
@@ -186,14 +202,22 @@ static int cpu_pm_suspend(void)
return ret;
ret = cpu_cluster_pm_enter();
- if (ret)
+ if (ret) {
cpu_pm_exit();
+ return ret;
+ }
+ ret = cpu_system_pm_enter();
+ if (ret) {
+ cpu_cluster_pm_exit();
+ cpu_pm_exit();
+ }
return ret;
}
static void cpu_pm_resume(void)
{
+ cpu_system_pm_exit();
cpu_cluster_pm_exit();
cpu_pm_exit();
}