diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-16 20:25:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-16 20:25:46 -0400 |
commit | dc7c65db2845a8d17432d89252c4227a9a7cb15f (patch) | |
tree | 79030b0aaaafc04bc4303c21495134e744afc058 /drivers/acpi/sleep/main.c | |
parent | 8a0ca91e1db5de5eb5b18cfa919d52ff8be375af (diff) | |
parent | 58b6e5538460be358fdf1286d9a2fbcfcc2cfaba (diff) |
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (72 commits)
Revert "x86/PCI: ACPI based PCI gap calculation"
PCI: remove unnecessary volatile in PCIe hotplug struct controller
x86/PCI: ACPI based PCI gap calculation
PCI: include linux/pm_wakeup.h for device_set_wakeup_capable
PCI PM: Fix pci_prepare_to_sleep
x86/PCI: Fix PCI config space for domains > 0
Fix acpi_pm_device_sleep_wake() by providing a stub for CONFIG_PM_SLEEP=n
PCI: Simplify PCI device PM code
PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
PCI ACPI: Rework PCI handling of wake-up
ACPI: Introduce new device wakeup flag 'prepared'
ACPI: Introduce acpi_device_sleep_wake function
PCI: rework pci_set_power_state function to call platform first
PCI: Introduce platform_pci_power_manageable function
ACPI: Introduce acpi_bus_power_manageable function
PCI: make pci_name use dev_name
PCI: handle pci_name() being const
PCI: add stub for pci_set_consistent_dma_mask()
PCI: remove unused arch pcibios_update_resource() functions
PCI: fix pci_setup_device()'s sprinting into a const buffer
...
Fixed up conflicts in various files (arch/x86/kernel/setup_64.c,
arch/x86/pci/irq.c, arch/x86/pci/pci.h, drivers/acpi/sleep/main.c,
drivers/pci/pci.c, drivers/pci/pci.h, include/acpi/acpi_bus.h) from x86
and ACPI updates manually.
Diffstat (limited to 'drivers/acpi/sleep/main.c')
-rw-r--r-- | drivers/acpi/sleep/main.c | 301 |
1 files changed, 188 insertions, 113 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 244e352f7661..0489a7d1d42c 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -24,10 +24,6 @@ | |||
24 | 24 | ||
25 | u8 sleep_states[ACPI_S_STATE_COUNT]; | 25 | u8 sleep_states[ACPI_S_STATE_COUNT]; |
26 | 26 | ||
27 | #ifdef CONFIG_PM_SLEEP | ||
28 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | ||
29 | #endif | ||
30 | |||
31 | static int acpi_sleep_prepare(u32 acpi_state) | 27 | static int acpi_sleep_prepare(u32 acpi_state) |
32 | { | 28 | { |
33 | #ifdef CONFIG_ACPI_SLEEP | 29 | #ifdef CONFIG_ACPI_SLEEP |
@@ -49,9 +45,96 @@ static int acpi_sleep_prepare(u32 acpi_state) | |||
49 | return 0; | 45 | return 0; |
50 | } | 46 | } |
51 | 47 | ||
52 | #ifdef CONFIG_SUSPEND | 48 | #ifdef CONFIG_PM_SLEEP |
53 | static struct platform_suspend_ops acpi_suspend_ops; | 49 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; |
50 | |||
51 | /* | ||
52 | * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the | ||
53 | * user to request that behavior by using the 'acpi_old_suspend_ordering' | ||
54 | * kernel command line option that causes the following variable to be set. | ||
55 | */ | ||
56 | static bool old_suspend_ordering; | ||
57 | |||
58 | void __init acpi_old_suspend_ordering(void) | ||
59 | { | ||
60 | old_suspend_ordering = true; | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * acpi_pm_disable_gpes - Disable the GPEs. | ||
65 | */ | ||
66 | static int acpi_pm_disable_gpes(void) | ||
67 | { | ||
68 | acpi_hw_disable_all_gpes(); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * __acpi_pm_prepare - Prepare the platform to enter the target state. | ||
74 | * | ||
75 | * If necessary, set the firmware waking vector and do arch-specific | ||
76 | * nastiness to get the wakeup code to the waking vector. | ||
77 | */ | ||
78 | static int __acpi_pm_prepare(void) | ||
79 | { | ||
80 | int error = acpi_sleep_prepare(acpi_target_sleep_state); | ||
81 | |||
82 | if (error) | ||
83 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
84 | return error; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * acpi_pm_prepare - Prepare the platform to enter the target sleep | ||
89 | * state and disable the GPEs. | ||
90 | */ | ||
91 | static int acpi_pm_prepare(void) | ||
92 | { | ||
93 | int error = __acpi_pm_prepare(); | ||
94 | |||
95 | if (!error) | ||
96 | acpi_hw_disable_all_gpes(); | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * acpi_pm_finish - Instruct the platform to leave a sleep state. | ||
102 | * | ||
103 | * This is called after we wake back up (or if entering the sleep state | ||
104 | * failed). | ||
105 | */ | ||
106 | static void acpi_pm_finish(void) | ||
107 | { | ||
108 | u32 acpi_state = acpi_target_sleep_state; | ||
109 | |||
110 | if (acpi_state == ACPI_STATE_S0) | ||
111 | return; | ||
112 | |||
113 | printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n", | ||
114 | acpi_state); | ||
115 | acpi_disable_wakeup_device(acpi_state); | ||
116 | acpi_leave_sleep_state(acpi_state); | ||
117 | |||
118 | /* reset firmware waking vector */ | ||
119 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | ||
120 | |||
121 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * acpi_pm_end - Finish up suspend sequence. | ||
126 | */ | ||
127 | static void acpi_pm_end(void) | ||
128 | { | ||
129 | /* | ||
130 | * This is necessary in case acpi_pm_finish() is not called during a | ||
131 | * failing transition to a sleep state. | ||
132 | */ | ||
133 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
134 | } | ||
135 | #endif /* CONFIG_PM_SLEEP */ | ||
54 | 136 | ||
137 | #ifdef CONFIG_SUSPEND | ||
55 | extern void do_suspend_lowlevel(void); | 138 | extern void do_suspend_lowlevel(void); |
56 | 139 | ||
57 | static u32 acpi_suspend_states[] = { | 140 | static u32 acpi_suspend_states[] = { |
@@ -65,7 +148,6 @@ static u32 acpi_suspend_states[] = { | |||
65 | * acpi_suspend_begin - Set the target system sleep state to the state | 148 | * acpi_suspend_begin - Set the target system sleep state to the state |
66 | * associated with given @pm_state, if supported. | 149 | * associated with given @pm_state, if supported. |
67 | */ | 150 | */ |
68 | |||
69 | static int acpi_suspend_begin(suspend_state_t pm_state) | 151 | static int acpi_suspend_begin(suspend_state_t pm_state) |
70 | { | 152 | { |
71 | u32 acpi_state = acpi_suspend_states[pm_state]; | 153 | u32 acpi_state = acpi_suspend_states[pm_state]; |
@@ -82,25 +164,6 @@ static int acpi_suspend_begin(suspend_state_t pm_state) | |||
82 | } | 164 | } |
83 | 165 | ||
84 | /** | 166 | /** |
85 | * acpi_suspend_prepare - Do preliminary suspend work. | ||
86 | * | ||
87 | * If necessary, set the firmware waking vector and do arch-specific | ||
88 | * nastiness to get the wakeup code to the waking vector. | ||
89 | */ | ||
90 | |||
91 | static int acpi_suspend_prepare(void) | ||
92 | { | ||
93 | int error = acpi_sleep_prepare(acpi_target_sleep_state); | ||
94 | |||
95 | if (error) { | ||
96 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * acpi_suspend_enter - Actually enter a sleep state. | 167 | * acpi_suspend_enter - Actually enter a sleep state. |
105 | * @pm_state: ignored | 168 | * @pm_state: ignored |
106 | * | 169 | * |
@@ -108,7 +171,6 @@ static int acpi_suspend_prepare(void) | |||
108 | * assembly, which in turn call acpi_enter_sleep_state(). | 171 | * assembly, which in turn call acpi_enter_sleep_state(). |
109 | * It's unfortunate, but it works. Please fix if you're feeling frisky. | 172 | * It's unfortunate, but it works. Please fix if you're feeling frisky. |
110 | */ | 173 | */ |
111 | |||
112 | static int acpi_suspend_enter(suspend_state_t pm_state) | 174 | static int acpi_suspend_enter(suspend_state_t pm_state) |
113 | { | 175 | { |
114 | acpi_status status = AE_OK; | 176 | acpi_status status = AE_OK; |
@@ -165,39 +227,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
165 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 227 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
166 | } | 228 | } |
167 | 229 | ||
168 | /** | ||
169 | * acpi_suspend_finish - Instruct the platform to leave a sleep state. | ||
170 | * | ||
171 | * This is called after we wake back up (or if entering the sleep state | ||
172 | * failed). | ||
173 | */ | ||
174 | |||
175 | static void acpi_suspend_finish(void) | ||
176 | { | ||
177 | u32 acpi_state = acpi_target_sleep_state; | ||
178 | |||
179 | acpi_disable_wakeup_device(acpi_state); | ||
180 | acpi_leave_sleep_state(acpi_state); | ||
181 | |||
182 | /* reset firmware waking vector */ | ||
183 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | ||
184 | |||
185 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * acpi_suspend_end - Finish up suspend sequence. | ||
190 | */ | ||
191 | |||
192 | static void acpi_suspend_end(void) | ||
193 | { | ||
194 | /* | ||
195 | * This is necessary in case acpi_suspend_finish() is not called during a | ||
196 | * failing transition to a sleep state. | ||
197 | */ | ||
198 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
199 | } | ||
200 | |||
201 | static int acpi_suspend_state_valid(suspend_state_t pm_state) | 230 | static int acpi_suspend_state_valid(suspend_state_t pm_state) |
202 | { | 231 | { |
203 | u32 acpi_state; | 232 | u32 acpi_state; |
@@ -217,10 +246,39 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state) | |||
217 | static struct platform_suspend_ops acpi_suspend_ops = { | 246 | static struct platform_suspend_ops acpi_suspend_ops = { |
218 | .valid = acpi_suspend_state_valid, | 247 | .valid = acpi_suspend_state_valid, |
219 | .begin = acpi_suspend_begin, | 248 | .begin = acpi_suspend_begin, |
220 | .prepare = acpi_suspend_prepare, | 249 | .prepare = acpi_pm_prepare, |
221 | .enter = acpi_suspend_enter, | 250 | .enter = acpi_suspend_enter, |
222 | .finish = acpi_suspend_finish, | 251 | .finish = acpi_pm_finish, |
223 | .end = acpi_suspend_end, | 252 | .end = acpi_pm_end, |
253 | }; | ||
254 | |||
255 | /** | ||
256 | * acpi_suspend_begin_old - Set the target system sleep state to the | ||
257 | * state associated with given @pm_state, if supported, and | ||
258 | * execute the _PTS control method. This function is used if the | ||
259 | * pre-ACPI 2.0 suspend ordering has been requested. | ||
260 | */ | ||
261 | static int acpi_suspend_begin_old(suspend_state_t pm_state) | ||
262 | { | ||
263 | int error = acpi_suspend_begin(pm_state); | ||
264 | |||
265 | if (!error) | ||
266 | error = __acpi_pm_prepare(); | ||
267 | return error; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has | ||
272 | * been requested. | ||
273 | */ | ||
274 | static struct platform_suspend_ops acpi_suspend_ops_old = { | ||
275 | .valid = acpi_suspend_state_valid, | ||
276 | .begin = acpi_suspend_begin_old, | ||
277 | .prepare = acpi_pm_disable_gpes, | ||
278 | .enter = acpi_suspend_enter, | ||
279 | .finish = acpi_pm_finish, | ||
280 | .end = acpi_pm_end, | ||
281 | .recover = acpi_pm_finish, | ||
224 | }; | 282 | }; |
225 | #endif /* CONFIG_SUSPEND */ | 283 | #endif /* CONFIG_SUSPEND */ |
226 | 284 | ||
@@ -228,22 +286,9 @@ static struct platform_suspend_ops acpi_suspend_ops = { | |||
228 | static int acpi_hibernation_begin(void) | 286 | static int acpi_hibernation_begin(void) |
229 | { | 287 | { |
230 | acpi_target_sleep_state = ACPI_STATE_S4; | 288 | acpi_target_sleep_state = ACPI_STATE_S4; |
231 | |||
232 | return 0; | 289 | return 0; |
233 | } | 290 | } |
234 | 291 | ||
235 | static int acpi_hibernation_prepare(void) | ||
236 | { | ||
237 | int error = acpi_sleep_prepare(ACPI_STATE_S4); | ||
238 | |||
239 | if (error) { | ||
240 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
241 | return error; | ||
242 | } | ||
243 | |||
244 | return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; | ||
245 | } | ||
246 | |||
247 | static int acpi_hibernation_enter(void) | 292 | static int acpi_hibernation_enter(void) |
248 | { | 293 | { |
249 | acpi_status status = AE_OK; | 294 | acpi_status status = AE_OK; |
@@ -273,52 +318,55 @@ static void acpi_hibernation_leave(void) | |||
273 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); | 318 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); |
274 | } | 319 | } |
275 | 320 | ||
276 | static void acpi_hibernation_finish(void) | 321 | static void acpi_pm_enable_gpes(void) |
277 | { | 322 | { |
278 | acpi_disable_wakeup_device(ACPI_STATE_S4); | 323 | acpi_hw_enable_all_runtime_gpes(); |
279 | acpi_leave_sleep_state(ACPI_STATE_S4); | ||
280 | |||
281 | /* reset firmware waking vector */ | ||
282 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | ||
283 | |||
284 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
285 | } | 324 | } |
286 | 325 | ||
287 | static void acpi_hibernation_end(void) | 326 | static struct platform_hibernation_ops acpi_hibernation_ops = { |
288 | { | 327 | .begin = acpi_hibernation_begin, |
289 | /* | 328 | .end = acpi_pm_end, |
290 | * This is necessary in case acpi_hibernation_finish() is not called | 329 | .pre_snapshot = acpi_pm_prepare, |
291 | * during a failing transition to the sleep state. | 330 | .finish = acpi_pm_finish, |
292 | */ | 331 | .prepare = acpi_pm_prepare, |
293 | acpi_target_sleep_state = ACPI_STATE_S0; | 332 | .enter = acpi_hibernation_enter, |
294 | } | 333 | .leave = acpi_hibernation_leave, |
334 | .pre_restore = acpi_pm_disable_gpes, | ||
335 | .restore_cleanup = acpi_pm_enable_gpes, | ||
336 | }; | ||
295 | 337 | ||
296 | static int acpi_hibernation_pre_restore(void) | 338 | /** |
339 | * acpi_hibernation_begin_old - Set the target system sleep state to | ||
340 | * ACPI_STATE_S4 and execute the _PTS control method. This | ||
341 | * function is used if the pre-ACPI 2.0 suspend ordering has been | ||
342 | * requested. | ||
343 | */ | ||
344 | static int acpi_hibernation_begin_old(void) | ||
297 | { | 345 | { |
298 | acpi_status status; | 346 | int error = acpi_sleep_prepare(ACPI_STATE_S4); |
299 | |||
300 | status = acpi_hw_disable_all_gpes(); | ||
301 | |||
302 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | ||
303 | } | ||
304 | 347 | ||
305 | static void acpi_hibernation_restore_cleanup(void) | 348 | if (!error) |
306 | { | 349 | acpi_target_sleep_state = ACPI_STATE_S4; |
307 | acpi_hw_enable_all_runtime_gpes(); | 350 | return error; |
308 | } | 351 | } |
309 | 352 | ||
310 | static struct platform_hibernation_ops acpi_hibernation_ops = { | 353 | /* |
311 | .begin = acpi_hibernation_begin, | 354 | * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has |
312 | .end = acpi_hibernation_end, | 355 | * been requested. |
313 | .pre_snapshot = acpi_hibernation_prepare, | 356 | */ |
314 | .finish = acpi_hibernation_finish, | 357 | static struct platform_hibernation_ops acpi_hibernation_ops_old = { |
315 | .prepare = acpi_hibernation_prepare, | 358 | .begin = acpi_hibernation_begin_old, |
359 | .end = acpi_pm_end, | ||
360 | .pre_snapshot = acpi_pm_disable_gpes, | ||
361 | .finish = acpi_pm_finish, | ||
362 | .prepare = acpi_pm_disable_gpes, | ||
316 | .enter = acpi_hibernation_enter, | 363 | .enter = acpi_hibernation_enter, |
317 | .leave = acpi_hibernation_leave, | 364 | .leave = acpi_hibernation_leave, |
318 | .pre_restore = acpi_hibernation_pre_restore, | 365 | .pre_restore = acpi_pm_disable_gpes, |
319 | .restore_cleanup = acpi_hibernation_restore_cleanup, | 366 | .restore_cleanup = acpi_pm_enable_gpes, |
367 | .recover = acpi_pm_finish, | ||
320 | }; | 368 | }; |
321 | #endif /* CONFIG_HIBERNATION */ | 369 | #endif /* CONFIG_HIBERNATION */ |
322 | 370 | ||
323 | int acpi_suspend(u32 acpi_state) | 371 | int acpi_suspend(u32 acpi_state) |
324 | { | 372 | { |
@@ -419,6 +467,31 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) | |||
419 | *d_min_p = d_min; | 467 | *d_min_p = d_min; |
420 | return d_max; | 468 | return d_max; |
421 | } | 469 | } |
470 | |||
471 | /** | ||
472 | * acpi_pm_device_sleep_wake - enable or disable the system wake-up | ||
473 | * capability of given device | ||
474 | * @dev: device to handle | ||
475 | * @enable: 'true' - enable, 'false' - disable the wake-up capability | ||
476 | */ | ||
477 | int acpi_pm_device_sleep_wake(struct device *dev, bool enable) | ||
478 | { | ||
479 | acpi_handle handle; | ||
480 | struct acpi_device *adev; | ||
481 | |||
482 | if (!device_may_wakeup(dev)) | ||
483 | return -EINVAL; | ||
484 | |||
485 | handle = DEVICE_ACPI_HANDLE(dev); | ||
486 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { | ||
487 | printk(KERN_DEBUG "ACPI handle has no context!\n"); | ||
488 | return -ENODEV; | ||
489 | } | ||
490 | |||
491 | return enable ? | ||
492 | acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : | ||
493 | acpi_disable_wakeup_device_power(adev); | ||
494 | } | ||
422 | #endif | 495 | #endif |
423 | 496 | ||
424 | static void acpi_power_off_prepare(void) | 497 | static void acpi_power_off_prepare(void) |
@@ -460,13 +533,15 @@ int __init acpi_sleep_init(void) | |||
460 | } | 533 | } |
461 | } | 534 | } |
462 | 535 | ||
463 | suspend_set_ops(&acpi_suspend_ops); | 536 | suspend_set_ops(old_suspend_ordering ? |
537 | &acpi_suspend_ops_old : &acpi_suspend_ops); | ||
464 | #endif | 538 | #endif |
465 | 539 | ||
466 | #ifdef CONFIG_HIBERNATION | 540 | #ifdef CONFIG_HIBERNATION |
467 | status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); | 541 | status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); |
468 | if (ACPI_SUCCESS(status)) { | 542 | if (ACPI_SUCCESS(status)) { |
469 | hibernation_set_ops(&acpi_hibernation_ops); | 543 | hibernation_set_ops(old_suspend_ordering ? |
544 | &acpi_hibernation_ops_old : &acpi_hibernation_ops); | ||
470 | sleep_states[ACPI_STATE_S4] = 1; | 545 | sleep_states[ACPI_STATE_S4] = 1; |
471 | printk(" S4"); | 546 | printk(" S4"); |
472 | } | 547 | } |