| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * kernel/power/suspend.c - Suspend to RAM and standby functionality. | 
|---|
| 4 | * | 
|---|
| 5 | * Copyright (c) 2003 Patrick Mochel | 
|---|
| 6 | * Copyright (c) 2003 Open Source Development Lab | 
|---|
| 7 | * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | 
|---|
| 8 | */ | 
|---|
| 9 |  | 
|---|
| 10 | #define pr_fmt(fmt) "PM: " fmt | 
|---|
| 11 |  | 
|---|
| 12 | #include <linux/string.h> | 
|---|
| 13 | #include <linux/delay.h> | 
|---|
| 14 | #include <linux/errno.h> | 
|---|
| 15 | #include <linux/init.h> | 
|---|
| 16 | #include <linux/console.h> | 
|---|
| 17 | #include <linux/cpu.h> | 
|---|
| 18 | #include <linux/cpuidle.h> | 
|---|
| 19 | #include <linux/gfp.h> | 
|---|
| 20 | #include <linux/io.h> | 
|---|
| 21 | #include <linux/kernel.h> | 
|---|
| 22 | #include <linux/list.h> | 
|---|
| 23 | #include <linux/mm.h> | 
|---|
| 24 | #include <linux/slab.h> | 
|---|
| 25 | #include <linux/export.h> | 
|---|
| 26 | #include <linux/suspend.h> | 
|---|
| 27 | #include <linux/syscore_ops.h> | 
|---|
| 28 | #include <linux/swait.h> | 
|---|
| 29 | #include <linux/ftrace.h> | 
|---|
| 30 | #include <trace/events/power.h> | 
|---|
| 31 | #include <linux/compiler.h> | 
|---|
| 32 | #include <linux/moduleparam.h> | 
|---|
| 33 | #include <linux/fs.h> | 
|---|
| 34 |  | 
|---|
| 35 | #include "power.h" | 
|---|
| 36 |  | 
|---|
| 37 | const char * const pm_labels[] = { | 
|---|
| 38 | [PM_SUSPEND_TO_IDLE] = "freeze", | 
|---|
| 39 | [PM_SUSPEND_STANDBY] = "standby", | 
|---|
| 40 | [PM_SUSPEND_MEM] = "mem", | 
|---|
| 41 | }; | 
|---|
| 42 | const char *pm_states[PM_SUSPEND_MAX]; | 
|---|
| 43 | static const char * const mem_sleep_labels[] = { | 
|---|
| 44 | [PM_SUSPEND_TO_IDLE] = "s2idle", | 
|---|
| 45 | [PM_SUSPEND_STANDBY] = "shallow", | 
|---|
| 46 | [PM_SUSPEND_MEM] = "deep", | 
|---|
| 47 | }; | 
|---|
| 48 | const char *mem_sleep_states[PM_SUSPEND_MAX]; | 
|---|
| 49 |  | 
|---|
| 50 | suspend_state_t mem_sleep_current = PM_SUSPEND_TO_IDLE; | 
|---|
| 51 | suspend_state_t mem_sleep_default = PM_SUSPEND_MAX; | 
|---|
| 52 | suspend_state_t pm_suspend_target_state; | 
|---|
| 53 | EXPORT_SYMBOL_GPL(pm_suspend_target_state); | 
|---|
| 54 |  | 
|---|
| 55 | unsigned int pm_suspend_global_flags; | 
|---|
| 56 | EXPORT_SYMBOL_GPL(pm_suspend_global_flags); | 
|---|
| 57 |  | 
|---|
| 58 | static const struct platform_suspend_ops *suspend_ops; | 
|---|
| 59 | static const struct platform_s2idle_ops *s2idle_ops; | 
|---|
| 60 | static DECLARE_SWAIT_QUEUE_HEAD(s2idle_wait_head); | 
|---|
| 61 |  | 
|---|
| 62 | enum s2idle_states __read_mostly s2idle_state; | 
|---|
| 63 | static DEFINE_RAW_SPINLOCK(s2idle_lock); | 
|---|
| 64 |  | 
|---|
| 65 | /** | 
|---|
| 66 | * pm_suspend_default_s2idle - Check if suspend-to-idle is the default suspend. | 
|---|
| 67 | * | 
|---|
| 68 | * Return 'true' if suspend-to-idle has been selected as the default system | 
|---|
| 69 | * suspend method. | 
|---|
| 70 | */ | 
|---|
| 71 | bool pm_suspend_default_s2idle(void) | 
|---|
| 72 | { | 
|---|
| 73 | return mem_sleep_current == PM_SUSPEND_TO_IDLE; | 
|---|
| 74 | } | 
|---|
| 75 | EXPORT_SYMBOL_GPL(pm_suspend_default_s2idle); | 
|---|
| 76 |  | 
|---|
| 77 | void s2idle_set_ops(const struct platform_s2idle_ops *ops) | 
|---|
| 78 | { | 
|---|
| 79 | unsigned int sleep_flags; | 
|---|
| 80 |  | 
|---|
| 81 | sleep_flags = lock_system_sleep(); | 
|---|
| 82 | s2idle_ops = ops; | 
|---|
| 83 | unlock_system_sleep(sleep_flags); | 
|---|
| 84 | } | 
|---|
| 85 |  | 
|---|
| 86 | static void s2idle_begin(void) | 
|---|
| 87 | { | 
|---|
| 88 | s2idle_state = S2IDLE_STATE_NONE; | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | static void s2idle_enter(void) | 
|---|
| 92 | { | 
|---|
| 93 | trace_suspend_resume(TPS( "machine_suspend"), PM_SUSPEND_TO_IDLE, start: true); | 
|---|
| 94 |  | 
|---|
| 95 | /* | 
|---|
| 96 | * The correctness of the code below depends on the number of online | 
|---|
| 97 | * CPUs being stable, but CPUs cannot be taken offline or put online | 
|---|
| 98 | * while it is running. | 
|---|
| 99 | * | 
|---|
| 100 | * The s2idle_lock must be acquired before the pending wakeup check to | 
|---|
| 101 | * prevent pm_system_wakeup() from running as a whole between that check | 
|---|
| 102 | * and the subsequent s2idle_state update in which case a wakeup event | 
|---|
| 103 | * would get lost. | 
|---|
| 104 | */ | 
|---|
| 105 | raw_spin_lock_irq(&s2idle_lock); | 
|---|
| 106 | if (pm_wakeup_pending()) | 
|---|
| 107 | goto out; | 
|---|
| 108 |  | 
|---|
| 109 | s2idle_state = S2IDLE_STATE_ENTER; | 
|---|
| 110 | raw_spin_unlock_irq(&s2idle_lock); | 
|---|
| 111 |  | 
|---|
| 112 | /* Push all the CPUs into the idle loop. */ | 
|---|
| 113 | wake_up_all_idle_cpus(); | 
|---|
| 114 | /* Make the current CPU wait so it can enter the idle loop too. */ | 
|---|
| 115 | swait_event_exclusive(s2idle_wait_head, | 
|---|
| 116 | s2idle_state == S2IDLE_STATE_WAKE); | 
|---|
| 117 |  | 
|---|
| 118 | /* | 
|---|
| 119 | * Kick all CPUs to ensure that they resume their timers and restore | 
|---|
| 120 | * consistent system state. | 
|---|
| 121 | */ | 
|---|
| 122 | wake_up_all_idle_cpus(); | 
|---|
| 123 |  | 
|---|
| 124 | raw_spin_lock_irq(&s2idle_lock); | 
|---|
| 125 |  | 
|---|
| 126 | out: | 
|---|
| 127 | s2idle_state = S2IDLE_STATE_NONE; | 
|---|
| 128 | raw_spin_unlock_irq(&s2idle_lock); | 
|---|
| 129 |  | 
|---|
| 130 | trace_suspend_resume(TPS( "machine_suspend"), PM_SUSPEND_TO_IDLE, start: false); | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | static void s2idle_loop(void) | 
|---|
| 134 | { | 
|---|
| 135 | pm_pr_dbg( "suspend-to-idle\n"); | 
|---|
| 136 |  | 
|---|
| 137 | /* | 
|---|
| 138 | * Suspend-to-idle equals: | 
|---|
| 139 | * frozen processes + suspended devices + idle processors. | 
|---|
| 140 | * Thus s2idle_enter() should be called right after all devices have | 
|---|
| 141 | * been suspended. | 
|---|
| 142 | * | 
|---|
| 143 | * Wakeups during the noirq suspend of devices may be spurious, so try | 
|---|
| 144 | * to avoid them upfront. | 
|---|
| 145 | */ | 
|---|
| 146 | for (;;) { | 
|---|
| 147 | if (s2idle_ops && s2idle_ops->wake) { | 
|---|
| 148 | if (s2idle_ops->wake()) | 
|---|
| 149 | break; | 
|---|
| 150 | } else if (pm_wakeup_pending()) { | 
|---|
| 151 | break; | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | if (s2idle_ops && s2idle_ops->check) | 
|---|
| 155 | s2idle_ops->check(); | 
|---|
| 156 |  | 
|---|
| 157 | s2idle_enter(); | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | pm_pr_dbg( "resume from suspend-to-idle\n"); | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | void s2idle_wake(void) | 
|---|
| 164 | { | 
|---|
| 165 | unsigned long flags; | 
|---|
| 166 |  | 
|---|
| 167 | raw_spin_lock_irqsave(&s2idle_lock, flags); | 
|---|
| 168 | if (s2idle_state > S2IDLE_STATE_NONE) { | 
|---|
| 169 | s2idle_state = S2IDLE_STATE_WAKE; | 
|---|
| 170 | swake_up_one(q: &s2idle_wait_head); | 
|---|
| 171 | } | 
|---|
| 172 | raw_spin_unlock_irqrestore(&s2idle_lock, flags); | 
|---|
| 173 | } | 
|---|
| 174 | EXPORT_SYMBOL_GPL(s2idle_wake); | 
|---|
| 175 |  | 
|---|
| 176 | static bool valid_state(suspend_state_t state) | 
|---|
| 177 | { | 
|---|
| 178 | /* | 
|---|
| 179 | * The PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states require low-level | 
|---|
| 180 | * support and need to be valid to the low-level implementation. | 
|---|
| 181 | * | 
|---|
| 182 | * No ->valid() or ->enter() callback implies that none are valid. | 
|---|
| 183 | */ | 
|---|
| 184 | return suspend_ops && suspend_ops->valid && suspend_ops->valid(state) && | 
|---|
| 185 | suspend_ops->enter; | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | void __init pm_states_init(void) | 
|---|
| 189 | { | 
|---|
| 190 | /* "mem" and "freeze" are always present in /sys/power/state. */ | 
|---|
| 191 | pm_states[PM_SUSPEND_MEM] = pm_labels[PM_SUSPEND_MEM]; | 
|---|
| 192 | pm_states[PM_SUSPEND_TO_IDLE] = pm_labels[PM_SUSPEND_TO_IDLE]; | 
|---|
| 193 | /* | 
|---|
| 194 | * Suspend-to-idle should be supported even without any suspend_ops, | 
|---|
| 195 | * initialize mem_sleep_states[] accordingly here. | 
|---|
| 196 | */ | 
|---|
| 197 | mem_sleep_states[PM_SUSPEND_TO_IDLE] = mem_sleep_labels[PM_SUSPEND_TO_IDLE]; | 
|---|
| 198 | } | 
|---|
| 199 |  | 
|---|
| 200 | static int __init mem_sleep_default_setup(char *str) | 
|---|
| 201 | { | 
|---|
| 202 | suspend_state_t state; | 
|---|
| 203 |  | 
|---|
| 204 | for (state = PM_SUSPEND_TO_IDLE; state <= PM_SUSPEND_MEM; state++) | 
|---|
| 205 | if (mem_sleep_labels[state] && | 
|---|
| 206 | !strcmp(str, mem_sleep_labels[state])) { | 
|---|
| 207 | mem_sleep_default = state; | 
|---|
| 208 | mem_sleep_current = state; | 
|---|
| 209 | break; | 
|---|
| 210 | } | 
|---|
| 211 |  | 
|---|
| 212 | return 1; | 
|---|
| 213 | } | 
|---|
| 214 | __setup( "mem_sleep_default=", mem_sleep_default_setup); | 
|---|
| 215 |  | 
|---|
| 216 | /** | 
|---|
| 217 | * suspend_set_ops - Set the global suspend method table. | 
|---|
| 218 | * @ops: Suspend operations to use. | 
|---|
| 219 | */ | 
|---|
| 220 | void suspend_set_ops(const struct platform_suspend_ops *ops) | 
|---|
| 221 | { | 
|---|
| 222 | unsigned int sleep_flags; | 
|---|
| 223 |  | 
|---|
| 224 | sleep_flags = lock_system_sleep(); | 
|---|
| 225 |  | 
|---|
| 226 | suspend_ops = ops; | 
|---|
| 227 |  | 
|---|
| 228 | if (valid_state(PM_SUSPEND_STANDBY)) { | 
|---|
| 229 | mem_sleep_states[PM_SUSPEND_STANDBY] = mem_sleep_labels[PM_SUSPEND_STANDBY]; | 
|---|
| 230 | pm_states[PM_SUSPEND_STANDBY] = pm_labels[PM_SUSPEND_STANDBY]; | 
|---|
| 231 | if (mem_sleep_default == PM_SUSPEND_STANDBY) | 
|---|
| 232 | mem_sleep_current = PM_SUSPEND_STANDBY; | 
|---|
| 233 | } | 
|---|
| 234 | if (valid_state(PM_SUSPEND_MEM)) { | 
|---|
| 235 | mem_sleep_states[PM_SUSPEND_MEM] = mem_sleep_labels[PM_SUSPEND_MEM]; | 
|---|
| 236 | if (mem_sleep_default >= PM_SUSPEND_MEM) | 
|---|
| 237 | mem_sleep_current = PM_SUSPEND_MEM; | 
|---|
| 238 | } | 
|---|
| 239 |  | 
|---|
| 240 | unlock_system_sleep(sleep_flags); | 
|---|
| 241 | } | 
|---|
| 242 | EXPORT_SYMBOL_GPL(suspend_set_ops); | 
|---|
| 243 |  | 
|---|
| 244 | /** | 
|---|
| 245 | * suspend_valid_only_mem - Generic memory-only valid callback. | 
|---|
| 246 | * @state: Target system sleep state. | 
|---|
| 247 | * | 
|---|
| 248 | * Platform drivers that implement mem suspend only and only need to check for | 
|---|
| 249 | * that in their .valid() callback can use this instead of rolling their own | 
|---|
| 250 | * .valid() callback. | 
|---|
| 251 | */ | 
|---|
| 252 | int suspend_valid_only_mem(suspend_state_t state) | 
|---|
| 253 | { | 
|---|
| 254 | return state == PM_SUSPEND_MEM; | 
|---|
| 255 | } | 
|---|
| 256 | EXPORT_SYMBOL_GPL(suspend_valid_only_mem); | 
|---|
| 257 |  | 
|---|
| 258 | static bool sleep_state_supported(suspend_state_t state) | 
|---|
| 259 | { | 
|---|
| 260 | return state == PM_SUSPEND_TO_IDLE || | 
|---|
| 261 | (valid_state(state) && !cxl_mem_active()); | 
|---|
| 262 | } | 
|---|
| 263 |  | 
|---|
| 264 | static int platform_suspend_prepare(suspend_state_t state) | 
|---|
| 265 | { | 
|---|
| 266 | return state != PM_SUSPEND_TO_IDLE && suspend_ops->prepare ? | 
|---|
| 267 | suspend_ops->prepare() : 0; | 
|---|
| 268 | } | 
|---|
| 269 |  | 
|---|
| 270 | static int platform_suspend_prepare_late(suspend_state_t state) | 
|---|
| 271 | { | 
|---|
| 272 | return state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->prepare ? | 
|---|
| 273 | s2idle_ops->prepare() : 0; | 
|---|
| 274 | } | 
|---|
| 275 |  | 
|---|
| 276 | static int platform_suspend_prepare_noirq(suspend_state_t state) | 
|---|
| 277 | { | 
|---|
| 278 | if (state == PM_SUSPEND_TO_IDLE) | 
|---|
| 279 | return s2idle_ops && s2idle_ops->prepare_late ? | 
|---|
| 280 | s2idle_ops->prepare_late() : 0; | 
|---|
| 281 |  | 
|---|
| 282 | return suspend_ops->prepare_late ? suspend_ops->prepare_late() : 0; | 
|---|
| 283 | } | 
|---|
| 284 |  | 
|---|
| 285 | static void platform_resume_noirq(suspend_state_t state) | 
|---|
| 286 | { | 
|---|
| 287 | if (state == PM_SUSPEND_TO_IDLE) { | 
|---|
| 288 | if (s2idle_ops && s2idle_ops->restore_early) | 
|---|
| 289 | s2idle_ops->restore_early(); | 
|---|
| 290 | } else if (suspend_ops->wake) { | 
|---|
| 291 | suspend_ops->wake(); | 
|---|
| 292 | } | 
|---|
| 293 | } | 
|---|
| 294 |  | 
|---|
| 295 | static void platform_resume_early(suspend_state_t state) | 
|---|
| 296 | { | 
|---|
| 297 | if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->restore) | 
|---|
| 298 | s2idle_ops->restore(); | 
|---|
| 299 | } | 
|---|
| 300 |  | 
|---|
| 301 | static void platform_resume_finish(suspend_state_t state) | 
|---|
| 302 | { | 
|---|
| 303 | if (state != PM_SUSPEND_TO_IDLE && suspend_ops->finish) | 
|---|
| 304 | suspend_ops->finish(); | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | static int platform_suspend_begin(suspend_state_t state) | 
|---|
| 308 | { | 
|---|
| 309 | if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->begin) | 
|---|
| 310 | return s2idle_ops->begin(); | 
|---|
| 311 | else if (suspend_ops && suspend_ops->begin) | 
|---|
| 312 | return suspend_ops->begin(state); | 
|---|
| 313 | else | 
|---|
| 314 | return 0; | 
|---|
| 315 | } | 
|---|
| 316 |  | 
|---|
| 317 | static void platform_resume_end(suspend_state_t state) | 
|---|
| 318 | { | 
|---|
| 319 | if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->end) | 
|---|
| 320 | s2idle_ops->end(); | 
|---|
| 321 | else if (suspend_ops && suspend_ops->end) | 
|---|
| 322 | suspend_ops->end(); | 
|---|
| 323 | } | 
|---|
| 324 |  | 
|---|
| 325 | static void platform_recover(suspend_state_t state) | 
|---|
| 326 | { | 
|---|
| 327 | if (state != PM_SUSPEND_TO_IDLE && suspend_ops->recover) | 
|---|
| 328 | suspend_ops->recover(); | 
|---|
| 329 | } | 
|---|
| 330 |  | 
|---|
| 331 | static bool platform_suspend_again(suspend_state_t state) | 
|---|
| 332 | { | 
|---|
| 333 | return state != PM_SUSPEND_TO_IDLE && suspend_ops->suspend_again ? | 
|---|
| 334 | suspend_ops->suspend_again() : false; | 
|---|
| 335 | } | 
|---|
| 336 |  | 
|---|
| 337 | #ifdef CONFIG_PM_DEBUG | 
|---|
| 338 | static unsigned int pm_test_delay = 5; | 
|---|
| 339 | module_param(pm_test_delay, uint, 0644); | 
|---|
| 340 | MODULE_PARM_DESC(pm_test_delay, | 
|---|
| 341 | "Number of seconds to wait before resuming from suspend test"); | 
|---|
| 342 | #endif | 
|---|
| 343 |  | 
|---|
| 344 | static int suspend_test(int level) | 
|---|
| 345 | { | 
|---|
| 346 | #ifdef CONFIG_PM_DEBUG | 
|---|
| 347 | if (pm_test_level == level) { | 
|---|
| 348 | pr_info( "suspend debug: Waiting for %d second(s).\n", | 
|---|
| 349 | pm_test_delay); | 
|---|
| 350 | mdelay(pm_test_delay * 1000); | 
|---|
| 351 | return 1; | 
|---|
| 352 | } | 
|---|
| 353 | #endif /* !CONFIG_PM_DEBUG */ | 
|---|
| 354 | return 0; | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | /** | 
|---|
| 358 | * suspend_prepare - Prepare for entering system sleep state. | 
|---|
| 359 | * @state: Target system sleep state. | 
|---|
| 360 | * | 
|---|
| 361 | * Common code run for every system sleep state that can be entered (except for | 
|---|
| 362 | * hibernation).  Run suspend notifiers, allocate the "suspend" console and | 
|---|
| 363 | * freeze processes. | 
|---|
| 364 | */ | 
|---|
| 365 | static int suspend_prepare(suspend_state_t state) | 
|---|
| 366 | { | 
|---|
| 367 | int error; | 
|---|
| 368 |  | 
|---|
| 369 | if (!sleep_state_supported(state)) | 
|---|
| 370 | return -EPERM; | 
|---|
| 371 |  | 
|---|
| 372 | pm_prepare_console(); | 
|---|
| 373 |  | 
|---|
| 374 | error = pm_notifier_call_chain_robust(PM_SUSPEND_PREPARE, PM_POST_SUSPEND); | 
|---|
| 375 | if (error) | 
|---|
| 376 | goto Restore; | 
|---|
| 377 |  | 
|---|
| 378 | if (filesystem_freeze_enabled) | 
|---|
| 379 | filesystems_freeze(); | 
|---|
| 380 | trace_suspend_resume(TPS( "freeze_processes"), val: 0, start: true); | 
|---|
| 381 | error = suspend_freeze_processes(); | 
|---|
| 382 | trace_suspend_resume(TPS( "freeze_processes"), val: 0, start: false); | 
|---|
| 383 | if (!error) | 
|---|
| 384 | return 0; | 
|---|
| 385 |  | 
|---|
| 386 | dpm_save_failed_step(step: SUSPEND_FREEZE); | 
|---|
| 387 | filesystems_thaw(); | 
|---|
| 388 | pm_notifier_call_chain(PM_POST_SUSPEND); | 
|---|
| 389 | Restore: | 
|---|
| 390 | pm_restore_console(); | 
|---|
| 391 | return error; | 
|---|
| 392 | } | 
|---|
| 393 |  | 
|---|
| 394 | /* default implementation */ | 
|---|
| 395 | void __weak arch_suspend_disable_irqs(void) | 
|---|
| 396 | { | 
|---|
| 397 | local_irq_disable(); | 
|---|
| 398 | } | 
|---|
| 399 |  | 
|---|
| 400 | /* default implementation */ | 
|---|
| 401 | void __weak arch_suspend_enable_irqs(void) | 
|---|
| 402 | { | 
|---|
| 403 | local_irq_enable(); | 
|---|
| 404 | } | 
|---|
| 405 |  | 
|---|
| 406 | /** | 
|---|
| 407 | * suspend_enter - Make the system enter the given sleep state. | 
|---|
| 408 | * @state: System sleep state to enter. | 
|---|
| 409 | * @wakeup: Returns information that the sleep state should not be re-entered. | 
|---|
| 410 | * | 
|---|
| 411 | * This function should be called after devices have been suspended. | 
|---|
| 412 | */ | 
|---|
| 413 | static int suspend_enter(suspend_state_t state, bool *wakeup) | 
|---|
| 414 | { | 
|---|
| 415 | int error; | 
|---|
| 416 |  | 
|---|
| 417 | error = platform_suspend_prepare(state); | 
|---|
| 418 | if (error) | 
|---|
| 419 | goto Platform_finish; | 
|---|
| 420 |  | 
|---|
| 421 | error = dpm_suspend_late(PMSG_SUSPEND); | 
|---|
| 422 | if (error) { | 
|---|
| 423 | pr_err( "late suspend of devices failed\n"); | 
|---|
| 424 | goto Platform_finish; | 
|---|
| 425 | } | 
|---|
| 426 | error = platform_suspend_prepare_late(state); | 
|---|
| 427 | if (error) | 
|---|
| 428 | goto Devices_early_resume; | 
|---|
| 429 |  | 
|---|
| 430 | error = dpm_suspend_noirq(PMSG_SUSPEND); | 
|---|
| 431 | if (error) { | 
|---|
| 432 | pr_err( "noirq suspend of devices failed\n"); | 
|---|
| 433 | goto Platform_early_resume; | 
|---|
| 434 | } | 
|---|
| 435 | error = platform_suspend_prepare_noirq(state); | 
|---|
| 436 | if (error) | 
|---|
| 437 | goto Platform_wake; | 
|---|
| 438 |  | 
|---|
| 439 | if (suspend_test(level: TEST_PLATFORM)) | 
|---|
| 440 | goto Platform_wake; | 
|---|
| 441 |  | 
|---|
| 442 | if (state == PM_SUSPEND_TO_IDLE) { | 
|---|
| 443 | s2idle_loop(); | 
|---|
| 444 | goto Platform_wake; | 
|---|
| 445 | } | 
|---|
| 446 |  | 
|---|
| 447 | error = pm_sleep_disable_secondary_cpus(); | 
|---|
| 448 | if (error || suspend_test(level: TEST_CPUS)) | 
|---|
| 449 | goto Enable_cpus; | 
|---|
| 450 |  | 
|---|
| 451 | arch_suspend_disable_irqs(); | 
|---|
| 452 | BUG_ON(!irqs_disabled()); | 
|---|
| 453 |  | 
|---|
| 454 | system_state = SYSTEM_SUSPEND; | 
|---|
| 455 |  | 
|---|
| 456 | error = syscore_suspend(); | 
|---|
| 457 | if (!error) { | 
|---|
| 458 | *wakeup = pm_wakeup_pending(); | 
|---|
| 459 | if (!(suspend_test(level: TEST_CORE) || *wakeup)) { | 
|---|
| 460 | trace_suspend_resume(TPS( "machine_suspend"), | 
|---|
| 461 | val: state, start: true); | 
|---|
| 462 | error = suspend_ops->enter(state); | 
|---|
| 463 | trace_suspend_resume(TPS( "machine_suspend"), | 
|---|
| 464 | val: state, start: false); | 
|---|
| 465 | } else if (*wakeup) { | 
|---|
| 466 | error = -EBUSY; | 
|---|
| 467 | } | 
|---|
| 468 | syscore_resume(); | 
|---|
| 469 | } | 
|---|
| 470 |  | 
|---|
| 471 | system_state = SYSTEM_RUNNING; | 
|---|
| 472 |  | 
|---|
| 473 | arch_suspend_enable_irqs(); | 
|---|
| 474 | BUG_ON(irqs_disabled()); | 
|---|
| 475 |  | 
|---|
| 476 | Enable_cpus: | 
|---|
| 477 | pm_sleep_enable_secondary_cpus(); | 
|---|
| 478 |  | 
|---|
| 479 | Platform_wake: | 
|---|
| 480 | platform_resume_noirq(state); | 
|---|
| 481 | dpm_resume_noirq(PMSG_RESUME); | 
|---|
| 482 |  | 
|---|
| 483 | Platform_early_resume: | 
|---|
| 484 | platform_resume_early(state); | 
|---|
| 485 |  | 
|---|
| 486 | Devices_early_resume: | 
|---|
| 487 | dpm_resume_early(PMSG_RESUME); | 
|---|
| 488 |  | 
|---|
| 489 | Platform_finish: | 
|---|
| 490 | platform_resume_finish(state); | 
|---|
| 491 | return error; | 
|---|
| 492 | } | 
|---|
| 493 |  | 
|---|
| 494 | /** | 
|---|
| 495 | * suspend_devices_and_enter - Suspend devices and enter system sleep state. | 
|---|
| 496 | * @state: System sleep state to enter. | 
|---|
| 497 | */ | 
|---|
| 498 | int suspend_devices_and_enter(suspend_state_t state) | 
|---|
| 499 | { | 
|---|
| 500 | int error; | 
|---|
| 501 | bool wakeup = false; | 
|---|
| 502 |  | 
|---|
| 503 | if (!sleep_state_supported(state)) | 
|---|
| 504 | return -ENOSYS; | 
|---|
| 505 |  | 
|---|
| 506 | pm_suspend_target_state = state; | 
|---|
| 507 |  | 
|---|
| 508 | if (state == PM_SUSPEND_TO_IDLE) | 
|---|
| 509 | pm_set_suspend_no_platform(); | 
|---|
| 510 |  | 
|---|
| 511 | error = platform_suspend_begin(state); | 
|---|
| 512 | if (error) | 
|---|
| 513 | goto Close; | 
|---|
| 514 |  | 
|---|
| 515 | console_suspend_all(); | 
|---|
| 516 | suspend_test_start(); | 
|---|
| 517 | error = dpm_suspend_start(PMSG_SUSPEND); | 
|---|
| 518 | if (error) { | 
|---|
| 519 | pr_err( "Some devices failed to suspend, or early wake event detected\n"); | 
|---|
| 520 | goto Recover_platform; | 
|---|
| 521 | } | 
|---|
| 522 | suspend_test_finish(label: "suspend devices"); | 
|---|
| 523 | if (suspend_test(level: TEST_DEVICES)) | 
|---|
| 524 | goto Recover_platform; | 
|---|
| 525 |  | 
|---|
| 526 | do { | 
|---|
| 527 | error = suspend_enter(state, wakeup: &wakeup); | 
|---|
| 528 | } while (!error && !wakeup && platform_suspend_again(state)); | 
|---|
| 529 |  | 
|---|
| 530 | Resume_devices: | 
|---|
| 531 | suspend_test_start(); | 
|---|
| 532 | dpm_resume_end(PMSG_RESUME); | 
|---|
| 533 | suspend_test_finish(label: "resume devices"); | 
|---|
| 534 | trace_suspend_resume(TPS( "console_resume_all"), val: state, start: true); | 
|---|
| 535 | console_resume_all(); | 
|---|
| 536 | trace_suspend_resume(TPS( "console_resume_all"), val: state, start: false); | 
|---|
| 537 |  | 
|---|
| 538 | Close: | 
|---|
| 539 | platform_resume_end(state); | 
|---|
| 540 | pm_suspend_target_state = PM_SUSPEND_ON; | 
|---|
| 541 | return error; | 
|---|
| 542 |  | 
|---|
| 543 | Recover_platform: | 
|---|
| 544 | platform_recover(state); | 
|---|
| 545 | goto Resume_devices; | 
|---|
| 546 | } | 
|---|
| 547 |  | 
|---|
| 548 | /** | 
|---|
| 549 | * suspend_finish - Clean up before finishing the suspend sequence. | 
|---|
| 550 | * | 
|---|
| 551 | * Call platform code to clean up, restart processes, and free the console that | 
|---|
| 552 | * we've allocated. This routine is not called for hibernation. | 
|---|
| 553 | */ | 
|---|
| 554 | static void suspend_finish(void) | 
|---|
| 555 | { | 
|---|
| 556 | suspend_thaw_processes(); | 
|---|
| 557 | filesystems_thaw(); | 
|---|
| 558 | pm_notifier_call_chain(PM_POST_SUSPEND); | 
|---|
| 559 | pm_restore_console(); | 
|---|
| 560 | } | 
|---|
| 561 |  | 
|---|
| 562 | /** | 
|---|
| 563 | * enter_state - Do common work needed to enter system sleep state. | 
|---|
| 564 | * @state: System sleep state to enter. | 
|---|
| 565 | * | 
|---|
| 566 | * Make sure that no one else is trying to put the system into a sleep state. | 
|---|
| 567 | * Fail if that's not the case.  Otherwise, prepare for system suspend, make the | 
|---|
| 568 | * system enter the given sleep state and clean up after wakeup. | 
|---|
| 569 | */ | 
|---|
| 570 | static int enter_state(suspend_state_t state) | 
|---|
| 571 | { | 
|---|
| 572 | int error; | 
|---|
| 573 |  | 
|---|
| 574 | trace_suspend_resume(TPS( "suspend_enter"), val: state, start: true); | 
|---|
| 575 | if (state == PM_SUSPEND_TO_IDLE) { | 
|---|
| 576 | #ifdef CONFIG_PM_DEBUG | 
|---|
| 577 | if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) { | 
|---|
| 578 | pr_warn( "Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n"); | 
|---|
| 579 | return -EAGAIN; | 
|---|
| 580 | } | 
|---|
| 581 | #endif | 
|---|
| 582 | } else if (!valid_state(state)) { | 
|---|
| 583 | return -EINVAL; | 
|---|
| 584 | } | 
|---|
| 585 | if (!mutex_trylock(lock: &system_transition_mutex)) | 
|---|
| 586 | return -EBUSY; | 
|---|
| 587 |  | 
|---|
| 588 | if (state == PM_SUSPEND_TO_IDLE) | 
|---|
| 589 | s2idle_begin(); | 
|---|
| 590 |  | 
|---|
| 591 | if (sync_on_suspend_enabled) { | 
|---|
| 592 | trace_suspend_resume(TPS( "sync_filesystems"), val: 0, start: true); | 
|---|
| 593 | ksys_sync_helper(); | 
|---|
| 594 | trace_suspend_resume(TPS( "sync_filesystems"), val: 0, start: false); | 
|---|
| 595 | } | 
|---|
| 596 |  | 
|---|
| 597 | pm_pr_dbg( "Preparing system for sleep (%s)\n", mem_sleep_labels[state]); | 
|---|
| 598 | pm_wakeup_clear(irq_number: 0); | 
|---|
| 599 | pm_suspend_clear_flags(); | 
|---|
| 600 | error = suspend_prepare(state); | 
|---|
| 601 | if (error) | 
|---|
| 602 | goto Unlock; | 
|---|
| 603 |  | 
|---|
| 604 | if (suspend_test(level: TEST_FREEZER)) | 
|---|
| 605 | goto Finish; | 
|---|
| 606 |  | 
|---|
| 607 | trace_suspend_resume(TPS( "suspend_enter"), val: state, start: false); | 
|---|
| 608 | pm_pr_dbg( "Suspending system (%s)\n", mem_sleep_labels[state]); | 
|---|
| 609 | error = suspend_devices_and_enter(state); | 
|---|
| 610 |  | 
|---|
| 611 | Finish: | 
|---|
| 612 | events_check_enabled = false; | 
|---|
| 613 | pm_pr_dbg( "Finishing wakeup.\n"); | 
|---|
| 614 | suspend_finish(); | 
|---|
| 615 | Unlock: | 
|---|
| 616 | mutex_unlock(lock: &system_transition_mutex); | 
|---|
| 617 | return error; | 
|---|
| 618 | } | 
|---|
| 619 |  | 
|---|
| 620 | /** | 
|---|
| 621 | * pm_suspend - Externally visible function for suspending the system. | 
|---|
| 622 | * @state: System sleep state to enter. | 
|---|
| 623 | * | 
|---|
| 624 | * Check if the value of @state represents one of the supported states, | 
|---|
| 625 | * execute enter_state() and update system suspend statistics. | 
|---|
| 626 | */ | 
|---|
| 627 | int pm_suspend(suspend_state_t state) | 
|---|
| 628 | { | 
|---|
| 629 | int error; | 
|---|
| 630 |  | 
|---|
| 631 | if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) | 
|---|
| 632 | return -EINVAL; | 
|---|
| 633 |  | 
|---|
| 634 | pr_info( "suspend entry (%s)\n", mem_sleep_labels[state]); | 
|---|
| 635 | error = enter_state(state); | 
|---|
| 636 | dpm_save_errno(err: error); | 
|---|
| 637 | pr_info( "suspend exit\n"); | 
|---|
| 638 | return error; | 
|---|
| 639 | } | 
|---|
| 640 | EXPORT_SYMBOL(pm_suspend); | 
|---|
| 641 |  | 
|---|