Blame view

kernel/power/hibernate.c 30.1 KB
55716d264   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
8b759b84c   Rafael J. Wysocki   PM/Hibernate: Ren...
3
   * kernel/power/hibernate.c - Hibernation (a.k.a suspend-to-disk) support.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
   *
   * Copyright (c) 2003 Patrick Mochel
   * Copyright (c) 2003 Open Source Development Lab
a2531293d   Pavel Machek   update email address
7
   * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
8b759b84c   Rafael J. Wysocki   PM/Hibernate: Ren...
8
   * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
62c552ccc   Bojan Smojver   PM / Hibernate: E...
9
   * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
11
  #define pr_fmt(fmt) "PM: hibernation: " fmt
2872de138   Rafael J. Wysocki   PM / hibernate: D...
12

6e5fdeedc   Paul Gortmaker   kernel: Fix files...
13
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/suspend.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
  #include <linux/reboot.h>
  #include <linux/string.h>
  #include <linux/device.h>
6f8d7022a   Barry Song   PM / Hibernate: A...
18
  #include <linux/async.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <linux/delay.h>
  #include <linux/fs.h>
d53d9f16e   Andrew Morton   [PATCH] name_to_d...
21
  #include <linux/mount.h>
88d10bbaa   Eric W. Biederman   [PATCH] suspend: ...
22
  #include <linux/pm.h>
38b8d208a   Ingo Molnar   sched/headers: Pr...
23
  #include <linux/nmi.h>
97c7801cd   Rafael J. Wysocki   [PATCH] swsusp: U...
24
  #include <linux/console.h>
e3920fb42   Rafael J. Wysocki   [PATCH] Disable C...
25
  #include <linux/cpu.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
26
  #include <linux/freezer.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/gfp.h>
40dc166cb   Rafael J. Wysocki   PM / Core: Introd...
28
  #include <linux/syscore_ops.h>
2df83fa4b   Minho Ban   PM / Hibernate: U...
29
30
  #include <linux/ctype.h>
  #include <linux/genhd.h>
db5976058   Tina Ruchandani   PM / Hibernate: M...
31
  #include <linux/ktime.h>
38bd94b8a   Josh Boyer   hibernate: Disabl...
32
  #include <linux/security.h>
bb3632c61   Todd E Brandt   PM / sleep: trace...
33
  #include <trace/events/power.h>
d53d9f16e   Andrew Morton   [PATCH] name_to_d...
34

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  #include "power.h"
d231ff1af   Barry Song   PM / Hibernate: D...
36
37
  static int nocompress;
  static int noresume;
a6e15a390   Kees Cook   PM / hibernate: i...
38
  static int nohibernate;
d231ff1af   Barry Song   PM / Hibernate: D...
39
  static int resume_wait;
f6514be5f   Dan Carpenter   PM / hibernate: F...
40
  static unsigned int resume_delay;
47a460d5a   Adrian Bunk   kernel/power/disk...
41
  static char resume_file[256] = CONFIG_PM_STD_PARTITION;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  dev_t swsusp_resume_device;
9a154d9d9   Rafael J. Wysocki   [PATCH] swsusp: a...
43
  sector_t swsusp_resume_block;
d6efc2f72   Andi Kleen   x86, asmlinkage, ...
44
  __visible int in_suspend __nosavedata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
46
47
48
  enum {
  	HIBERNATION_INVALID,
  	HIBERNATION_PLATFORM,
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
49
50
  	HIBERNATION_SHUTDOWN,
  	HIBERNATION_REBOOT,
62c552ccc   Bojan Smojver   PM / Hibernate: E...
51
52
53
  #ifdef CONFIG_SUSPEND
  	HIBERNATION_SUSPEND,
  #endif
fe12c00d2   Chen Yu   PM / hibernate: I...
54
  	HIBERNATION_TEST_RESUME,
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
55
56
57
58
59
60
61
  	/* keep last */
  	__HIBERNATION_AFTER_LAST
  };
  #define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
  #define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
  
  static int hibernation_mode = HIBERNATION_SHUTDOWN;
97819a262   Srivatsa S. Bhat   PM / Hibernate: T...
62
  bool freezer_test_done;
aa9a7b118   Srivatsa S. Bhat   PM / Hibernate: F...
63

073ef1f6e   Lionel Debroux   hibernation: cons...
64
  static const struct platform_hibernation_ops *hibernation_ops;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
65

ab7e9b067   Domenico Andreoli   PM: hibernate: In...
66
67
68
69
70
71
72
73
74
75
76
  static atomic_t hibernate_atomic = ATOMIC_INIT(1);
  
  bool hibernate_acquire(void)
  {
  	return atomic_add_unless(&hibernate_atomic, -1, 0);
  }
  
  void hibernate_release(void)
  {
  	atomic_inc(&hibernate_atomic);
  }
a6e15a390   Kees Cook   PM / hibernate: i...
77
78
  bool hibernation_available(void)
  {
38bd94b8a   Josh Boyer   hibernate: Disabl...
79
  	return nohibernate == 0 && !security_locked_down(LOCKDOWN_HIBERNATION);
a6e15a390   Kees Cook   PM / hibernate: i...
80
  }
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
81
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
82
83
   * hibernation_set_ops - Set the global hibernate operations.
   * @ops: Hibernation operations to use in subsequent hibernation transitions.
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
84
   */
073ef1f6e   Lionel Debroux   hibernation: cons...
85
  void hibernation_set_ops(const struct platform_hibernation_ops *ops)
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
86
  {
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
87
88
  	if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
  	    && ops->prepare && ops->finish && ops->enter && ops->pre_restore
5729c63a5   MyungJoo Ham   PM / Hibernate: h...
89
  	    && ops->restore_cleanup && ops->leave)) {
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
90
91
92
  		WARN_ON(1);
  		return;
  	}
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
93
  	lock_system_sleep();
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
94
95
96
97
98
  	hibernation_ops = ops;
  	if (ops)
  		hibernation_mode = HIBERNATION_PLATFORM;
  	else if (hibernation_mode == HIBERNATION_PLATFORM)
  		hibernation_mode = HIBERNATION_SHUTDOWN;
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
99
  	unlock_system_sleep();
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
100
  }
e0c7855e3   Leonardo Potenza   PM / hibernate: e...
101
  EXPORT_SYMBOL_GPL(hibernation_set_ops);
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
102

abfe2d7b9   Rafael J. Wysocki   Hibernation: Intr...
103
104
105
106
107
108
109
  static bool entering_platform_hibernation;
  
  bool system_entering_hibernation(void)
  {
  	return entering_platform_hibernation;
  }
  EXPORT_SYMBOL(system_entering_hibernation);
4cc79776c   Rafael J. Wysocki   Hibernation: New ...
110
111
112
  #ifdef CONFIG_PM_DEBUG
  static void hibernation_debug_sleep(void)
  {
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
113
114
  	pr_info("debug: Waiting for 5 seconds.
  ");
4cc79776c   Rafael J. Wysocki   Hibernation: New ...
115
116
  	mdelay(5000);
  }
4cc79776c   Rafael J. Wysocki   Hibernation: New ...
117
118
119
120
121
122
123
124
125
  static int hibernation_test(int level)
  {
  	if (pm_test_level == level) {
  		hibernation_debug_sleep();
  		return 1;
  	}
  	return 0;
  }
  #else /* !CONFIG_PM_DEBUG */
4cc79776c   Rafael J. Wysocki   Hibernation: New ...
126
127
  static int hibernation_test(int level) { return 0; }
  #endif /* !CONFIG_PM_DEBUG */
74f270af0   Rafael J. Wysocki   PM: Rework struct...
128
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
129
130
   * platform_begin - Call platform to start hibernation.
   * @platform_mode: Whether or not to use the platform driver.
74f270af0   Rafael J. Wysocki   PM: Rework struct...
131
   */
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
132
  static int platform_begin(int platform_mode)
74f270af0   Rafael J. Wysocki   PM: Rework struct...
133
134
  {
  	return (platform_mode && hibernation_ops) ?
bb1869012   Rafael J. Wysocki   ACPI: PM: Call pm...
135
  		hibernation_ops->begin(PMSG_FREEZE) : 0;
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
136
137
138
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
139
140
   * platform_end - Call platform to finish transition to the working state.
   * @platform_mode: Whether or not to use the platform driver.
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
141
   */
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
142
143
144
145
  static void platform_end(int platform_mode)
  {
  	if (platform_mode && hibernation_ops)
  		hibernation_ops->end();
74f270af0   Rafael J. Wysocki   PM: Rework struct...
146
  }
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
147

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
149
150
151
152
153
   * platform_pre_snapshot - Call platform to prepare the machine for hibernation.
   * @platform_mode: Whether or not to use the platform driver.
   *
   * Use the platform driver to prepare the system for creating a hibernate image,
   * if so configured, and return an error code if that fails.
8a05aac26   Stefan Seyfried   [PATCH] swsusp: f...
154
   */
74f270af0   Rafael J. Wysocki   PM: Rework struct...
155
  static int platform_pre_snapshot(int platform_mode)
8a05aac26   Stefan Seyfried   [PATCH] swsusp: f...
156
  {
7777fab98   Rafael J. Wysocki   swsusp: remove co...
157
  	return (platform_mode && hibernation_ops) ?
74f270af0   Rafael J. Wysocki   PM: Rework struct...
158
  		hibernation_ops->pre_snapshot() : 0;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
159
  }
8a05aac26   Stefan Seyfried   [PATCH] swsusp: f...
160

a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
161
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
162
163
164
165
166
167
168
   * platform_leave - Call platform to prepare a transition to the working state.
   * @platform_mode: Whether or not to use the platform driver.
   *
   * Use the platform driver prepare to prepare the machine for switching to the
   * normal mode of operation.
   *
   * This routine is called on one CPU with interrupts disabled.
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
169
   */
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
170
171
172
173
174
175
176
  static void platform_leave(int platform_mode)
  {
  	if (platform_mode && hibernation_ops)
  		hibernation_ops->leave();
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
177
178
179
180
181
182
183
   * platform_finish - Call platform to switch the system to the working state.
   * @platform_mode: Whether or not to use the platform driver.
   *
   * Use the platform driver to switch the machine to the normal mode of
   * operation.
   *
   * This routine must be called after platform_prepare().
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
184
   */
7777fab98   Rafael J. Wysocki   swsusp: remove co...
185
  static void platform_finish(int platform_mode)
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
186
  {
7777fab98   Rafael J. Wysocki   swsusp: remove co...
187
  	if (platform_mode && hibernation_ops)
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
188
  		hibernation_ops->finish();
8a05aac26   Stefan Seyfried   [PATCH] swsusp: f...
189
190
191
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
192
193
194
195
196
197
198
199
   * platform_pre_restore - Prepare for hibernate image restoration.
   * @platform_mode: Whether or not to use the platform driver.
   *
   * Use the platform driver to prepare the system for resume from a hibernation
   * image.
   *
   * If the restore fails after this function has been called,
   * platform_restore_cleanup() must be called.
a634cc101   Rafael J. Wysocki   swsusp: introduce...
200
   */
a634cc101   Rafael J. Wysocki   swsusp: introduce...
201
202
203
204
205
206
207
  static int platform_pre_restore(int platform_mode)
  {
  	return (platform_mode && hibernation_ops) ?
  		hibernation_ops->pre_restore() : 0;
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
208
209
210
211
212
213
214
215
216
   * platform_restore_cleanup - Switch to the working state after failing restore.
   * @platform_mode: Whether or not to use the platform driver.
   *
   * Use the platform driver to switch the system to the normal mode of operation
   * after a failing restore.
   *
   * If platform_pre_restore() has been called before the failing restore, this
   * function must be called too, regardless of the result of
   * platform_pre_restore().
a634cc101   Rafael J. Wysocki   swsusp: introduce...
217
   */
a634cc101   Rafael J. Wysocki   swsusp: introduce...
218
219
220
221
222
223
224
  static void platform_restore_cleanup(int platform_mode)
  {
  	if (platform_mode && hibernation_ops)
  		hibernation_ops->restore_cleanup();
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
225
226
   * platform_recover - Recover from a failure to suspend devices.
   * @platform_mode: Whether or not to use the platform driver.
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
227
   */
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
228
229
230
231
232
233
234
  static void platform_recover(int platform_mode)
  {
  	if (platform_mode && hibernation_ops && hibernation_ops->recover)
  		hibernation_ops->recover();
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
235
236
237
238
239
   * swsusp_show_speed - Print time elapsed between two events during hibernation.
   * @start: Starting event.
   * @stop: Final event.
   * @nr_pages: Number of memory pages processed between @start and @stop.
   * @msg: Additional diagnostic message to print.
8e60c6a13   Nigel Cunningham   PM / Hibernate: S...
240
   */
db5976058   Tina Ruchandani   PM / Hibernate: M...
241
242
  void swsusp_show_speed(ktime_t start, ktime_t stop,
  		      unsigned nr_pages, char *msg)
8e60c6a13   Nigel Cunningham   PM / Hibernate: S...
243
  {
db5976058   Tina Ruchandani   PM / Hibernate: M...
244
  	ktime_t diff;
4881f603d   Chen Gang   PM / hibernate: u...
245
246
247
248
  	u64 elapsed_centisecs64;
  	unsigned int centisecs;
  	unsigned int k;
  	unsigned int kps;
8e60c6a13   Nigel Cunningham   PM / Hibernate: S...
249

db5976058   Tina Ruchandani   PM / Hibernate: M...
250
251
  	diff = ktime_sub(stop, start);
  	elapsed_centisecs64 = ktime_divns(diff, 10*NSEC_PER_MSEC);
8e60c6a13   Nigel Cunningham   PM / Hibernate: S...
252
253
254
255
256
  	centisecs = elapsed_centisecs64;
  	if (centisecs == 0)
  		centisecs = 1;	/* avoid div-by-zero */
  	k = nr_pages * (PAGE_SIZE / 1024);
  	kps = (k * 100) / centisecs;
2872de138   Rafael J. Wysocki   PM / hibernate: D...
257
258
259
260
  	pr_info("%s %u kbytes in %u.%02u seconds (%u.%02u MB/s)
  ",
  		msg, k, centisecs / 100, centisecs % 100, kps / 1000,
  		(kps % 1000) / 10);
8e60c6a13   Nigel Cunningham   PM / Hibernate: S...
261
  }
ec527c318   Jiri Kosina   x86/power: Fix 'n...
262
263
264
265
  __weak int arch_resume_nosmt(void)
  {
  	return 0;
  }
8e60c6a13   Nigel Cunningham   PM / Hibernate: S...
266
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
267
268
269
   * create_image - Create a hibernation image.
   * @platform_mode: Whether or not to use the platform driver.
   *
cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
270
271
   * Execute device drivers' "late" and "noirq" freeze callbacks, create a
   * hibernation image and run the drivers' "noirq" and "early" thaw callbacks.
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
272
273
   *
   * Control reappears in this routine after the subsequent restore.
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
274
   */
47a460d5a   Adrian Bunk   kernel/power/disk...
275
  static int create_image(int platform_mode)
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
276
277
  {
  	int error;
cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
278
  	error = dpm_suspend_end(PMSG_FREEZE);
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
279
  	if (error) {
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
280
281
  		pr_err("Some devices failed to power down, aborting
  ");
32bdfac54   Rafael J. Wysocki   PM: Do not hold d...
282
  		return error;
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
283
  	}
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
284

4aecd6718   Rafael J. Wysocki   PM: Change hibern...
285
286
287
  	error = platform_pre_snapshot(platform_mode);
  	if (error || hibernation_test(TEST_PLATFORM))
  		goto Platform_finish;
2f1a6fbbe   Nicholas Piggin   power/suspend: Ad...
288
  	error = suspend_disable_secondary_cpus();
48580ab87   Srivatsa S. Bhat   PM / Hibernate: R...
289
  	if (error || hibernation_test(TEST_CPUS))
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
290
  		goto Enable_cpus;
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
291
  	local_irq_disable();
c1a957d17   Thomas Gleixner   PM / suspend: Pre...
292
  	system_state = SYSTEM_SUSPEND;
2e711c04d   Rafael J. Wysocki   PM: Remove sysdev...
293
  	error = syscore_suspend();
770824bdc   Rafael J. Wysocki   PM: Split up sysd...
294
  	if (error) {
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
295
296
  		pr_err("Some system devices failed to power down, aborting
  ");
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
297
  		goto Enable_irqs;
770824bdc   Rafael J. Wysocki   PM: Split up sysd...
298
  	}
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
299

a2867e08c   Rafael J. Wysocki   PM / Wakeup: Repl...
300
  	if (hibernation_test(TEST_CORE) || pm_wakeup_pending())
4cc79776c   Rafael J. Wysocki   Hibernation: New ...
301
302
303
  		goto Power_up;
  
  	in_suspend = 1;
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
304
  	save_processor_state();
bb3632c61   Todd E Brandt   PM / sleep: trace...
305
  	trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true);
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
306
  	error = swsusp_arch_suspend();
62822e2ec   Thomas Garnier   PM / hibernate: R...
307
308
  	/* Restore control flow magically appears here */
  	restore_processor_state();
bb3632c61   Todd E Brandt   PM / sleep: trace...
309
  	trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
310
  	if (error)
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
311
312
  		pr_err("Error %d creating image
  ", error);
2872de138   Rafael J. Wysocki   PM / hibernate: D...
313

1ad1410f6   Anisse Astier   PM / Hibernate: a...
314
  	if (!in_suspend) {
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
315
  		events_check_enabled = false;
1ad1410f6   Anisse Astier   PM / Hibernate: a...
316
317
  		clear_free_pages();
  	}
362e77d1c   Bjørn Mork   PM / hibernate: C...
318
319
  
  	platform_leave(platform_mode);
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
320

4cc79776c   Rafael J. Wysocki   Hibernation: New ...
321
   Power_up:
40dc166cb   Rafael J. Wysocki   PM / Core: Introd...
322
  	syscore_resume();
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
323

4aecd6718   Rafael J. Wysocki   PM: Change hibern...
324
   Enable_irqs:
c1a957d17   Thomas Gleixner   PM / suspend: Pre...
325
  	system_state = SYSTEM_RUNNING;
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
326
  	local_irq_enable();
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
327
   Enable_cpus:
2f1a6fbbe   Nicholas Piggin   power/suspend: Ad...
328
  	suspend_enable_secondary_cpus();
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
329

ec527c318   Jiri Kosina   x86/power: Fix 'n...
330
331
332
  	/* Allow architectures to do nosmt-specific post-resume dances */
  	if (!in_suspend)
  		error = arch_resume_nosmt();
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
333
334
   Platform_finish:
  	platform_finish(platform_mode);
cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
335
  	dpm_resume_start(in_suspend ?
1eede070a   Rafael J. Wysocki   Introduce new top...
336
  		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
337

c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
338
339
340
341
  	return error;
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
342
343
   * hibernation_snapshot - Quiesce devices and create a hibernation image.
   * @platform_mode: If set, use platform driver to prepare for the transition.
7777fab98   Rafael J. Wysocki   swsusp: remove co...
344
   *
55f2503c3   Pingfan Liu   PM / reboot: Elim...
345
   * This routine must be called with system_transition_mutex held.
7777fab98   Rafael J. Wysocki   swsusp: remove co...
346
   */
7777fab98   Rafael J. Wysocki   swsusp: remove co...
347
348
  int hibernation_snapshot(int platform_mode)
  {
953a20639   Srivatsa S. Bhat   PM / Hibernate: R...
349
  	pm_message_t msg;
cbe2f5a6e   Ingo Molnar   tracing: allow tr...
350
  	int error;
7777fab98   Rafael J. Wysocki   swsusp: remove co...
351

276142730   Lukas Wunner   PM / sleep: Clear...
352
  	pm_suspend_clear_flags();
3fe0313e6   Zhang Rui   Hibernate: Call p...
353
  	error = platform_begin(platform_mode);
7777fab98   Rafael J. Wysocki   swsusp: remove co...
354
  	if (error)
d074ee023   Rafael J. Wysocki   PM / Hibernate: F...
355
  		goto Close;
7777fab98   Rafael J. Wysocki   swsusp: remove co...
356

64a473cb7   Rafael J. Wysocki   PM/Hibernate: Do ...
357
358
  	/* Preallocate image memory before shutting down devices. */
  	error = hibernate_preallocate_memory();
74f270af0   Rafael J. Wysocki   PM: Rework struct...
359
  	if (error)
2aede851d   Rafael J. Wysocki   PM / Hibernate: F...
360
361
362
363
  		goto Close;
  
  	error = freeze_kernel_threads();
  	if (error)
bb58dd5d1   Rafael J. Wysocki   PM / Hibernate: D...
364
  		goto Cleanup;
2aede851d   Rafael J. Wysocki   PM / Hibernate: F...
365

48580ab87   Srivatsa S. Bhat   PM / Hibernate: R...
366
  	if (hibernation_test(TEST_FREEZER)) {
aa9a7b118   Srivatsa S. Bhat   PM / Hibernate: F...
367
368
369
370
371
372
  
  		/*
  		 * Indicate to the caller that we are returning due to a
  		 * successful freezer test.
  		 */
  		freezer_test_done = true;
51d6ff7ac   Srivatsa S. Bhat   PM / Hibernate: T...
373
  		goto Thaw;
aa9a7b118   Srivatsa S. Bhat   PM / Hibernate: F...
374
  	}
2aede851d   Rafael J. Wysocki   PM / Hibernate: F...
375
  	error = dpm_prepare(PMSG_FREEZE);
bb58dd5d1   Rafael J. Wysocki   PM / Hibernate: D...
376
  	if (error) {
953a20639   Srivatsa S. Bhat   PM / Hibernate: R...
377
  		dpm_complete(PMSG_RECOVER);
51d6ff7ac   Srivatsa S. Bhat   PM / Hibernate: T...
378
  		goto Thaw;
bb58dd5d1   Rafael J. Wysocki   PM / Hibernate: D...
379
  	}
74f270af0   Rafael J. Wysocki   PM: Rework struct...
380

7777fab98   Rafael J. Wysocki   swsusp: remove co...
381
  	suspend_console();
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
382
  	pm_restrict_gfp_mask();
953a20639   Srivatsa S. Bhat   PM / Hibernate: R...
383

91e7c75ba   Rafael J. Wysocki   PM: Allow drivers...
384
  	error = dpm_suspend(PMSG_FREEZE);
10a1803d6   Rafael J. Wysocki   swsusp: fix hiber...
385

953a20639   Srivatsa S. Bhat   PM / Hibernate: R...
386
387
388
389
  	if (error || hibernation_test(TEST_DEVICES))
  		platform_recover(platform_mode);
  	else
  		error = create_image(platform_mode);
7777fab98   Rafael J. Wysocki   swsusp: remove co...
390

c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
391
  	/*
953a20639   Srivatsa S. Bhat   PM / Hibernate: R...
392
393
  	 * In the case that we call create_image() above, the control
  	 * returns here (1) after the image has been created or the
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
394
395
  	 * image creation has failed and (2) after a successful restore.
  	 */
4cc79776c   Rafael J. Wysocki   Hibernation: New ...
396

64a473cb7   Rafael J. Wysocki   PM/Hibernate: Do ...
397
398
399
  	/* We may need to release the preallocated image pages here. */
  	if (error || !in_suspend)
  		swsusp_free();
91e7c75ba   Rafael J. Wysocki   PM: Allow drivers...
400
401
  	msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE;
  	dpm_resume(msg);
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
402
403
404
  
  	if (error || !in_suspend)
  		pm_restore_gfp_mask();
7777fab98   Rafael J. Wysocki   swsusp: remove co...
405
  	resume_console();
91e7c75ba   Rafael J. Wysocki   PM: Allow drivers...
406
  	dpm_complete(msg);
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
407
408
   Close:
  	platform_end(platform_mode);
7777fab98   Rafael J. Wysocki   swsusp: remove co...
409
  	return error;
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
410

51d6ff7ac   Srivatsa S. Bhat   PM / Hibernate: T...
411
412
   Thaw:
  	thaw_kernel_threads();
bb58dd5d1   Rafael J. Wysocki   PM / Hibernate: D...
413
414
415
   Cleanup:
  	swsusp_free();
  	goto Close;
7777fab98   Rafael J. Wysocki   swsusp: remove co...
416
  }
406f992e4   Rafael J. Wysocki   x86 / hibernate: ...
417
418
  int __weak hibernate_resume_nonboot_cpu_disable(void)
  {
2f1a6fbbe   Nicholas Piggin   power/suspend: Ad...
419
  	return suspend_disable_secondary_cpus();
406f992e4   Rafael J. Wysocki   x86 / hibernate: ...
420
  }
7777fab98   Rafael J. Wysocki   swsusp: remove co...
421
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
422
423
424
   * resume_target_kernel - Restore system state from a hibernation image.
   * @platform_mode: Whether or not to use the platform driver.
   *
cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
425
426
427
428
   * Execute device drivers' "noirq" and "late" freeze callbacks, restore the
   * contents of highmem that have not been restored yet from the image and run
   * the low-level code that will restore the remaining contents of memory and
   * switch to the just restored target kernel.
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
429
   */
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
430
  static int resume_target_kernel(bool platform_mode)
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
431
432
  {
  	int error;
cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
433
  	error = dpm_suspend_end(PMSG_QUIESCE);
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
434
  	if (error) {
2872de138   Rafael J. Wysocki   PM / hibernate: D...
435
436
  		pr_err("Some devices failed to power down, aborting resume
  ");
32bdfac54   Rafael J. Wysocki   PM: Do not hold d...
437
  		return error;
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
438
  	}
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
439

4aecd6718   Rafael J. Wysocki   PM: Change hibern...
440
441
442
  	error = platform_pre_restore(platform_mode);
  	if (error)
  		goto Cleanup;
406f992e4   Rafael J. Wysocki   x86 / hibernate: ...
443
  	error = hibernate_resume_nonboot_cpu_disable();
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
444
445
  	if (error)
  		goto Enable_cpus;
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
446
  	local_irq_disable();
c1a957d17   Thomas Gleixner   PM / suspend: Pre...
447
  	system_state = SYSTEM_SUSPEND;
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
448

2e711c04d   Rafael J. Wysocki   PM: Remove sysdev...
449
  	error = syscore_suspend();
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
450
451
  	if (error)
  		goto Enable_irqs;
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
452
453
454
455
456
457
  	save_processor_state();
  	error = restore_highmem();
  	if (!error) {
  		error = swsusp_arch_resume();
  		/*
  		 * The code below is only ever reached in case of a failure.
4e2d9491a   Rafael J. Wysocki   PM / Hibernate: U...
458
459
  		 * Otherwise, execution continues at the place where
  		 * swsusp_arch_suspend() was called.
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
460
461
  		 */
  		BUG_ON(!error);
4e2d9491a   Rafael J. Wysocki   PM / Hibernate: U...
462
463
464
465
  		/*
  		 * This call to restore_highmem() reverts the changes made by
  		 * the previous one.
  		 */
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
466
467
468
469
470
  		restore_highmem();
  	}
  	/*
  	 * The only reason why swsusp_arch_resume() can fail is memory being
  	 * very tight, so we have to free it as soon as we can to avoid
4e2d9491a   Rafael J. Wysocki   PM / Hibernate: U...
471
  	 * subsequent failures.
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
472
473
474
475
  	 */
  	swsusp_free();
  	restore_processor_state();
  	touch_softlockup_watchdog();
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
476

40dc166cb   Rafael J. Wysocki   PM / Core: Introd...
477
  	syscore_resume();
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
478

4aecd6718   Rafael J. Wysocki   PM: Change hibern...
479
   Enable_irqs:
c1a957d17   Thomas Gleixner   PM / suspend: Pre...
480
  	system_state = SYSTEM_RUNNING;
72df68ca8   Rafael J. Wysocki   Hibernation: Move...
481
  	local_irq_enable();
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
482

4aecd6718   Rafael J. Wysocki   PM: Change hibern...
483
   Enable_cpus:
2f1a6fbbe   Nicholas Piggin   power/suspend: Ad...
484
  	suspend_enable_secondary_cpus();
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
485
486
487
  
   Cleanup:
  	platform_restore_cleanup(platform_mode);
cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
488
  	dpm_resume_start(PMSG_RECOVER);
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
489

72df68ca8   Rafael J. Wysocki   Hibernation: Move...
490
491
492
493
  	return error;
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
494
495
   * hibernation_restore - Quiesce devices and restore from a hibernation image.
   * @platform_mode: If set, use platform driver to prepare for the transition.
7777fab98   Rafael J. Wysocki   swsusp: remove co...
496
   *
55f2503c3   Pingfan Liu   PM / reboot: Elim...
497
498
499
   * This routine must be called with system_transition_mutex held.  If it is
   * successful, control reappears in the restored target kernel in
   * hibernation_snapshot().
7777fab98   Rafael J. Wysocki   swsusp: remove co...
500
   */
a634cc101   Rafael J. Wysocki   swsusp: introduce...
501
  int hibernation_restore(int platform_mode)
7777fab98   Rafael J. Wysocki   swsusp: remove co...
502
  {
cbe2f5a6e   Ingo Molnar   tracing: allow tr...
503
  	int error;
7777fab98   Rafael J. Wysocki   swsusp: remove co...
504
505
506
  
  	pm_prepare_console();
  	suspend_console();
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
507
  	pm_restrict_gfp_mask();
d16163029   Alan Stern   PM core: rename s...
508
  	error = dpm_suspend_start(PMSG_QUIESCE);
a634cc101   Rafael J. Wysocki   swsusp: introduce...
509
  	if (!error) {
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
510
  		error = resume_target_kernel(platform_mode);
94fb823fc   Imre Deak   PM / Sleep: fix r...
511
512
513
514
515
516
  		/*
  		 * The above should either succeed and jump to the new kernel,
  		 * or return with an error. Otherwise things are just
  		 * undefined, so let's be paranoid.
  		 */
  		BUG_ON(!error);
a634cc101   Rafael J. Wysocki   swsusp: introduce...
517
  	}
94fb823fc   Imre Deak   PM / Sleep: fix r...
518
  	dpm_resume_end(PMSG_RECOVER);
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
519
  	pm_restore_gfp_mask();
7777fab98   Rafael J. Wysocki   swsusp: remove co...
520
521
522
523
524
525
  	resume_console();
  	pm_restore_console();
  	return error;
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
526
   * hibernation_platform_enter - Power off the system using the platform driver.
7777fab98   Rafael J. Wysocki   swsusp: remove co...
527
   */
7777fab98   Rafael J. Wysocki   swsusp: remove co...
528
529
  int hibernation_platform_enter(void)
  {
cbe2f5a6e   Ingo Molnar   tracing: allow tr...
530
  	int error;
b1457bcc3   Rafael J. Wysocki   Hibernation: prep...
531

9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
532
533
534
535
536
537
538
539
  	if (!hibernation_ops)
  		return -ENOSYS;
  
  	/*
  	 * We have cancelled the power transition by running
  	 * hibernation_ops->finish() before saving the image, so we should let
  	 * the firmware know that we're going to enter the sleep state after all
  	 */
bb1869012   Rafael J. Wysocki   ACPI: PM: Call pm...
540
  	error = hibernation_ops->begin(PMSG_HIBERNATE);
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
541
  	if (error)
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
542
  		goto Close;
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
543

abfe2d7b9   Rafael J. Wysocki   Hibernation: Intr...
544
  	entering_platform_hibernation = true;
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
545
  	suspend_console();
d16163029   Alan Stern   PM core: rename s...
546
  	error = dpm_suspend_start(PMSG_HIBERNATE);
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
547
548
549
550
551
  	if (error) {
  		if (hibernation_ops->recover)
  			hibernation_ops->recover();
  		goto Resume_devices;
  	}
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
552

cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
553
  	error = dpm_suspend_end(PMSG_HIBERNATE);
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
554
  	if (error)
32bdfac54   Rafael J. Wysocki   PM: Do not hold d...
555
  		goto Resume_devices;
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
556

9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
557
558
  	error = hibernation_ops->prepare();
  	if (error)
e681c9dd6   Thadeu Lima de Souza Cascardo   PM: Fix typo in l...
559
  		goto Platform_finish;
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
560

2f1a6fbbe   Nicholas Piggin   power/suspend: Ad...
561
  	error = suspend_disable_secondary_cpus();
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
562
  	if (error)
8c506608c   Vitaly Kuznetsov   PM / hibernate: r...
563
  		goto Enable_cpus;
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
564

4aecd6718   Rafael J. Wysocki   PM: Change hibern...
565
  	local_irq_disable();
c1a957d17   Thomas Gleixner   PM / suspend: Pre...
566
  	system_state = SYSTEM_SUSPEND;
40dc166cb   Rafael J. Wysocki   PM / Core: Introd...
567
  	syscore_suspend();
a2867e08c   Rafael J. Wysocki   PM / Wakeup: Repl...
568
  	if (pm_wakeup_pending()) {
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
569
570
571
  		error = -EAGAIN;
  		goto Power_up;
  	}
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
572
573
574
  	hibernation_ops->enter();
  	/* We should never get here */
  	while (1);
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
575

c125e96f0   Rafael J. Wysocki   PM: Make it possi...
576
   Power_up:
40dc166cb   Rafael J. Wysocki   PM / Core: Introd...
577
  	syscore_resume();
c1a957d17   Thomas Gleixner   PM / suspend: Pre...
578
  	system_state = SYSTEM_RUNNING;
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
579
  	local_irq_enable();
8c506608c   Vitaly Kuznetsov   PM / hibernate: r...
580
581
  
   Enable_cpus:
2f1a6fbbe   Nicholas Piggin   power/suspend: Ad...
582
  	suspend_enable_secondary_cpus();
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
583

e681c9dd6   Thadeu Lima de Souza Cascardo   PM: Fix typo in l...
584
   Platform_finish:
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
585
  	hibernation_ops->finish();
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
586

cf579dfb8   Rafael J. Wysocki   PM / Sleep: Intro...
587
  	dpm_resume_start(PMSG_RESTORE);
4aecd6718   Rafael J. Wysocki   PM: Change hibern...
588

9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
589
   Resume_devices:
abfe2d7b9   Rafael J. Wysocki   Hibernation: Intr...
590
  	entering_platform_hibernation = false;
d16163029   Alan Stern   PM core: rename s...
591
  	dpm_resume_end(PMSG_RESTORE);
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
592
  	resume_console();
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
593

caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
594
595
   Close:
  	hibernation_ops->end();
2ed8d2b3a   Rafael J. Wysocki   PM: Rework handli...
596

b1457bcc3   Rafael J. Wysocki   Hibernation: prep...
597
  	return error;
7777fab98   Rafael J. Wysocki   swsusp: remove co...
598
599
600
  }
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
601
   * power_down - Shut the machine down for hibernation.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
   *
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
603
604
605
   * Use the platform driver, if configured, to put the system into the sleep
   * state corresponding to hibernation, or try to power it off or reboot,
   * depending on the value of hibernation_mode.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
   */
fe0c935a6   Johannes Berg   rework pm_ops pm_...
607
  static void power_down(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  {
62c552ccc   Bojan Smojver   PM / Hibernate: E...
609
610
  #ifdef CONFIG_SUSPEND
  	int error;
81d45bdf8   Rafael J. Wysocki   PM / hibernate: U...
611
612
613
614
615
616
617
618
619
620
621
  
  	if (hibernation_mode == HIBERNATION_SUSPEND) {
  		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
  		if (error) {
  			hibernation_mode = hibernation_ops ?
  						HIBERNATION_PLATFORM :
  						HIBERNATION_SHUTDOWN;
  		} else {
  			/* Restore swap signature. */
  			error = swsusp_unmark();
  			if (error)
2872de138   Rafael J. Wysocki   PM / hibernate: D...
622
623
  				pr_err("Swap will be unusable! Try swapon -a.
  ");
81d45bdf8   Rafael J. Wysocki   PM / hibernate: U...
624
625
626
627
  
  			return;
  		}
  	}
62c552ccc   Bojan Smojver   PM / Hibernate: E...
628
  #endif
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
629
  	switch (hibernation_mode) {
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
630
  	case HIBERNATION_REBOOT:
fdde86ac5   Eric W. Biederman   [PATCH] swpsuspen...
631
  		kernel_restart(NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  		break;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
633
  	case HIBERNATION_PLATFORM:
7777fab98   Rafael J. Wysocki   swsusp: remove co...
634
  		hibernation_platform_enter();
df561f668   Gustavo A. R. Silva   treewide: Use fal...
635
  		fallthrough;
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
636
  	case HIBERNATION_SHUTDOWN:
2c730785d   Sebastian Capella   PM / hibernate: n...
637
638
  		if (pm_power_off)
  			kernel_power_off();
9cd9a0058   Rafael J. Wysocki   Hibernation: Ente...
639
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  	}
fdde86ac5   Eric W. Biederman   [PATCH] swpsuspen...
641
  	kernel_halt();
fe0c935a6   Johannes Berg   rework pm_ops pm_...
642
643
644
645
  	/*
  	 * Valid image is on the disk, if we continue we risk serious data
  	 * corruption after resume.
  	 */
2872de138   Rafael J. Wysocki   PM / hibernate: D...
646
647
  	pr_crit("Power down manually
  ");
2c730785d   Sebastian Capella   PM / hibernate: n...
648
649
  	while (1)
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  }
fe12c00d2   Chen Yu   PM / hibernate: I...
651
652
653
654
  static int load_image_and_restore(void)
  {
  	int error;
  	unsigned int flags;
8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
655
656
  	pm_pr_dbg("Loading hibernation image.
  ");
fe12c00d2   Chen Yu   PM / hibernate: I...
657
658
659
660
661
662
663
664
665
  
  	lock_device_hotplug();
  	error = create_basic_memory_bitmaps();
  	if (error)
  		goto Unlock;
  
  	error = swsusp_read(&flags);
  	swsusp_close(FMODE_READ);
  	if (!error)
3704a6a44   Dexuan Cui   PM: hibernate: Pr...
666
  		error = hibernation_restore(flags & SF_PLATFORM_MODE);
fe12c00d2   Chen Yu   PM / hibernate: I...
667

7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
668
669
  	pr_err("Failed to load image, recovering.
  ");
fe12c00d2   Chen Yu   PM / hibernate: I...
670
671
672
673
674
675
676
  	swsusp_free();
  	free_basic_memory_bitmaps();
   Unlock:
  	unlock_device_hotplug();
  
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
678
   * hibernate - Carry out system hibernation, including saving the image.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
   */
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
680
  int hibernate(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  {
fe12c00d2   Chen Yu   PM / hibernate: I...
682
  	bool snapshot_test = false;
70d932985   Peter Zijlstra   notifier: Fix bro...
683
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684

a6e15a390   Kees Cook   PM / hibernate: i...
685
  	if (!hibernation_available()) {
8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
686
687
  		pm_pr_dbg("Hibernation not available.
  ");
a6e15a390   Kees Cook   PM / hibernate: i...
688
689
  		return -EPERM;
  	}
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
690
  	lock_system_sleep();
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
691
  	/* The snapshot device should not be opened while we're running */
ab7e9b067   Domenico Andreoli   PM: hibernate: In...
692
  	if (!hibernate_acquire()) {
b10d91174   Rafael J. Wysocki   PM: introduce hib...
693
694
695
  		error = -EBUSY;
  		goto Unlock;
  	}
8915aa204   Rafael J. Wysocki   PM / sleep: Mark ...
696
697
  	pr_info("hibernation entry
  ");
5a0a2f304   Rafael J. Wysocki   Hibernation: Invo...
698
  	pm_prepare_console();
70d932985   Peter Zijlstra   notifier: Fix bro...
699
700
701
  	error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
  	if (error)
  		goto Restore;
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
702

b5dee3130   Harry Pan   PM / sleep: Refac...
703
  	ksys_sync_helper();
232b14328   Rafael J. Wysocki   freezer: do not s...
704

03afed8bc   Tejun Heo   freezer: clean up...
705
  	error = freeze_processes();
5a72e04df   Li Shaohua   [PATCH] suspend/r...
706
  	if (error)
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
707
  		goto Exit;
942f40155   Rafael J. Wysocki   PM / hibernate / ...
708
  	lock_device_hotplug();
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
709
710
711
712
  	/* Allocate memory management structures */
  	error = create_basic_memory_bitmaps();
  	if (error)
  		goto Thaw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713

7777fab98   Rafael J. Wysocki   swsusp: remove co...
714
  	error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
a556d5b58   Srivatsa S. Bhat   PM / Hibernate: R...
715
  	if (error || freezer_test_done)
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
716
  		goto Free_bitmaps;
64a473cb7   Rafael J. Wysocki   PM/Hibernate: Do ...
717
718
  
  	if (in_suspend) {
a634cc101   Rafael J. Wysocki   swsusp: introduce...
719
720
721
722
  		unsigned int flags = 0;
  
  		if (hibernation_mode == HIBERNATION_PLATFORM)
  			flags |= SF_PLATFORM_MODE;
f996fc967   Bojan Smojver   PM / Hibernate: C...
723
724
  		if (nocompress)
  			flags |= SF_NOCOMPRESS_MODE;
081a9d043   Bojan Smojver   PM / Hibernate: I...
725
726
  		else
  		        flags |= SF_CRC32_MODE;
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
727
728
  		pm_pr_dbg("Writing hibernation image.
  ");
a634cc101   Rafael J. Wysocki   swsusp: introduce...
729
  		error = swsusp_write(flags);
7777fab98   Rafael J. Wysocki   swsusp: remove co...
730
  		swsusp_free();
fe12c00d2   Chen Yu   PM / hibernate: I...
731
732
733
734
735
736
  		if (!error) {
  			if (hibernation_mode == HIBERNATION_TEST_RESUME)
  				snapshot_test = true;
  			else
  				power_down();
  		}
5262a4750   MyungJoo Ham   PM / Hibernate: W...
737
  		in_suspend = 0;
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
738
  		pm_restore_gfp_mask();
b918f6e62   Rafael J. Wysocki   [PATCH] swsusp: d...
739
  	} else {
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
740
741
  		pm_pr_dbg("Hibernation image restored successfully.
  ");
b918f6e62   Rafael J. Wysocki   [PATCH] swsusp: d...
742
  	}
64a473cb7   Rafael J. Wysocki   PM/Hibernate: Do ...
743

8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
744
745
   Free_bitmaps:
  	free_basic_memory_bitmaps();
b918f6e62   Rafael J. Wysocki   [PATCH] swsusp: d...
746
   Thaw:
942f40155   Rafael J. Wysocki   PM / hibernate / ...
747
  	unlock_device_hotplug();
fe12c00d2   Chen Yu   PM / hibernate: I...
748
  	if (snapshot_test) {
8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
749
750
  		pm_pr_dbg("Checking hibernation image
  ");
fe12c00d2   Chen Yu   PM / hibernate: I...
751
752
753
754
  		error = swsusp_check();
  		if (!error)
  			error = load_image_and_restore();
  	}
5a0a2f304   Rafael J. Wysocki   Hibernation: Invo...
755
  	thaw_processes();
a556d5b58   Srivatsa S. Bhat   PM / Hibernate: R...
756
757
758
  
  	/* Don't bother checking whether freezer_test_done is true */
  	freezer_test_done = false;
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
759
   Exit:
70d932985   Peter Zijlstra   notifier: Fix bro...
760
761
  	pm_notifier_call_chain(PM_POST_HIBERNATION);
   Restore:
5a0a2f304   Rafael J. Wysocki   Hibernation: Invo...
762
  	pm_restore_console();
ab7e9b067   Domenico Andreoli   PM: hibernate: In...
763
  	hibernate_release();
b10d91174   Rafael J. Wysocki   PM: introduce hib...
764
   Unlock:
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
765
  	unlock_system_sleep();
8915aa204   Rafael J. Wysocki   PM / sleep: Mark ...
766
767
  	pr_info("hibernation exit
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
  	return error;
  }
48001ea50   Dan Williams   PM, libnvdimm: Ad...
770
771
772
773
774
775
776
777
778
  /**
   * hibernate_quiet_exec - Execute a function with all devices frozen.
   * @func: Function to execute.
   * @data: Data pointer to pass to @func.
   *
   * Return the @func return value or an error code if it cannot be executed.
   */
  int hibernate_quiet_exec(int (*func)(void *data), void *data)
  {
70d932985   Peter Zijlstra   notifier: Fix bro...
779
  	int error;
48001ea50   Dan Williams   PM, libnvdimm: Ad...
780
781
782
783
784
785
786
787
788
  
  	lock_system_sleep();
  
  	if (!hibernate_acquire()) {
  		error = -EBUSY;
  		goto unlock;
  	}
  
  	pm_prepare_console();
70d932985   Peter Zijlstra   notifier: Fix bro...
789
790
791
  	error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
  	if (error)
  		goto restore;
48001ea50   Dan Williams   PM, libnvdimm: Ad...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
  
  	error = freeze_processes();
  	if (error)
  		goto exit;
  
  	lock_device_hotplug();
  
  	pm_suspend_clear_flags();
  
  	error = platform_begin(true);
  	if (error)
  		goto thaw;
  
  	error = freeze_kernel_threads();
  	if (error)
  		goto thaw;
  
  	error = dpm_prepare(PMSG_FREEZE);
  	if (error)
  		goto dpm_complete;
  
  	suspend_console();
  
  	error = dpm_suspend(PMSG_FREEZE);
  	if (error)
  		goto dpm_resume;
  
  	error = dpm_suspend_end(PMSG_FREEZE);
  	if (error)
  		goto dpm_resume;
  
  	error = platform_pre_snapshot(true);
  	if (error)
  		goto skip;
  
  	error = func(data);
  
  skip:
  	platform_finish(true);
  
  	dpm_resume_start(PMSG_THAW);
  
  dpm_resume:
  	dpm_resume(PMSG_THAW);
  
  	resume_console();
  
  dpm_complete:
  	dpm_complete(PMSG_THAW);
  
  	thaw_kernel_threads();
  
  thaw:
  	platform_end(true);
  
  	unlock_device_hotplug();
  
  	thaw_processes();
  
  exit:
70d932985   Peter Zijlstra   notifier: Fix bro...
852
  	pm_notifier_call_chain(PM_POST_HIBERNATION);
48001ea50   Dan Williams   PM, libnvdimm: Ad...
853

70d932985   Peter Zijlstra   notifier: Fix bro...
854
  restore:
48001ea50   Dan Williams   PM, libnvdimm: Ad...
855
856
857
858
859
860
861
862
863
864
  	pm_restore_console();
  
  	hibernate_release();
  
  unlock:
  	unlock_system_sleep();
  
  	return error;
  }
  EXPORT_SYMBOL_GPL(hibernate_quiet_exec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
  
  /**
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
867
868
869
870
   * software_resume - Resume from a saved hibernation image.
   *
   * This routine is called as a late initcall, when all devices have been
   * discovered and initialized already.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
   *
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
872
873
874
   * The image reading code is called to see if there is a hibernation image
   * available for reading.  If that is the case, devices are quiesced and the
   * contents of memory is restored from the saved image.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
   *
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
876
   * If this is successful, control reappears in the restored target kernel in
d439e64f2   Geliang Tang   PM / hibernate: f...
877
   * hibernation_snapshot() which returns to hibernate().  Otherwise, the routine
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
878
879
   * attempts to recover gracefully and make the kernel return to the normal mode
   * of operation.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
882
  static int software_resume(void)
  {
70d932985   Peter Zijlstra   notifier: Fix bro...
883
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884

60a0d2338   Johannes Berg   hibernate: fix lo...
885
  	/*
eed3ee082   Arjan van de Ven   PM/resume: wait f...
886
887
  	 * If the user said "noresume".. bail out early.
  	 */
a6e15a390   Kees Cook   PM / hibernate: i...
888
  	if (noresume || !hibernation_available())
eed3ee082   Arjan van de Ven   PM/resume: wait f...
889
890
891
  		return 0;
  
  	/*
60a0d2338   Johannes Berg   hibernate: fix lo...
892
893
894
  	 * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
  	 * is configured into the kernel. Since the regular hibernate
  	 * trigger path is via sysfs which takes a buffer mutex before
55f2503c3   Pingfan Liu   PM / reboot: Elim...
895
896
  	 * calling hibernate functions (which take system_transition_mutex)
  	 * this can cause lockdep to complain about a possible ABBA deadlock
60a0d2338   Johannes Berg   hibernate: fix lo...
897
898
899
900
  	 * which cannot happen since we're in the boot code here and
  	 * sysfs can't be invoked yet. Therefore, we use a subclass
  	 * here to avoid lockdep complaining.
  	 */
55f2503c3   Pingfan Liu   PM / reboot: Elim...
901
  	mutex_lock_nested(&system_transition_mutex, SINGLE_DEPTH_NESTING);
0c8454f56   Rafael J. Wysocki   PM/Hibernate: Fix...
902
903
904
905
906
907
908
909
  
  	if (swsusp_resume_device)
  		goto Check_image;
  
  	if (!strlen(resume_file)) {
  		error = -ENOENT;
  		goto Unlock;
  	}
8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
910
911
  	pm_pr_dbg("Checking hibernation image partition %s
  ", resume_file);
0c8454f56   Rafael J. Wysocki   PM/Hibernate: Fix...
912

f126f7334   Barry Song   PM / Hibernate: A...
913
  	if (resume_delay) {
2872de138   Rafael J. Wysocki   PM / hibernate: D...
914
915
  		pr_info("Waiting %dsec before reading resume device ...
  ",
f126f7334   Barry Song   PM / Hibernate: A...
916
917
918
  			resume_delay);
  		ssleep(resume_delay);
  	}
0c8454f56   Rafael J. Wysocki   PM/Hibernate: Fix...
919
920
  	/* Check if the device is there */
  	swsusp_resume_device = name_to_dev_t(resume_file);
3efa147ad   Pavel Machek   [PATCH] pm: Fix r...
921
  	if (!swsusp_resume_device) {
eed3ee082   Arjan van de Ven   PM/resume: wait f...
922
923
924
925
926
  		/*
  		 * Some device discovery might still be in progress; we need
  		 * to wait for this to finish.
  		 */
  		wait_for_device_probe();
6f8d7022a   Barry Song   PM / Hibernate: A...
927
928
929
930
931
932
  
  		if (resume_wait) {
  			while ((swsusp_resume_device = name_to_dev_t(resume_file)) == 0)
  				msleep(10);
  			async_synchronize_full();
  		}
3efa147ad   Pavel Machek   [PATCH] pm: Fix r...
933
  		swsusp_resume_device = name_to_dev_t(resume_file);
0c8454f56   Rafael J. Wysocki   PM/Hibernate: Fix...
934
935
936
937
  		if (!swsusp_resume_device) {
  			error = -ENODEV;
  			goto Unlock;
  		}
3efa147ad   Pavel Machek   [PATCH] pm: Fix r...
938
  	}
0c8454f56   Rafael J. Wysocki   PM/Hibernate: Fix...
939
   Check_image:
8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
940
941
  	pm_pr_dbg("Hibernation image partition %d:%d present
  ",
0c8454f56   Rafael J. Wysocki   PM/Hibernate: Fix...
942
  		MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943

8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
944
945
  	pm_pr_dbg("Looking for hibernation image.
  ");
ed746e3b1   Rafael J. Wysocki   [PATCH] swsusp: C...
946
947
  	error = swsusp_check();
  	if (error)
74dfd666d   Rafael J. Wysocki   swsusp: do not us...
948
  		goto Unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949

0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
950
  	/* The snapshot device should not be opened while we're running */
ab7e9b067   Domenico Andreoli   PM: hibernate: In...
951
  	if (!hibernate_acquire()) {
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
952
  		error = -EBUSY;
76b57e613   Jiri Slaby   PM / Hibernate: F...
953
  		swsusp_close(FMODE_READ);
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
954
955
  		goto Unlock;
  	}
8915aa204   Rafael J. Wysocki   PM / sleep: Mark ...
956
957
  	pr_info("resume from hibernation
  ");
5a0a2f304   Rafael J. Wysocki   Hibernation: Invo...
958
  	pm_prepare_console();
70d932985   Peter Zijlstra   notifier: Fix bro...
959
960
961
  	error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE);
  	if (error)
  		goto Restore;
1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
962

7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
963
964
  	pm_pr_dbg("Preparing processes for hibernation restore.
  ");
03afed8bc   Tejun Heo   freezer: clean up...
965
  	error = freeze_processes();
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
966
967
  	if (error)
  		goto Close_Finish;
2351f8d29   Dexuan Cui   PM: hibernate: Fr...
968
969
970
971
972
973
  
  	error = freeze_kernel_threads();
  	if (error) {
  		thaw_processes();
  		goto Close_Finish;
  	}
fe12c00d2   Chen Yu   PM / hibernate: I...
974
  	error = load_image_and_restore();
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
975
  	thaw_processes();
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
976
   Finish:
70d932985   Peter Zijlstra   notifier: Fix bro...
977
978
  	pm_notifier_call_chain(PM_POST_RESTORE);
   Restore:
5a0a2f304   Rafael J. Wysocki   Hibernation: Invo...
979
  	pm_restore_console();
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
980
981
  	pr_info("resume failed (%d)
  ", error);
ab7e9b067   Domenico Andreoli   PM: hibernate: In...
982
  	hibernate_release();
dd5d666b7   Shaohua Li   [PATCH] swsusp: a...
983
  	/* For success case, the suspend path will release the lock */
74dfd666d   Rafael J. Wysocki   swsusp: do not us...
984
   Unlock:
55f2503c3   Pingfan Liu   PM / reboot: Elim...
985
  	mutex_unlock(&system_transition_mutex);
8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
986
987
  	pm_pr_dbg("Hibernation image not present or could not be loaded.
  ");
7777fab98   Rafael J. Wysocki   swsusp: remove co...
988
  	return error;
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
989
   Close_Finish:
76b57e613   Jiri Slaby   PM / Hibernate: F...
990
991
  	swsusp_close(FMODE_READ);
  	goto Finish;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
  }
d3c345dbc   Russ Dill   PM / hibernate: M...
993
  late_initcall_sync(software_resume);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994

a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
995
996
997
998
  static const char * const hibernation_modes[] = {
  	[HIBERNATION_PLATFORM]	= "platform",
  	[HIBERNATION_SHUTDOWN]	= "shutdown",
  	[HIBERNATION_REBOOT]	= "reboot",
62c552ccc   Bojan Smojver   PM / Hibernate: E...
999
1000
1001
  #ifdef CONFIG_SUSPEND
  	[HIBERNATION_SUSPEND]	= "suspend",
  #endif
fe12c00d2   Chen Yu   PM / hibernate: I...
1002
  	[HIBERNATION_TEST_RESUME]	= "test_resume",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
  };
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
1004
1005
  /*
   * /sys/power/disk - Control hibernation mode.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
   *
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
1007
1008
1009
   * Hibernation can be handled in several ways.  There are a few different ways
   * to put the system into the sleep state: using the platform driver (e.g. ACPI
   * or other hibernation_ops), powering it off or rebooting it (for testing
48580ab87   Srivatsa S. Bhat   PM / Hibernate: R...
1010
   * mostly).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011
   *
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
1012
1013
   * The sysfs file /sys/power/disk provides an interface for selecting the
   * hibernation mode to use.  Reading from this file causes the available modes
48580ab87   Srivatsa S. Bhat   PM / Hibernate: R...
1014
   * to be printed.  There are 3 modes that can be supported:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
1019
   *	'platform'
   *	'shutdown'
   *	'reboot'
   *
f42a9813f   Rafael J. Wysocki   PM / Hibernate: U...
1020
1021
1022
1023
1024
1025
1026
1027
   * If a platform hibernation driver is in use, 'platform' will be supported
   * and will be used by default.  Otherwise, 'shutdown' will be used by default.
   * The selected option (i.e. the one corresponding to the current value of
   * hibernation_mode) is enclosed by a square bracket.
   *
   * To select a given hibernation mode it is necessary to write the mode's
   * string representation (as returned by reading from /sys/power/disk) back
   * into /sys/power/disk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
   */
386f275f5   Kay Sievers   Driver Core: swit...
1029
1030
  static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
  			 char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  {
f0ced9b22   Johannes Berg   power management:...
1032
1033
  	int i;
  	char *start = buf;
a6e15a390   Kees Cook   PM / hibernate: i...
1034
1035
1036
  	if (!hibernation_available())
  		return sprintf(buf, "[disabled]
  ");
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1037
1038
  	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
  		if (!hibernation_modes[i])
f0ced9b22   Johannes Berg   power management:...
1039
1040
  			continue;
  		switch (i) {
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1041
1042
  		case HIBERNATION_SHUTDOWN:
  		case HIBERNATION_REBOOT:
62c552ccc   Bojan Smojver   PM / Hibernate: E...
1043
1044
1045
  #ifdef CONFIG_SUSPEND
  		case HIBERNATION_SUSPEND:
  #endif
fe12c00d2   Chen Yu   PM / hibernate: I...
1046
  		case HIBERNATION_TEST_RESUME:
f0ced9b22   Johannes Berg   power management:...
1047
  			break;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1048
1049
  		case HIBERNATION_PLATFORM:
  			if (hibernation_ops)
f0ced9b22   Johannes Berg   power management:...
1050
1051
1052
1053
  				break;
  			/* not a valid mode, continue with loop */
  			continue;
  		}
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1054
1055
  		if (i == hibernation_mode)
  			buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
f0ced9b22   Johannes Berg   power management:...
1056
  		else
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1057
  			buf += sprintf(buf, "%s ", hibernation_modes[i]);
f0ced9b22   Johannes Berg   power management:...
1058
1059
1060
1061
  	}
  	buf += sprintf(buf, "
  ");
  	return buf-start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  }
386f275f5   Kay Sievers   Driver Core: swit...
1063
1064
  static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
  			  const char *buf, size_t n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
1067
1068
1069
  {
  	int error = 0;
  	int i;
  	int len;
  	char *p;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1070
  	int mode = HIBERNATION_INVALID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071

a6e15a390   Kees Cook   PM / hibernate: i...
1072
1073
  	if (!hibernation_available())
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
1076
  	p = memchr(buf, '
  ', n);
  	len = p ? p - buf : n;
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
1077
  	lock_system_sleep();
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1078
  	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
8d98a690f   Rafael J. Wysocki   swsusp: fix sysfs...
1079
1080
  		if (len == strlen(hibernation_modes[i])
  		    && !strncmp(buf, hibernation_modes[i], len)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
  			mode = i;
  			break;
  		}
  	}
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1085
  	if (mode != HIBERNATION_INVALID) {
fe0c935a6   Johannes Berg   rework pm_ops pm_...
1086
  		switch (mode) {
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1087
1088
  		case HIBERNATION_SHUTDOWN:
  		case HIBERNATION_REBOOT:
62c552ccc   Bojan Smojver   PM / Hibernate: E...
1089
1090
1091
  #ifdef CONFIG_SUSPEND
  		case HIBERNATION_SUSPEND:
  #endif
fe12c00d2   Chen Yu   PM / hibernate: I...
1092
  		case HIBERNATION_TEST_RESUME:
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1093
  			hibernation_mode = mode;
fe0c935a6   Johannes Berg   rework pm_ops pm_...
1094
  			break;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1095
1096
1097
  		case HIBERNATION_PLATFORM:
  			if (hibernation_ops)
  				hibernation_mode = mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
  			else
  				error = -EINVAL;
  		}
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1101
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
  		error = -EINVAL;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
1103
  	if (!error)
8d8b2441d   Rafael J. Wysocki   PM / sleep: Do no...
1104
1105
1106
  		pm_pr_dbg("Hibernation mode set to '%s'
  ",
  			       hibernation_modes[mode]);
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
1107
  	unlock_system_sleep();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
1110
1111
  	return error ? error : n;
  }
  
  power_attr(disk);
386f275f5   Kay Sievers   Driver Core: swit...
1112
1113
  static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
  {
6ada7ba2f   Xiang Chen   PM: hibernate: fi...
1115
1116
  	return sprintf(buf, "%d:%d
  ", MAJOR(swsusp_resume_device),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
1118
  		       MINOR(swsusp_resume_device));
  }
386f275f5   Kay Sievers   Driver Core: swit...
1119
1120
  static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
  			    const char *buf, size_t n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
  	dev_t res;
421a5fa1a   Sebastian Capella   PM / hibernate: u...
1123
1124
  	int len = n;
  	char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125

421a5fa1a   Sebastian Capella   PM / hibernate: u...
1126
1127
1128
1129
1130
1131
  	if (len && buf[len-1] == '
  ')
  		len--;
  	name = kstrndup(buf, len, GFP_KERNEL);
  	if (!name)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132

421a5fa1a   Sebastian Capella   PM / hibernate: u...
1133
1134
1135
1136
  	res = name_to_dev_t(name);
  	kfree(name);
  	if (!res)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137

bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
1138
  	lock_system_sleep();
a576219ac   Andrew Morton   [PATCH] swsusp: r...
1139
  	swsusp_resume_device = res;
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
1140
  	unlock_system_sleep();
7a7b99bf8   Luigi Semenzato   PM: hibernate: Ad...
1141
1142
1143
  	pm_pr_dbg("Configured hibernation resume from disk to %u
  ",
  		  swsusp_resume_device);
a576219ac   Andrew Morton   [PATCH] swsusp: r...
1144
1145
  	noresume = 0;
  	software_resume();
421a5fa1a   Sebastian Capella   PM / hibernate: u...
1146
  	return n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
1149
  }
  
  power_attr(resume);
355064675   Mario Limonciello   PM / hibernate: M...
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  static ssize_t resume_offset_show(struct kobject *kobj,
  				  struct kobj_attribute *attr, char *buf)
  {
  	return sprintf(buf, "%llu
  ", (unsigned long long)swsusp_resume_block);
  }
  
  static ssize_t resume_offset_store(struct kobject *kobj,
  				   struct kobj_attribute *attr, const char *buf,
  				   size_t n)
  {
  	unsigned long long offset;
  	int rc;
  
  	rc = kstrtoull(buf, 0, &offset);
  	if (rc)
  		return rc;
  	swsusp_resume_block = offset;
  
  	return n;
  }
  
  power_attr(resume_offset);
386f275f5   Kay Sievers   Driver Core: swit...
1173
1174
  static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
  			       char *buf)
ca0aec0f7   Rafael J. Wysocki   [PATCH] swsusp: m...
1175
  {
853609b61   Rafael J. Wysocki   [PATCH] swsusp: u...
1176
1177
  	return sprintf(buf, "%lu
  ", image_size);
ca0aec0f7   Rafael J. Wysocki   [PATCH] swsusp: m...
1178
  }
386f275f5   Kay Sievers   Driver Core: swit...
1179
1180
  static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
  				const char *buf, size_t n)
ca0aec0f7   Rafael J. Wysocki   [PATCH] swsusp: m...
1181
  {
853609b61   Rafael J. Wysocki   [PATCH] swsusp: u...
1182
  	unsigned long size;
ca0aec0f7   Rafael J. Wysocki   [PATCH] swsusp: m...
1183

853609b61   Rafael J. Wysocki   [PATCH] swsusp: u...
1184
  	if (sscanf(buf, "%lu", &size) == 1) {
ca0aec0f7   Rafael J. Wysocki   [PATCH] swsusp: m...
1185
1186
1187
1188
1189
1190
1191
1192
  		image_size = size;
  		return n;
  	}
  
  	return -EINVAL;
  }
  
  power_attr(image_size);
ddeb64870   Rafael J. Wysocki   PM / Hibernate: A...
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
  static ssize_t reserved_size_show(struct kobject *kobj,
  				  struct kobj_attribute *attr, char *buf)
  {
  	return sprintf(buf, "%lu
  ", reserved_size);
  }
  
  static ssize_t reserved_size_store(struct kobject *kobj,
  				   struct kobj_attribute *attr,
  				   const char *buf, size_t n)
  {
  	unsigned long size;
  
  	if (sscanf(buf, "%lu", &size) == 1) {
  		reserved_size = size;
  		return n;
  	}
  
  	return -EINVAL;
  }
  
  power_attr(reserved_size);
6ada7ba2f   Xiang Chen   PM: hibernate: fi...
1215
  static struct attribute *g[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  	&disk_attr.attr,
355064675   Mario Limonciello   PM / hibernate: M...
1217
  	&resume_offset_attr.attr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
  	&resume_attr.attr,
ca0aec0f7   Rafael J. Wysocki   [PATCH] swsusp: m...
1219
  	&image_size_attr.attr,
ddeb64870   Rafael J. Wysocki   PM / Hibernate: A...
1220
  	&reserved_size_attr.attr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
  	NULL,
  };
59494fe2c   Arvind Yadav   PM: hibernate: co...
1223
  static const struct attribute_group attr_group = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
1226
1227
1228
1229
  	.attrs = g,
  };
  
  
  static int __init pm_disk_init(void)
  {
d76e15fb2   Greg Kroah-Hartman   driver core: make...
1230
  	return sysfs_create_group(power_kobj, &attr_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
1232
1233
1234
1235
1236
1237
1238
1239
  }
  
  core_initcall(pm_disk_init);
  
  
  static int __init resume_setup(char *str)
  {
  	if (noresume)
  		return 1;
6ada7ba2f   Xiang Chen   PM: hibernate: fi...
1240
  	strncpy(resume_file, str, 255);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
1242
  	return 1;
  }
9a154d9d9   Rafael J. Wysocki   [PATCH] swsusp: a...
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
  static int __init resume_offset_setup(char *str)
  {
  	unsigned long long offset;
  
  	if (noresume)
  		return 1;
  
  	if (sscanf(str, "%llu", &offset) == 1)
  		swsusp_resume_block = offset;
  
  	return 1;
  }
f996fc967   Bojan Smojver   PM / Hibernate: C...
1255
1256
  static int __init hibernate_setup(char *str)
  {
2f88e41a2   Rafael J. Wysocki   PM / hibernate: A...
1257
  	if (!strncmp(str, "noresume", 8)) {
f996fc967   Bojan Smojver   PM / Hibernate: C...
1258
  		noresume = 1;
2f88e41a2   Rafael J. Wysocki   PM / hibernate: A...
1259
  	} else if (!strncmp(str, "nocompress", 10)) {
f996fc967   Bojan Smojver   PM / Hibernate: C...
1260
  		nocompress = 1;
2f88e41a2   Rafael J. Wysocki   PM / hibernate: A...
1261
  	} else if (!strncmp(str, "no", 2)) {
a6e15a390   Kees Cook   PM / hibernate: i...
1262
1263
  		noresume = 1;
  		nohibernate = 1;
0f5bf6d0a   Laura Abbott   arch: Rename CONF...
1264
  	} else if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)
4c0b6c10f   Rafael J. Wysocki   PM / hibernate: I...
1265
1266
  		   && !strncmp(str, "protect_image", 13)) {
  		enable_restore_image_protection();
a6e15a390   Kees Cook   PM / hibernate: i...
1267
  	}
f996fc967   Bojan Smojver   PM / Hibernate: C...
1268
1269
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270
1271
1272
1273
1274
  static int __init noresume_setup(char *str)
  {
  	noresume = 1;
  	return 1;
  }
6f8d7022a   Barry Song   PM / Hibernate: A...
1275
1276
1277
1278
1279
  static int __init resumewait_setup(char *str)
  {
  	resume_wait = 1;
  	return 1;
  }
f126f7334   Barry Song   PM / Hibernate: A...
1280
1281
  static int __init resumedelay_setup(char *str)
  {
f6514be5f   Dan Carpenter   PM / hibernate: F...
1282
  	int rc = kstrtouint(str, 0, &resume_delay);
317cf7e5e   Fabian Frederick   PM / hibernate: c...
1283
1284
1285
  
  	if (rc)
  		return rc;
f126f7334   Barry Song   PM / Hibernate: A...
1286
1287
  	return 1;
  }
a6e15a390   Kees Cook   PM / hibernate: i...
1288
1289
1290
1291
1292
1293
  static int __init nohibernate_setup(char *str)
  {
  	noresume = 1;
  	nohibernate = 1;
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  __setup("noresume", noresume_setup);
9a154d9d9   Rafael J. Wysocki   [PATCH] swsusp: a...
1295
  __setup("resume_offset=", resume_offset_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
  __setup("resume=", resume_setup);
f996fc967   Bojan Smojver   PM / Hibernate: C...
1297
  __setup("hibernate=", hibernate_setup);
6f8d7022a   Barry Song   PM / Hibernate: A...
1298
  __setup("resumewait", resumewait_setup);
f126f7334   Barry Song   PM / Hibernate: A...
1299
  __setup("resumedelay=", resumedelay_setup);
a6e15a390   Kees Cook   PM / hibernate: i...
1300
  __setup("nohibernate", nohibernate_setup);