diff options
Diffstat (limited to 'drivers/acpi')
| -rw-r--r-- | drivers/acpi/processor_idle.c | 6 | ||||
| -rw-r--r-- | drivers/acpi/sleep.c | 202 |
2 files changed, 191 insertions, 17 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index df38e81cc672..d50a7b6ccddd 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -791,7 +791,7 @@ static int acpi_idle_enter(struct cpuidle_device *dev, | |||
| 791 | return index; | 791 | return index; |
| 792 | } | 792 | } |
| 793 | 793 | ||
| 794 | static void acpi_idle_enter_freeze(struct cpuidle_device *dev, | 794 | static void acpi_idle_enter_s2idle(struct cpuidle_device *dev, |
| 795 | struct cpuidle_driver *drv, int index) | 795 | struct cpuidle_driver *drv, int index) |
| 796 | { | 796 | { |
| 797 | struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); | 797 | struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); |
| @@ -876,14 +876,14 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) | |||
| 876 | drv->safe_state_index = count; | 876 | drv->safe_state_index = count; |
| 877 | } | 877 | } |
| 878 | /* | 878 | /* |
| 879 | * Halt-induced C1 is not good for ->enter_freeze, because it | 879 | * Halt-induced C1 is not good for ->enter_s2idle, because it |
| 880 | * re-enables interrupts on exit. Moreover, C1 is generally not | 880 | * re-enables interrupts on exit. Moreover, C1 is generally not |
| 881 | * particularly interesting from the suspend-to-idle angle, so | 881 | * particularly interesting from the suspend-to-idle angle, so |
| 882 | * avoid C1 and the situations in which we may need to fall back | 882 | * avoid C1 and the situations in which we may need to fall back |
| 883 | * to it altogether. | 883 | * to it altogether. |
| 884 | */ | 884 | */ |
| 885 | if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr)) | 885 | if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr)) |
| 886 | state->enter_freeze = acpi_idle_enter_freeze; | 886 | state->enter_s2idle = acpi_idle_enter_s2idle; |
| 887 | 887 | ||
| 888 | count++; | 888 | count++; |
| 889 | if (count == CPUIDLE_STATE_MAX) | 889 | if (count == CPUIDLE_STATE_MAX) |
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 */ |
