diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-09-03 18:06:02 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-09-03 18:06:02 -0400 |
commit | 7b01463e51f6849d0787b24d06a62efcb243dd44 (patch) | |
tree | c084f9b5290fe4b6f279e711c0ada7be9dca8b32 /drivers/acpi/sleep.c | |
parent | a1b5fd8fa29fb2359f398ef17a706449d94de80d (diff) | |
parent | 726fb6b4f2a82a14a906f39bdabac4863b87c01a (diff) |
Merge branch 'pm-sleep'
* pm-sleep:
ACPI / PM: Check low power idle constraints for debug only
PM / s2idle: Rename platform operations structure
PM / s2idle: Rename ->enter_freeze to ->enter_s2idle
PM / s2idle: Rename freeze_state enum and related items
PM / s2idle: Rename PM_SUSPEND_FREEZE to PM_SUSPEND_TO_IDLE
ACPI / PM: Prefer suspend-to-idle over S3 on some systems
platform/x86: intel-hid: Wake up Dell Latitude 7275 from suspend-to-idle
PM / suspend: Define pr_fmt() in suspend.c
PM / suspend: Use mem_sleep_labels[] strings in messages
PM / sleep: Put pm_test under CONFIG_PM_SLEEP_DEBUG
PM / sleep: Check pm_wakeup_pending() in __device_suspend_noirq()
PM / core: Add error argument to dpm_show_time()
PM / core: Split dpm_suspend_noirq() and dpm_resume_noirq()
PM / s2idle: Rearrange the main suspend-to-idle loop
PM / timekeeping: Print debug messages when requested
PM / sleep: Mark suspend/hibernation start and finish
PM / sleep: Do not print debug messages by default
PM / suspend: Export pm_suspend_target_state
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r-- | drivers/acpi/sleep.c | 202 |
1 files changed, 188 insertions, 14 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fa8243c5c062..09460d9f9208 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -669,6 +669,7 @@ static const struct acpi_device_id lps0_device_ids[] = { | |||
669 | 669 | ||
670 | #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" | 670 | #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" |
671 | 671 | ||
672 | #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1 | ||
672 | #define ACPI_LPS0_SCREEN_OFF 3 | 673 | #define ACPI_LPS0_SCREEN_OFF 3 |
673 | #define ACPI_LPS0_SCREEN_ON 4 | 674 | #define ACPI_LPS0_SCREEN_ON 4 |
674 | #define ACPI_LPS0_ENTRY 5 | 675 | #define ACPI_LPS0_ENTRY 5 |
@@ -680,6 +681,166 @@ static acpi_handle lps0_device_handle; | |||
680 | static guid_t lps0_dsm_guid; | 681 | static guid_t lps0_dsm_guid; |
681 | static char lps0_dsm_func_mask; | 682 | static char lps0_dsm_func_mask; |
682 | 683 | ||
684 | /* Device constraint entry structure */ | ||
685 | struct lpi_device_info { | ||
686 | char *name; | ||
687 | int enabled; | ||
688 | union acpi_object *package; | ||
689 | }; | ||
690 | |||
691 | /* Constraint package structure */ | ||
692 | struct lpi_device_constraint { | ||
693 | int uid; | ||
694 | int min_dstate; | ||
695 | int function_states; | ||
696 | }; | ||
697 | |||
698 | struct lpi_constraints { | ||
699 | acpi_handle handle; | ||
700 | int min_dstate; | ||
701 | }; | ||
702 | |||
703 | static struct lpi_constraints *lpi_constraints_table; | ||
704 | static int lpi_constraints_table_size; | ||
705 | |||
706 | static void lpi_device_get_constraints(void) | ||
707 | { | ||
708 | union acpi_object *out_obj; | ||
709 | int i; | ||
710 | |||
711 | out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid, | ||
712 | 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, | ||
713 | NULL, ACPI_TYPE_PACKAGE); | ||
714 | |||
715 | acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n", | ||
716 | out_obj ? "successful" : "failed"); | ||
717 | |||
718 | if (!out_obj) | ||
719 | return; | ||
720 | |||
721 | lpi_constraints_table = kcalloc(out_obj->package.count, | ||
722 | sizeof(*lpi_constraints_table), | ||
723 | GFP_KERNEL); | ||
724 | if (!lpi_constraints_table) | ||
725 | goto free_acpi_buffer; | ||
726 | |||
727 | acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n"); | ||
728 | |||
729 | for (i = 0; i < out_obj->package.count; i++) { | ||
730 | struct lpi_constraints *constraint; | ||
731 | acpi_status status; | ||
732 | union acpi_object *package = &out_obj->package.elements[i]; | ||
733 | struct lpi_device_info info = { }; | ||
734 | int package_count = 0, j; | ||
735 | |||
736 | if (!package) | ||
737 | continue; | ||
738 | |||
739 | for (j = 0; j < package->package.count; ++j) { | ||
740 | union acpi_object *element = | ||
741 | &(package->package.elements[j]); | ||
742 | |||
743 | switch (element->type) { | ||
744 | case ACPI_TYPE_INTEGER: | ||
745 | info.enabled = element->integer.value; | ||
746 | break; | ||
747 | case ACPI_TYPE_STRING: | ||
748 | info.name = element->string.pointer; | ||
749 | break; | ||
750 | case ACPI_TYPE_PACKAGE: | ||
751 | package_count = element->package.count; | ||
752 | info.package = element->package.elements; | ||
753 | break; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | if (!info.enabled || !info.package || !info.name) | ||
758 | continue; | ||
759 | |||
760 | constraint = &lpi_constraints_table[lpi_constraints_table_size]; | ||
761 | |||
762 | status = acpi_get_handle(NULL, info.name, &constraint->handle); | ||
763 | if (ACPI_FAILURE(status)) | ||
764 | continue; | ||
765 | |||
766 | acpi_handle_debug(lps0_device_handle, | ||
767 | "index:%d Name:%s\n", i, info.name); | ||
768 | |||
769 | constraint->min_dstate = -1; | ||
770 | |||
771 | for (j = 0; j < package_count; ++j) { | ||
772 | union acpi_object *info_obj = &info.package[j]; | ||
773 | union acpi_object *cnstr_pkg; | ||
774 | union acpi_object *obj; | ||
775 | struct lpi_device_constraint dev_info; | ||
776 | |||
777 | switch (info_obj->type) { | ||
778 | case ACPI_TYPE_INTEGER: | ||
779 | /* version */ | ||
780 | break; | ||
781 | case ACPI_TYPE_PACKAGE: | ||
782 | if (info_obj->package.count < 2) | ||
783 | break; | ||
784 | |||
785 | cnstr_pkg = info_obj->package.elements; | ||
786 | obj = &cnstr_pkg[0]; | ||
787 | dev_info.uid = obj->integer.value; | ||
788 | obj = &cnstr_pkg[1]; | ||
789 | dev_info.min_dstate = obj->integer.value; | ||
790 | |||
791 | acpi_handle_debug(lps0_device_handle, | ||
792 | "uid:%d min_dstate:%s\n", | ||
793 | dev_info.uid, | ||
794 | acpi_power_state_string(dev_info.min_dstate)); | ||
795 | |||
796 | constraint->min_dstate = dev_info.min_dstate; | ||
797 | break; | ||
798 | } | ||
799 | } | ||
800 | |||
801 | if (constraint->min_dstate < 0) { | ||
802 | acpi_handle_debug(lps0_device_handle, | ||
803 | "Incomplete constraint defined\n"); | ||
804 | continue; | ||
805 | } | ||
806 | |||
807 | lpi_constraints_table_size++; | ||
808 | } | ||
809 | |||
810 | acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n"); | ||
811 | |||
812 | free_acpi_buffer: | ||
813 | ACPI_FREE(out_obj); | ||
814 | } | ||
815 | |||
816 | static void lpi_check_constraints(void) | ||
817 | { | ||
818 | int i; | ||
819 | |||
820 | for (i = 0; i < lpi_constraints_table_size; ++i) { | ||
821 | struct acpi_device *adev; | ||
822 | |||
823 | if (acpi_bus_get_device(lpi_constraints_table[i].handle, &adev)) | ||
824 | continue; | ||
825 | |||
826 | acpi_handle_debug(adev->handle, | ||
827 | "LPI: required min power state:%s current power state:%s\n", | ||
828 | acpi_power_state_string(lpi_constraints_table[i].min_dstate), | ||
829 | acpi_power_state_string(adev->power.state)); | ||
830 | |||
831 | if (!adev->flags.power_manageable) { | ||
832 | acpi_handle_info(adev->handle, "LPI: Device not power manageble\n"); | ||
833 | continue; | ||
834 | } | ||
835 | |||
836 | if (adev->power.state < lpi_constraints_table[i].min_dstate) | ||
837 | acpi_handle_info(adev->handle, | ||
838 | "LPI: Constraint not met; min power state:%s current power state:%s\n", | ||
839 | acpi_power_state_string(lpi_constraints_table[i].min_dstate), | ||
840 | acpi_power_state_string(adev->power.state)); | ||
841 | } | ||
842 | } | ||
843 | |||
683 | static void acpi_sleep_run_lps0_dsm(unsigned int func) | 844 | static void acpi_sleep_run_lps0_dsm(unsigned int func) |
684 | { | 845 | { |
685 | union acpi_object *out_obj; | 846 | union acpi_object *out_obj; |
@@ -714,6 +875,12 @@ static int lps0_device_attach(struct acpi_device *adev, | |||
714 | if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { | 875 | if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { |
715 | lps0_dsm_func_mask = bitmask; | 876 | lps0_dsm_func_mask = bitmask; |
716 | lps0_device_handle = adev->handle; | 877 | lps0_device_handle = adev->handle; |
878 | /* | ||
879 | * Use suspend-to-idle by default if the default | ||
880 | * suspend mode was not set from the command line. | ||
881 | */ | ||
882 | if (mem_sleep_default > PM_SUSPEND_MEM) | ||
883 | mem_sleep_current = PM_SUSPEND_TO_IDLE; | ||
717 | } | 884 | } |
718 | 885 | ||
719 | acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", | 886 | acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", |
@@ -723,6 +890,9 @@ static int lps0_device_attach(struct acpi_device *adev, | |||
723 | "_DSM function 0 evaluation failed\n"); | 890 | "_DSM function 0 evaluation failed\n"); |
724 | } | 891 | } |
725 | ACPI_FREE(out_obj); | 892 | ACPI_FREE(out_obj); |
893 | |||
894 | lpi_device_get_constraints(); | ||
895 | |||
726 | return 0; | 896 | return 0; |
727 | } | 897 | } |
728 | 898 | ||
@@ -731,14 +901,14 @@ static struct acpi_scan_handler lps0_handler = { | |||
731 | .attach = lps0_device_attach, | 901 | .attach = lps0_device_attach, |
732 | }; | 902 | }; |
733 | 903 | ||
734 | static int acpi_freeze_begin(void) | 904 | static int acpi_s2idle_begin(void) |
735 | { | 905 | { |
736 | acpi_scan_lock_acquire(); | 906 | acpi_scan_lock_acquire(); |
737 | s2idle_in_progress = true; | 907 | s2idle_in_progress = true; |
738 | return 0; | 908 | return 0; |
739 | } | 909 | } |
740 | 910 | ||
741 | static int acpi_freeze_prepare(void) | 911 | static int acpi_s2idle_prepare(void) |
742 | { | 912 | { |
743 | if (lps0_device_handle) { | 913 | if (lps0_device_handle) { |
744 | acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); | 914 | acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); |
@@ -758,8 +928,12 @@ static int acpi_freeze_prepare(void) | |||
758 | return 0; | 928 | return 0; |
759 | } | 929 | } |
760 | 930 | ||
761 | static void acpi_freeze_wake(void) | 931 | static void acpi_s2idle_wake(void) |
762 | { | 932 | { |
933 | |||
934 | if (pm_debug_messages_on) | ||
935 | lpi_check_constraints(); | ||
936 | |||
763 | /* | 937 | /* |
764 | * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means | 938 | * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means |
765 | * that the SCI has triggered while suspended, so cancel the wakeup in | 939 | * that the SCI has triggered while suspended, so cancel the wakeup in |
@@ -772,7 +946,7 @@ static void acpi_freeze_wake(void) | |||
772 | } | 946 | } |
773 | } | 947 | } |
774 | 948 | ||
775 | static void acpi_freeze_sync(void) | 949 | static void acpi_s2idle_sync(void) |
776 | { | 950 | { |
777 | /* | 951 | /* |
778 | * Process all pending events in case there are any wakeup ones. | 952 | * Process all pending events in case there are any wakeup ones. |
@@ -785,7 +959,7 @@ static void acpi_freeze_sync(void) | |||
785 | s2idle_wakeup = false; | 959 | s2idle_wakeup = false; |
786 | } | 960 | } |
787 | 961 | ||
788 | static void acpi_freeze_restore(void) | 962 | static void acpi_s2idle_restore(void) |
789 | { | 963 | { |
790 | if (acpi_sci_irq_valid()) | 964 | if (acpi_sci_irq_valid()) |
791 | disable_irq_wake(acpi_sci_irq); | 965 | disable_irq_wake(acpi_sci_irq); |
@@ -798,19 +972,19 @@ static void acpi_freeze_restore(void) | |||
798 | } | 972 | } |
799 | } | 973 | } |
800 | 974 | ||
801 | static void acpi_freeze_end(void) | 975 | static void acpi_s2idle_end(void) |
802 | { | 976 | { |
803 | s2idle_in_progress = false; | 977 | s2idle_in_progress = false; |
804 | acpi_scan_lock_release(); | 978 | acpi_scan_lock_release(); |
805 | } | 979 | } |
806 | 980 | ||
807 | static const struct platform_freeze_ops acpi_freeze_ops = { | 981 | static const struct platform_s2idle_ops acpi_s2idle_ops = { |
808 | .begin = acpi_freeze_begin, | 982 | .begin = acpi_s2idle_begin, |
809 | .prepare = acpi_freeze_prepare, | 983 | .prepare = acpi_s2idle_prepare, |
810 | .wake = acpi_freeze_wake, | 984 | .wake = acpi_s2idle_wake, |
811 | .sync = acpi_freeze_sync, | 985 | .sync = acpi_s2idle_sync, |
812 | .restore = acpi_freeze_restore, | 986 | .restore = acpi_s2idle_restore, |
813 | .end = acpi_freeze_end, | 987 | .end = acpi_s2idle_end, |
814 | }; | 988 | }; |
815 | 989 | ||
816 | static void acpi_sleep_suspend_setup(void) | 990 | static void acpi_sleep_suspend_setup(void) |
@@ -825,7 +999,7 @@ static void acpi_sleep_suspend_setup(void) | |||
825 | &acpi_suspend_ops_old : &acpi_suspend_ops); | 999 | &acpi_suspend_ops_old : &acpi_suspend_ops); |
826 | 1000 | ||
827 | acpi_scan_add_handler(&lps0_handler); | 1001 | acpi_scan_add_handler(&lps0_handler); |
828 | freeze_set_ops(&acpi_freeze_ops); | 1002 | s2idle_set_ops(&acpi_s2idle_ops); |
829 | } | 1003 | } |
830 | 1004 | ||
831 | #else /* !CONFIG_SUSPEND */ | 1005 | #else /* !CONFIG_SUSPEND */ |