diff options
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r-- | drivers/acpi/sleep.c | 76 |
1 files changed, 68 insertions, 8 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index ca191ff97844..1d661b5c3287 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/suspend.h> | 17 | #include <linux/suspend.h> |
18 | #include <linux/reboot.h> | 18 | #include <linux/reboot.h> |
19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
20 | #include <linux/module.h> | ||
21 | #include <linux/pm_runtime.h> | ||
20 | 22 | ||
21 | #include <asm/io.h> | 23 | #include <asm/io.h> |
22 | 24 | ||
@@ -26,6 +28,24 @@ | |||
26 | #include "internal.h" | 28 | #include "internal.h" |
27 | #include "sleep.h" | 29 | #include "sleep.h" |
28 | 30 | ||
31 | static unsigned int gts, bfs; | ||
32 | module_param(gts, uint, 0644); | ||
33 | module_param(bfs, uint, 0644); | ||
34 | MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); | ||
35 | MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); | ||
36 | |||
37 | static u8 wake_sleep_flags(void) | ||
38 | { | ||
39 | u8 flags = ACPI_NO_OPTIONAL_METHODS; | ||
40 | |||
41 | if (gts) | ||
42 | flags |= ACPI_EXECUTE_GTS; | ||
43 | if (bfs) | ||
44 | flags |= ACPI_EXECUTE_BFS; | ||
45 | |||
46 | return flags; | ||
47 | } | ||
48 | |||
29 | static u8 sleep_states[ACPI_S_STATE_COUNT]; | 49 | static u8 sleep_states[ACPI_S_STATE_COUNT]; |
30 | 50 | ||
31 | static void acpi_sleep_tts_switch(u32 acpi_state) | 51 | static void acpi_sleep_tts_switch(u32 acpi_state) |
@@ -243,6 +263,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
243 | { | 263 | { |
244 | acpi_status status = AE_OK; | 264 | acpi_status status = AE_OK; |
245 | u32 acpi_state = acpi_target_sleep_state; | 265 | u32 acpi_state = acpi_target_sleep_state; |
266 | u8 flags = wake_sleep_flags(); | ||
246 | int error; | 267 | int error; |
247 | 268 | ||
248 | ACPI_FLUSH_CPU_CACHE(); | 269 | ACPI_FLUSH_CPU_CACHE(); |
@@ -250,7 +271,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
250 | switch (acpi_state) { | 271 | switch (acpi_state) { |
251 | case ACPI_STATE_S1: | 272 | case ACPI_STATE_S1: |
252 | barrier(); | 273 | barrier(); |
253 | status = acpi_enter_sleep_state(acpi_state); | 274 | status = acpi_enter_sleep_state(acpi_state, flags); |
254 | break; | 275 | break; |
255 | 276 | ||
256 | case ACPI_STATE_S3: | 277 | case ACPI_STATE_S3: |
@@ -265,7 +286,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
265 | acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); | 286 | acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); |
266 | 287 | ||
267 | /* Reprogram control registers and execute _BFS */ | 288 | /* Reprogram control registers and execute _BFS */ |
268 | acpi_leave_sleep_state_prep(acpi_state); | 289 | acpi_leave_sleep_state_prep(acpi_state, flags); |
269 | 290 | ||
270 | /* ACPI 3.0 specs (P62) says that it's the responsibility | 291 | /* ACPI 3.0 specs (P62) says that it's the responsibility |
271 | * of the OSPM to clear the status bit [ implying that the | 292 | * of the OSPM to clear the status bit [ implying that the |
@@ -529,27 +550,30 @@ static int acpi_hibernation_begin(void) | |||
529 | 550 | ||
530 | static int acpi_hibernation_enter(void) | 551 | static int acpi_hibernation_enter(void) |
531 | { | 552 | { |
553 | u8 flags = wake_sleep_flags(); | ||
532 | acpi_status status = AE_OK; | 554 | acpi_status status = AE_OK; |
533 | 555 | ||
534 | ACPI_FLUSH_CPU_CACHE(); | 556 | ACPI_FLUSH_CPU_CACHE(); |
535 | 557 | ||
536 | /* This shouldn't return. If it returns, we have a problem */ | 558 | /* This shouldn't return. If it returns, we have a problem */ |
537 | status = acpi_enter_sleep_state(ACPI_STATE_S4); | 559 | status = acpi_enter_sleep_state(ACPI_STATE_S4, flags); |
538 | /* Reprogram control registers and execute _BFS */ | 560 | /* Reprogram control registers and execute _BFS */ |
539 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); | 561 | acpi_leave_sleep_state_prep(ACPI_STATE_S4, flags); |
540 | 562 | ||
541 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 563 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
542 | } | 564 | } |
543 | 565 | ||
544 | static void acpi_hibernation_leave(void) | 566 | static void acpi_hibernation_leave(void) |
545 | { | 567 | { |
568 | u8 flags = wake_sleep_flags(); | ||
569 | |||
546 | /* | 570 | /* |
547 | * If ACPI is not enabled by the BIOS and the boot kernel, we need to | 571 | * If ACPI is not enabled by the BIOS and the boot kernel, we need to |
548 | * enable it here. | 572 | * enable it here. |
549 | */ | 573 | */ |
550 | acpi_enable(); | 574 | acpi_enable(); |
551 | /* Reprogram control registers and execute _BFS */ | 575 | /* Reprogram control registers and execute _BFS */ |
552 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); | 576 | acpi_leave_sleep_state_prep(ACPI_STATE_S4, flags); |
553 | /* Check the hardware signature */ | 577 | /* Check the hardware signature */ |
554 | if (facs && s4_hardware_signature != facs->hardware_signature) { | 578 | if (facs && s4_hardware_signature != facs->hardware_signature) { |
555 | printk(KERN_EMERG "ACPI: Hardware changed while hibernated, " | 579 | printk(KERN_EMERG "ACPI: Hardware changed while hibernated, " |
@@ -730,6 +754,40 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) | |||
730 | 754 | ||
731 | #ifdef CONFIG_PM_SLEEP | 755 | #ifdef CONFIG_PM_SLEEP |
732 | /** | 756 | /** |
757 | * acpi_pm_device_run_wake - Enable/disable wake-up for given device. | ||
758 | * @phys_dev: Device to enable/disable the platform to wake-up the system for. | ||
759 | * @enable: Whether enable or disable the wake-up functionality. | ||
760 | * | ||
761 | * Find the ACPI device object corresponding to @pci_dev and try to | ||
762 | * enable/disable the GPE associated with it. | ||
763 | */ | ||
764 | int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) | ||
765 | { | ||
766 | struct acpi_device *dev; | ||
767 | acpi_handle handle; | ||
768 | |||
769 | if (!device_run_wake(phys_dev)) | ||
770 | return -EINVAL; | ||
771 | |||
772 | handle = DEVICE_ACPI_HANDLE(phys_dev); | ||
773 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) { | ||
774 | dev_dbg(phys_dev, "ACPI handle has no context in %s!\n", | ||
775 | __func__); | ||
776 | return -ENODEV; | ||
777 | } | ||
778 | |||
779 | if (enable) { | ||
780 | acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); | ||
781 | acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); | ||
782 | } else { | ||
783 | acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); | ||
784 | acpi_disable_wakeup_device_power(dev); | ||
785 | } | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | /** | ||
733 | * acpi_pm_device_sleep_wake - enable or disable the system wake-up | 791 | * acpi_pm_device_sleep_wake - enable or disable the system wake-up |
734 | * capability of given device | 792 | * capability of given device |
735 | * @dev: device to handle | 793 | * @dev: device to handle |
@@ -770,10 +828,12 @@ static void acpi_power_off_prepare(void) | |||
770 | 828 | ||
771 | static void acpi_power_off(void) | 829 | static void acpi_power_off(void) |
772 | { | 830 | { |
831 | u8 flags = wake_sleep_flags(); | ||
832 | |||
773 | /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ | 833 | /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ |
774 | printk(KERN_DEBUG "%s called\n", __func__); | 834 | printk(KERN_DEBUG "%s called\n", __func__); |
775 | local_irq_disable(); | 835 | local_irq_disable(); |
776 | acpi_enter_sleep_state(ACPI_STATE_S5); | 836 | acpi_enter_sleep_state(ACPI_STATE_S5, flags); |
777 | } | 837 | } |
778 | 838 | ||
779 | /* | 839 | /* |
@@ -788,13 +848,13 @@ static void __init acpi_gts_bfs_check(void) | |||
788 | { | 848 | { |
789 | acpi_handle dummy; | 849 | acpi_handle dummy; |
790 | 850 | ||
791 | if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__GTS, &dummy))) | 851 | if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__GTS, &dummy))) |
792 | { | 852 | { |
793 | printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n"); | 853 | printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n"); |
794 | printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, " | 854 | printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, " |
795 | "please notify linux-acpi@vger.kernel.org\n"); | 855 | "please notify linux-acpi@vger.kernel.org\n"); |
796 | } | 856 | } |
797 | if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__BFS, &dummy))) | 857 | if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__BFS, &dummy))) |
798 | { | 858 | { |
799 | printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n"); | 859 | printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n"); |
800 | printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, " | 860 | printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, " |