diff options
Diffstat (limited to 'drivers/acpi/processor_throttling.c')
-rw-r--r-- | drivers/acpi/processor_throttling.c | 190 |
1 files changed, 73 insertions, 117 deletions
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ff3632717c51..fa84e9744330 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c | |||
@@ -32,10 +32,6 @@ | |||
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 | #ifdef CONFIG_ACPI_PROCFS | ||
36 | #include <linux/proc_fs.h> | ||
37 | #include <linux/seq_file.h> | ||
38 | #endif | ||
39 | 35 | ||
40 | #include <asm/io.h> | 36 | #include <asm/io.h> |
41 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
@@ -370,6 +366,58 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr) | |||
370 | } | 366 | } |
371 | 367 | ||
372 | /* | 368 | /* |
369 | * This function is used to reevaluate whether the T-state is valid | ||
370 | * after one CPU is onlined/offlined. | ||
371 | * It is noted that it won't reevaluate the following properties for | ||
372 | * the T-state. | ||
373 | * 1. Control method. | ||
374 | * 2. the number of supported T-state | ||
375 | * 3. TSD domain | ||
376 | */ | ||
377 | void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, | ||
378 | unsigned long action) | ||
379 | { | ||
380 | int result = 0; | ||
381 | |||
382 | if (action == CPU_DEAD) { | ||
383 | /* When one CPU is offline, the T-state throttling | ||
384 | * will be invalidated. | ||
385 | */ | ||
386 | pr->flags.throttling = 0; | ||
387 | return; | ||
388 | } | ||
389 | /* the following is to recheck whether the T-state is valid for | ||
390 | * the online CPU | ||
391 | */ | ||
392 | if (!pr->throttling.state_count) { | ||
393 | /* If the number of T-state is invalid, it is | ||
394 | * invalidated. | ||
395 | */ | ||
396 | pr->flags.throttling = 0; | ||
397 | return; | ||
398 | } | ||
399 | pr->flags.throttling = 1; | ||
400 | |||
401 | /* Disable throttling (if enabled). We'll let subsequent | ||
402 | * policy (e.g.thermal) decide to lower performance if it | ||
403 | * so chooses, but for now we'll crank up the speed. | ||
404 | */ | ||
405 | |||
406 | result = acpi_processor_get_throttling(pr); | ||
407 | if (result) | ||
408 | goto end; | ||
409 | |||
410 | if (pr->throttling.state) { | ||
411 | result = acpi_processor_set_throttling(pr, 0, false); | ||
412 | if (result) | ||
413 | goto end; | ||
414 | } | ||
415 | |||
416 | end: | ||
417 | if (result) | ||
418 | pr->flags.throttling = 0; | ||
419 | } | ||
420 | /* | ||
373 | * _PTC - Processor Throttling Control (and status) register location | 421 | * _PTC - Processor Throttling Control (and status) register location |
374 | */ | 422 | */ |
375 | static int acpi_processor_get_throttling_control(struct acpi_processor *pr) | 423 | static int acpi_processor_get_throttling_control(struct acpi_processor *pr) |
@@ -876,7 +924,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) | |||
876 | */ | 924 | */ |
877 | cpumask_copy(saved_mask, ¤t->cpus_allowed); | 925 | cpumask_copy(saved_mask, ¤t->cpus_allowed); |
878 | /* FIXME: use work_on_cpu() */ | 926 | /* FIXME: use work_on_cpu() */ |
879 | set_cpus_allowed_ptr(current, cpumask_of(pr->id)); | 927 | if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { |
928 | /* Can't migrate to the target pr->id CPU. Exit */ | ||
929 | free_cpumask_var(saved_mask); | ||
930 | return -ENODEV; | ||
931 | } | ||
880 | ret = pr->throttling.acpi_processor_get_throttling(pr); | 932 | ret = pr->throttling.acpi_processor_get_throttling(pr); |
881 | /* restore the previous state */ | 933 | /* restore the previous state */ |
882 | set_cpus_allowed_ptr(current, saved_mask); | 934 | set_cpus_allowed_ptr(current, saved_mask); |
@@ -1051,6 +1103,14 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1051 | return -ENOMEM; | 1103 | return -ENOMEM; |
1052 | } | 1104 | } |
1053 | 1105 | ||
1106 | if (cpu_is_offline(pr->id)) { | ||
1107 | /* | ||
1108 | * the cpu pointed by pr->id is offline. Unnecessary to change | ||
1109 | * the throttling state any more. | ||
1110 | */ | ||
1111 | return -ENODEV; | ||
1112 | } | ||
1113 | |||
1054 | cpumask_copy(saved_mask, ¤t->cpus_allowed); | 1114 | cpumask_copy(saved_mask, ¤t->cpus_allowed); |
1055 | t_state.target_state = state; | 1115 | t_state.target_state = state; |
1056 | p_throttling = &(pr->throttling); | 1116 | p_throttling = &(pr->throttling); |
@@ -1074,7 +1134,11 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1074 | */ | 1134 | */ |
1075 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { | 1135 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { |
1076 | /* FIXME: use work_on_cpu() */ | 1136 | /* FIXME: use work_on_cpu() */ |
1077 | set_cpus_allowed_ptr(current, cpumask_of(pr->id)); | 1137 | if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { |
1138 | /* Can't migrate to the pr->id CPU. Exit */ | ||
1139 | ret = -ENODEV; | ||
1140 | goto exit; | ||
1141 | } | ||
1078 | ret = p_throttling->acpi_processor_set_throttling(pr, | 1142 | ret = p_throttling->acpi_processor_set_throttling(pr, |
1079 | t_state.target_state, force); | 1143 | t_state.target_state, force); |
1080 | } else { | 1144 | } else { |
@@ -1106,7 +1170,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1106 | } | 1170 | } |
1107 | t_state.cpu = i; | 1171 | t_state.cpu = i; |
1108 | /* FIXME: use work_on_cpu() */ | 1172 | /* FIXME: use work_on_cpu() */ |
1109 | set_cpus_allowed_ptr(current, cpumask_of(i)); | 1173 | if (set_cpus_allowed_ptr(current, cpumask_of(i))) |
1174 | continue; | ||
1110 | ret = match_pr->throttling. | 1175 | ret = match_pr->throttling. |
1111 | acpi_processor_set_throttling( | 1176 | acpi_processor_set_throttling( |
1112 | match_pr, t_state.target_state, force); | 1177 | match_pr, t_state.target_state, force); |
@@ -1126,6 +1191,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1126 | /* restore the previous state */ | 1191 | /* restore the previous state */ |
1127 | /* FIXME: use work_on_cpu() */ | 1192 | /* FIXME: use work_on_cpu() */ |
1128 | set_cpus_allowed_ptr(current, saved_mask); | 1193 | set_cpus_allowed_ptr(current, saved_mask); |
1194 | exit: | ||
1129 | free_cpumask_var(online_throttling_cpus); | 1195 | free_cpumask_var(online_throttling_cpus); |
1130 | free_cpumask_var(saved_mask); | 1196 | free_cpumask_var(saved_mask); |
1131 | return ret; | 1197 | return ret; |
@@ -1216,113 +1282,3 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) | |||
1216 | return result; | 1282 | return result; |
1217 | } | 1283 | } |
1218 | 1284 | ||
1219 | #ifdef CONFIG_ACPI_PROCFS | ||
1220 | /* proc interface */ | ||
1221 | static int acpi_processor_throttling_seq_show(struct seq_file *seq, | ||
1222 | void *offset) | ||
1223 | { | ||
1224 | struct acpi_processor *pr = seq->private; | ||
1225 | int i = 0; | ||
1226 | int result = 0; | ||
1227 | |||
1228 | if (!pr) | ||
1229 | goto end; | ||
1230 | |||
1231 | if (!(pr->throttling.state_count > 0)) { | ||
1232 | seq_puts(seq, "<not supported>\n"); | ||
1233 | goto end; | ||
1234 | } | ||
1235 | |||
1236 | result = acpi_processor_get_throttling(pr); | ||
1237 | |||
1238 | if (result) { | ||
1239 | seq_puts(seq, | ||
1240 | "Could not determine current throttling state.\n"); | ||
1241 | goto end; | ||
1242 | } | ||
1243 | |||
1244 | seq_printf(seq, "state count: %d\n" | ||
1245 | "active state: T%d\n" | ||
1246 | "state available: T%d to T%d\n", | ||
1247 | pr->throttling.state_count, pr->throttling.state, | ||
1248 | pr->throttling_platform_limit, | ||
1249 | pr->throttling.state_count - 1); | ||
1250 | |||
1251 | seq_puts(seq, "states:\n"); | ||
1252 | if (pr->throttling.acpi_processor_get_throttling == | ||
1253 | acpi_processor_get_throttling_fadt) { | ||
1254 | for (i = 0; i < pr->throttling.state_count; i++) | ||
1255 | seq_printf(seq, " %cT%d: %02d%%\n", | ||
1256 | (i == pr->throttling.state ? '*' : ' '), i, | ||
1257 | (pr->throttling.states[i].performance ? pr-> | ||
1258 | throttling.states[i].performance / 10 : 0)); | ||
1259 | } else { | ||
1260 | for (i = 0; i < pr->throttling.state_count; i++) | ||
1261 | seq_printf(seq, " %cT%d: %02d%%\n", | ||
1262 | (i == pr->throttling.state ? '*' : ' '), i, | ||
1263 | (int)pr->throttling.states_tss[i]. | ||
1264 | freqpercentage); | ||
1265 | } | ||
1266 | |||
1267 | end: | ||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static int acpi_processor_throttling_open_fs(struct inode *inode, | ||
1272 | struct file *file) | ||
1273 | { | ||
1274 | return single_open(file, acpi_processor_throttling_seq_show, | ||
1275 | PDE(inode)->data); | ||
1276 | } | ||
1277 | |||
1278 | static ssize_t acpi_processor_write_throttling(struct file *file, | ||
1279 | const char __user * buffer, | ||
1280 | size_t count, loff_t * data) | ||
1281 | { | ||
1282 | int result = 0; | ||
1283 | struct seq_file *m = file->private_data; | ||
1284 | struct acpi_processor *pr = m->private; | ||
1285 | char state_string[5] = ""; | ||
1286 | char *charp = NULL; | ||
1287 | size_t state_val = 0; | ||
1288 | char tmpbuf[5] = ""; | ||
1289 | |||
1290 | if (!pr || (count > sizeof(state_string) - 1)) | ||
1291 | return -EINVAL; | ||
1292 | |||
1293 | if (copy_from_user(state_string, buffer, count)) | ||
1294 | return -EFAULT; | ||
1295 | |||
1296 | state_string[count] = '\0'; | ||
1297 | if ((count > 0) && (state_string[count-1] == '\n')) | ||
1298 | state_string[count-1] = '\0'; | ||
1299 | |||
1300 | charp = state_string; | ||
1301 | if ((state_string[0] == 't') || (state_string[0] == 'T')) | ||
1302 | charp++; | ||
1303 | |||
1304 | state_val = simple_strtoul(charp, NULL, 0); | ||
1305 | if (state_val >= pr->throttling.state_count) | ||
1306 | return -EINVAL; | ||
1307 | |||
1308 | snprintf(tmpbuf, 5, "%zu", state_val); | ||
1309 | |||
1310 | if (strcmp(tmpbuf, charp) != 0) | ||
1311 | return -EINVAL; | ||
1312 | |||
1313 | result = acpi_processor_set_throttling(pr, state_val, false); | ||
1314 | if (result) | ||
1315 | return result; | ||
1316 | |||
1317 | return count; | ||
1318 | } | ||
1319 | |||
1320 | const struct file_operations acpi_processor_throttling_fops = { | ||
1321 | .owner = THIS_MODULE, | ||
1322 | .open = acpi_processor_throttling_open_fs, | ||
1323 | .read = seq_read, | ||
1324 | .write = acpi_processor_write_throttling, | ||
1325 | .llseek = seq_lseek, | ||
1326 | .release = single_release, | ||
1327 | }; | ||
1328 | #endif | ||