diff options
author | Sudeep Holla <Sudeep.Holla@arm.com> | 2016-07-21 12:18:07 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-07-21 17:25:58 -0400 |
commit | a36a7fecfe6071732075ad5aa31196adce13181b (patch) | |
tree | e3d88c1b278e013b10bd1280dc0257d5b23cba3c /drivers/acpi | |
parent | 35ae713355868aa493edbfbabf615473473215cc (diff) |
ACPI / processor_idle: Add support for Low Power Idle(LPI) states
ACPI 6.0 introduced an optional object _LPI that provides an alternate
method to describe Low Power Idle states. It defines the local power
states for each node in a hierarchical processor topology. The OSPM can
use _LPI object to select a local power state for each level of processor
hierarchy in the system. They used to produce a composite power state
request that is presented to the platform by the OSPM.
Since multiple processors affect the idle state for any non-leaf hierarchy
node, coordination of idle state requests between the processors is
required. ACPI supports two different coordination schemes: Platform
coordinated and OS initiated.
This patch adds initial support for Platform coordination scheme of LPI.
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/bus.c | 14 | ||||
-rw-r--r-- | drivers/acpi/processor_driver.c | 2 | ||||
-rw-r--r-- | drivers/acpi/processor_idle.c | 466 |
3 files changed, 425 insertions, 57 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 262ca31b86d9..80ebb05e387c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -302,6 +302,14 @@ out_kfree: | |||
302 | EXPORT_SYMBOL(acpi_run_osc); | 302 | EXPORT_SYMBOL(acpi_run_osc); |
303 | 303 | ||
304 | bool osc_sb_apei_support_acked; | 304 | bool osc_sb_apei_support_acked; |
305 | |||
306 | /* | ||
307 | * ACPI 6.0 Section 8.4.4.2 Idle State Coordination | ||
308 | * OSPM supports platform coordinated low power idle(LPI) states | ||
309 | */ | ||
310 | bool osc_pc_lpi_support_confirmed; | ||
311 | EXPORT_SYMBOL_GPL(osc_pc_lpi_support_confirmed); | ||
312 | |||
305 | static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; | 313 | static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; |
306 | static void acpi_bus_osc_support(void) | 314 | static void acpi_bus_osc_support(void) |
307 | { | 315 | { |
@@ -322,6 +330,7 @@ static void acpi_bus_osc_support(void) | |||
322 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT; | 330 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT; |
323 | 331 | ||
324 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT; | 332 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT; |
333 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT; | ||
325 | 334 | ||
326 | if (!ghes_disable) | 335 | if (!ghes_disable) |
327 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; | 336 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; |
@@ -329,9 +338,12 @@ static void acpi_bus_osc_support(void) | |||
329 | return; | 338 | return; |
330 | if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) { | 339 | if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) { |
331 | u32 *capbuf_ret = context.ret.pointer; | 340 | u32 *capbuf_ret = context.ret.pointer; |
332 | if (context.ret.length > OSC_SUPPORT_DWORD) | 341 | if (context.ret.length > OSC_SUPPORT_DWORD) { |
333 | osc_sb_apei_support_acked = | 342 | osc_sb_apei_support_acked = |
334 | capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT; | 343 | capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT; |
344 | osc_pc_lpi_support_confirmed = | ||
345 | capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT; | ||
346 | } | ||
335 | kfree(context.ret.pointer); | 347 | kfree(context.ret.pointer); |
336 | } | 348 | } |
337 | /* do we need to check other returned cap? Sounds no */ | 349 | /* do we need to check other returned cap? Sounds no */ |
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index d2fa8cb82d2b..0ca14ac7bb28 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c | |||
@@ -90,7 +90,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) | |||
90 | pr->performance_platform_limit); | 90 | pr->performance_platform_limit); |
91 | break; | 91 | break; |
92 | case ACPI_PROCESSOR_NOTIFY_POWER: | 92 | case ACPI_PROCESSOR_NOTIFY_POWER: |
93 | acpi_processor_cst_has_changed(pr); | 93 | acpi_processor_power_state_has_changed(pr); |
94 | acpi_bus_generate_netlink_event(device->pnp.device_class, | 94 | acpi_bus_generate_netlink_event(device->pnp.device_class, |
95 | dev_name(&device->dev), event, 0); | 95 | dev_name(&device->dev), event, 0); |
96 | break; | 96 | break; |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ca0de35d1c3a..cea52528aa18 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -303,7 +303,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) | |||
303 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 303 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
304 | union acpi_object *cst; | 304 | union acpi_object *cst; |
305 | 305 | ||
306 | |||
307 | if (nocst) | 306 | if (nocst) |
308 | return -ENODEV; | 307 | return -ENODEV; |
309 | 308 | ||
@@ -576,7 +575,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) | |||
576 | return (working); | 575 | return (working); |
577 | } | 576 | } |
578 | 577 | ||
579 | static int acpi_processor_get_power_info(struct acpi_processor *pr) | 578 | static int acpi_processor_get_cstate_info(struct acpi_processor *pr) |
580 | { | 579 | { |
581 | unsigned int i; | 580 | unsigned int i; |
582 | int result; | 581 | int result; |
@@ -810,31 +809,12 @@ static void acpi_idle_enter_freeze(struct cpuidle_device *dev, | |||
810 | acpi_idle_do_entry(cx); | 809 | acpi_idle_do_entry(cx); |
811 | } | 810 | } |
812 | 811 | ||
813 | /** | ||
814 | * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE | ||
815 | * device i.e. per-cpu data | ||
816 | * | ||
817 | * @pr: the ACPI processor | ||
818 | * @dev : the cpuidle device | ||
819 | */ | ||
820 | static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, | 812 | static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, |
821 | struct cpuidle_device *dev) | 813 | struct cpuidle_device *dev) |
822 | { | 814 | { |
823 | int i, count = CPUIDLE_DRIVER_STATE_START; | 815 | int i, count = CPUIDLE_DRIVER_STATE_START; |
824 | struct acpi_processor_cx *cx; | 816 | struct acpi_processor_cx *cx; |
825 | 817 | ||
826 | if (!pr->flags.power_setup_done) | ||
827 | return -EINVAL; | ||
828 | |||
829 | if (pr->flags.power == 0) { | ||
830 | return -EINVAL; | ||
831 | } | ||
832 | |||
833 | if (!dev) | ||
834 | return -EINVAL; | ||
835 | |||
836 | dev->cpu = pr->id; | ||
837 | |||
838 | if (max_cstate == 0) | 818 | if (max_cstate == 0) |
839 | max_cstate = 1; | 819 | max_cstate = 1; |
840 | 820 | ||
@@ -857,31 +837,13 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, | |||
857 | return 0; | 837 | return 0; |
858 | } | 838 | } |
859 | 839 | ||
860 | /** | 840 | static int acpi_processor_setup_cstates(struct acpi_processor *pr) |
861 | * acpi_processor_setup_cpuidle states- prepares and configures cpuidle | ||
862 | * global state data i.e. idle routines | ||
863 | * | ||
864 | * @pr: the ACPI processor | ||
865 | */ | ||
866 | static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | ||
867 | { | 841 | { |
868 | int i, count = CPUIDLE_DRIVER_STATE_START; | 842 | int i, count = CPUIDLE_DRIVER_STATE_START; |
869 | struct acpi_processor_cx *cx; | 843 | struct acpi_processor_cx *cx; |
870 | struct cpuidle_state *state; | 844 | struct cpuidle_state *state; |
871 | struct cpuidle_driver *drv = &acpi_idle_driver; | 845 | struct cpuidle_driver *drv = &acpi_idle_driver; |
872 | 846 | ||
873 | if (!pr->flags.power_setup_done) | ||
874 | return -EINVAL; | ||
875 | |||
876 | if (pr->flags.power == 0) | ||
877 | return -EINVAL; | ||
878 | |||
879 | drv->safe_state_index = -1; | ||
880 | for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) { | ||
881 | drv->states[i].name[0] = '\0'; | ||
882 | drv->states[i].desc[0] = '\0'; | ||
883 | } | ||
884 | |||
885 | if (max_cstate == 0) | 847 | if (max_cstate == 0) |
886 | max_cstate = 1; | 848 | max_cstate = 1; |
887 | 849 | ||
@@ -893,7 +855,7 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | |||
893 | 855 | ||
894 | state = &drv->states[count]; | 856 | state = &drv->states[count]; |
895 | snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); | 857 | snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); |
896 | strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); | 858 | strlcpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); |
897 | state->exit_latency = cx->latency; | 859 | state->exit_latency = cx->latency; |
898 | state->target_residency = cx->latency * latency_factor; | 860 | state->target_residency = cx->latency * latency_factor; |
899 | state->enter = acpi_idle_enter; | 861 | state->enter = acpi_idle_enter; |
@@ -952,7 +914,7 @@ static inline void acpi_processor_cstate_first_run_checks(void) | |||
952 | 914 | ||
953 | static inline int disabled_by_idle_boot_param(void) { return 0; } | 915 | static inline int disabled_by_idle_boot_param(void) { return 0; } |
954 | static inline void acpi_processor_cstate_first_run_checks(void) { } | 916 | static inline void acpi_processor_cstate_first_run_checks(void) { } |
955 | static int acpi_processor_get_power_info(struct acpi_processor *pr) | 917 | static int acpi_processor_get_cstate_info(struct acpi_processor *pr) |
956 | { | 918 | { |
957 | return -ENODEV; | 919 | return -ENODEV; |
958 | } | 920 | } |
@@ -963,13 +925,413 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, | |||
963 | return -EINVAL; | 925 | return -EINVAL; |
964 | } | 926 | } |
965 | 927 | ||
966 | static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | 928 | static int acpi_processor_setup_cstates(struct acpi_processor *pr) |
967 | { | 929 | { |
968 | return -EINVAL; | 930 | return -EINVAL; |
969 | } | 931 | } |
970 | 932 | ||
971 | #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ | 933 | #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ |
972 | 934 | ||
935 | struct acpi_lpi_states_array { | ||
936 | unsigned int size; | ||
937 | unsigned int composite_states_size; | ||
938 | struct acpi_lpi_state *entries; | ||
939 | struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER]; | ||
940 | }; | ||
941 | |||
942 | static int obj_get_integer(union acpi_object *obj, u32 *value) | ||
943 | { | ||
944 | if (obj->type != ACPI_TYPE_INTEGER) | ||
945 | return -EINVAL; | ||
946 | |||
947 | *value = obj->integer.value; | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static int acpi_processor_evaluate_lpi(acpi_handle handle, | ||
952 | struct acpi_lpi_states_array *info) | ||
953 | { | ||
954 | acpi_status status; | ||
955 | int ret = 0; | ||
956 | int pkg_count, state_idx = 1, loop; | ||
957 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
958 | union acpi_object *lpi_data; | ||
959 | struct acpi_lpi_state *lpi_state; | ||
960 | |||
961 | status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer); | ||
962 | if (ACPI_FAILURE(status)) { | ||
963 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _LPI, giving up\n")); | ||
964 | return -ENODEV; | ||
965 | } | ||
966 | |||
967 | lpi_data = buffer.pointer; | ||
968 | |||
969 | /* There must be at least 4 elements = 3 elements + 1 package */ | ||
970 | if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE || | ||
971 | lpi_data->package.count < 4) { | ||
972 | pr_debug("not enough elements in _LPI\n"); | ||
973 | ret = -ENODATA; | ||
974 | goto end; | ||
975 | } | ||
976 | |||
977 | pkg_count = lpi_data->package.elements[2].integer.value; | ||
978 | |||
979 | /* Validate number of power states. */ | ||
980 | if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) { | ||
981 | pr_debug("count given by _LPI is not valid\n"); | ||
982 | ret = -ENODATA; | ||
983 | goto end; | ||
984 | } | ||
985 | |||
986 | lpi_state = kcalloc(pkg_count, sizeof(*lpi_state), GFP_KERNEL); | ||
987 | if (!lpi_state) { | ||
988 | ret = -ENOMEM; | ||
989 | goto end; | ||
990 | } | ||
991 | |||
992 | info->size = pkg_count; | ||
993 | info->entries = lpi_state; | ||
994 | |||
995 | /* LPI States start at index 3 */ | ||
996 | for (loop = 3; state_idx <= pkg_count; loop++, state_idx++, lpi_state++) { | ||
997 | union acpi_object *element, *pkg_elem, *obj; | ||
998 | |||
999 | element = &lpi_data->package.elements[loop]; | ||
1000 | if (element->type != ACPI_TYPE_PACKAGE || element->package.count < 7) | ||
1001 | continue; | ||
1002 | |||
1003 | pkg_elem = element->package.elements; | ||
1004 | |||
1005 | obj = pkg_elem + 6; | ||
1006 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
1007 | struct acpi_power_register *reg; | ||
1008 | |||
1009 | reg = (struct acpi_power_register *)obj->buffer.pointer; | ||
1010 | if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO && | ||
1011 | reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) | ||
1012 | continue; | ||
1013 | |||
1014 | lpi_state->address = reg->address; | ||
1015 | lpi_state->entry_method = | ||
1016 | reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE ? | ||
1017 | ACPI_CSTATE_FFH : ACPI_CSTATE_SYSTEMIO; | ||
1018 | } else if (obj->type == ACPI_TYPE_INTEGER) { | ||
1019 | lpi_state->entry_method = ACPI_CSTATE_INTEGER; | ||
1020 | lpi_state->address = obj->integer.value; | ||
1021 | } else { | ||
1022 | continue; | ||
1023 | } | ||
1024 | |||
1025 | /* elements[7,8] skipped for now i.e. Residency/Usage counter*/ | ||
1026 | |||
1027 | obj = pkg_elem + 9; | ||
1028 | if (obj->type == ACPI_TYPE_STRING) | ||
1029 | strlcpy(lpi_state->desc, obj->string.pointer, | ||
1030 | ACPI_CX_DESC_LEN); | ||
1031 | |||
1032 | lpi_state->index = state_idx; | ||
1033 | if (obj_get_integer(pkg_elem + 0, &lpi_state->min_residency)) { | ||
1034 | pr_debug("No min. residency found, assuming 10 us\n"); | ||
1035 | lpi_state->min_residency = 10; | ||
1036 | } | ||
1037 | |||
1038 | if (obj_get_integer(pkg_elem + 1, &lpi_state->wake_latency)) { | ||
1039 | pr_debug("No wakeup residency found, assuming 10 us\n"); | ||
1040 | lpi_state->wake_latency = 10; | ||
1041 | } | ||
1042 | |||
1043 | if (obj_get_integer(pkg_elem + 2, &lpi_state->flags)) | ||
1044 | lpi_state->flags = 0; | ||
1045 | |||
1046 | if (obj_get_integer(pkg_elem + 3, &lpi_state->arch_flags)) | ||
1047 | lpi_state->arch_flags = 0; | ||
1048 | |||
1049 | if (obj_get_integer(pkg_elem + 4, &lpi_state->res_cnt_freq)) | ||
1050 | lpi_state->res_cnt_freq = 1; | ||
1051 | |||
1052 | if (obj_get_integer(pkg_elem + 5, &lpi_state->enable_parent_state)) | ||
1053 | lpi_state->enable_parent_state = 0; | ||
1054 | } | ||
1055 | |||
1056 | acpi_handle_debug(handle, "Found %d power states\n", state_idx); | ||
1057 | end: | ||
1058 | kfree(buffer.pointer); | ||
1059 | return ret; | ||
1060 | } | ||
1061 | |||
1062 | /* | ||
1063 | * flat_state_cnt - the number of composite LPI states after the process of flattening | ||
1064 | */ | ||
1065 | static int flat_state_cnt; | ||
1066 | |||
1067 | /** | ||
1068 | * combine_lpi_states - combine local and parent LPI states to form a composite LPI state | ||
1069 | * | ||
1070 | * @local: local LPI state | ||
1071 | * @parent: parent LPI state | ||
1072 | * @result: composite LPI state | ||
1073 | */ | ||
1074 | static bool combine_lpi_states(struct acpi_lpi_state *local, | ||
1075 | struct acpi_lpi_state *parent, | ||
1076 | struct acpi_lpi_state *result) | ||
1077 | { | ||
1078 | if (parent->entry_method == ACPI_CSTATE_INTEGER) { | ||
1079 | if (!parent->address) /* 0 means autopromotable */ | ||
1080 | return false; | ||
1081 | result->address = local->address + parent->address; | ||
1082 | } else { | ||
1083 | result->address = parent->address; | ||
1084 | } | ||
1085 | |||
1086 | result->min_residency = max(local->min_residency, parent->min_residency); | ||
1087 | result->wake_latency = local->wake_latency + parent->wake_latency; | ||
1088 | result->enable_parent_state = parent->enable_parent_state; | ||
1089 | result->entry_method = local->entry_method; | ||
1090 | |||
1091 | result->flags = parent->flags; | ||
1092 | result->arch_flags = parent->arch_flags; | ||
1093 | result->index = parent->index; | ||
1094 | |||
1095 | strlcpy(result->desc, local->desc, ACPI_CX_DESC_LEN); | ||
1096 | strlcat(result->desc, "+", ACPI_CX_DESC_LEN); | ||
1097 | strlcat(result->desc, parent->desc, ACPI_CX_DESC_LEN); | ||
1098 | return true; | ||
1099 | } | ||
1100 | |||
1101 | #define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0) | ||
1102 | |||
1103 | static void stash_composite_state(struct acpi_lpi_states_array *curr_level, | ||
1104 | struct acpi_lpi_state *t) | ||
1105 | { | ||
1106 | curr_level->composite_states[curr_level->composite_states_size++] = t; | ||
1107 | } | ||
1108 | |||
1109 | static int flatten_lpi_states(struct acpi_processor *pr, | ||
1110 | struct acpi_lpi_states_array *curr_level, | ||
1111 | struct acpi_lpi_states_array *prev_level) | ||
1112 | { | ||
1113 | int i, j, state_count = curr_level->size; | ||
1114 | struct acpi_lpi_state *p, *t = curr_level->entries; | ||
1115 | |||
1116 | curr_level->composite_states_size = 0; | ||
1117 | for (j = 0; j < state_count; j++, t++) { | ||
1118 | struct acpi_lpi_state *flpi; | ||
1119 | |||
1120 | if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED)) | ||
1121 | continue; | ||
1122 | |||
1123 | if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) { | ||
1124 | pr_warn("Limiting number of LPI states to max (%d)\n", | ||
1125 | ACPI_PROCESSOR_MAX_POWER); | ||
1126 | pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n"); | ||
1127 | break; | ||
1128 | } | ||
1129 | |||
1130 | flpi = &pr->power.lpi_states[flat_state_cnt]; | ||
1131 | |||
1132 | if (!prev_level) { /* leaf/processor node */ | ||
1133 | memcpy(flpi, t, sizeof(*t)); | ||
1134 | stash_composite_state(curr_level, flpi); | ||
1135 | flat_state_cnt++; | ||
1136 | continue; | ||
1137 | } | ||
1138 | |||
1139 | for (i = 0; i < prev_level->composite_states_size; i++) { | ||
1140 | p = prev_level->composite_states[i]; | ||
1141 | if (t->index <= p->enable_parent_state && | ||
1142 | combine_lpi_states(p, t, flpi)) { | ||
1143 | stash_composite_state(curr_level, flpi); | ||
1144 | flat_state_cnt++; | ||
1145 | flpi++; | ||
1146 | } | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | kfree(curr_level->entries); | ||
1151 | return 0; | ||
1152 | } | ||
1153 | |||
1154 | static int acpi_processor_get_lpi_info(struct acpi_processor *pr) | ||
1155 | { | ||
1156 | int ret, i; | ||
1157 | acpi_status status; | ||
1158 | acpi_handle handle = pr->handle, pr_ahandle; | ||
1159 | struct acpi_device *d = NULL; | ||
1160 | struct acpi_lpi_states_array info[2], *tmp, *prev, *curr; | ||
1161 | |||
1162 | if (!osc_pc_lpi_support_confirmed) | ||
1163 | return -EOPNOTSUPP; | ||
1164 | |||
1165 | if (!acpi_has_method(handle, "_LPI")) | ||
1166 | return -EINVAL; | ||
1167 | |||
1168 | flat_state_cnt = 0; | ||
1169 | prev = &info[0]; | ||
1170 | curr = &info[1]; | ||
1171 | handle = pr->handle; | ||
1172 | ret = acpi_processor_evaluate_lpi(handle, prev); | ||
1173 | if (ret) | ||
1174 | return ret; | ||
1175 | flatten_lpi_states(pr, prev, NULL); | ||
1176 | |||
1177 | status = acpi_get_parent(handle, &pr_ahandle); | ||
1178 | while (ACPI_SUCCESS(status)) { | ||
1179 | acpi_bus_get_device(pr_ahandle, &d); | ||
1180 | handle = pr_ahandle; | ||
1181 | |||
1182 | if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID)) | ||
1183 | break; | ||
1184 | |||
1185 | /* can be optional ? */ | ||
1186 | if (!acpi_has_method(handle, "_LPI")) | ||
1187 | break; | ||
1188 | |||
1189 | ret = acpi_processor_evaluate_lpi(handle, curr); | ||
1190 | if (ret) | ||
1191 | break; | ||
1192 | |||
1193 | /* flatten all the LPI states in this level of hierarchy */ | ||
1194 | flatten_lpi_states(pr, curr, prev); | ||
1195 | |||
1196 | tmp = prev, prev = curr, curr = tmp; | ||
1197 | |||
1198 | status = acpi_get_parent(handle, &pr_ahandle); | ||
1199 | } | ||
1200 | |||
1201 | pr->power.count = flat_state_cnt; | ||
1202 | /* reset the index after flattening */ | ||
1203 | for (i = 0; i < pr->power.count; i++) | ||
1204 | pr->power.lpi_states[i].index = i; | ||
1205 | |||
1206 | /* Tell driver that _LPI is supported. */ | ||
1207 | pr->flags.has_lpi = 1; | ||
1208 | pr->flags.power = 1; | ||
1209 | |||
1210 | return 0; | ||
1211 | } | ||
1212 | |||
1213 | int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu) | ||
1214 | { | ||
1215 | return -ENODEV; | ||
1216 | } | ||
1217 | |||
1218 | int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi) | ||
1219 | { | ||
1220 | return -ENODEV; | ||
1221 | } | ||
1222 | |||
1223 | /** | ||
1224 | * acpi_idle_lpi_enter - enters an ACPI any LPI state | ||
1225 | * @dev: the target CPU | ||
1226 | * @drv: cpuidle driver containing cpuidle state info | ||
1227 | * @index: index of target state | ||
1228 | * | ||
1229 | * Return: 0 for success or negative value for error | ||
1230 | */ | ||
1231 | static int acpi_idle_lpi_enter(struct cpuidle_device *dev, | ||
1232 | struct cpuidle_driver *drv, int index) | ||
1233 | { | ||
1234 | struct acpi_processor *pr; | ||
1235 | struct acpi_lpi_state *lpi; | ||
1236 | |||
1237 | pr = __this_cpu_read(processors); | ||
1238 | |||
1239 | if (unlikely(!pr)) | ||
1240 | return -EINVAL; | ||
1241 | |||
1242 | lpi = &pr->power.lpi_states[index]; | ||
1243 | if (lpi->entry_method == ACPI_CSTATE_FFH) | ||
1244 | return acpi_processor_ffh_lpi_enter(lpi); | ||
1245 | |||
1246 | return -EINVAL; | ||
1247 | } | ||
1248 | |||
1249 | static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) | ||
1250 | { | ||
1251 | int i; | ||
1252 | struct acpi_lpi_state *lpi; | ||
1253 | struct cpuidle_state *state; | ||
1254 | struct cpuidle_driver *drv = &acpi_idle_driver; | ||
1255 | |||
1256 | if (!pr->flags.has_lpi) | ||
1257 | return -EOPNOTSUPP; | ||
1258 | |||
1259 | for (i = 0; i < pr->power.count && i < CPUIDLE_STATE_MAX; i++) { | ||
1260 | lpi = &pr->power.lpi_states[i]; | ||
1261 | |||
1262 | state = &drv->states[i]; | ||
1263 | snprintf(state->name, CPUIDLE_NAME_LEN, "LPI-%d", i); | ||
1264 | strlcpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN); | ||
1265 | state->exit_latency = lpi->wake_latency; | ||
1266 | state->target_residency = lpi->min_residency; | ||
1267 | if (lpi->arch_flags) | ||
1268 | state->flags |= CPUIDLE_FLAG_TIMER_STOP; | ||
1269 | state->enter = acpi_idle_lpi_enter; | ||
1270 | drv->safe_state_index = i; | ||
1271 | } | ||
1272 | |||
1273 | drv->state_count = i; | ||
1274 | |||
1275 | return 0; | ||
1276 | } | ||
1277 | |||
1278 | /** | ||
1279 | * acpi_processor_setup_cpuidle_states- prepares and configures cpuidle | ||
1280 | * global state data i.e. idle routines | ||
1281 | * | ||
1282 | * @pr: the ACPI processor | ||
1283 | */ | ||
1284 | static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | ||
1285 | { | ||
1286 | int i; | ||
1287 | struct cpuidle_driver *drv = &acpi_idle_driver; | ||
1288 | |||
1289 | if (!pr->flags.power_setup_done || !pr->flags.power) | ||
1290 | return -EINVAL; | ||
1291 | |||
1292 | drv->safe_state_index = -1; | ||
1293 | for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) { | ||
1294 | drv->states[i].name[0] = '\0'; | ||
1295 | drv->states[i].desc[0] = '\0'; | ||
1296 | } | ||
1297 | |||
1298 | if (pr->flags.has_lpi) | ||
1299 | return acpi_processor_setup_lpi_states(pr); | ||
1300 | |||
1301 | return acpi_processor_setup_cstates(pr); | ||
1302 | } | ||
1303 | |||
1304 | /** | ||
1305 | * acpi_processor_setup_cpuidle_dev - prepares and configures CPUIDLE | ||
1306 | * device i.e. per-cpu data | ||
1307 | * | ||
1308 | * @pr: the ACPI processor | ||
1309 | * @dev : the cpuidle device | ||
1310 | */ | ||
1311 | static int acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr, | ||
1312 | struct cpuidle_device *dev) | ||
1313 | { | ||
1314 | if (!pr->flags.power_setup_done || !pr->flags.power || !dev) | ||
1315 | return -EINVAL; | ||
1316 | |||
1317 | dev->cpu = pr->id; | ||
1318 | if (pr->flags.has_lpi) | ||
1319 | return acpi_processor_ffh_lpi_probe(pr->id); | ||
1320 | |||
1321 | return acpi_processor_setup_cpuidle_cx(pr, dev); | ||
1322 | } | ||
1323 | |||
1324 | static int acpi_processor_get_power_info(struct acpi_processor *pr) | ||
1325 | { | ||
1326 | int ret; | ||
1327 | |||
1328 | ret = acpi_processor_get_lpi_info(pr); | ||
1329 | if (ret) | ||
1330 | ret = acpi_processor_get_cstate_info(pr); | ||
1331 | |||
1332 | return ret; | ||
1333 | } | ||
1334 | |||
973 | int acpi_processor_hotplug(struct acpi_processor *pr) | 1335 | int acpi_processor_hotplug(struct acpi_processor *pr) |
974 | { | 1336 | { |
975 | int ret = 0; | 1337 | int ret = 0; |
@@ -978,18 +1340,15 @@ int acpi_processor_hotplug(struct acpi_processor *pr) | |||
978 | if (disabled_by_idle_boot_param()) | 1340 | if (disabled_by_idle_boot_param()) |
979 | return 0; | 1341 | return 0; |
980 | 1342 | ||
981 | if (nocst) | ||
982 | return -ENODEV; | ||
983 | |||
984 | if (!pr->flags.power_setup_done) | 1343 | if (!pr->flags.power_setup_done) |
985 | return -ENODEV; | 1344 | return -ENODEV; |
986 | 1345 | ||
987 | dev = per_cpu(acpi_cpuidle_device, pr->id); | 1346 | dev = per_cpu(acpi_cpuidle_device, pr->id); |
988 | cpuidle_pause_and_lock(); | 1347 | cpuidle_pause_and_lock(); |
989 | cpuidle_disable_device(dev); | 1348 | cpuidle_disable_device(dev); |
990 | acpi_processor_get_power_info(pr); | 1349 | ret = acpi_processor_get_power_info(pr); |
991 | if (pr->flags.power) { | 1350 | if (!ret && pr->flags.power) { |
992 | acpi_processor_setup_cpuidle_cx(pr, dev); | 1351 | acpi_processor_setup_cpuidle_dev(pr, dev); |
993 | ret = cpuidle_enable_device(dev); | 1352 | ret = cpuidle_enable_device(dev); |
994 | } | 1353 | } |
995 | cpuidle_resume_and_unlock(); | 1354 | cpuidle_resume_and_unlock(); |
@@ -997,7 +1356,7 @@ int acpi_processor_hotplug(struct acpi_processor *pr) | |||
997 | return ret; | 1356 | return ret; |
998 | } | 1357 | } |
999 | 1358 | ||
1000 | int acpi_processor_cst_has_changed(struct acpi_processor *pr) | 1359 | int acpi_processor_power_state_has_changed(struct acpi_processor *pr) |
1001 | { | 1360 | { |
1002 | int cpu; | 1361 | int cpu; |
1003 | struct acpi_processor *_pr; | 1362 | struct acpi_processor *_pr; |
@@ -1006,9 +1365,6 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) | |||
1006 | if (disabled_by_idle_boot_param()) | 1365 | if (disabled_by_idle_boot_param()) |
1007 | return 0; | 1366 | return 0; |
1008 | 1367 | ||
1009 | if (nocst) | ||
1010 | return -ENODEV; | ||
1011 | |||
1012 | if (!pr->flags.power_setup_done) | 1368 | if (!pr->flags.power_setup_done) |
1013 | return -ENODEV; | 1369 | return -ENODEV; |
1014 | 1370 | ||
@@ -1045,7 +1401,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) | |||
1045 | acpi_processor_get_power_info(_pr); | 1401 | acpi_processor_get_power_info(_pr); |
1046 | if (_pr->flags.power) { | 1402 | if (_pr->flags.power) { |
1047 | dev = per_cpu(acpi_cpuidle_device, cpu); | 1403 | dev = per_cpu(acpi_cpuidle_device, cpu); |
1048 | acpi_processor_setup_cpuidle_cx(_pr, dev); | 1404 | acpi_processor_setup_cpuidle_dev(_pr, dev); |
1049 | cpuidle_enable_device(dev); | 1405 | cpuidle_enable_device(dev); |
1050 | } | 1406 | } |
1051 | } | 1407 | } |
@@ -1092,7 +1448,7 @@ int acpi_processor_power_init(struct acpi_processor *pr) | |||
1092 | return -ENOMEM; | 1448 | return -ENOMEM; |
1093 | per_cpu(acpi_cpuidle_device, pr->id) = dev; | 1449 | per_cpu(acpi_cpuidle_device, pr->id) = dev; |
1094 | 1450 | ||
1095 | acpi_processor_setup_cpuidle_cx(pr, dev); | 1451 | acpi_processor_setup_cpuidle_dev(pr, dev); |
1096 | 1452 | ||
1097 | /* Register per-cpu cpuidle_device. Cpuidle driver | 1453 | /* Register per-cpu cpuidle_device. Cpuidle driver |
1098 | * must already be registered before registering device | 1454 | * must already be registered before registering device |