diff options
Diffstat (limited to 'drivers/acpi/processor_throttling.c')
-rw-r--r-- | drivers/acpi/processor_throttling.c | 76 |
1 files changed, 34 insertions, 42 deletions
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index e7dd2c1fee79..84243c32e29c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c | |||
@@ -32,14 +32,11 @@ | |||
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/cpufreq.h> | 34 | #include <linux/cpufreq.h> |
35 | 35 | #include <linux/acpi.h> | |
36 | #include <acpi/processor.h> | ||
36 | #include <asm/io.h> | 37 | #include <asm/io.h> |
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | 39 | ||
39 | #include <acpi/acpi_bus.h> | ||
40 | #include <acpi/acpi_drivers.h> | ||
41 | #include <acpi/processor.h> | ||
42 | |||
43 | #define PREFIX "ACPI: " | 40 | #define PREFIX "ACPI: " |
44 | 41 | ||
45 | #define ACPI_PROCESSOR_CLASS "processor" | 42 | #define ACPI_PROCESSOR_CLASS "processor" |
@@ -59,6 +56,12 @@ struct throttling_tstate { | |||
59 | int target_state; /* target T-state */ | 56 | int target_state; /* target T-state */ |
60 | }; | 57 | }; |
61 | 58 | ||
59 | struct acpi_processor_throttling_arg { | ||
60 | struct acpi_processor *pr; | ||
61 | int target_state; | ||
62 | bool force; | ||
63 | }; | ||
64 | |||
62 | #define THROTTLING_PRECHANGE (1) | 65 | #define THROTTLING_PRECHANGE (1) |
63 | #define THROTTLING_POSTCHANGE (2) | 66 | #define THROTTLING_POSTCHANGE (2) |
64 | 67 | ||
@@ -1063,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, | |||
1063 | return 0; | 1066 | return 0; |
1064 | } | 1067 | } |
1065 | 1068 | ||
1069 | static long acpi_processor_throttling_fn(void *data) | ||
1070 | { | ||
1071 | struct acpi_processor_throttling_arg *arg = data; | ||
1072 | struct acpi_processor *pr = arg->pr; | ||
1073 | |||
1074 | return pr->throttling.acpi_processor_set_throttling(pr, | ||
1075 | arg->target_state, arg->force); | ||
1076 | } | ||
1077 | |||
1066 | int acpi_processor_set_throttling(struct acpi_processor *pr, | 1078 | int acpi_processor_set_throttling(struct acpi_processor *pr, |
1067 | int state, bool force) | 1079 | int state, bool force) |
1068 | { | 1080 | { |
1069 | cpumask_var_t saved_mask; | ||
1070 | int ret = 0; | 1081 | int ret = 0; |
1071 | unsigned int i; | 1082 | unsigned int i; |
1072 | struct acpi_processor *match_pr; | 1083 | struct acpi_processor *match_pr; |
1073 | struct acpi_processor_throttling *p_throttling; | 1084 | struct acpi_processor_throttling *p_throttling; |
1085 | struct acpi_processor_throttling_arg arg; | ||
1074 | struct throttling_tstate t_state; | 1086 | struct throttling_tstate t_state; |
1075 | cpumask_var_t online_throttling_cpus; | ||
1076 | 1087 | ||
1077 | if (!pr) | 1088 | if (!pr) |
1078 | return -EINVAL; | 1089 | return -EINVAL; |
@@ -1083,14 +1094,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1083 | if ((state < 0) || (state > (pr->throttling.state_count - 1))) | 1094 | if ((state < 0) || (state > (pr->throttling.state_count - 1))) |
1084 | return -EINVAL; | 1095 | return -EINVAL; |
1085 | 1096 | ||
1086 | if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) | ||
1087 | return -ENOMEM; | ||
1088 | |||
1089 | if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) { | ||
1090 | free_cpumask_var(saved_mask); | ||
1091 | return -ENOMEM; | ||
1092 | } | ||
1093 | |||
1094 | if (cpu_is_offline(pr->id)) { | 1097 | if (cpu_is_offline(pr->id)) { |
1095 | /* | 1098 | /* |
1096 | * the cpu pointed by pr->id is offline. Unnecessary to change | 1099 | * the cpu pointed by pr->id is offline. Unnecessary to change |
@@ -1099,17 +1102,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1099 | return -ENODEV; | 1102 | return -ENODEV; |
1100 | } | 1103 | } |
1101 | 1104 | ||
1102 | cpumask_copy(saved_mask, ¤t->cpus_allowed); | ||
1103 | t_state.target_state = state; | 1105 | t_state.target_state = state; |
1104 | p_throttling = &(pr->throttling); | 1106 | p_throttling = &(pr->throttling); |
1105 | cpumask_and(online_throttling_cpus, cpu_online_mask, | 1107 | |
1106 | p_throttling->shared_cpu_map); | ||
1107 | /* | 1108 | /* |
1108 | * The throttling notifier will be called for every | 1109 | * The throttling notifier will be called for every |
1109 | * affected cpu in order to get one proper T-state. | 1110 | * affected cpu in order to get one proper T-state. |
1110 | * The notifier event is THROTTLING_PRECHANGE. | 1111 | * The notifier event is THROTTLING_PRECHANGE. |
1111 | */ | 1112 | */ |
1112 | for_each_cpu(i, online_throttling_cpus) { | 1113 | for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { |
1113 | t_state.cpu = i; | 1114 | t_state.cpu = i; |
1114 | acpi_processor_throttling_notifier(THROTTLING_PRECHANGE, | 1115 | acpi_processor_throttling_notifier(THROTTLING_PRECHANGE, |
1115 | &t_state); | 1116 | &t_state); |
@@ -1121,21 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1121 | * it can be called only for the cpu pointed by pr. | 1122 | * it can be called only for the cpu pointed by pr. |
1122 | */ | 1123 | */ |
1123 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { | 1124 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { |
1124 | /* FIXME: use work_on_cpu() */ | 1125 | arg.pr = pr; |
1125 | if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { | 1126 | arg.target_state = state; |
1126 | /* Can't migrate to the pr->id CPU. Exit */ | 1127 | arg.force = force; |
1127 | ret = -ENODEV; | 1128 | ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); |
1128 | goto exit; | ||
1129 | } | ||
1130 | ret = p_throttling->acpi_processor_set_throttling(pr, | ||
1131 | t_state.target_state, force); | ||
1132 | } else { | 1129 | } else { |
1133 | /* | 1130 | /* |
1134 | * When the T-state coordination is SW_ALL or HW_ALL, | 1131 | * When the T-state coordination is SW_ALL or HW_ALL, |
1135 | * it is necessary to set T-state for every affected | 1132 | * it is necessary to set T-state for every affected |
1136 | * cpus. | 1133 | * cpus. |
1137 | */ | 1134 | */ |
1138 | for_each_cpu(i, online_throttling_cpus) { | 1135 | for_each_cpu_and(i, cpu_online_mask, |
1136 | p_throttling->shared_cpu_map) { | ||
1139 | match_pr = per_cpu(processors, i); | 1137 | match_pr = per_cpu(processors, i); |
1140 | /* | 1138 | /* |
1141 | * If the pointer is invalid, we will report the | 1139 | * If the pointer is invalid, we will report the |
@@ -1156,13 +1154,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1156 | "on CPU %d\n", i)); | 1154 | "on CPU %d\n", i)); |
1157 | continue; | 1155 | continue; |
1158 | } | 1156 | } |
1159 | t_state.cpu = i; | 1157 | |
1160 | /* FIXME: use work_on_cpu() */ | 1158 | arg.pr = match_pr; |
1161 | if (set_cpus_allowed_ptr(current, cpumask_of(i))) | 1159 | arg.target_state = state; |
1162 | continue; | 1160 | arg.force = force; |
1163 | ret = match_pr->throttling. | 1161 | ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, |
1164 | acpi_processor_set_throttling( | 1162 | &arg); |
1165 | match_pr, t_state.target_state, force); | ||
1166 | } | 1163 | } |
1167 | } | 1164 | } |
1168 | /* | 1165 | /* |
@@ -1171,17 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1171 | * affected cpu to update the T-states. | 1168 | * affected cpu to update the T-states. |
1172 | * The notifier event is THROTTLING_POSTCHANGE | 1169 | * The notifier event is THROTTLING_POSTCHANGE |
1173 | */ | 1170 | */ |
1174 | for_each_cpu(i, online_throttling_cpus) { | 1171 | for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { |
1175 | t_state.cpu = i; | 1172 | t_state.cpu = i; |
1176 | acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE, | 1173 | acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE, |
1177 | &t_state); | 1174 | &t_state); |
1178 | } | 1175 | } |
1179 | /* restore the previous state */ | 1176 | |
1180 | /* FIXME: use work_on_cpu() */ | ||
1181 | set_cpus_allowed_ptr(current, saved_mask); | ||
1182 | exit: | ||
1183 | free_cpumask_var(online_throttling_cpus); | ||
1184 | free_cpumask_var(saved_mask); | ||
1185 | return ret; | 1177 | return ret; |
1186 | } | 1178 | } |
1187 | 1179 | ||