Blame view

drivers/acpi/sleep.c 19.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * sleep.c - ACPI sleep support.
   *
e2a5b420f   Alexey Starikovskiy   [ACPI] ACPI power...
4
   * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
12
13
14
15
16
17
   * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
   * Copyright (c) 2000-2003 Patrick Mochel
   * Copyright (c) 2003 Open Source Development Lab
   *
   * This file is released under the GPLv2.
   *
   */
  
  #include <linux/delay.h>
  #include <linux/irq.h>
  #include <linux/dmi.h>
  #include <linux/device.h>
  #include <linux/suspend.h>
e49f711cc   Zhao Yakui   ACPI: Add the sup...
18
  #include <linux/reboot.h>
f216cc374   Alexey Starikovskiy   ACPI: suspend: co...
19
20
  
  #include <asm/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  #include <acpi/acpi_bus.h>
  #include <acpi/acpi_drivers.h>
e60cc7a6f   Bjorn Helgaas   ACPI: move privat...
23
24
  
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
  #include "sleep.h"
  
  u8 sleep_states[ACPI_S_STATE_COUNT];
e49f711cc   Zhao Yakui   ACPI: Add the sup...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  static void acpi_sleep_tts_switch(u32 acpi_state)
  {
  	union acpi_object in_arg = { ACPI_TYPE_INTEGER };
  	struct acpi_object_list arg_list = { 1, &in_arg };
  	acpi_status status = AE_OK;
  
  	in_arg.integer.value = acpi_state;
  	status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
  	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
  		/*
  		 * OS can't evaluate the _TTS object correctly. Some warning
  		 * message will be printed. But it won't break anything.
  		 */
  		printk(KERN_NOTICE "Failure in evaluating _TTS object
  ");
  	}
  }
  
  static int tts_notify_reboot(struct notifier_block *this,
  			unsigned long code, void *x)
  {
  	acpi_sleep_tts_switch(ACPI_STATE_S5);
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block tts_notifier = {
  	.notifier_call	= tts_notify_reboot,
  	.next		= NULL,
  	.priority	= 0,
  };
c9b6c8f68   Rafael J. Wysocki   ACPI: Print messa...
58
  static int acpi_sleep_prepare(u32 acpi_state)
2f3f22269   Alexey Starikovskiy   ACPI: suspend: bu...
59
60
61
62
63
64
65
  {
  #ifdef CONFIG_ACPI_SLEEP
  	/* do we have a wakeup address for S2 and S3? */
  	if (acpi_state == ACPI_STATE_S3) {
  		if (!acpi_wakeup_address) {
  			return -EFAULT;
  		}
4b4f7280d   H. Peter Anvin   x86 ACPI: normali...
66
67
  		acpi_set_firmware_waking_vector(
  				(acpi_physical_address)acpi_wakeup_address);
2f3f22269   Alexey Starikovskiy   ACPI: suspend: bu...
68
69
70
  
  	}
  	ACPI_FLUSH_CPU_CACHE();
2f3f22269   Alexey Starikovskiy   ACPI: suspend: bu...
71
  #endif
c9b6c8f68   Rafael J. Wysocki   ACPI: Print messa...
72
73
74
  	printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d
  ",
  		acpi_state);
78f5f0231   Rafael J. Wysocki   ACPI / Wakeup: Si...
75
  	acpi_enable_wakeup_devices(acpi_state);
2f3f22269   Alexey Starikovskiy   ACPI: suspend: bu...
76
77
78
  	acpi_enter_sleep_state_prep(acpi_state);
  	return 0;
  }
5d1e072b6   Rafael J. Wysocki   ACPI suspend: Fix...
79
  #ifdef CONFIG_ACPI_SLEEP
b849075c0   Len Brown   ACPI suspend: fix...
80
  static u32 acpi_target_sleep_state = ACPI_STATE_S0;
d7f0eea9e   Zhang Rui   ACPI: introduce k...
81
82
  
  /*
72ad5d77f   Rafael J. Wysocki   ACPI / Sleep: All...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
   * The ACPI specification wants us to save NVS memory regions during hibernation
   * and to restore them during the subsequent resume.  Windows does that also for
   * suspend to RAM.  However, it is known that this mechanism does not work on
   * all machines, so we allow the user to disable it with the help of the
   * 'acpi_sleep=nonvs' kernel command line option.
   */
  static bool nvs_nosave;
  
  void __init acpi_nvs_nosave(void)
  {
  	nvs_nosave = true;
  }
  
  /*
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
97
98
99
100
101
102
103
104
105
106
107
108
   * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
   * user to request that behavior by using the 'acpi_old_suspend_ordering'
   * kernel command line option that causes the following variable to be set.
   */
  static bool old_suspend_ordering;
  
  void __init acpi_old_suspend_ordering(void)
  {
  	old_suspend_ordering = true;
  }
  
  /**
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
109
   * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
110
   */
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
111
  static int acpi_pm_freeze(void)
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
112
  {
3d97e426a   Lin Ming   ACPI: main.c: use...
113
  	acpi_disable_all_gpes();
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
114
  	acpi_os_wait_events_complete(NULL);
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
115
  	acpi_ec_block_transactions();
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
116
117
118
119
  	return 0;
  }
  
  /**
c5f7a1bb6   Rafael J. Wysocki   ACPI / Sleep: Con...
120
121
122
123
124
125
126
127
128
129
   * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS.
   */
  static int acpi_pm_pre_suspend(void)
  {
  	acpi_pm_freeze();
  	suspend_nvs_save();
  	return 0;
  }
  
  /**
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
130
131
132
133
134
135
136
137
   *	__acpi_pm_prepare - Prepare the platform to enter the target state.
   *
   *	If necessary, set the firmware waking vector and do arch-specific
   *	nastiness to get the wakeup code to the waking vector.
   */
  static int __acpi_pm_prepare(void)
  {
  	int error = acpi_sleep_prepare(acpi_target_sleep_state);
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
138
139
  	if (error)
  		acpi_target_sleep_state = ACPI_STATE_S0;
c5f7a1bb6   Rafael J. Wysocki   ACPI / Sleep: Con...
140

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
141
142
143
144
145
146
147
148
149
150
  	return error;
  }
  
  /**
   *	acpi_pm_prepare - Prepare the platform to enter the target sleep
   *		state and disable the GPEs.
   */
  static int acpi_pm_prepare(void)
  {
  	int error = __acpi_pm_prepare();
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
151
  	if (!error)
c5f7a1bb6   Rafael J. Wysocki   ACPI / Sleep: Con...
152
  		acpi_pm_pre_suspend();
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
153

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
154
155
156
157
158
159
160
161
162
163
164
165
  	return error;
  }
  
  /**
   *	acpi_pm_finish - Instruct the platform to leave a sleep state.
   *
   *	This is called after we wake back up (or if entering the sleep state
   *	failed).
   */
  static void acpi_pm_finish(void)
  {
  	u32 acpi_state = acpi_target_sleep_state;
42de5532f   Len Brown   Merge branch 'bug...
166
  	acpi_ec_unblock_transactions();
2a6b69765   Matthew Garrett   ACPI: Store NVS s...
167

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
168
169
  	if (acpi_state == ACPI_STATE_S0)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
171
172
173
  	printk(KERN_INFO PREFIX "Waking up from system sleep state S%d
  ",
  		acpi_state);
78f5f0231   Rafael J. Wysocki   ACPI / Wakeup: Si...
174
  	acpi_disable_wakeup_devices(acpi_state);
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
175
176
177
178
179
180
181
182
183
184
185
186
187
  	acpi_leave_sleep_state(acpi_state);
  
  	/* reset firmware waking vector */
  	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
  
  	acpi_target_sleep_state = ACPI_STATE_S0;
  }
  
  /**
   *	acpi_pm_end - Finish up suspend sequence.
   */
  static void acpi_pm_end(void)
  {
e96c4b081   Rafael J. Wysocki   ACPI / Sleep: Fre...
188
  	suspend_nvs_free();
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
189
190
191
192
193
  	/*
  	 * This is necessary in case acpi_pm_finish() is not called during a
  	 * failing transition to a sleep state.
  	 */
  	acpi_target_sleep_state = ACPI_STATE_S0;
e49f711cc   Zhao Yakui   ACPI: Add the sup...
194
  	acpi_sleep_tts_switch(acpi_target_sleep_state);
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
195
  }
92daa7b53   Rafael J. Wysocki   ACPI suspend: bui...
196
197
  #else /* !CONFIG_ACPI_SLEEP */
  #define acpi_target_sleep_state	ACPI_STATE_S0
5d1e072b6   Rafael J. Wysocki   ACPI suspend: Fix...
198
  #endif /* CONFIG_ACPI_SLEEP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
200
  #ifdef CONFIG_SUSPEND
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
  extern void do_suspend_lowlevel(void);
  
  static u32 acpi_suspend_states[] = {
e2a5b420f   Alexey Starikovskiy   [ACPI] ACPI power...
204
205
206
  	[PM_SUSPEND_ON] = ACPI_STATE_S0,
  	[PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
  	[PM_SUSPEND_MEM] = ACPI_STATE_S3,
e2a5b420f   Alexey Starikovskiy   [ACPI] ACPI power...
207
  	[PM_SUSPEND_MAX] = ACPI_STATE_S5
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  };
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
209
  /**
2c6e33c36   Len Brown   ACPI: re-name acp...
210
   *	acpi_suspend_begin - Set the target system sleep state to the state
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
211
212
   *		associated with given @pm_state, if supported.
   */
2c6e33c36   Len Brown   ACPI: re-name acp...
213
  static int acpi_suspend_begin(suspend_state_t pm_state)
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
214
215
216
  {
  	u32 acpi_state = acpi_suspend_states[pm_state];
  	int error = 0;
72ad5d77f   Rafael J. Wysocki   ACPI / Sleep: All...
217
  	error = nvs_nosave ? 0 : suspend_nvs_alloc();
2a6b69765   Matthew Garrett   ACPI: Store NVS s...
218
219
  	if (error)
  		return error;
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
220
221
  	if (sleep_states[acpi_state]) {
  		acpi_target_sleep_state = acpi_state;
e49f711cc   Zhao Yakui   ACPI: Add the sup...
222
  		acpi_sleep_tts_switch(acpi_target_sleep_state);
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
223
224
225
226
227
228
229
230
  	} else {
  		printk(KERN_ERR "ACPI does not support this state: %d
  ",
  			pm_state);
  		error = -ENOSYS;
  	}
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  /**
2c6e33c36   Len Brown   ACPI: re-name acp...
232
   *	acpi_suspend_enter - Actually enter a sleep state.
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
233
   *	@pm_state: ignored
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
   *
50ad147aa   Rafael J. Wysocki   ACPI: Remove refe...
235
236
   *	Flush caches and go to sleep. For STR we have to call arch-specific
   *	assembly, which in turn call acpi_enter_sleep_state().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
   *	It's unfortunate, but it works. Please fix if you're feeling frisky.
   */
2c6e33c36   Len Brown   ACPI: re-name acp...
239
  static int acpi_suspend_enter(suspend_state_t pm_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
  {
  	acpi_status status = AE_OK;
  	unsigned long flags = 0;
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
243
  	u32 acpi_state = acpi_target_sleep_state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
  
  	ACPI_FLUSH_CPU_CACHE();
  
  	/* Do arch specific saving of state. */
50ad147aa   Rafael J. Wysocki   ACPI: Remove refe...
248
  	if (acpi_state == ACPI_STATE_S3) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  		int error = acpi_save_state_mem();
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
250

60417f597   Rafael J. Wysocki   ACPI suspend: Cal...
251
  		if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
  			return error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  	local_irq_save(flags);
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
255
256
  	switch (acpi_state) {
  	case ACPI_STATE_S1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
  		barrier();
  		status = acpi_enter_sleep_state(acpi_state);
  		break;
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
260
  	case ACPI_STATE_S3:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
  		do_suspend_lowlevel();
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  	}
872d83d00   Arnaud Patard   ACPI: suppress po...
264

b6dacf63e   Matthew Garrett   ACPI: Uncondition...
265
266
  	/* This violates the spec but is required for bug compatibility. */
  	acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
65df78473   Rafael J. Wysocki   ACPI suspend: Bla...
267

c95d47a86   Rafael J. Wysocki   ACPI: Separate in...
268
269
  	/* Reprogram control registers and execute _BFS */
  	acpi_leave_sleep_state_prep(acpi_state);
23b168d42   Pavel Machek   PM: documentation...
270
  	/* ACPI 3.0 specs (P62) says that it's the responsibility
872d83d00   Arnaud Patard   ACPI: suppress po...
271
272
273
274
275
  	 * of the OSPM to clear the status bit [ implying that the
  	 * POWER_BUTTON event should not reach userspace ]
  	 */
  	if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
  		acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
a3627f67b   Shaohua Li   ACPI: clear GPE e...
276
277
278
279
280
  	/*
  	 * Disable and clear GPE status before interrupt is enabled. Some GPEs
  	 * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
  	 * acpi_leave_sleep_state will reenable specific GPEs later
  	 */
3d97e426a   Lin Ming   ACPI: main.c: use...
281
  	acpi_disable_all_gpes();
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
282
  	/* Allow EC transactions to happen. */
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
283
  	acpi_ec_unblock_transactions_early();
a3627f67b   Shaohua Li   ACPI: clear GPE e...
284

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
  	local_irq_restore(flags);
  	printk(KERN_DEBUG "Back to C!
  ");
e9b3aba88   Rafael J. Wysocki   ACPI: Implement t...
288
  	/* restore processor state */
50ad147aa   Rafael J. Wysocki   ACPI: Remove refe...
289
  	if (acpi_state == ACPI_STATE_S3)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  		acpi_restore_state_mem();
2a6b69765   Matthew Garrett   ACPI: Store NVS s...
291
  	suspend_nvs_restore();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
  }
2c6e33c36   Len Brown   ACPI: re-name acp...
294
  static int acpi_suspend_state_valid(suspend_state_t pm_state)
eb9289eb2   Shaohua Li   [PATCH] introduce...
295
  {
e8c9c5026   Johannes Berg   power management:...
296
  	u32 acpi_state;
eb9289eb2   Shaohua Li   [PATCH] introduce...
297

e8c9c5026   Johannes Berg   power management:...
298
299
300
301
302
303
304
305
306
307
  	switch (pm_state) {
  	case PM_SUSPEND_ON:
  	case PM_SUSPEND_STANDBY:
  	case PM_SUSPEND_MEM:
  		acpi_state = acpi_suspend_states[pm_state];
  
  		return sleep_states[acpi_state];
  	default:
  		return 0;
  	}
eb9289eb2   Shaohua Li   [PATCH] introduce...
308
  }
2c6e33c36   Len Brown   ACPI: re-name acp...
309
310
311
  static struct platform_suspend_ops acpi_suspend_ops = {
  	.valid = acpi_suspend_state_valid,
  	.begin = acpi_suspend_begin,
6a7c7eaf7   Rafael J. Wysocki   PM/Suspend: Intro...
312
  	.prepare_late = acpi_pm_prepare,
2c6e33c36   Len Brown   ACPI: re-name acp...
313
  	.enter = acpi_suspend_enter,
618d7fd0d   Rafael J. Wysocki   ACPI / Sleep: Dro...
314
  	.wake = acpi_pm_finish,
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
315
316
317
318
319
320
321
322
323
324
325
326
  	.end = acpi_pm_end,
  };
  
  /**
   *	acpi_suspend_begin_old - Set the target system sleep state to the
   *		state associated with given @pm_state, if supported, and
   *		execute the _PTS control method.  This function is used if the
   *		pre-ACPI 2.0 suspend ordering has been requested.
   */
  static int acpi_suspend_begin_old(suspend_state_t pm_state)
  {
  	int error = acpi_suspend_begin(pm_state);
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
327
328
  	if (!error)
  		error = __acpi_pm_prepare();
c5f7a1bb6   Rafael J. Wysocki   ACPI / Sleep: Con...
329

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
330
331
332
333
334
335
336
337
338
339
  	return error;
  }
  
  /*
   * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
   * been requested.
   */
  static struct platform_suspend_ops acpi_suspend_ops_old = {
  	.valid = acpi_suspend_state_valid,
  	.begin = acpi_suspend_begin_old,
c5f7a1bb6   Rafael J. Wysocki   ACPI / Sleep: Con...
340
  	.prepare_late = acpi_pm_pre_suspend,
2c6e33c36   Len Brown   ACPI: re-name acp...
341
  	.enter = acpi_suspend_enter,
618d7fd0d   Rafael J. Wysocki   ACPI / Sleep: Dro...
342
  	.wake = acpi_pm_finish,
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
343
344
  	.end = acpi_pm_end,
  	.recover = acpi_pm_finish,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  };
e41fb7c58   Carlos Corbacho   pm: acpi pm: add ...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  
  static int __init init_old_suspend_ordering(const struct dmi_system_id *d)
  {
  	old_suspend_ordering = true;
  	return 0;
  }
  
  static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
  	{
  	.callback = init_old_suspend_ordering,
  	.ident = "Abit KN9 (nForce4 variant)",
  	.matches = {
  		DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"),
  		DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
  		},
  	},
4fb507b6b   Rafael J. Wysocki   ACPI suspend: Bla...
362
363
364
365
366
367
368
369
  	{
  	.callback = init_old_suspend_ordering,
  	.ident = "HP xw4600 Workstation",
  	.matches = {
  		DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
  		DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
  		},
  	},
65df78473   Rafael J. Wysocki   ACPI suspend: Bla...
370
  	{
a14044958   Andy Whitcroft   suspend: switch t...
371
372
373
374
375
376
377
  	.callback = init_old_suspend_ordering,
  	.ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
  	.matches = {
  		DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."),
  		DMI_MATCH(DMI_BOARD_NAME, "M2N8L"),
  		},
  	},
45e779888   Zhang Rui   ACPI suspend: Bla...
378
  	{
2a9ef8e1a   Zhao Yakui   ACPI: suspend: Ad...
379
380
381
382
383
384
385
386
  	.callback = init_old_suspend_ordering,
  	.ident = "Panasonic CF51-2L",
  	.matches = {
  		DMI_MATCH(DMI_BOARD_VENDOR,
  				"Matsushita Electric Industrial Co.,Ltd."),
  		DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
  		},
  	},
e41fb7c58   Carlos Corbacho   pm: acpi pm: add ...
387
388
  	{},
  };
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
389
  #endif /* CONFIG_SUSPEND */
b0cb1a19d   Rafael J. Wysocki   Replace CONFIG_SO...
390
  #ifdef CONFIG_HIBERNATION
bdfe6b7c6   Shaohua Li   pm: acpi hibernat...
391
392
393
394
395
396
397
398
  static unsigned long s4_hardware_signature;
  static struct acpi_table_facs *facs;
  static bool nosigcheck;
  
  void __init acpi_no_s4_hw_signature(void)
  {
  	nosigcheck = true;
  }
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
399
  static int acpi_hibernation_begin(void)
74f270af0   Rafael J. Wysocki   PM: Rework struct...
400
  {
3f4b0ef7f   Rafael J. Wysocki   ACPI hibernate: A...
401
  	int error;
72ad5d77f   Rafael J. Wysocki   ACPI / Sleep: All...
402
  	error = nvs_nosave ? 0 : suspend_nvs_alloc();
3f4b0ef7f   Rafael J. Wysocki   ACPI hibernate: A...
403
404
405
406
407
408
409
  	if (!error) {
  		acpi_target_sleep_state = ACPI_STATE_S4;
  		acpi_sleep_tts_switch(acpi_target_sleep_state);
  	}
  
  	return error;
  }
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
410
411
412
413
414
415
416
417
  static int acpi_hibernation_enter(void)
  {
  	acpi_status status = AE_OK;
  	unsigned long flags = 0;
  
  	ACPI_FLUSH_CPU_CACHE();
  
  	local_irq_save(flags);
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
418
419
  	/* This shouldn't return.  If it returns, we have a problem */
  	status = acpi_enter_sleep_state(ACPI_STATE_S4);
c95d47a86   Rafael J. Wysocki   ACPI: Separate in...
420
421
  	/* Reprogram control registers and execute _BFS */
  	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
422
423
424
425
  	local_irq_restore(flags);
  
  	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
  }
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
426
427
428
429
430
431
432
  static void acpi_hibernation_leave(void)
  {
  	/*
  	 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
  	 * enable it here.
  	 */
  	acpi_enable();
c95d47a86   Rafael J. Wysocki   ACPI: Separate in...
433
434
  	/* Reprogram control registers and execute _BFS */
  	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
bdfe6b7c6   Shaohua Li   pm: acpi hibernat...
435
436
437
438
439
440
441
  	/* Check the hardware signature */
  	if (facs && s4_hardware_signature != facs->hardware_signature) {
  		printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
  			"cannot resume!
  ");
  		panic("ACPI S4 hardware signature mismatch");
  	}
3f4b0ef7f   Rafael J. Wysocki   ACPI hibernate: A...
442
  	/* Restore the NVS memory area */
dd4c4f17d   Matthew Garrett   suspend: Move NVS...
443
  	suspend_nvs_restore();
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
444
  	/* Allow EC transactions to happen. */
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
445
  	acpi_ec_unblock_transactions_early();
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
446
  }
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
447
  static void acpi_pm_thaw(void)
f6bb13aa1   Rafael J. Wysocki   ACPI / EC / PM: C...
448
  {
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
449
  	acpi_ec_unblock_transactions();
3d97e426a   Lin Ming   ACPI: main.c: use...
450
  	acpi_enable_all_runtime_gpes();
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
451
  }
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
452
453
454
  static struct platform_hibernation_ops acpi_hibernation_ops = {
  	.begin = acpi_hibernation_begin,
  	.end = acpi_pm_end,
c5f7a1bb6   Rafael J. Wysocki   ACPI / Sleep: Con...
455
  	.pre_snapshot = acpi_pm_prepare,
2a6b69765   Matthew Garrett   ACPI: Store NVS s...
456
  	.finish = acpi_pm_finish,
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
457
458
459
  	.prepare = acpi_pm_prepare,
  	.enter = acpi_hibernation_enter,
  	.leave = acpi_hibernation_leave,
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
460
461
  	.pre_restore = acpi_pm_freeze,
  	.restore_cleanup = acpi_pm_thaw,
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
462
  };
caea99ef3   Rafael J. Wysocki   Hibernation: Intr...
463

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
464
465
466
467
468
469
470
  /**
   *	acpi_hibernation_begin_old - Set the target system sleep state to
   *		ACPI_STATE_S4 and execute the _PTS control method.  This
   *		function is used if the pre-ACPI 2.0 suspend ordering has been
   *		requested.
   */
  static int acpi_hibernation_begin_old(void)
a634cc101   Rafael J. Wysocki   swsusp: introduce...
471
  {
e49f711cc   Zhao Yakui   ACPI: Add the sup...
472
473
474
475
476
477
478
479
480
  	int error;
  	/*
  	 * The _TTS object should always be evaluated before the _PTS object.
  	 * When the old_suspended_ordering is true, the _PTS object is
  	 * evaluated in the acpi_sleep_prepare.
  	 */
  	acpi_sleep_tts_switch(ACPI_STATE_S4);
  
  	error = acpi_sleep_prepare(ACPI_STATE_S4);
a634cc101   Rafael J. Wysocki   swsusp: introduce...
481

3f4b0ef7f   Rafael J. Wysocki   ACPI hibernate: A...
482
  	if (!error) {
72ad5d77f   Rafael J. Wysocki   ACPI / Sleep: All...
483
  		if (!nvs_nosave)
dd4c4f17d   Matthew Garrett   suspend: Move NVS...
484
  			error = suspend_nvs_alloc();
3f4b0ef7f   Rafael J. Wysocki   ACPI hibernate: A...
485
486
487
488
489
  		if (!error)
  			acpi_target_sleep_state = ACPI_STATE_S4;
  	}
  	return error;
  }
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
490
491
492
493
494
495
496
  /*
   * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
   * been requested.
   */
  static struct platform_hibernation_ops acpi_hibernation_ops_old = {
  	.begin = acpi_hibernation_begin_old,
  	.end = acpi_pm_end,
c5f7a1bb6   Rafael J. Wysocki   ACPI / Sleep: Con...
497
  	.pre_snapshot = acpi_pm_pre_suspend,
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
498
  	.prepare = acpi_pm_freeze,
2a6b69765   Matthew Garrett   ACPI: Store NVS s...
499
  	.finish = acpi_pm_finish,
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
500
  	.enter = acpi_hibernation_enter,
c7e0831d3   Rafael J. Wysocki   Hibernation: Chec...
501
  	.leave = acpi_hibernation_leave,
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
502
503
  	.pre_restore = acpi_pm_freeze,
  	.restore_cleanup = acpi_pm_thaw,
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
504
  	.recover = acpi_pm_finish,
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
505
  };
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
506
  #endif /* CONFIG_HIBERNATION */
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
507

296699de6   Rafael J. Wysocki   Introduce CONFIG_...
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  int acpi_suspend(u32 acpi_state)
  {
  	suspend_state_t states[] = {
  		[1] = PM_SUSPEND_STANDBY,
  		[3] = PM_SUSPEND_MEM,
  		[5] = PM_SUSPEND_MAX
  	};
  
  	if (acpi_state < 6 && states[acpi_state])
  		return pm_suspend(states[acpi_state]);
  	if (acpi_state == 4)
  		return hibernate();
  	return -EINVAL;
  }
853298bc0   Alexey Starikovskiy   ACPI: CONFIG_ACPI...
522
  #ifdef CONFIG_PM_SLEEP
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
523
524
525
  /**
   *	acpi_pm_device_sleep_state - return preferred power state of ACPI device
   *		in the system sleep state given by %acpi_target_sleep_state
2fe2de5f6   David Brownell   ACPI PM: acpi_pm_...
526
527
   *	@dev: device to examine; its driver model wakeup flags control
   *		whether it should be able to wake up the system
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
   *	@d_min_p: used to store the upper limit of allowed states range
   *	Return value: preferred power state of the device on success, -ENODEV on
   *		failure (ie. if there's no 'struct acpi_device' for @dev)
   *
   *	Find the lowest power (highest number) ACPI device power state that
   *	device @dev can be in while the system is in the sleep state represented
   *	by %acpi_target_sleep_state.  If @wake is nonzero, the device should be
   *	able to wake up the system from this sleep state.  If @d_min_p is set,
   *	the highest power (lowest number) device power state of @dev allowed
   *	in this system sleep state is stored at the location pointed to by it.
   *
   *	The caller must ensure that @dev is valid before using this function.
   *	The caller is also responsible for figuring out if the device is
   *	supposed to be able to wake up the system and passing this information
   *	via @wake.
   */
2fe2de5f6   David Brownell   ACPI PM: acpi_pm_...
544
  int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
545
546
547
548
  {
  	acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
  	struct acpi_device *adev;
  	char acpi_method[] = "_SxD";
27663c585   Matthew Wilcox   ACPI: Change acpi...
549
  	unsigned long long d_min, d_max;
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
550
551
  
  	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
ead77594a   Shaohua Li   ACPI: "ACPI handl...
552
553
  		printk(KERN_DEBUG "ACPI handle has no context!
  ");
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  		return -ENODEV;
  	}
  
  	acpi_method[2] = '0' + acpi_target_sleep_state;
  	/*
  	 * If the sleep state is S0, we will return D3, but if the device has
  	 * _S0W, we will use the value from _S0W
  	 */
  	d_min = ACPI_STATE_D0;
  	d_max = ACPI_STATE_D3;
  
  	/*
  	 * If present, _SxD methods return the minimum D-state (highest power
  	 * state) we can use for the corresponding S-states.  Otherwise, the
  	 * minimum D-state is D0 (ACPI 3.x).
  	 *
  	 * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer
  	 * provided -- that's our fault recovery, we ignore retval.
  	 */
  	if (acpi_target_sleep_state > ACPI_STATE_S0)
  		acpi_evaluate_integer(handle, acpi_method, NULL, &d_min);
  
  	/*
  	 * If _PRW says we can wake up the system from the target sleep state,
  	 * the D-state returned by _SxD is sufficient for that (we assume a
  	 * wakeup-aware driver if wake is set).  Still, if _SxW exists
  	 * (ACPI 3.x), it should return the maximum (lowest power) D-state that
  	 * can wake the system.  _S0W may be valid, too.
  	 */
  	if (acpi_target_sleep_state == ACPI_STATE_S0 ||
2fe2de5f6   David Brownell   ACPI PM: acpi_pm_...
584
  	    (device_may_wakeup(dev) && adev->wakeup.state.enabled &&
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
585
  	     adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
ad3399c37   Rafael J. Wysocki   ACPI: Fix acpi_pm...
586
  		acpi_status status;
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
587
  		acpi_method[3] = 'W';
ad3399c37   Rafael J. Wysocki   ACPI: Fix acpi_pm...
588
589
590
591
592
593
594
595
596
597
  		status = acpi_evaluate_integer(handle, acpi_method, NULL,
  						&d_max);
  		if (ACPI_FAILURE(status)) {
  			d_max = d_min;
  		} else if (d_max < d_min) {
  			/* Warn the user of the broken DSDT */
  			printk(KERN_WARNING "ACPI: Wrong value from %s
  ",
  				acpi_method);
  			/* Sanitize it */
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
598
  			d_min = d_max;
ad3399c37   Rafael J. Wysocki   ACPI: Fix acpi_pm...
599
  		}
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
600
601
602
603
604
605
  	}
  
  	if (d_min_p)
  		*d_min_p = d_min;
  	return d_max;
  }
eb9d0fe40   Rafael J. Wysocki   PCI ACPI: Rework ...
606
607
608
609
610
611
612
613
614
615
616
  
  /**
   *	acpi_pm_device_sleep_wake - enable or disable the system wake-up
   *                                  capability of given device
   *	@dev: device to handle
   *	@enable: 'true' - enable, 'false' - disable the wake-up capability
   */
  int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
  {
  	acpi_handle handle;
  	struct acpi_device *adev;
df8db91fc   Rafael J. Wysocki   PCI / ACPI PM: Re...
617
  	int error;
eb9d0fe40   Rafael J. Wysocki   PCI ACPI: Rework ...
618

0baed8da1   Rafael J. Wysocki   PCI / ACPI PM: Pr...
619
  	if (!device_can_wakeup(dev))
eb9d0fe40   Rafael J. Wysocki   PCI ACPI: Rework ...
620
621
622
623
  		return -EINVAL;
  
  	handle = DEVICE_ACPI_HANDLE(dev);
  	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
df8db91fc   Rafael J. Wysocki   PCI / ACPI PM: Re...
624
625
  		dev_dbg(dev, "ACPI handle has no context in %s!
  ", __func__);
eb9d0fe40   Rafael J. Wysocki   PCI ACPI: Rework ...
626
627
  		return -ENODEV;
  	}
e8b6f9701   Rafael J. Wysocki   ACPICA: Introduce...
628
629
630
  	error = enable ?
  		acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) :
  		acpi_disable_wakeup_device_power(adev);
df8db91fc   Rafael J. Wysocki   PCI / ACPI PM: Re...
631
632
633
634
635
636
  	if (!error)
  		dev_info(dev, "wake-up capability %s by ACPI
  ",
  				enable ? "enabled" : "disabled");
  
  	return error;
eb9d0fe40   Rafael J. Wysocki   PCI ACPI: Rework ...
637
  }
853298bc0   Alexey Starikovskiy   ACPI: CONFIG_ACPI...
638
  #endif
fd4aff1a2   Shaohua Li   ACPI: Add acpi_pm...
639

f216cc374   Alexey Starikovskiy   ACPI: suspend: co...
640
641
642
643
  static void acpi_power_off_prepare(void)
  {
  	/* Prepare to power off the system */
  	acpi_sleep_prepare(ACPI_STATE_S5);
3d97e426a   Lin Ming   ACPI: main.c: use...
644
  	acpi_disable_all_gpes();
f216cc374   Alexey Starikovskiy   ACPI: suspend: co...
645
646
647
648
649
  }
  
  static void acpi_power_off(void)
  {
  	/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
4d9391557   Frank Seidel   ACPI: add missing...
650
651
  	printk(KERN_DEBUG "%s called
  ", __func__);
f216cc374   Alexey Starikovskiy   ACPI: suspend: co...
652
653
654
  	local_irq_disable();
  	acpi_enter_sleep_state(ACPI_STATE_S5);
  }
96f15efce   Len Brown   ACPI: Disable _GT...
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  /*
   * ACPI 2.0 created the optional _GTS and _BFS,
   * but industry adoption has been neither rapid nor broad.
   *
   * Linux gets into trouble when it executes poorly validated
   * paths through the BIOS, so disable _GTS and _BFS by default,
   * but do speak up and offer the option to enable them.
   */
  void __init acpi_gts_bfs_check(void)
  {
  	acpi_handle dummy;
  
  	if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__GTS, &dummy)))
  	{
  		printk(KERN_NOTICE PREFIX "BIOS offers _GTS
  ");
  		printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, "
  			"please notify linux-acpi@vger.kernel.org
  ");
  	}
  	if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__BFS, &dummy)))
  	{
  		printk(KERN_NOTICE PREFIX "BIOS offers _BFS
  ");
  		printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, "
  			"please notify linux-acpi@vger.kernel.org
  ");
  	}
  }
aafbcd165   Alexey Starikovskiy   ACPI: invoke acpi...
684
  int __init acpi_sleep_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  {
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
686
687
688
  	acpi_status status;
  	u8 type_a, type_b;
  #ifdef CONFIG_SUSPEND
e2a5b420f   Alexey Starikovskiy   [ACPI] ACPI power...
689
  	int i = 0;
e41fb7c58   Carlos Corbacho   pm: acpi pm: add ...
690
691
  
  	dmi_check_system(acpisleep_dmi_table);
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
692
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
  
  	if (acpi_disabled)
  		return 0;
5a50fe709   Frans Pop   ACPI: suspend: co...
696
697
  	sleep_states[ACPI_STATE_S0] = 1;
  	printk(KERN_INFO PREFIX "(supports S0");
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
698
  #ifdef CONFIG_SUSPEND
5a50fe709   Frans Pop   ACPI: suspend: co...
699
  	for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
  		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
  		if (ACPI_SUCCESS(status)) {
  			sleep_states[i] = 1;
  			printk(" S%d", i);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706

d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
707
708
  	suspend_set_ops(old_suspend_ordering ?
  		&acpi_suspend_ops_old : &acpi_suspend_ops);
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
709
  #endif
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
710

b0cb1a19d   Rafael J. Wysocki   Replace CONFIG_SO...
711
  #ifdef CONFIG_HIBERNATION
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
712
713
  	status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
  	if (ACPI_SUCCESS(status)) {
d8f3de0d2   Rafael J. Wysocki   Suspend-related p...
714
715
  		hibernation_set_ops(old_suspend_ordering ?
  			&acpi_hibernation_ops_old : &acpi_hibernation_ops);
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
716
  		sleep_states[ACPI_STATE_S4] = 1;
f216cc374   Alexey Starikovskiy   ACPI: suspend: co...
717
  		printk(" S4");
bdfe6b7c6   Shaohua Li   pm: acpi hibernat...
718
  		if (!nosigcheck) {
3d97e426a   Lin Ming   ACPI: main.c: use...
719
  			acpi_get_table(ACPI_SIG_FACS, 1,
bdfe6b7c6   Shaohua Li   pm: acpi hibernat...
720
721
722
723
724
  				(struct acpi_table_header **)&facs);
  			if (facs)
  				s4_hardware_signature =
  					facs->hardware_signature;
  		}
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
725
  	}
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
726
  #endif
f216cc374   Alexey Starikovskiy   ACPI: suspend: co...
727
728
729
730
731
732
733
734
735
  	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
  	if (ACPI_SUCCESS(status)) {
  		sleep_states[ACPI_STATE_S5] = 1;
  		printk(" S5");
  		pm_power_off_prepare = acpi_power_off_prepare;
  		pm_power_off = acpi_power_off;
  	}
  	printk(")
  ");
e49f711cc   Zhao Yakui   ACPI: Add the sup...
736
737
738
739
740
  	/*
  	 * Register the tts_notifier to reboot notifier list so that the _TTS
  	 * object can also be evaluated when the system enters S5.
  	 */
  	register_reboot_notifier(&tts_notifier);
96f15efce   Len Brown   ACPI: Disable _GT...
741
  	acpi_gts_bfs_check();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
  	return 0;
  }