blob: 559acef3fddb8974348d19d3c2ad8a742b32a678 [file] [log] [blame]
Thomas Gleixner55716d22019-06-01 10:08:42 +02001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Rafael J. Wysocki8b759b82009-06-10 01:27:49 +02003 * kernel/power/hibernate.c - Hibernation (a.k.a suspend-to-disk) support.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * Copyright (c) 2003 Patrick Mochel
6 * Copyright (c) 2003 Open Source Development Lab
Pavel Macheka2531292010-07-18 14:27:13 +02007 * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
Rafael J. Wysocki8b759b82009-06-10 01:27:49 +02008 * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
Bojan Smojver62c552c2012-06-16 00:09:58 +02009 * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 */
11
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -080012#define pr_fmt(fmt) "PM: hibernation: " fmt
Rafael J. Wysocki2872de12017-02-24 00:26:15 +010013
Paul Gortmaker6e5fdee2011-05-26 16:00:52 -040014#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/suspend.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/reboot.h>
17#include <linux/string.h>
18#include <linux/device.h>
Barry Song6f8d7022011-10-06 20:34:46 +020019#include <linux/async.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/delay.h>
21#include <linux/fs.h>
Andrew Mortond53d9f12005-07-12 13:58:07 -070022#include <linux/mount.h>
Eric W. Biederman88d10bb2005-09-22 21:43:46 -070023#include <linux/pm.h>
Ingo Molnar38b8d202017-02-08 18:51:31 +010024#include <linux/nmi.h>
Rafael J. Wysocki97c78012006-10-11 01:20:45 -070025#include <linux/console.h>
Rafael J. Wysockie3920fb2006-09-25 23:32:48 -070026#include <linux/cpu.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080027#include <linux/freezer.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/gfp.h>
Rafael J. Wysocki40dc1662011-03-15 00:43:46 +010029#include <linux/syscore_ops.h>
Minho Ban2df83fa2012-05-14 21:45:31 +020030#include <linux/ctype.h>
31#include <linux/genhd.h>
Tina Ruchandanidb597602014-10-30 11:04:53 -070032#include <linux/ktime.h>
Josh Boyer38bd94b2019-08-19 17:17:46 -070033#include <linux/security.h>
Mike Rapoport9a436f82021-07-07 18:08:07 -070034#include <linux/secretmem.h>
Todd E Brandtbb3632c2014-06-06 05:40:17 -070035#include <trace/events/power.h>
Andrew Mortond53d9f12005-07-12 13:58:07 -070036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "power.h"
38
39
Barry Songd231ff12011-10-11 23:29:18 -070040static int nocompress;
41static int noresume;
Kees Cooka6e15a32014-06-13 13:30:35 -070042static int nohibernate;
Barry Songd231ff12011-10-11 23:29:18 -070043static int resume_wait;
Dan Carpenterf6514be2014-05-14 19:08:46 +030044static unsigned int resume_delay;
Adrian Bunk47a460d2008-02-04 22:30:06 -080045static char resume_file[256] = CONFIG_PM_STD_PARTITION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046dev_t swsusp_resume_device;
Rafael J. Wysocki9a154d92006-12-06 20:34:12 -080047sector_t swsusp_resume_block;
Andi Kleend6efc2f2013-08-05 15:02:49 -070048__visible int in_suspend __nosavedata;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070050enum {
51 HIBERNATION_INVALID,
52 HIBERNATION_PLATFORM,
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070053 HIBERNATION_SHUTDOWN,
54 HIBERNATION_REBOOT,
Bojan Smojver62c552c2012-06-16 00:09:58 +020055#ifdef CONFIG_SUSPEND
56 HIBERNATION_SUSPEND,
57#endif
Chen Yufe12c002016-07-22 10:30:47 +080058 HIBERNATION_TEST_RESUME,
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070059 /* keep last */
60 __HIBERNATION_AFTER_LAST
61};
62#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
63#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
64
65static int hibernation_mode = HIBERNATION_SHUTDOWN;
66
Srivatsa S. Bhat97819a22011-12-01 22:33:10 +010067bool freezer_test_done;
Srivatsa S. Bhataa9a7b12011-11-18 23:02:42 +010068
Lionel Debroux073ef1f2010-11-09 21:48:49 +010069static const struct platform_hibernation_ops *hibernation_ops;
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070070
Domenico Andreoliab7e9b02020-05-07 09:19:52 +020071static atomic_t hibernate_atomic = ATOMIC_INIT(1);
72
73bool hibernate_acquire(void)
74{
75 return atomic_add_unless(&hibernate_atomic, -1, 0);
76}
77
78void hibernate_release(void)
79{
80 atomic_inc(&hibernate_atomic);
81}
82
Kees Cooka6e15a32014-06-13 13:30:35 -070083bool hibernation_available(void)
84{
Mike Rapoport9a436f82021-07-07 18:08:07 -070085 return nohibernate == 0 &&
86 !security_locked_down(LOCKDOWN_HIBERNATION) &&
87 !secretmem_active();
Kees Cooka6e15a32014-06-13 13:30:35 -070088}
89
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070090/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +020091 * hibernation_set_ops - Set the global hibernate operations.
92 * @ops: Hibernation operations to use in subsequent hibernation transitions.
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070093 */
Lionel Debroux073ef1f2010-11-09 21:48:49 +010094void hibernation_set_ops(const struct platform_hibernation_ops *ops)
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070095{
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +010096 if (ops && !(ops->begin && ops->end && ops->pre_snapshot
97 && ops->prepare && ops->finish && ops->enter && ops->pre_restore
MyungJoo Ham5729c632010-11-26 23:07:48 +010098 && ops->restore_cleanup && ops->leave)) {
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -070099 WARN_ON(1);
100 return;
101 }
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +0100102 lock_system_sleep();
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700103 hibernation_ops = ops;
104 if (ops)
105 hibernation_mode = HIBERNATION_PLATFORM;
106 else if (hibernation_mode == HIBERNATION_PLATFORM)
107 hibernation_mode = HIBERNATION_SHUTDOWN;
108
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +0100109 unlock_system_sleep();
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700110}
Leonardo Potenzae0c78552013-11-19 12:27:41 +0000111EXPORT_SYMBOL_GPL(hibernation_set_ops);
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700112
Rafael J. Wysockiabfe2d72009-01-19 20:54:54 +0100113static bool entering_platform_hibernation;
114
115bool system_entering_hibernation(void)
116{
117 return entering_platform_hibernation;
118}
119EXPORT_SYMBOL(system_entering_hibernation);
120
Rafael J. Wysocki4cc79772007-11-19 23:42:31 +0100121#ifdef CONFIG_PM_DEBUG
122static void hibernation_debug_sleep(void)
123{
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800124 pr_info("debug: Waiting for 5 seconds.\n");
Rafael J. Wysocki4cc79772007-11-19 23:42:31 +0100125 mdelay(5000);
126}
127
Rafael J. Wysocki4cc79772007-11-19 23:42:31 +0100128static int hibernation_test(int level)
129{
130 if (pm_test_level == level) {
131 hibernation_debug_sleep();
132 return 1;
133 }
134 return 0;
135}
136#else /* !CONFIG_PM_DEBUG */
Rafael J. Wysocki4cc79772007-11-19 23:42:31 +0100137static int hibernation_test(int level) { return 0; }
138#endif /* !CONFIG_PM_DEBUG */
139
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700140/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200141 * platform_begin - Call platform to start hibernation.
142 * @platform_mode: Whether or not to use the platform driver.
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700143 */
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +0100144static int platform_begin(int platform_mode)
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700145{
146 return (platform_mode && hibernation_ops) ?
Rafael J. Wysockibb186902019-05-16 12:43:19 +0200147 hibernation_ops->begin(PMSG_FREEZE) : 0;
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +0100148}
149
150/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200151 * platform_end - Call platform to finish transition to the working state.
152 * @platform_mode: Whether or not to use the platform driver.
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +0100153 */
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +0100154static void platform_end(int platform_mode)
155{
156 if (platform_mode && hibernation_ops)
157 hibernation_ops->end();
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700158}
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200161 * platform_pre_snapshot - Call platform to prepare the machine for hibernation.
162 * @platform_mode: Whether or not to use the platform driver.
163 *
164 * Use the platform driver to prepare the system for creating a hibernate image,
165 * if so configured, and return an error code if that fails.
Stefan Seyfried8a05aac2006-12-06 20:34:21 -0800166 */
167
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700168static int platform_pre_snapshot(int platform_mode)
Stefan Seyfried8a05aac2006-12-06 20:34:21 -0800169{
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700170 return (platform_mode && hibernation_ops) ?
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700171 hibernation_ops->pre_snapshot() : 0;
Stefan Seyfried8a05aac2006-12-06 20:34:21 -0800172}
173
174/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200175 * platform_leave - Call platform to prepare a transition to the working state.
176 * @platform_mode: Whether or not to use the platform driver.
177 *
178 * Use the platform driver prepare to prepare the machine for switching to the
179 * normal mode of operation.
180 *
181 * This routine is called on one CPU with interrupts disabled.
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700182 */
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700183static void platform_leave(int platform_mode)
184{
185 if (platform_mode && hibernation_ops)
186 hibernation_ops->leave();
187}
188
189/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200190 * platform_finish - Call platform to switch the system to the working state.
191 * @platform_mode: Whether or not to use the platform driver.
192 *
193 * Use the platform driver to switch the machine to the normal mode of
194 * operation.
195 *
196 * This routine must be called after platform_prepare().
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700197 */
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700198static void platform_finish(int platform_mode)
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700199{
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700200 if (platform_mode && hibernation_ops)
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700201 hibernation_ops->finish();
202}
203
204/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200205 * platform_pre_restore - Prepare for hibernate image restoration.
206 * @platform_mode: Whether or not to use the platform driver.
207 *
208 * Use the platform driver to prepare the system for resume from a hibernation
209 * image.
210 *
211 * If the restore fails after this function has been called,
212 * platform_restore_cleanup() must be called.
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700213 */
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700214static int platform_pre_restore(int platform_mode)
215{
216 return (platform_mode && hibernation_ops) ?
217 hibernation_ops->pre_restore() : 0;
218}
219
220/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200221 * platform_restore_cleanup - Switch to the working state after failing restore.
222 * @platform_mode: Whether or not to use the platform driver.
223 *
224 * Use the platform driver to switch the system to the normal mode of operation
225 * after a failing restore.
226 *
227 * If platform_pre_restore() has been called before the failing restore, this
228 * function must be called too, regardless of the result of
229 * platform_pre_restore().
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700230 */
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700231static void platform_restore_cleanup(int platform_mode)
232{
233 if (platform_mode && hibernation_ops)
234 hibernation_ops->restore_cleanup();
235}
236
237/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200238 * platform_recover - Recover from a failure to suspend devices.
239 * @platform_mode: Whether or not to use the platform driver.
Rafael J. Wysockid8f3de02008-06-12 23:24:06 +0200240 */
Rafael J. Wysockid8f3de02008-06-12 23:24:06 +0200241static void platform_recover(int platform_mode)
242{
243 if (platform_mode && hibernation_ops && hibernation_ops->recover)
244 hibernation_ops->recover();
245}
246
247/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200248 * swsusp_show_speed - Print time elapsed between two events during hibernation.
249 * @start: Starting event.
250 * @stop: Final event.
251 * @nr_pages: Number of memory pages processed between @start and @stop.
252 * @msg: Additional diagnostic message to print.
Nigel Cunningham8e60c6a2009-12-06 16:16:07 +0100253 */
Tina Ruchandanidb597602014-10-30 11:04:53 -0700254void swsusp_show_speed(ktime_t start, ktime_t stop,
255 unsigned nr_pages, char *msg)
Nigel Cunningham8e60c6a2009-12-06 16:16:07 +0100256{
Tina Ruchandanidb597602014-10-30 11:04:53 -0700257 ktime_t diff;
Chen Gang4881f602014-04-25 08:44:59 +0800258 u64 elapsed_centisecs64;
259 unsigned int centisecs;
260 unsigned int k;
261 unsigned int kps;
Nigel Cunningham8e60c6a2009-12-06 16:16:07 +0100262
Tina Ruchandanidb597602014-10-30 11:04:53 -0700263 diff = ktime_sub(stop, start);
264 elapsed_centisecs64 = ktime_divns(diff, 10*NSEC_PER_MSEC);
Nigel Cunningham8e60c6a2009-12-06 16:16:07 +0100265 centisecs = elapsed_centisecs64;
266 if (centisecs == 0)
267 centisecs = 1; /* avoid div-by-zero */
268 k = nr_pages * (PAGE_SIZE / 1024);
269 kps = (k * 100) / centisecs;
Rafael J. Wysocki2872de12017-02-24 00:26:15 +0100270 pr_info("%s %u kbytes in %u.%02u seconds (%u.%02u MB/s)\n",
271 msg, k, centisecs / 100, centisecs % 100, kps / 1000,
272 (kps % 1000) / 10);
Nigel Cunningham8e60c6a2009-12-06 16:16:07 +0100273}
274
Jiri Kosinaec527c32019-05-30 00:09:39 +0200275__weak int arch_resume_nosmt(void)
276{
277 return 0;
278}
279
Nigel Cunningham8e60c6a2009-12-06 16:16:07 +0100280/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200281 * create_image - Create a hibernation image.
282 * @platform_mode: Whether or not to use the platform driver.
283 *
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100284 * Execute device drivers' "late" and "noirq" freeze callbacks, create a
285 * hibernation image and run the drivers' "noirq" and "early" thaw callbacks.
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200286 *
287 * Control reappears in this routine after the subsequent restore.
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700288 */
Adrian Bunk47a460d2008-02-04 22:30:06 -0800289static int create_image(int platform_mode)
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700290{
291 int error;
292
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100293 error = dpm_suspend_end(PMSG_FREEZE);
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700294 if (error) {
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800295 pr_err("Some devices failed to power down, aborting\n");
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200296 return error;
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700297 }
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100298
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100299 error = platform_pre_snapshot(platform_mode);
300 if (error || hibernation_test(TEST_PLATFORM))
301 goto Platform_finish;
302
Nicholas Piggin2f1a6fb2019-04-11 13:34:45 +1000303 error = suspend_disable_secondary_cpus();
Srivatsa S. Bhat48580ab2011-12-01 22:33:20 +0100304 if (error || hibernation_test(TEST_CPUS))
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100305 goto Enable_cpus;
306
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100307 local_irq_disable();
308
Thomas Gleixnerc1a957d2018-05-25 17:54:41 +0200309 system_state = SYSTEM_SUSPEND;
310
Rafael J. Wysocki2e711c02011-04-26 19:15:07 +0200311 error = syscore_suspend();
Rafael J. Wysocki770824b2009-02-22 18:38:50 +0100312 if (error) {
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800313 pr_err("Some system devices failed to power down, aborting\n");
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100314 goto Enable_irqs;
Rafael J. Wysocki770824b2009-02-22 18:38:50 +0100315 }
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700316
Rafael J. Wysockia2867e02010-12-03 22:58:31 +0100317 if (hibernation_test(TEST_CORE) || pm_wakeup_pending())
Rafael J. Wysocki4cc79772007-11-19 23:42:31 +0100318 goto Power_up;
319
320 in_suspend = 1;
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700321 save_processor_state();
Todd E Brandtbb3632c2014-06-06 05:40:17 -0700322 trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true);
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700323 error = swsusp_arch_suspend();
Thomas Garnier62822e22016-08-11 14:49:29 -0700324 /* Restore control flow magically appears here */
325 restore_processor_state();
Todd E Brandtbb3632c2014-06-06 05:40:17 -0700326 trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700327 if (error)
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800328 pr_err("Error %d creating image\n", error);
Rafael J. Wysocki2872de12017-02-24 00:26:15 +0100329
Anisse Astier1ad14102016-09-09 10:43:32 +0200330 if (!in_suspend) {
Rafael J. Wysockic125e962010-07-05 22:43:53 +0200331 events_check_enabled = false;
Vlastimil Babka03b6c9a2020-12-14 19:13:38 -0800332 clear_or_poison_free_pages();
Anisse Astier1ad14102016-09-09 10:43:32 +0200333 }
Bjørn Mork362e77d2013-12-04 16:06:58 +0100334
335 platform_leave(platform_mode);
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100336
Rafael J. Wysocki4cc79772007-11-19 23:42:31 +0100337 Power_up:
Rafael J. Wysocki40dc1662011-03-15 00:43:46 +0100338 syscore_resume();
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100339
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100340 Enable_irqs:
Thomas Gleixnerc1a957d2018-05-25 17:54:41 +0200341 system_state = SYSTEM_RUNNING;
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100342 local_irq_enable();
343
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100344 Enable_cpus:
Nicholas Piggin2f1a6fb2019-04-11 13:34:45 +1000345 suspend_enable_secondary_cpus();
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100346
Jiri Kosinaec527c32019-05-30 00:09:39 +0200347 /* Allow architectures to do nosmt-specific post-resume dances */
348 if (!in_suspend)
349 error = arch_resume_nosmt();
350
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100351 Platform_finish:
352 platform_finish(platform_mode);
353
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100354 dpm_resume_start(in_suspend ?
Rafael J. Wysocki1eede072008-05-20 23:00:01 +0200355 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100356
Rafael J. Wysockic7e08312007-10-18 03:04:55 -0700357 return error;
358}
359
360/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200361 * hibernation_snapshot - Quiesce devices and create a hibernation image.
362 * @platform_mode: If set, use platform driver to prepare for the transition.
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700363 *
Pingfan Liu55f25032018-07-31 16:51:32 +0800364 * This routine must be called with system_transition_mutex held.
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700365 */
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700366int hibernation_snapshot(int platform_mode)
367{
Srivatsa S. Bhat953a2062011-11-22 23:20:31 +0100368 pm_message_t msg;
Ingo Molnarcbe2f5a2008-11-23 10:37:12 +0100369 int error;
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700370
Lukas Wunner27614272016-03-23 00:11:20 +0100371 pm_suspend_clear_flags();
Zhang Rui3fe03132008-10-26 20:50:26 +0100372 error = platform_begin(platform_mode);
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700373 if (error)
Rafael J. Wysockid074ee02010-07-07 23:43:35 +0200374 goto Close;
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700375
Rafael J. Wysocki64a473c2009-07-08 13:24:05 +0200376 /* Preallocate image memory before shutting down devices. */
377 error = hibernate_preallocate_memory();
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700378 if (error)
Rafael J. Wysocki2aede852011-09-26 20:32:27 +0200379 goto Close;
380
381 error = freeze_kernel_threads();
382 if (error)
Rafael J. Wysockibb58dd52011-11-22 23:08:10 +0100383 goto Cleanup;
Rafael J. Wysocki2aede852011-09-26 20:32:27 +0200384
Srivatsa S. Bhat48580ab2011-12-01 22:33:20 +0100385 if (hibernation_test(TEST_FREEZER)) {
Srivatsa S. Bhataa9a7b12011-11-18 23:02:42 +0100386
387 /*
388 * Indicate to the caller that we are returning due to a
389 * successful freezer test.
390 */
391 freezer_test_done = true;
Srivatsa S. Bhat51d6ff72012-02-04 22:26:38 +0100392 goto Thaw;
Srivatsa S. Bhataa9a7b12011-11-18 23:02:42 +0100393 }
394
Rafael J. Wysocki2aede852011-09-26 20:32:27 +0200395 error = dpm_prepare(PMSG_FREEZE);
Rafael J. Wysockibb58dd52011-11-22 23:08:10 +0100396 if (error) {
Srivatsa S. Bhat953a2062011-11-22 23:20:31 +0100397 dpm_complete(PMSG_RECOVER);
Srivatsa S. Bhat51d6ff72012-02-04 22:26:38 +0100398 goto Thaw;
Rafael J. Wysockibb58dd52011-11-22 23:08:10 +0100399 }
Rafael J. Wysocki74f270a2007-10-18 03:04:42 -0700400
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700401 suspend_console();
Rafael J. Wysockic9e664f2010-12-03 22:57:45 +0100402 pm_restrict_gfp_mask();
Srivatsa S. Bhat953a2062011-11-22 23:20:31 +0100403
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200404 error = dpm_suspend(PMSG_FREEZE);
Rafael J. Wysocki10a18032007-07-19 01:47:31 -0700405
Srivatsa S. Bhat953a2062011-11-22 23:20:31 +0100406 if (error || hibernation_test(TEST_DEVICES))
407 platform_recover(platform_mode);
408 else
409 error = create_image(platform_mode);
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700410
Rafael J. Wysockic9e664f2010-12-03 22:57:45 +0100411 /*
Srivatsa S. Bhat953a2062011-11-22 23:20:31 +0100412 * In the case that we call create_image() above, the control
413 * returns here (1) after the image has been created or the
Rafael J. Wysockic9e664f2010-12-03 22:57:45 +0100414 * image creation has failed and (2) after a successful restore.
415 */
Rafael J. Wysocki4cc79772007-11-19 23:42:31 +0100416
Rafael J. Wysocki64a473c2009-07-08 13:24:05 +0200417 /* We may need to release the preallocated image pages here. */
418 if (error || !in_suspend)
419 swsusp_free();
420
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200421 msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE;
422 dpm_resume(msg);
Rafael J. Wysockic9e664f2010-12-03 22:57:45 +0100423
424 if (error || !in_suspend)
425 pm_restore_gfp_mask();
426
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700427 resume_console();
Rafael J. Wysocki91e7c752011-05-17 23:26:00 +0200428 dpm_complete(msg);
429
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +0100430 Close:
431 platform_end(platform_mode);
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700432 return error;
Rafael J. Wysockid8f3de02008-06-12 23:24:06 +0200433
Srivatsa S. Bhat51d6ff72012-02-04 22:26:38 +0100434 Thaw:
435 thaw_kernel_threads();
Rafael J. Wysockibb58dd52011-11-22 23:08:10 +0100436 Cleanup:
437 swsusp_free();
438 goto Close;
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700439}
440
Rafael J. Wysocki406f9922016-07-14 03:55:23 +0200441int __weak hibernate_resume_nonboot_cpu_disable(void)
442{
Nicholas Piggin2f1a6fb2019-04-11 13:34:45 +1000443 return suspend_disable_secondary_cpus();
Rafael J. Wysocki406f9922016-07-14 03:55:23 +0200444}
445
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700446/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200447 * resume_target_kernel - Restore system state from a hibernation image.
448 * @platform_mode: Whether or not to use the platform driver.
449 *
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100450 * Execute device drivers' "noirq" and "late" freeze callbacks, restore the
451 * contents of highmem that have not been restored yet from the image and run
452 * the low-level code that will restore the remaining contents of memory and
453 * switch to the just restored target kernel.
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100454 */
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100455static int resume_target_kernel(bool platform_mode)
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100456{
457 int error;
458
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100459 error = dpm_suspend_end(PMSG_QUIESCE);
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100460 if (error) {
Rafael J. Wysocki2872de12017-02-24 00:26:15 +0100461 pr_err("Some devices failed to power down, aborting resume\n");
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200462 return error;
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100463 }
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100464
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100465 error = platform_pre_restore(platform_mode);
466 if (error)
467 goto Cleanup;
468
Rafael J. Wysocki406f9922016-07-14 03:55:23 +0200469 error = hibernate_resume_nonboot_cpu_disable();
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100470 if (error)
471 goto Enable_cpus;
472
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100473 local_irq_disable();
Thomas Gleixnerc1a957d2018-05-25 17:54:41 +0200474 system_state = SYSTEM_SUSPEND;
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100475
Rafael J. Wysocki2e711c02011-04-26 19:15:07 +0200476 error = syscore_suspend();
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100477 if (error)
478 goto Enable_irqs;
479
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100480 save_processor_state();
481 error = restore_highmem();
482 if (!error) {
483 error = swsusp_arch_resume();
484 /*
485 * The code below is only ever reached in case of a failure.
Rafael J. Wysocki4e2d9492011-05-24 00:21:26 +0200486 * Otherwise, execution continues at the place where
487 * swsusp_arch_suspend() was called.
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100488 */
489 BUG_ON(!error);
Rafael J. Wysocki4e2d9492011-05-24 00:21:26 +0200490 /*
491 * This call to restore_highmem() reverts the changes made by
492 * the previous one.
493 */
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100494 restore_highmem();
495 }
496 /*
497 * The only reason why swsusp_arch_resume() can fail is memory being
498 * very tight, so we have to free it as soon as we can to avoid
Rafael J. Wysocki4e2d9492011-05-24 00:21:26 +0200499 * subsequent failures.
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100500 */
501 swsusp_free();
502 restore_processor_state();
503 touch_softlockup_watchdog();
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100504
Rafael J. Wysocki40dc1662011-03-15 00:43:46 +0100505 syscore_resume();
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100506
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100507 Enable_irqs:
Thomas Gleixnerc1a957d2018-05-25 17:54:41 +0200508 system_state = SYSTEM_RUNNING;
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100509 local_irq_enable();
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100510
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100511 Enable_cpus:
Nicholas Piggin2f1a6fb2019-04-11 13:34:45 +1000512 suspend_enable_secondary_cpus();
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100513
514 Cleanup:
515 platform_restore_cleanup(platform_mode);
516
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100517 dpm_resume_start(PMSG_RECOVER);
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100518
Rafael J. Wysocki72df68c2007-12-08 02:04:21 +0100519 return error;
520}
521
522/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200523 * hibernation_restore - Quiesce devices and restore from a hibernation image.
524 * @platform_mode: If set, use platform driver to prepare for the transition.
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700525 *
Pingfan Liu55f25032018-07-31 16:51:32 +0800526 * This routine must be called with system_transition_mutex held. If it is
527 * successful, control reappears in the restored target kernel in
528 * hibernation_snapshot().
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700529 */
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700530int hibernation_restore(int platform_mode)
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700531{
Ingo Molnarcbe2f5a2008-11-23 10:37:12 +0100532 int error;
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700533
534 pm_prepare_console();
535 suspend_console();
Rafael J. Wysockic9e664f2010-12-03 22:57:45 +0100536 pm_restrict_gfp_mask();
Alan Sternd1616302009-05-24 22:05:42 +0200537 error = dpm_suspend_start(PMSG_QUIESCE);
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700538 if (!error) {
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100539 error = resume_target_kernel(platform_mode);
Imre Deak94fb8232014-10-24 20:29:10 +0300540 /*
541 * The above should either succeed and jump to the new kernel,
542 * or return with an error. Otherwise things are just
543 * undefined, so let's be paranoid.
544 */
545 BUG_ON(!error);
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700546 }
Imre Deak94fb8232014-10-24 20:29:10 +0300547 dpm_resume_end(PMSG_RECOVER);
Rafael J. Wysockic9e664f2010-12-03 22:57:45 +0100548 pm_restore_gfp_mask();
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700549 resume_console();
550 pm_restore_console();
551 return error;
552}
553
554/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200555 * hibernation_platform_enter - Power off the system using the platform driver.
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700556 */
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700557int hibernation_platform_enter(void)
558{
Ingo Molnarcbe2f5a2008-11-23 10:37:12 +0100559 int error;
Rafael J. Wysockib1457bc2007-07-19 01:47:31 -0700560
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700561 if (!hibernation_ops)
562 return -ENOSYS;
563
564 /*
565 * We have cancelled the power transition by running
566 * hibernation_ops->finish() before saving the image, so we should let
567 * the firmware know that we're going to enter the sleep state after all
568 */
Rafael J. Wysockibb186902019-05-16 12:43:19 +0200569 error = hibernation_ops->begin(PMSG_HIBERNATE);
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700570 if (error)
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +0100571 goto Close;
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700572
Rafael J. Wysockiabfe2d72009-01-19 20:54:54 +0100573 entering_platform_hibernation = true;
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700574 suspend_console();
Alan Sternd1616302009-05-24 22:05:42 +0200575 error = dpm_suspend_start(PMSG_HIBERNATE);
Rafael J. Wysockid8f3de02008-06-12 23:24:06 +0200576 if (error) {
577 if (hibernation_ops->recover)
578 hibernation_ops->recover();
579 goto Resume_devices;
580 }
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700581
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100582 error = dpm_suspend_end(PMSG_HIBERNATE);
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100583 if (error)
Rafael J. Wysocki32bdfac2009-05-24 21:15:07 +0200584 goto Resume_devices;
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100585
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100586 error = hibernation_ops->prepare();
587 if (error)
Thadeu Lima de Souza Cascardoe681c9d2009-07-08 13:23:32 +0200588 goto Platform_finish;
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100589
Nicholas Piggin2f1a6fb2019-04-11 13:34:45 +1000590 error = suspend_disable_secondary_cpus();
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100591 if (error)
Vitaly Kuznetsov8c506602015-06-24 16:02:06 +0200592 goto Enable_cpus;
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100593
594 local_irq_disable();
Thomas Gleixnerc1a957d2018-05-25 17:54:41 +0200595 system_state = SYSTEM_SUSPEND;
Rafael J. Wysocki40dc1662011-03-15 00:43:46 +0100596 syscore_suspend();
Rafael J. Wysockia2867e02010-12-03 22:58:31 +0100597 if (pm_wakeup_pending()) {
Rafael J. Wysockic125e962010-07-05 22:43:53 +0200598 error = -EAGAIN;
599 goto Power_up;
600 }
601
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100602 hibernation_ops->enter();
603 /* We should never get here */
604 while (1);
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700605
Rafael J. Wysockic125e962010-07-05 22:43:53 +0200606 Power_up:
Rafael J. Wysocki40dc1662011-03-15 00:43:46 +0100607 syscore_resume();
Thomas Gleixnerc1a957d2018-05-25 17:54:41 +0200608 system_state = SYSTEM_RUNNING;
Rafael J. Wysockic125e962010-07-05 22:43:53 +0200609 local_irq_enable();
Vitaly Kuznetsov8c506602015-06-24 16:02:06 +0200610
611 Enable_cpus:
Nicholas Piggin2f1a6fb2019-04-11 13:34:45 +1000612 suspend_enable_secondary_cpus();
Rafael J. Wysockic125e962010-07-05 22:43:53 +0200613
Thadeu Lima de Souza Cascardoe681c9d2009-07-08 13:23:32 +0200614 Platform_finish:
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700615 hibernation_ops->finish();
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100616
Rafael J. Wysockicf579df2012-01-29 20:38:29 +0100617 dpm_resume_start(PMSG_RESTORE);
Rafael J. Wysocki4aecd672009-03-16 22:34:26 +0100618
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700619 Resume_devices:
Rafael J. Wysockiabfe2d72009-01-19 20:54:54 +0100620 entering_platform_hibernation = false;
Alan Sternd1616302009-05-24 22:05:42 +0200621 dpm_resume_end(PMSG_RESTORE);
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700622 resume_console();
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100623
Rafael J. Wysockicaea99e2008-01-08 00:08:44 +0100624 Close:
625 hibernation_ops->end();
Rafael J. Wysocki2ed8d2b2009-03-16 22:34:06 +0100626
Rafael J. Wysockib1457bc2007-07-19 01:47:31 -0700627 return error;
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700628}
629
630/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200631 * power_down - Shut the machine down for hibernation.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 *
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200633 * Use the platform driver, if configured, to put the system into the sleep
634 * state corresponding to hibernation, or try to power it off or reboot,
635 * depending on the value of hibernation_mode.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 */
Johannes Bergfe0c935a2007-04-30 15:09:51 -0700637static void power_down(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
Bojan Smojver62c552c2012-06-16 00:09:58 +0200639#ifdef CONFIG_SUSPEND
640 int error;
Rafael J. Wysocki81d45bd2017-02-24 00:25:28 +0100641
642 if (hibernation_mode == HIBERNATION_SUSPEND) {
643 error = suspend_devices_and_enter(PM_SUSPEND_MEM);
644 if (error) {
645 hibernation_mode = hibernation_ops ?
646 HIBERNATION_PLATFORM :
647 HIBERNATION_SHUTDOWN;
648 } else {
649 /* Restore swap signature. */
650 error = swsusp_unmark();
651 if (error)
Rafael J. Wysocki2872de12017-02-24 00:26:15 +0100652 pr_err("Swap will be unusable! Try swapon -a.\n");
Rafael J. Wysocki81d45bd2017-02-24 00:25:28 +0100653
654 return;
655 }
656 }
Bojan Smojver62c552c2012-06-16 00:09:58 +0200657#endif
658
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700659 switch (hibernation_mode) {
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700660 case HIBERNATION_REBOOT:
Eric W. Biedermanfdde86a2005-07-26 12:01:17 -0600661 kernel_restart(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700663 case HIBERNATION_PLATFORM:
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700664 hibernation_platform_enter();
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500665 fallthrough;
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700666 case HIBERNATION_SHUTDOWN:
Sebastian Capella2c730782014-04-21 17:30:46 -0700667 if (pm_power_off)
668 kernel_power_off();
Rafael J. Wysocki9cd9a002007-10-18 03:04:56 -0700669 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 }
Eric W. Biedermanfdde86a2005-07-26 12:01:17 -0600671 kernel_halt();
Johannes Bergfe0c935a2007-04-30 15:09:51 -0700672 /*
673 * Valid image is on the disk, if we continue we risk serious data
674 * corruption after resume.
675 */
Rafael J. Wysocki2872de12017-02-24 00:26:15 +0100676 pr_crit("Power down manually\n");
Sebastian Capella2c730782014-04-21 17:30:46 -0700677 while (1)
678 cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
Chen Yufe12c002016-07-22 10:30:47 +0800681static int load_image_and_restore(void)
682{
683 int error;
684 unsigned int flags;
685
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +0200686 pm_pr_dbg("Loading hibernation image.\n");
Chen Yufe12c002016-07-22 10:30:47 +0800687
688 lock_device_hotplug();
689 error = create_basic_memory_bitmaps();
690 if (error)
691 goto Unlock;
692
693 error = swsusp_read(&flags);
694 swsusp_close(FMODE_READ);
695 if (!error)
Dexuan Cui3704a6a2020-03-31 08:55:25 -0700696 error = hibernation_restore(flags & SF_PLATFORM_MODE);
Chen Yufe12c002016-07-22 10:30:47 +0800697
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800698 pr_err("Failed to load image, recovering.\n");
Chen Yufe12c002016-07-22 10:30:47 +0800699 swsusp_free();
700 free_basic_memory_bitmaps();
701 Unlock:
702 unlock_device_hotplug();
703
704 return error;
705}
706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200708 * hibernate - Carry out system hibernation, including saving the image.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 */
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -0700710int hibernate(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
Chen Yufe12c002016-07-22 10:30:47 +0800712 bool snapshot_test = false;
Peter Zijlstra70d93292020-08-18 15:57:36 +0200713 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Kees Cooka6e15a32014-06-13 13:30:35 -0700715 if (!hibernation_available()) {
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +0200716 pm_pr_dbg("Hibernation not available.\n");
Kees Cooka6e15a32014-06-13 13:30:35 -0700717 return -EPERM;
718 }
719
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +0100720 lock_system_sleep();
Rafael J. Wysocki0709db62007-05-06 14:50:45 -0700721 /* The snapshot device should not be opened while we're running */
Domenico Andreoliab7e9b02020-05-07 09:19:52 +0200722 if (!hibernate_acquire()) {
Rafael J. Wysockib10d9112007-07-19 01:47:36 -0700723 error = -EBUSY;
724 goto Unlock;
725 }
726
Rafael J. Wysocki8915aa202017-07-20 03:38:07 +0200727 pr_info("hibernation entry\n");
Rafael J. Wysocki5a0a2f32008-01-11 01:25:21 +0100728 pm_prepare_console();
Peter Zijlstra70d93292020-08-18 15:57:36 +0200729 error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
730 if (error)
731 goto Restore;
Rafael J. Wysocki0709db62007-05-06 14:50:45 -0700732
Harry Panb5dee312019-02-25 20:36:41 +0800733 ksys_sync_helper();
Rafael J. Wysocki232b1432007-10-18 03:04:44 -0700734
Tejun Heo03afed82011-11-21 12:32:24 -0800735 error = freeze_processes();
Li Shaohua5a72e042005-06-25 14:55:06 -0700736 if (error)
Rafael J. Wysocki8fd37a42013-08-30 14:19:38 +0200737 goto Exit;
738
Rafael J. Wysocki942f4012013-08-30 14:19:46 +0200739 lock_device_hotplug();
Rafael J. Wysocki8fd37a42013-08-30 14:19:38 +0200740 /* Allocate memory management structures */
741 error = create_basic_memory_bitmaps();
742 if (error)
743 goto Thaw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700745 error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
Srivatsa S. Bhata556d5b52012-02-04 23:39:56 +0100746 if (error || freezer_test_done)
Rafael J. Wysocki8fd37a42013-08-30 14:19:38 +0200747 goto Free_bitmaps;
Rafael J. Wysocki64a473c2009-07-08 13:24:05 +0200748
749 if (in_suspend) {
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700750 unsigned int flags = 0;
751
752 if (hibernation_mode == HIBERNATION_PLATFORM)
753 flags |= SF_PLATFORM_MODE;
Bojan Smojverf996fc92010-09-09 23:06:23 +0200754 if (nocompress)
755 flags |= SF_NOCOMPRESS_MODE;
Bojan Smojver081a9d02011-10-13 23:58:07 +0200756 else
757 flags |= SF_CRC32_MODE;
758
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800759 pm_pr_dbg("Writing hibernation image.\n");
Rafael J. Wysockia634cc12007-07-19 01:47:30 -0700760 error = swsusp_write(flags);
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -0700761 swsusp_free();
Chen Yufe12c002016-07-22 10:30:47 +0800762 if (!error) {
763 if (hibernation_mode == HIBERNATION_TEST_RESUME)
764 snapshot_test = true;
765 else
766 power_down();
767 }
MyungJoo Ham5262a472010-11-26 23:07:56 +0100768 in_suspend = 0;
Rafael J. Wysockic9e664f2010-12-03 22:57:45 +0100769 pm_restore_gfp_mask();
Rafael J. Wysockib918f6e2006-11-02 22:07:19 -0800770 } else {
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800771 pm_pr_dbg("Hibernation image restored successfully.\n");
Rafael J. Wysockib918f6e2006-11-02 22:07:19 -0800772 }
Rafael J. Wysocki64a473c2009-07-08 13:24:05 +0200773
Rafael J. Wysocki8fd37a42013-08-30 14:19:38 +0200774 Free_bitmaps:
775 free_basic_memory_bitmaps();
Rafael J. Wysockib918f6e2006-11-02 22:07:19 -0800776 Thaw:
Rafael J. Wysocki942f4012013-08-30 14:19:46 +0200777 unlock_device_hotplug();
Chen Yufe12c002016-07-22 10:30:47 +0800778 if (snapshot_test) {
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +0200779 pm_pr_dbg("Checking hibernation image\n");
Chen Yufe12c002016-07-22 10:30:47 +0800780 error = swsusp_check();
781 if (!error)
782 error = load_image_and_restore();
783 }
Rafael J. Wysocki5a0a2f32008-01-11 01:25:21 +0100784 thaw_processes();
Srivatsa S. Bhata556d5b52012-02-04 23:39:56 +0100785
786 /* Don't bother checking whether freezer_test_done is true */
787 freezer_test_done = false;
Rafael J. Wysocki0709db62007-05-06 14:50:45 -0700788 Exit:
Peter Zijlstra70d93292020-08-18 15:57:36 +0200789 pm_notifier_call_chain(PM_POST_HIBERNATION);
790 Restore:
Rafael J. Wysocki5a0a2f32008-01-11 01:25:21 +0100791 pm_restore_console();
Domenico Andreoliab7e9b02020-05-07 09:19:52 +0200792 hibernate_release();
Rafael J. Wysockib10d9112007-07-19 01:47:36 -0700793 Unlock:
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +0100794 unlock_system_sleep();
Rafael J. Wysocki8915aa202017-07-20 03:38:07 +0200795 pr_info("hibernation exit\n");
796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 return error;
798}
799
Dan Williams48001ea2020-07-20 15:08:18 -0700800/**
801 * hibernate_quiet_exec - Execute a function with all devices frozen.
802 * @func: Function to execute.
803 * @data: Data pointer to pass to @func.
804 *
805 * Return the @func return value or an error code if it cannot be executed.
806 */
807int hibernate_quiet_exec(int (*func)(void *data), void *data)
808{
Peter Zijlstra70d93292020-08-18 15:57:36 +0200809 int error;
Dan Williams48001ea2020-07-20 15:08:18 -0700810
811 lock_system_sleep();
812
813 if (!hibernate_acquire()) {
814 error = -EBUSY;
815 goto unlock;
816 }
817
818 pm_prepare_console();
819
Peter Zijlstra70d93292020-08-18 15:57:36 +0200820 error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
821 if (error)
822 goto restore;
Dan Williams48001ea2020-07-20 15:08:18 -0700823
824 error = freeze_processes();
825 if (error)
826 goto exit;
827
828 lock_device_hotplug();
829
830 pm_suspend_clear_flags();
831
832 error = platform_begin(true);
833 if (error)
834 goto thaw;
835
836 error = freeze_kernel_threads();
837 if (error)
838 goto thaw;
839
840 error = dpm_prepare(PMSG_FREEZE);
841 if (error)
842 goto dpm_complete;
843
844 suspend_console();
845
846 error = dpm_suspend(PMSG_FREEZE);
847 if (error)
848 goto dpm_resume;
849
850 error = dpm_suspend_end(PMSG_FREEZE);
851 if (error)
852 goto dpm_resume;
853
854 error = platform_pre_snapshot(true);
855 if (error)
856 goto skip;
857
858 error = func(data);
859
860skip:
861 platform_finish(true);
862
863 dpm_resume_start(PMSG_THAW);
864
865dpm_resume:
866 dpm_resume(PMSG_THAW);
867
868 resume_console();
869
870dpm_complete:
871 dpm_complete(PMSG_THAW);
872
873 thaw_kernel_threads();
874
875thaw:
876 platform_end(true);
877
878 unlock_device_hotplug();
879
880 thaw_processes();
881
882exit:
Peter Zijlstra70d93292020-08-18 15:57:36 +0200883 pm_notifier_call_chain(PM_POST_HIBERNATION);
Dan Williams48001ea2020-07-20 15:08:18 -0700884
Peter Zijlstra70d93292020-08-18 15:57:36 +0200885restore:
Dan Williams48001ea2020-07-20 15:08:18 -0700886 pm_restore_console();
887
888 hibernate_release();
889
890unlock:
891 unlock_system_sleep();
892
893 return error;
894}
895EXPORT_SYMBOL_GPL(hibernate_quiet_exec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897/**
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200898 * software_resume - Resume from a saved hibernation image.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 *
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200900 * This routine is called as a late initcall, when all devices have been
901 * discovered and initialized already.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 *
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200903 * The image reading code is called to see if there is a hibernation image
904 * available for reading. If that is the case, devices are quiesced and the
905 * contents of memory is restored from the saved image.
906 *
907 * If this is successful, control reappears in the restored target kernel in
Geliang Tangd439e642015-09-29 20:36:58 -0700908 * hibernation_snapshot() which returns to hibernate(). Otherwise, the routine
Rafael J. Wysockif42a9812011-05-24 23:36:06 +0200909 * attempts to recover gracefully and make the kernel return to the normal mode
910 * of operation.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912static int software_resume(void)
913{
Peter Zijlstra70d93292020-08-18 15:57:36 +0200914 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Johannes Berg60a0d232007-11-14 17:00:16 -0800916 /*
Arjan van de Veneed3ee02009-02-14 02:00:19 +0100917 * If the user said "noresume".. bail out early.
918 */
Kees Cooka6e15a32014-06-13 13:30:35 -0700919 if (noresume || !hibernation_available())
Arjan van de Veneed3ee02009-02-14 02:00:19 +0100920 return 0;
921
922 /*
Johannes Berg60a0d232007-11-14 17:00:16 -0800923 * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
924 * is configured into the kernel. Since the regular hibernate
925 * trigger path is via sysfs which takes a buffer mutex before
Pingfan Liu55f25032018-07-31 16:51:32 +0800926 * calling hibernate functions (which take system_transition_mutex)
927 * this can cause lockdep to complain about a possible ABBA deadlock
Johannes Berg60a0d232007-11-14 17:00:16 -0800928 * which cannot happen since we're in the boot code here and
929 * sysfs can't be invoked yet. Therefore, we use a subclass
930 * here to avoid lockdep complaining.
931 */
Pingfan Liu55f25032018-07-31 16:51:32 +0800932 mutex_lock_nested(&system_transition_mutex, SINGLE_DEPTH_NESTING);
Rafael J. Wysocki0c8454f2009-04-25 00:16:06 +0200933
934 if (swsusp_resume_device)
935 goto Check_image;
936
937 if (!strlen(resume_file)) {
938 error = -ENOENT;
939 goto Unlock;
940 }
941
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +0200942 pm_pr_dbg("Checking hibernation image partition %s\n", resume_file);
Rafael J. Wysocki0c8454f2009-04-25 00:16:06 +0200943
Barry Songf126f732011-10-10 23:38:41 +0200944 if (resume_delay) {
Rafael J. Wysocki2872de12017-02-24 00:26:15 +0100945 pr_info("Waiting %dsec before reading resume device ...\n",
Barry Songf126f732011-10-10 23:38:41 +0200946 resume_delay);
947 ssleep(resume_delay);
948 }
949
Rafael J. Wysocki0c8454f2009-04-25 00:16:06 +0200950 /* Check if the device is there */
951 swsusp_resume_device = name_to_dev_t(resume_file);
Pavel Machek3efa1472005-07-07 17:56:43 -0700952 if (!swsusp_resume_device) {
Arjan van de Veneed3ee02009-02-14 02:00:19 +0100953 /*
954 * Some device discovery might still be in progress; we need
955 * to wait for this to finish.
956 */
957 wait_for_device_probe();
Barry Song6f8d7022011-10-06 20:34:46 +0200958
959 if (resume_wait) {
960 while ((swsusp_resume_device = name_to_dev_t(resume_file)) == 0)
961 msleep(10);
962 async_synchronize_full();
963 }
964
Pavel Machek3efa1472005-07-07 17:56:43 -0700965 swsusp_resume_device = name_to_dev_t(resume_file);
Rafael J. Wysocki0c8454f2009-04-25 00:16:06 +0200966 if (!swsusp_resume_device) {
967 error = -ENODEV;
968 goto Unlock;
969 }
Pavel Machek3efa1472005-07-07 17:56:43 -0700970 }
971
Rafael J. Wysocki0c8454f2009-04-25 00:16:06 +0200972 Check_image:
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +0200973 pm_pr_dbg("Hibernation image partition %d:%d present\n",
Rafael J. Wysocki0c8454f2009-04-25 00:16:06 +0200974 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +0200976 pm_pr_dbg("Looking for hibernation image.\n");
Rafael J. Wysockied746e32007-02-10 01:43:32 -0800977 error = swsusp_check();
978 if (error)
Rafael J. Wysocki74dfd662007-05-06 14:50:43 -0700979 goto Unlock;
980
Rafael J. Wysocki0709db62007-05-06 14:50:45 -0700981 /* The snapshot device should not be opened while we're running */
Domenico Andreoliab7e9b02020-05-07 09:19:52 +0200982 if (!hibernate_acquire()) {
Rafael J. Wysocki0709db62007-05-06 14:50:45 -0700983 error = -EBUSY;
Jiri Slaby76b57e62009-10-07 22:37:35 +0200984 swsusp_close(FMODE_READ);
Rafael J. Wysocki0709db62007-05-06 14:50:45 -0700985 goto Unlock;
986 }
987
Rafael J. Wysocki8915aa202017-07-20 03:38:07 +0200988 pr_info("resume from hibernation\n");
Rafael J. Wysocki5a0a2f32008-01-11 01:25:21 +0100989 pm_prepare_console();
Peter Zijlstra70d93292020-08-18 15:57:36 +0200990 error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE);
991 if (error)
992 goto Restore;
Rafael J. Wysocki1bfcf132008-10-15 22:01:21 -0700993
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -0800994 pm_pr_dbg("Preparing processes for hibernation restore.\n");
Tejun Heo03afed82011-11-21 12:32:24 -0800995 error = freeze_processes();
Rafael J. Wysocki8fd37a42013-08-30 14:19:38 +0200996 if (error)
997 goto Close_Finish;
Dexuan Cui2351f8d2020-04-23 20:40:16 -0700998
999 error = freeze_kernel_threads();
1000 if (error) {
1001 thaw_processes();
1002 goto Close_Finish;
1003 }
1004
Chen Yufe12c002016-07-22 10:30:47 +08001005 error = load_image_and_restore();
Rafael J. Wysocki8fd37a42013-08-30 14:19:38 +02001006 thaw_processes();
Rafael J. Wysocki0709db62007-05-06 14:50:45 -07001007 Finish:
Peter Zijlstra70d93292020-08-18 15:57:36 +02001008 pm_notifier_call_chain(PM_POST_RESTORE);
1009 Restore:
Rafael J. Wysocki5a0a2f32008-01-11 01:25:21 +01001010 pm_restore_console();
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -08001011 pr_info("resume failed (%d)\n", error);
Domenico Andreoliab7e9b02020-05-07 09:19:52 +02001012 hibernate_release();
Shaohua Lidd5d6662005-09-03 15:57:04 -07001013 /* For success case, the suspend path will release the lock */
Rafael J. Wysocki74dfd662007-05-06 14:50:43 -07001014 Unlock:
Pingfan Liu55f25032018-07-31 16:51:32 +08001015 mutex_unlock(&system_transition_mutex);
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +02001016 pm_pr_dbg("Hibernation image not present or could not be loaded.\n");
Rafael J. Wysocki7777fab2007-07-19 01:47:29 -07001017 return error;
Rafael J. Wysocki8fd37a42013-08-30 14:19:38 +02001018 Close_Finish:
Jiri Slaby76b57e62009-10-07 22:37:35 +02001019 swsusp_close(FMODE_READ);
1020 goto Finish;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021}
1022
Russ Dilld3c345d2013-10-24 14:25:26 +01001023late_initcall_sync(software_resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001026static const char * const hibernation_modes[] = {
1027 [HIBERNATION_PLATFORM] = "platform",
1028 [HIBERNATION_SHUTDOWN] = "shutdown",
1029 [HIBERNATION_REBOOT] = "reboot",
Bojan Smojver62c552c2012-06-16 00:09:58 +02001030#ifdef CONFIG_SUSPEND
1031 [HIBERNATION_SUSPEND] = "suspend",
1032#endif
Chen Yufe12c002016-07-22 10:30:47 +08001033 [HIBERNATION_TEST_RESUME] = "test_resume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034};
1035
Rafael J. Wysockif42a9812011-05-24 23:36:06 +02001036/*
1037 * /sys/power/disk - Control hibernation mode.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 *
Rafael J. Wysockif42a9812011-05-24 23:36:06 +02001039 * Hibernation can be handled in several ways. There are a few different ways
1040 * to put the system into the sleep state: using the platform driver (e.g. ACPI
1041 * or other hibernation_ops), powering it off or rebooting it (for testing
Srivatsa S. Bhat48580ab2011-12-01 22:33:20 +01001042 * mostly).
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 *
Rafael J. Wysockif42a9812011-05-24 23:36:06 +02001044 * The sysfs file /sys/power/disk provides an interface for selecting the
1045 * hibernation mode to use. Reading from this file causes the available modes
Srivatsa S. Bhat48580ab2011-12-01 22:33:20 +01001046 * to be printed. There are 3 modes that can be supported:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 * 'platform'
1049 * 'shutdown'
1050 * 'reboot'
1051 *
Rafael J. Wysockif42a9812011-05-24 23:36:06 +02001052 * If a platform hibernation driver is in use, 'platform' will be supported
1053 * and will be used by default. Otherwise, 'shutdown' will be used by default.
1054 * The selected option (i.e. the one corresponding to the current value of
1055 * hibernation_mode) is enclosed by a square bracket.
1056 *
1057 * To select a given hibernation mode it is necessary to write the mode's
1058 * string representation (as returned by reading from /sys/power/disk) back
1059 * into /sys/power/disk.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 */
1061
Kay Sievers386f2752007-11-02 13:47:53 +01001062static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
1063 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
Johannes Bergf0ced9b2007-05-06 14:50:50 -07001065 int i;
1066 char *start = buf;
1067
Kees Cooka6e15a32014-06-13 13:30:35 -07001068 if (!hibernation_available())
1069 return sprintf(buf, "[disabled]\n");
1070
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001071 for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
1072 if (!hibernation_modes[i])
Johannes Bergf0ced9b2007-05-06 14:50:50 -07001073 continue;
1074 switch (i) {
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001075 case HIBERNATION_SHUTDOWN:
1076 case HIBERNATION_REBOOT:
Bojan Smojver62c552c2012-06-16 00:09:58 +02001077#ifdef CONFIG_SUSPEND
1078 case HIBERNATION_SUSPEND:
1079#endif
Chen Yufe12c002016-07-22 10:30:47 +08001080 case HIBERNATION_TEST_RESUME:
Johannes Bergf0ced9b2007-05-06 14:50:50 -07001081 break;
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001082 case HIBERNATION_PLATFORM:
1083 if (hibernation_ops)
Johannes Bergf0ced9b2007-05-06 14:50:50 -07001084 break;
1085 /* not a valid mode, continue with loop */
1086 continue;
1087 }
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001088 if (i == hibernation_mode)
1089 buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
Johannes Bergf0ced9b2007-05-06 14:50:50 -07001090 else
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001091 buf += sprintf(buf, "%s ", hibernation_modes[i]);
Johannes Bergf0ced9b2007-05-06 14:50:50 -07001092 }
1093 buf += sprintf(buf, "\n");
1094 return buf-start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
Kay Sievers386f2752007-11-02 13:47:53 +01001097static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
1098 const char *buf, size_t n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099{
1100 int error = 0;
1101 int i;
1102 int len;
1103 char *p;
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001104 int mode = HIBERNATION_INVALID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Kees Cooka6e15a32014-06-13 13:30:35 -07001106 if (!hibernation_available())
1107 return -EPERM;
1108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 p = memchr(buf, '\n', n);
1110 len = p ? p - buf : n;
1111
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +01001112 lock_system_sleep();
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001113 for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
Rafael J. Wysocki8d98a692007-05-16 22:11:19 -07001114 if (len == strlen(hibernation_modes[i])
1115 && !strncmp(buf, hibernation_modes[i], len)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 mode = i;
1117 break;
1118 }
1119 }
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001120 if (mode != HIBERNATION_INVALID) {
Johannes Bergfe0c935a2007-04-30 15:09:51 -07001121 switch (mode) {
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001122 case HIBERNATION_SHUTDOWN:
1123 case HIBERNATION_REBOOT:
Bojan Smojver62c552c2012-06-16 00:09:58 +02001124#ifdef CONFIG_SUSPEND
1125 case HIBERNATION_SUSPEND:
1126#endif
Chen Yufe12c002016-07-22 10:30:47 +08001127 case HIBERNATION_TEST_RESUME:
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001128 hibernation_mode = mode;
Johannes Bergfe0c935a2007-04-30 15:09:51 -07001129 break;
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001130 case HIBERNATION_PLATFORM:
1131 if (hibernation_ops)
1132 hibernation_mode = mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 else
1134 error = -EINVAL;
1135 }
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001136 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 error = -EINVAL;
1138
Rafael J. Wysockia3d25c22007-05-09 02:33:18 -07001139 if (!error)
Rafael J. Wysocki8d8b2442017-07-19 02:38:44 +02001140 pm_pr_dbg("Hibernation mode set to '%s'\n",
1141 hibernation_modes[mode]);
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +01001142 unlock_system_sleep();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 return error ? error : n;
1144}
1145
1146power_attr(disk);
1147
Kay Sievers386f2752007-11-02 13:47:53 +01001148static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
1149 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150{
Xiang Chen6ada7ba2020-06-22 17:09:13 +08001151 return sprintf(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 MINOR(swsusp_resume_device));
1153}
1154
Kay Sievers386f2752007-11-02 13:47:53 +01001155static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
1156 const char *buf, size_t n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 dev_t res;
Sebastian Capella421a5fa2014-02-14 14:52:56 -08001159 int len = n;
1160 char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Sebastian Capella421a5fa2014-02-14 14:52:56 -08001162 if (len && buf[len-1] == '\n')
1163 len--;
1164 name = kstrndup(buf, len, GFP_KERNEL);
1165 if (!name)
1166 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Sebastian Capella421a5fa2014-02-14 14:52:56 -08001168 res = name_to_dev_t(name);
1169 kfree(name);
1170 if (!res)
1171 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +01001173 lock_system_sleep();
Andrew Mortona5762192006-01-06 00:09:50 -08001174 swsusp_resume_device = res;
Srivatsa S. Bhatbcda53f2011-12-07 22:29:54 +01001175 unlock_system_sleep();
Luigi Semenzato7a7b99bf2020-01-02 15:19:40 -08001176 pm_pr_dbg("Configured hibernation resume from disk to %u\n",
1177 swsusp_resume_device);
Andrew Mortona5762192006-01-06 00:09:50 -08001178 noresume = 0;
1179 software_resume();
Sebastian Capella421a5fa2014-02-14 14:52:56 -08001180 return n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
1183power_attr(resume);
1184
Mario Limonciello35506462018-03-28 12:01:09 -05001185static ssize_t resume_offset_show(struct kobject *kobj,
1186 struct kobj_attribute *attr, char *buf)
1187{
1188 return sprintf(buf, "%llu\n", (unsigned long long)swsusp_resume_block);
1189}
1190
1191static ssize_t resume_offset_store(struct kobject *kobj,
1192 struct kobj_attribute *attr, const char *buf,
1193 size_t n)
1194{
1195 unsigned long long offset;
1196 int rc;
1197
1198 rc = kstrtoull(buf, 0, &offset);
1199 if (rc)
1200 return rc;
1201 swsusp_resume_block = offset;
1202
1203 return n;
1204}
1205
1206power_attr(resume_offset);
1207
Kay Sievers386f2752007-11-02 13:47:53 +01001208static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
1209 char *buf)
Rafael J. Wysockica0aec02006-01-06 00:15:56 -08001210{
Rafael J. Wysocki853609b2006-02-01 03:05:07 -08001211 return sprintf(buf, "%lu\n", image_size);
Rafael J. Wysockica0aec02006-01-06 00:15:56 -08001212}
1213
Kay Sievers386f2752007-11-02 13:47:53 +01001214static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
1215 const char *buf, size_t n)
Rafael J. Wysockica0aec02006-01-06 00:15:56 -08001216{
Rafael J. Wysocki853609b2006-02-01 03:05:07 -08001217 unsigned long size;
Rafael J. Wysockica0aec02006-01-06 00:15:56 -08001218
Rafael J. Wysocki853609b2006-02-01 03:05:07 -08001219 if (sscanf(buf, "%lu", &size) == 1) {
Rafael J. Wysockica0aec02006-01-06 00:15:56 -08001220 image_size = size;
1221 return n;
1222 }
1223
1224 return -EINVAL;
1225}
1226
1227power_attr(image_size);
1228
Rafael J. Wysockiddeb6482011-05-15 11:38:48 +02001229static ssize_t reserved_size_show(struct kobject *kobj,
1230 struct kobj_attribute *attr, char *buf)
1231{
1232 return sprintf(buf, "%lu\n", reserved_size);
1233}
1234
1235static ssize_t reserved_size_store(struct kobject *kobj,
1236 struct kobj_attribute *attr,
1237 const char *buf, size_t n)
1238{
1239 unsigned long size;
1240
1241 if (sscanf(buf, "%lu", &size) == 1) {
1242 reserved_size = size;
1243 return n;
1244 }
1245
1246 return -EINVAL;
1247}
1248
1249power_attr(reserved_size);
1250
Xiang Chen6ada7ba2020-06-22 17:09:13 +08001251static struct attribute *g[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 &disk_attr.attr,
Mario Limonciello35506462018-03-28 12:01:09 -05001253 &resume_offset_attr.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 &resume_attr.attr,
Rafael J. Wysockica0aec02006-01-06 00:15:56 -08001255 &image_size_attr.attr,
Rafael J. Wysockiddeb6482011-05-15 11:38:48 +02001256 &reserved_size_attr.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 NULL,
1258};
1259
1260
Arvind Yadav59494fe2017-06-29 16:58:40 +05301261static const struct attribute_group attr_group = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 .attrs = g,
1263};
1264
1265
1266static int __init pm_disk_init(void)
1267{
Greg Kroah-Hartmand76e15f2007-11-27 11:28:26 -08001268 return sysfs_create_group(power_kobj, &attr_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269}
1270
1271core_initcall(pm_disk_init);
1272
1273
1274static int __init resume_setup(char *str)
1275{
1276 if (noresume)
1277 return 1;
1278
Xiang Chen6ada7ba2020-06-22 17:09:13 +08001279 strncpy(resume_file, str, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 return 1;
1281}
1282
Rafael J. Wysocki9a154d92006-12-06 20:34:12 -08001283static int __init resume_offset_setup(char *str)
1284{
1285 unsigned long long offset;
1286
1287 if (noresume)
1288 return 1;
1289
1290 if (sscanf(str, "%llu", &offset) == 1)
1291 swsusp_resume_block = offset;
1292
1293 return 1;
1294}
1295
Bojan Smojverf996fc92010-09-09 23:06:23 +02001296static int __init hibernate_setup(char *str)
1297{
Rafael J. Wysocki2f88e412016-07-06 02:40:56 +02001298 if (!strncmp(str, "noresume", 8)) {
Bojan Smojverf996fc92010-09-09 23:06:23 +02001299 noresume = 1;
Rafael J. Wysocki2f88e412016-07-06 02:40:56 +02001300 } else if (!strncmp(str, "nocompress", 10)) {
Bojan Smojverf996fc92010-09-09 23:06:23 +02001301 nocompress = 1;
Rafael J. Wysocki2f88e412016-07-06 02:40:56 +02001302 } else if (!strncmp(str, "no", 2)) {
Kees Cooka6e15a32014-06-13 13:30:35 -07001303 noresume = 1;
1304 nohibernate = 1;
Laura Abbott0f5bf6d2017-02-06 16:31:58 -08001305 } else if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)
Rafael J. Wysocki4c0b6c12016-07-10 02:12:10 +02001306 && !strncmp(str, "protect_image", 13)) {
1307 enable_restore_image_protection();
Kees Cooka6e15a32014-06-13 13:30:35 -07001308 }
Bojan Smojverf996fc92010-09-09 23:06:23 +02001309 return 1;
1310}
1311
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312static int __init noresume_setup(char *str)
1313{
1314 noresume = 1;
1315 return 1;
1316}
1317
Barry Song6f8d7022011-10-06 20:34:46 +02001318static int __init resumewait_setup(char *str)
1319{
1320 resume_wait = 1;
1321 return 1;
1322}
1323
Barry Songf126f732011-10-10 23:38:41 +02001324static int __init resumedelay_setup(char *str)
1325{
Dan Carpenterf6514be2014-05-14 19:08:46 +03001326 int rc = kstrtouint(str, 0, &resume_delay);
Fabian Frederick317cf7e2014-05-09 23:32:08 +02001327
1328 if (rc)
1329 return rc;
Barry Songf126f732011-10-10 23:38:41 +02001330 return 1;
1331}
1332
Kees Cooka6e15a32014-06-13 13:30:35 -07001333static int __init nohibernate_setup(char *str)
1334{
1335 noresume = 1;
1336 nohibernate = 1;
1337 return 1;
1338}
1339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340__setup("noresume", noresume_setup);
Rafael J. Wysocki9a154d92006-12-06 20:34:12 -08001341__setup("resume_offset=", resume_offset_setup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342__setup("resume=", resume_setup);
Bojan Smojverf996fc92010-09-09 23:06:23 +02001343__setup("hibernate=", hibernate_setup);
Barry Song6f8d7022011-10-06 20:34:46 +02001344__setup("resumewait", resumewait_setup);
Barry Songf126f732011-10-10 23:38:41 +02001345__setup("resumedelay=", resumedelay_setup);
Kees Cooka6e15a32014-06-13 13:30:35 -07001346__setup("nohibernate", nohibernate_setup);