| 1 | |
| 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 <[email protected]>, 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, 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 |
|
| 113 | wake_up_all_idle_cpus();
|
| 114 |
|
| 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, 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(&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 |
|
| 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 | int i;
|
| 348 |
|
| 349 | if (pm_test_level == level) {
|
| 350 | pr_info("suspend debug: Waiting for %d second(s).\n",
|
| 351 | pm_test_delay);
|
| 352 | for (i = 0; i < pm_test_delay && !pm_wakeup_pending(); i++) {
|
| 353 | if (level > TEST_CORE)
|
| 354 | msleep(1000);
|
| 355 | else
|
| 356 | mdelay(1000);
|
| 357 | }
|
| 358 | return 1;
|
| 359 | }
|
| 360 | #endif
|
| 361 | return 0;
|
| 362 | }
|
| 363 |
|
| 364 | |
| 365 | * suspend_prepare - Prepare for entering system sleep state.
|
| 366 | * @state: Target system sleep state.
|
| 367 | *
|
| 368 | * Common code run for every system sleep state that can be entered (except for
|
| 369 | * hibernation). Run suspend notifiers, allocate the "suspend" console and
|
| 370 | * freeze processes.
|
| 371 |
|
| 372 | static int suspend_prepare(suspend_state_t state)
|
| 373 | {
|
| 374 | int error;
|
| 375 |
|
| 376 | if (!sleep_state_supported(state))
|
| 377 | return -EPERM;
|
| 378 |
|
| 379 | pm_prepare_console();
|
| 380 |
|
| 381 | error = pm_notifier_call_chain_robust(PM_SUSPEND_PREPARE, PM_POST_SUSPEND);
|
| 382 | if (error)
|
| 383 | goto Restore;
|
| 384 |
|
| 385 | filesystems_freeze(filesystem_freeze_enabled);
|
| 386 | trace_suspend_resume(TPS("freeze_processes"), 0, true);
|
| 387 | error = suspend_freeze_processes();
|
| 388 | trace_suspend_resume(TPS("freeze_processes"), 0, false);
|
| 389 | if (!error)
|
| 390 | return 0;
|
| 391 |
|
| 392 | dpm_save_failed_step(SUSPEND_FREEZE);
|
| 393 | filesystems_thaw();
|
| 394 | pm_notifier_call_chain(PM_POST_SUSPEND);
|
| 395 | Restore:
|
| 396 | pm_restore_console();
|
| 397 | return error;
|
| 398 | }
|
| 399 |
|
| 400 |
|
| 401 | void __weak arch_suspend_disable_irqs(void)
|
| 402 | {
|
| 403 | local_irq_disable();
|
| 404 | }
|
| 405 |
|
| 406 |
|
| 407 | void __weak arch_suspend_enable_irqs(void)
|
| 408 | {
|
| 409 | local_irq_enable();
|
| 410 | }
|
| 411 |
|
| 412 | |
| 413 | * suspend_enter - Make the system enter the given sleep state.
|
| 414 | * @state: System sleep state to enter.
|
| 415 | * @wakeup: Returns information that the sleep state should not be re-entered.
|
| 416 | *
|
| 417 | * This function should be called after devices have been suspended.
|
| 418 |
|
| 419 | static int suspend_enter(suspend_state_t state, bool *wakeup)
|
| 420 | {
|
| 421 | int error;
|
| 422 |
|
| 423 | error = platform_suspend_prepare(state);
|
| 424 | if (error)
|
| 425 | goto Platform_finish;
|
| 426 |
|
| 427 | error = dpm_suspend_late(PMSG_SUSPEND);
|
| 428 | if (error) {
|
| 429 | pr_err("late suspend of devices failed\n");
|
| 430 | goto Platform_finish;
|
| 431 | }
|
| 432 | error = platform_suspend_prepare_late(state);
|
| 433 | if (error)
|
| 434 | goto Devices_early_resume;
|
| 435 |
|
| 436 | error = dpm_suspend_noirq(PMSG_SUSPEND);
|
| 437 | if (error) {
|
| 438 | pr_err("noirq suspend of devices failed\n");
|
| 439 | goto Platform_early_resume;
|
| 440 | }
|
| 441 | error = platform_suspend_prepare_noirq(state);
|
| 442 | if (error)
|
| 443 | goto Platform_wake;
|
| 444 |
|
| 445 | if (suspend_test(TEST_PLATFORM))
|
| 446 | goto Platform_wake;
|
| 447 |
|
| 448 | if (state == PM_SUSPEND_TO_IDLE) {
|
| 449 | s2idle_loop();
|
| 450 | goto Platform_wake;
|
| 451 | }
|
| 452 |
|
| 453 | error = pm_sleep_disable_secondary_cpus();
|
| 454 | if (error || suspend_test(TEST_CPUS))
|
| 455 | goto Enable_cpus;
|
| 456 |
|
| 457 | arch_suspend_disable_irqs();
|
| 458 | BUG_ON(!irqs_disabled());
|
| 459 |
|
| 460 | system_state = SYSTEM_SUSPEND;
|
| 461 |
|
| 462 | error = syscore_suspend();
|
| 463 | if (!error) {
|
| 464 | *wakeup = pm_wakeup_pending();
|
| 465 | if (!(suspend_test(TEST_CORE) || *wakeup)) {
|
| 466 | trace_suspend_resume(TPS("machine_suspend"),
|
| 467 | state, true);
|
| 468 | error = suspend_ops->enter(state);
|
| 469 | trace_suspend_resume(TPS("machine_suspend"),
|
| 470 | state, false);
|
| 471 | } else if (*wakeup) {
|
| 472 | error = -EBUSY;
|
| 473 | }
|
| 474 | syscore_resume();
|
| 475 | }
|
| 476 |
|
| 477 | system_state = SYSTEM_RUNNING;
|
| 478 |
|
| 479 | arch_suspend_enable_irqs();
|
| 480 | BUG_ON(irqs_disabled());
|
| 481 |
|
| 482 | Enable_cpus:
|
| 483 | pm_sleep_enable_secondary_cpus();
|
| 484 |
|
| 485 | Platform_wake:
|
| 486 | platform_resume_noirq(state);
|
| 487 | dpm_resume_noirq(PMSG_RESUME);
|
| 488 |
|
| 489 | Platform_early_resume:
|
| 490 | platform_resume_early(state);
|
| 491 |
|
| 492 | Devices_early_resume:
|
| 493 | dpm_resume_early(PMSG_RESUME);
|
| 494 |
|
| 495 | Platform_finish:
|
| 496 | platform_resume_finish(state);
|
| 497 | return error;
|
| 498 | }
|
| 499 |
|
| 500 | |
| 501 | * suspend_devices_and_enter - Suspend devices and enter system sleep state.
|
| 502 | * @state: System sleep state to enter.
|
| 503 |
|
| 504 | int suspend_devices_and_enter(suspend_state_t state)
|
| 505 | {
|
| 506 | int error;
|
| 507 | bool wakeup = false;
|
| 508 |
|
| 509 | if (!sleep_state_supported(state))
|
| 510 | return -ENOSYS;
|
| 511 |
|
| 512 | pm_suspend_target_state = state;
|
| 513 |
|
| 514 | if (state == PM_SUSPEND_TO_IDLE)
|
| 515 | pm_set_suspend_no_platform();
|
| 516 |
|
| 517 | error = platform_suspend_begin(state);
|
| 518 | if (error)
|
| 519 | goto Close;
|
| 520 |
|
| 521 | console_suspend_all();
|
| 522 | suspend_test_start();
|
| 523 | error = dpm_suspend_start(PMSG_SUSPEND);
|
| 524 | if (error) {
|
| 525 | pr_err("Some devices failed to suspend, or early wake event detected\n");
|
| 526 | goto Recover_platform;
|
| 527 | }
|
| 528 | suspend_test_finish("suspend devices");
|
| 529 | if (suspend_test(TEST_DEVICES))
|
| 530 | goto Recover_platform;
|
| 531 |
|
| 532 | do {
|
| 533 | error = suspend_enter(state, &wakeup);
|
| 534 | } while (!error && !wakeup && platform_suspend_again(state));
|
| 535 |
|
| 536 | Resume_devices:
|
| 537 | suspend_test_start();
|
| 538 | dpm_resume_end(PMSG_RESUME);
|
| 539 | suspend_test_finish("resume devices");
|
| 540 | trace_suspend_resume(TPS("console_resume_all"), state, true);
|
| 541 | console_resume_all();
|
| 542 | trace_suspend_resume(TPS("console_resume_all"), state, false);
|
| 543 |
|
| 544 | Close:
|
| 545 | platform_resume_end(state);
|
| 546 | pm_suspend_target_state = PM_SUSPEND_ON;
|
| 547 | return error;
|
| 548 |
|
| 549 | Recover_platform:
|
| 550 | platform_recover(state);
|
| 551 | goto Resume_devices;
|
| 552 | }
|
| 553 |
|
| 554 | |
| 555 | * suspend_finish - Clean up before finishing the suspend sequence.
|
| 556 | *
|
| 557 | * Call platform code to clean up, restart processes, and free the console that
|
| 558 | * we've allocated. This routine is not called for hibernation.
|
| 559 |
|
| 560 | static void suspend_finish(void)
|
| 561 | {
|
| 562 | suspend_thaw_processes();
|
| 563 | filesystems_thaw();
|
| 564 | pm_notifier_call_chain(PM_POST_SUSPEND);
|
| 565 | pm_restore_console();
|
| 566 | }
|
| 567 |
|
| 568 | |
| 569 | * enter_state - Do common work needed to enter system sleep state.
|
| 570 | * @state: System sleep state to enter.
|
| 571 | *
|
| 572 | * Make sure that no one else is trying to put the system into a sleep state.
|
| 573 | * Fail if that's not the case. Otherwise, prepare for system suspend, make the
|
| 574 | * system enter the given sleep state and clean up after wakeup.
|
| 575 |
|
| 576 | static int enter_state(suspend_state_t state)
|
| 577 | {
|
| 578 | int error;
|
| 579 |
|
| 580 | trace_suspend_resume(TPS("suspend_enter"), state, true);
|
| 581 | if (state == PM_SUSPEND_TO_IDLE) {
|
| 582 | #ifdef CONFIG_PM_DEBUG
|
| 583 | if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {
|
| 584 | pr_warn("Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n");
|
| 585 | return -EAGAIN;
|
| 586 | }
|
| 587 | #endif
|
| 588 | } else if (!valid_state(state)) {
|
| 589 | return -EINVAL;
|
| 590 | }
|
| 591 | if (!mutex_trylock(&system_transition_mutex))
|
| 592 | return -EBUSY;
|
| 593 |
|
| 594 | if (state == PM_SUSPEND_TO_IDLE)
|
| 595 | s2idle_begin();
|
| 596 |
|
| 597 | if (sync_on_suspend_enabled) {
|
| 598 | trace_suspend_resume(TPS("sync_filesystems"), 0, true);
|
| 599 |
|
| 600 | error = pm_sleep_fs_sync();
|
| 601 | if (error)
|
| 602 | goto Unlock;
|
| 603 |
|
| 604 | trace_suspend_resume(TPS("sync_filesystems"), 0, false);
|
| 605 | }
|
| 606 |
|
| 607 | pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
|
| 608 | pm_suspend_clear_flags();
|
| 609 | error = suspend_prepare(state);
|
| 610 | if (error)
|
| 611 | goto Unlock;
|
| 612 |
|
| 613 | if (suspend_test(TEST_FREEZER))
|
| 614 | goto Finish;
|
| 615 |
|
| 616 | trace_suspend_resume(TPS("suspend_enter"), state, false);
|
| 617 | pm_pr_dbg("Suspending system (%s)\n", mem_sleep_labels[state]);
|
| 618 | error = suspend_devices_and_enter(state);
|
| 619 |
|
| 620 | Finish:
|
| 621 | events_check_enabled = false;
|
| 622 | pm_pr_dbg("Finishing wakeup.\n");
|
| 623 | suspend_finish();
|
| 624 | Unlock:
|
| 625 | mutex_unlock(&system_transition_mutex);
|
| 626 | return error;
|
| 627 | }
|
| 628 |
|
| 629 | |
| 630 | * pm_suspend - Externally visible function for suspending the system.
|
| 631 | * @state: System sleep state to enter.
|
| 632 | *
|
| 633 | * Check if the value of @state represents one of the supported states,
|
| 634 | * execute enter_state() and update system suspend statistics.
|
| 635 |
|
| 636 | int pm_suspend(suspend_state_t state)
|
| 637 | {
|
| 638 | int error;
|
| 639 |
|
| 640 | if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
|
| 641 | return -EINVAL;
|
| 642 |
|
| 643 | pr_info("suspend entry (%s)\n", mem_sleep_labels[state]);
|
| 644 | error = enter_state(state);
|
| 645 | dpm_save_errno(error);
|
| 646 | pr_info("suspend exit\n");
|
| 647 | return error;
|
| 648 | }
|
| 649 | EXPORT_SYMBOL(pm_suspend);
|