hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/kernel/power/suspend.c
....@@ -1,11 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * kernel/power/suspend.c - Suspend to RAM and standby functionality.
34 *
45 * Copyright (c) 2003 Patrick Mochel
56 * Copyright (c) 2003 Open Source Development Lab
67 * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
7
- *
8
- * This file is released under the GPLv2.
98 */
109
1110 #define pr_fmt(fmt) "PM: " fmt
....@@ -17,7 +16,6 @@
1716 #include <linux/console.h>
1817 #include <linux/cpu.h>
1918 #include <linux/cpuidle.h>
20
-#include <linux/syscalls.h>
2119 #include <linux/gfp.h>
2220 #include <linux/io.h>
2321 #include <linux/kernel.h>
....@@ -46,8 +44,6 @@
4644 [PM_SUSPEND_TO_IDLE] = "s2idle",
4745 [PM_SUSPEND_STANDBY] = "shallow",
4846 [PM_SUSPEND_MEM] = "deep",
49
- [PM_SUSPEND_MEM_LITE] = "lite",
50
- [PM_SUSPEND_MEM_ULTRA] = "ultra",
5147 };
5248 const char *mem_sleep_states[PM_SUSPEND_MAX];
5349
....@@ -66,11 +62,17 @@
6662 enum s2idle_states __read_mostly s2idle_state;
6763 static DEFINE_RAW_SPINLOCK(s2idle_lock);
6864
69
-bool pm_suspend_via_s2idle(void)
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)
7072 {
7173 return mem_sleep_current == PM_SUSPEND_TO_IDLE;
7274 }
73
-EXPORT_SYMBOL_GPL(pm_suspend_via_s2idle);
75
+EXPORT_SYMBOL_GPL(pm_suspend_default_s2idle);
7476
7577 void s2idle_set_ops(const struct platform_s2idle_ops *ops)
7678 {
....@@ -78,7 +80,6 @@
7880 s2idle_ops = ops;
7981 unlock_system_sleep();
8082 }
81
-EXPORT_SYMBOL_GPL(s2idle_set_ops);
8283
8384 static void s2idle_begin(void)
8485 {
....@@ -121,44 +122,25 @@
121122 {
122123 pm_pr_dbg("suspend-to-idle\n");
123124
125
+ /*
126
+ * Suspend-to-idle equals:
127
+ * frozen processes + suspended devices + idle processors.
128
+ * Thus s2idle_enter() should be called right after all devices have
129
+ * been suspended.
130
+ *
131
+ * Wakeups during the noirq suspend of devices may be spurious, so try
132
+ * to avoid them upfront.
133
+ */
124134 for (;;) {
125
- int error;
126
-
127
- dpm_noirq_begin();
128
-
129
- /*
130
- * Suspend-to-idle equals
131
- * frozen processes + suspended devices + idle processors.
132
- * Thus s2idle_enter() should be called right after
133
- * all devices have been suspended.
134
- *
135
- * Wakeups during the noirq suspend of devices may be spurious,
136
- * so prevent them from terminating the loop right away.
137
- */
138
- error = dpm_noirq_suspend_devices(PMSG_SUSPEND);
139
- if (!error)
140
- s2idle_enter();
141
- else if (error == -EBUSY && pm_wakeup_pending())
142
- error = 0;
143
-
144
- if (!error && s2idle_ops && s2idle_ops->wake)
145
- s2idle_ops->wake();
146
-
147
- dpm_noirq_resume_devices(PMSG_RESUME);
148
-
149
- dpm_noirq_end();
150
-
151
- if (error)
135
+ if (s2idle_ops && s2idle_ops->wake) {
136
+ if (s2idle_ops->wake())
137
+ break;
138
+ } else if (pm_wakeup_pending()) {
152139 break;
140
+ }
153141
154
- if (s2idle_ops && s2idle_ops->sync)
155
- s2idle_ops->sync();
156
-
157
- if (pm_wakeup_pending())
158
- break;
159
-
160
- pm_wakeup_clear(false);
161142 clear_wakeup_reasons();
143
+ s2idle_enter();
162144 }
163145
164146 pm_pr_dbg("resume from suspend-to-idle\n");
....@@ -232,8 +214,6 @@
232214 }
233215 if (valid_state(PM_SUSPEND_MEM)) {
234216 mem_sleep_states[PM_SUSPEND_MEM] = mem_sleep_labels[PM_SUSPEND_MEM];
235
- mem_sleep_states[PM_SUSPEND_MEM_LITE] = mem_sleep_labels[PM_SUSPEND_MEM_LITE];
236
- mem_sleep_states[PM_SUSPEND_MEM_ULTRA] = mem_sleep_labels[PM_SUSPEND_MEM_ULTRA];
237217 if (mem_sleep_default >= PM_SUSPEND_MEM)
238218 mem_sleep_current = PM_SUSPEND_MEM;
239219 }
....@@ -274,14 +254,21 @@
274254
275255 static int platform_suspend_prepare_noirq(suspend_state_t state)
276256 {
277
- return state != PM_SUSPEND_TO_IDLE && suspend_ops->prepare_late ?
278
- suspend_ops->prepare_late() : 0;
257
+ if (state == PM_SUSPEND_TO_IDLE)
258
+ return s2idle_ops && s2idle_ops->prepare_late ?
259
+ s2idle_ops->prepare_late() : 0;
260
+
261
+ return suspend_ops->prepare_late ? suspend_ops->prepare_late() : 0;
279262 }
280263
281264 static void platform_resume_noirq(suspend_state_t state)
282265 {
283
- if (state != PM_SUSPEND_TO_IDLE && suspend_ops->wake)
266
+ if (state == PM_SUSPEND_TO_IDLE) {
267
+ if (s2idle_ops && s2idle_ops->restore_early)
268
+ s2idle_ops->restore_early();
269
+ } else if (suspend_ops->wake) {
284270 suspend_ops->wake();
271
+ }
285272 }
286273
287274 static void platform_resume_early(suspend_state_t state)
....@@ -355,18 +342,16 @@
355342 */
356343 static int suspend_prepare(suspend_state_t state)
357344 {
358
- int error, nr_calls = 0;
345
+ int error;
359346
360347 if (!sleep_state_supported(state))
361348 return -EPERM;
362349
363350 pm_prepare_console();
364351
365
- error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls);
366
- if (error) {
367
- nr_calls--;
368
- goto Finish;
369
- }
352
+ error = pm_notifier_call_chain_robust(PM_SUSPEND_PREPARE, PM_POST_SUSPEND);
353
+ if (error)
354
+ goto Restore;
370355
371356 trace_suspend_resume(TPS("freeze_processes"), 0, true);
372357 error = suspend_freeze_processes();
....@@ -377,8 +362,8 @@
377362 log_suspend_abort_reason("One or more tasks refusing to freeze");
378363 suspend_stats.failed_freeze++;
379364 dpm_save_failed_step(SUSPEND_FREEZE);
380
- Finish:
381
- __pm_notifier_call_chain(PM_POST_SUSPEND, nr_calls, NULL);
365
+ pm_notifier_call_chain(PM_POST_SUSPEND);
366
+ Restore:
382367 pm_restore_console();
383368 return error;
384369 }
....@@ -423,11 +408,6 @@
423408 if (error)
424409 goto Devices_early_resume;
425410
426
- if (state == PM_SUSPEND_TO_IDLE && pm_test_level != TEST_PLATFORM) {
427
- s2idle_loop();
428
- goto Platform_early_resume;
429
- }
430
-
431411 error = dpm_suspend_noirq(PMSG_SUSPEND);
432412 if (error) {
433413 last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
....@@ -444,7 +424,12 @@
444424 if (suspend_test(TEST_PLATFORM))
445425 goto Platform_wake;
446426
447
- error = disable_nonboot_cpus();
427
+ if (state == PM_SUSPEND_TO_IDLE) {
428
+ s2idle_loop();
429
+ goto Platform_wake;
430
+ }
431
+
432
+ error = suspend_disable_secondary_cpus();
448433 if (error || suspend_test(TEST_CPUS)) {
449434 log_suspend_abort_reason("Disabling non-boot cpus failed");
450435 goto Enable_cpus;
....@@ -476,7 +461,7 @@
476461 BUG_ON(irqs_disabled());
477462
478463 Enable_cpus:
479
- enable_nonboot_cpus();
464
+ suspend_enable_secondary_cpus();
480465
481466 Platform_wake:
482467 platform_resume_noirq(state);
....@@ -506,6 +491,9 @@
506491 return -ENOSYS;
507492
508493 pm_suspend_target_state = state;
494
+
495
+ if (state == PM_SUSPEND_TO_IDLE)
496
+ pm_set_suspend_no_platform();
509497
510498 error = platform_suspend_begin(state);
511499 if (error)
....@@ -588,13 +576,11 @@
588576 if (state == PM_SUSPEND_TO_IDLE)
589577 s2idle_begin();
590578
591
-#ifndef CONFIG_SUSPEND_SKIP_SYNC
592
- trace_suspend_resume(TPS("sync_filesystems"), 0, true);
593
- pr_info("Syncing filesystems ... ");
594
- ksys_sync();
595
- pr_cont("done.\n");
596
- trace_suspend_resume(TPS("sync_filesystems"), 0, false);
597
-#endif
579
+ if (sync_on_suspend_enabled) {
580
+ trace_suspend_resume(TPS("sync_filesystems"), 0, true);
581
+ ksys_sync_helper();
582
+ trace_suspend_resume(TPS("sync_filesystems"), 0, false);
583
+ }
598584
599585 pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
600586 pm_suspend_clear_flags();
....@@ -620,8 +606,6 @@
620606 return error;
621607 }
622608
623
-bool pm_in_action;
624
-
625609 /**
626610 * pm_suspend - Externally visible function for suspending the system.
627611 * @state: System sleep state to enter.
....@@ -636,12 +620,7 @@
636620 if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
637621 return -EINVAL;
638622
639
- pm_in_action = true;
640623 pr_info("suspend entry (%s)\n", mem_sleep_labels[state]);
641
-
642
- if (state == PM_SUSPEND_MEM_LITE || state == PM_SUSPEND_MEM_ULTRA)
643
- state = PM_SUSPEND_MEM;
644
-
645624 error = enter_state(state);
646625 if (error) {
647626 suspend_stats.fail++;
....@@ -650,7 +629,6 @@
650629 suspend_stats.success++;
651630 }
652631 pr_info("suspend exit\n");
653
- pm_in_action = false;
654632 return error;
655633 }
656634 EXPORT_SYMBOL(pm_suspend);