diff options
author | Sudeep Holla <Sudeep.Holla@arm.com> | 2016-08-19 09:41:00 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-09-12 20:17:19 -0400 |
commit | fa7fd6fa38e36d88bc9f2d0e45e5b9bd0387079f (patch) | |
tree | 21c9156a38c00468ba0b3a332282f101055f03c4 | |
parent | 5b3f249c94ce1f46bacd9814385b0ee2d1ae52f3 (diff) |
PM / sleep: enable suspend-to-idle even without registered suspend_ops
Suspend-to-idle (aka the "freeze" sleep state) is a system sleep state
in which all of the processors enter deepest possible idle state and
wait for interrupts right after suspending all the devices.
There is no hard requirement for a platform to support and register
platform specific suspend_ops to enter suspend-to-idle/freeze state.
Only deeper system sleep states like PM_SUSPEND_STANDBY and
PM_SUSPEND_MEM rely on such low level support/implementation.
suspend-to-idle can be entered as along as all the devices can be
suspended. This patch enables the support for suspend-to-idle even on
systems that don't have any low level support for deeper system sleep
states and/or don't register any platform specific suspend_ops.
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Tested-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | include/linux/suspend.h | 2 | ||||
-rw-r--r-- | kernel/power/main.c | 1 | ||||
-rw-r--r-- | kernel/power/suspend.c | 14 |
3 files changed, 14 insertions, 3 deletions
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 7693e39b14fe..d9718378a8be 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h | |||
@@ -245,6 +245,7 @@ static inline bool idle_should_freeze(void) | |||
245 | return unlikely(suspend_freeze_state == FREEZE_STATE_ENTER); | 245 | return unlikely(suspend_freeze_state == FREEZE_STATE_ENTER); |
246 | } | 246 | } |
247 | 247 | ||
248 | extern void __init pm_states_init(void); | ||
248 | extern void freeze_set_ops(const struct platform_freeze_ops *ops); | 249 | extern void freeze_set_ops(const struct platform_freeze_ops *ops); |
249 | extern void freeze_wake(void); | 250 | extern void freeze_wake(void); |
250 | 251 | ||
@@ -279,6 +280,7 @@ static inline bool pm_resume_via_firmware(void) { return false; } | |||
279 | static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} | 280 | static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} |
280 | static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } | 281 | static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } |
281 | static inline bool idle_should_freeze(void) { return false; } | 282 | static inline bool idle_should_freeze(void) { return false; } |
283 | static inline void __init pm_states_init(void) {} | ||
282 | static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {} | 284 | static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {} |
283 | static inline void freeze_wake(void) {} | 285 | static inline void freeze_wake(void) {} |
284 | #endif /* !CONFIG_SUSPEND */ | 286 | #endif /* !CONFIG_SUSPEND */ |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 5ea50b1b7595..281a697fd458 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -644,6 +644,7 @@ static int __init pm_init(void) | |||
644 | return error; | 644 | return error; |
645 | hibernate_image_size_init(); | 645 | hibernate_image_size_init(); |
646 | hibernate_reserved_size_init(); | 646 | hibernate_reserved_size_init(); |
647 | pm_states_init(); | ||
647 | power_kobj = kobject_create_and_add("power", NULL); | 648 | power_kobj = kobject_create_and_add("power", NULL); |
648 | if (!power_kobj) | 649 | if (!power_kobj) |
649 | return -ENOMEM; | 650 | return -ENOMEM; |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 0acab9d7f96f..1e7f5da648d9 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -118,10 +118,18 @@ static bool valid_state(suspend_state_t state) | |||
118 | */ | 118 | */ |
119 | static bool relative_states; | 119 | static bool relative_states; |
120 | 120 | ||
121 | void __init pm_states_init(void) | ||
122 | { | ||
123 | /* | ||
124 | * freeze state should be supported even without any suspend_ops, | ||
125 | * initialize pm_states accordingly here | ||
126 | */ | ||
127 | pm_states[PM_SUSPEND_FREEZE] = pm_labels[relative_states ? 0 : 2]; | ||
128 | } | ||
129 | |||
121 | static int __init sleep_states_setup(char *str) | 130 | static int __init sleep_states_setup(char *str) |
122 | { | 131 | { |
123 | relative_states = !strncmp(str, "1", 1); | 132 | relative_states = !strncmp(str, "1", 1); |
124 | pm_states[PM_SUSPEND_FREEZE] = pm_labels[relative_states ? 0 : 2]; | ||
125 | return 1; | 133 | return 1; |
126 | } | 134 | } |
127 | 135 | ||
@@ -211,7 +219,7 @@ static int platform_suspend_begin(suspend_state_t state) | |||
211 | { | 219 | { |
212 | if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->begin) | 220 | if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->begin) |
213 | return freeze_ops->begin(); | 221 | return freeze_ops->begin(); |
214 | else if (suspend_ops->begin) | 222 | else if (suspend_ops && suspend_ops->begin) |
215 | return suspend_ops->begin(state); | 223 | return suspend_ops->begin(state); |
216 | else | 224 | else |
217 | return 0; | 225 | return 0; |
@@ -221,7 +229,7 @@ static void platform_resume_end(suspend_state_t state) | |||
221 | { | 229 | { |
222 | if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->end) | 230 | if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->end) |
223 | freeze_ops->end(); | 231 | freeze_ops->end(); |
224 | else if (suspend_ops->end) | 232 | else if (suspend_ops && suspend_ops->end) |
225 | suspend_ops->end(); | 233 | suspend_ops->end(); |
226 | } | 234 | } |
227 | 235 | ||