blob: 3b10d8612aea39e0ad48c182ef6980bf2baaa02a [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * kernel/power/suspend.c - Suspend to RAM and standby functionality.
3 *
4 * Copyright (c) 2003 Patrick Mochel
5 * Copyright (c) 2003 Open Source Development Lab
6 * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
7 *
8 * This file is released under the GPLv2.
9 */
10
11#include <linux/string.h>
12#include <linux/delay.h>
13#include <linux/errno.h>
14#include <linux/init.h>
15#include <linux/console.h>
16#include <linux/cpu.h>
17#include <linux/syscalls.h>
18#include <linux/gfp.h>
19#include <linux/io.h>
20#include <linux/kernel.h>
21#include <linux/list.h>
22#include <linux/mm.h>
23#include <linux/slab.h>
24#include <linux/export.h>
25#include <linux/suspend.h>
26#include <linux/syscore_ops.h>
27#include <linux/ftrace.h>
28#include <linux/rtc.h>
29#include <trace/events/power.h>
30
31#include "power.h"
32
33const char *const pm_states[PM_SUSPEND_MAX] = {
34 [PM_SUSPEND_STANDBY] = "standby",
35 [PM_SUSPEND_MEM] = "mem",
36};
37
38static const struct platform_suspend_ops *suspend_ops;
39
40/**
41 * suspend_set_ops - Set the global suspend method table.
42 * @ops: Suspend operations to use.
43 */
44void suspend_set_ops(const struct platform_suspend_ops *ops)
45{
46 lock_system_sleep();
47 suspend_ops = ops;
48 unlock_system_sleep();
49}
50EXPORT_SYMBOL_GPL(suspend_set_ops);
51
52bool valid_state(suspend_state_t state)
53{
54 /*
55 * All states need lowlevel support and need to be valid to the lowlevel
56 * implementation, no valid callback implies that none are valid.
57 */
58 return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
59}
60
61/**
62 * suspend_valid_only_mem - Generic memory-only valid callback.
63 *
64 * Platform drivers that implement mem suspend only and only need to check for
65 * that in their .valid() callback can use this instead of rolling their own
66 * .valid() callback.
67 */
68int suspend_valid_only_mem(suspend_state_t state)
69{
70 return state == PM_SUSPEND_MEM;
71}
72EXPORT_SYMBOL_GPL(suspend_valid_only_mem);
73
74static int suspend_test(int level)
75{
76#ifdef CONFIG_PM_DEBUG
77 if (pm_test_level == level) {
78 printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
79 mdelay(5000);
80 return 1;
81 }
82#endif /* !CONFIG_PM_DEBUG */
83 return 0;
84}
85
86/**
87 * suspend_prepare - Prepare for entering system sleep state.
88 *
89 * Common code run for every system sleep state that can be entered (except for
90 * hibernation). Run suspend notifiers, allocate the "suspend" console and
91 * freeze processes.
92 */
93static int suspend_prepare(void)
94{
95 int error;
96
97 if (!suspend_ops || !suspend_ops->enter)
98 return -EPERM;
99
100 pm_prepare_console();
101
102 error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
103 if (error)
104 goto Finish;
105
106 error = suspend_freeze_processes();
107 if (!error)
108 return 0;
109
110 suspend_stats.failed_freeze++;
111 dpm_save_failed_step(SUSPEND_FREEZE);
112 Finish:
113 pm_notifier_call_chain(PM_POST_SUSPEND);
114 pm_restore_console();
115 return error;
116}
117
118/* default implementation */
119void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
120{
121 local_irq_disable();
122}
123
124/* default implementation */
125void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
126{
127 local_irq_enable();
128}
129
130/**
131 * suspend_enter - Make the system enter the given sleep state.
132 * @state: System sleep state to enter.
133 * @wakeup: Returns information that the sleep state should not be re-entered.
134 *
135 * This function should be called after devices have been suspended.
136 */
137static int suspend_enter(suspend_state_t state, bool *wakeup)
138{
139 int error;
140
141 if (suspend_ops->prepare) {
142 error = suspend_ops->prepare();
143 if (error)
144 goto Platform_finish;
145 }
146
147 error = dpm_suspend_end(PMSG_SUSPEND);
148 if (error) {
149 PSM_DBG("PM: Some devices failed to power down;");
150 goto Platform_finish;
151 }
152
153 if (suspend_ops->prepare_late) {
154 error = suspend_ops->prepare_late();
155 if (error)
156 goto Platform_wake;
157 }
158
159 if (suspend_test(TEST_PLATFORM))
160 goto Platform_wake;
161
162 error = disable_nonboot_cpus();
163 if (error || suspend_test(TEST_CPUS))
164 goto Enable_cpus;
165
166 arch_suspend_disable_irqs();
167 BUG_ON(!irqs_disabled());
168
169 system_state = SYSTEM_SUSPEND;
170
171 error = syscore_suspend();
172 if (!error) {
173 *wakeup = pm_wakeup_pending();
174 PSM_DBG("wakeupcnt = %d", *wakeup);
175 if (!(suspend_test(TEST_CORE) || *wakeup)) {
176 error = suspend_ops->enter(state);
177 events_check_enabled = false;
178 PSM_DBG("pm enter error = %d", error);
179 }
180 syscore_resume();
181 }
182
183 system_state = SYSTEM_RUNNING;
184
185 arch_suspend_enable_irqs();
186 BUG_ON(irqs_disabled());
187
188 Enable_cpus:
189 enable_nonboot_cpus();
190
191 Platform_wake:
192 if (suspend_ops->wake)
193 suspend_ops->wake();
194
195 dpm_resume_start(PMSG_RESUME);
196
197 Platform_finish:
198 if (suspend_ops->finish)
199 suspend_ops->finish();
200
201 return error;
202}
203
204/**
205 * suspend_devices_and_enter - Suspend devices and enter system sleep state.
206 * @state: System sleep state to enter.
207 */
208int suspend_devices_and_enter(suspend_state_t state)
209{
210 int error;
211 bool wakeup = false;
212
213 if (!suspend_ops)
214 return -ENOSYS;
215
216 trace_machine_suspend(state);
217 if (suspend_ops->begin) {
218 error = suspend_ops->begin(state);
219 if (error)
220 goto Close;
221 }
222 suspend_console();
223 suspend_test_start();
224 error = dpm_suspend_start(PMSG_SUSPEND);
225 if (error) {
226 PSM_DBG("%s","PM: Some devices failed to suspend");
227 goto Recover_platform;
228 }
229 suspend_test_finish("suspend devices");
230 if (suspend_test(TEST_DEVICES))
231 goto Recover_platform;
232
233 do {
234 error = suspend_enter(state, &wakeup);
235 } while (!error && !wakeup
236 && suspend_ops->suspend_again && suspend_ops->suspend_again());
237
238 Resume_devices:
239 suspend_test_start();
240 dpm_resume_end(PMSG_RESUME);
241 suspend_test_finish("resume devices");
242 resume_console();
243 Close:
244 if (suspend_ops->end)
245 suspend_ops->end();
246 trace_machine_suspend(PWR_EVENT_EXIT);
247 return error;
248
249 Recover_platform:
250 if (suspend_ops->recover)
251 suspend_ops->recover();
252 goto Resume_devices;
253}
254
255/**
256 * suspend_finish - Clean up before finishing the suspend sequence.
257 *
258 * Call platform code to clean up, restart processes, and free the console that
259 * we've allocated. This routine is not called for hibernation.
260 */
261static void suspend_finish(void)
262{
263 suspend_thaw_processes();
264 pm_notifier_call_chain(PM_POST_SUSPEND);
265 pm_restore_console();
266}
267
268/**
269 * enter_state - Do common work needed to enter system sleep state.
270 * @state: System sleep state to enter.
271 *
272 * Make sure that no one else is trying to put the system into a sleep state.
273 * Fail if that's not the case. Otherwise, prepare for system suspend, make the
274 * system enter the given sleep state and clean up after wakeup.
275 */
276static int enter_state(suspend_state_t state)
277{
278 int error;
279
280 if (!valid_state(state))
281 return -ENODEV;
282
283 if (!mutex_trylock(&pm_mutex))
284 return -EBUSY;
285
286 PSM_DBG("%s:", "PM: Syncing filesystems");
287 sys_sync();
288
289 error = suspend_prepare();
290 PSM_DBG("suspend_prepare error= %d", error);
291 if (error)
292 goto Unlock;
293
294 if (suspend_test(TEST_FREEZER))
295 goto Finish;
296
297 PSM_DBG("pm_states = %d", pm_states[state]);
298 pm_restrict_gfp_mask();
299 error = suspend_devices_and_enter(state);
300 pm_restore_gfp_mask();
301
302 Finish:
303 PSM_DBG("%s", "PM Finishing wakeup");
304 suspend_finish();
305 Unlock:
306 mutex_unlock(&pm_mutex);
307 return error;
308}
309
310static void pm_suspend_marker(char *annotation)
311{
312 struct timespec ts;
313 struct rtc_time tm;
314
315 getnstimeofday(&ts);
316 rtc_time_to_tm(ts.tv_sec, &tm);
317 pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n",
318 annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
319 tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
320}
321
322/**
323 * pm_suspend - Externally visible function for suspending the system.
324 * @state: System sleep state to enter.
325 *
326 * Check if the value of @state represents one of the supported states,
327 * execute enter_state() and update system suspend statistics.
328 */
329int pm_suspend(suspend_state_t state)
330{
331 int error;
332
333 if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
334 return -EINVAL;
335
336 pm_suspend_marker("entry");
337 error = enter_state(state);
338 if (error) {
339 suspend_stats.fail++;
340 dpm_save_failed_errno(error);
341 PSM_DBG("suspend_stats.fail = %d time = %d", suspend_stats.fail, ktime_to_us(ktime_get()));
342 } else {
343 suspend_stats.success++;
344 }
345 pm_suspend_marker("exit");
346 return error;
347}
348EXPORT_SYMBOL(pm_suspend);