diff options
Diffstat (limited to 'drivers/acpi/processor_throttling.c')
-rw-r--r-- | drivers/acpi/processor_throttling.c | 220 |
1 files changed, 84 insertions, 136 deletions
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 730863855ed5..605a2954ef17 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c | |||
@@ -32,8 +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 | #include <linux/proc_fs.h> | ||
36 | #include <linux/seq_file.h> | ||
37 | 35 | ||
38 | #include <asm/io.h> | 36 | #include <asm/io.h> |
39 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
@@ -368,6 +366,58 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr) | |||
368 | } | 366 | } |
369 | 367 | ||
370 | /* | 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 | /* | ||
371 | * _PTC - Processor Throttling Control (and status) register location | 421 | * _PTC - Processor Throttling Control (and status) register location |
372 | */ | 422 | */ |
373 | static int acpi_processor_get_throttling_control(struct acpi_processor *pr) | 423 | static int acpi_processor_get_throttling_control(struct acpi_processor *pr) |
@@ -660,20 +710,14 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) | |||
660 | } | 710 | } |
661 | 711 | ||
662 | #ifdef CONFIG_X86 | 712 | #ifdef CONFIG_X86 |
663 | static int acpi_throttling_rdmsr(struct acpi_processor *pr, | 713 | static int acpi_throttling_rdmsr(u64 *value) |
664 | u64 *value) | ||
665 | { | 714 | { |
666 | struct cpuinfo_x86 *c; | ||
667 | u64 msr_high, msr_low; | 715 | u64 msr_high, msr_low; |
668 | unsigned int cpu; | ||
669 | u64 msr = 0; | 716 | u64 msr = 0; |
670 | int ret = -1; | 717 | int ret = -1; |
671 | 718 | ||
672 | cpu = pr->id; | 719 | if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || |
673 | c = &cpu_data(cpu); | 720 | !this_cpu_has(X86_FEATURE_ACPI)) { |
674 | |||
675 | if ((c->x86_vendor != X86_VENDOR_INTEL) || | ||
676 | !cpu_has(c, X86_FEATURE_ACPI)) { | ||
677 | printk(KERN_ERR PREFIX | 721 | printk(KERN_ERR PREFIX |
678 | "HARDWARE addr space,NOT supported yet\n"); | 722 | "HARDWARE addr space,NOT supported yet\n"); |
679 | } else { | 723 | } else { |
@@ -688,18 +732,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr, | |||
688 | return ret; | 732 | return ret; |
689 | } | 733 | } |
690 | 734 | ||
691 | static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) | 735 | static int acpi_throttling_wrmsr(u64 value) |
692 | { | 736 | { |
693 | struct cpuinfo_x86 *c; | ||
694 | unsigned int cpu; | ||
695 | int ret = -1; | 737 | int ret = -1; |
696 | u64 msr; | 738 | u64 msr; |
697 | 739 | ||
698 | cpu = pr->id; | 740 | if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || |
699 | c = &cpu_data(cpu); | 741 | !this_cpu_has(X86_FEATURE_ACPI)) { |
700 | |||
701 | if ((c->x86_vendor != X86_VENDOR_INTEL) || | ||
702 | !cpu_has(c, X86_FEATURE_ACPI)) { | ||
703 | printk(KERN_ERR PREFIX | 742 | printk(KERN_ERR PREFIX |
704 | "HARDWARE addr space,NOT supported yet\n"); | 743 | "HARDWARE addr space,NOT supported yet\n"); |
705 | } else { | 744 | } else { |
@@ -711,15 +750,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) | |||
711 | return ret; | 750 | return ret; |
712 | } | 751 | } |
713 | #else | 752 | #else |
714 | static int acpi_throttling_rdmsr(struct acpi_processor *pr, | 753 | static int acpi_throttling_rdmsr(u64 *value) |
715 | u64 *value) | ||
716 | { | 754 | { |
717 | printk(KERN_ERR PREFIX | 755 | printk(KERN_ERR PREFIX |
718 | "HARDWARE addr space,NOT supported yet\n"); | 756 | "HARDWARE addr space,NOT supported yet\n"); |
719 | return -1; | 757 | return -1; |
720 | } | 758 | } |
721 | 759 | ||
722 | static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) | 760 | static int acpi_throttling_wrmsr(u64 value) |
723 | { | 761 | { |
724 | printk(KERN_ERR PREFIX | 762 | printk(KERN_ERR PREFIX |
725 | "HARDWARE addr space,NOT supported yet\n"); | 763 | "HARDWARE addr space,NOT supported yet\n"); |
@@ -751,7 +789,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr, | |||
751 | ret = 0; | 789 | ret = 0; |
752 | break; | 790 | break; |
753 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | 791 | case ACPI_ADR_SPACE_FIXED_HARDWARE: |
754 | ret = acpi_throttling_rdmsr(pr, value); | 792 | ret = acpi_throttling_rdmsr(value); |
755 | break; | 793 | break; |
756 | default: | 794 | default: |
757 | printk(KERN_ERR PREFIX "Unknown addr space %d\n", | 795 | printk(KERN_ERR PREFIX "Unknown addr space %d\n", |
@@ -784,7 +822,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr, | |||
784 | ret = 0; | 822 | ret = 0; |
785 | break; | 823 | break; |
786 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | 824 | case ACPI_ADR_SPACE_FIXED_HARDWARE: |
787 | ret = acpi_throttling_wrmsr(pr, value); | 825 | ret = acpi_throttling_wrmsr(value); |
788 | break; | 826 | break; |
789 | default: | 827 | default: |
790 | printk(KERN_ERR PREFIX "Unknown addr space %d\n", | 828 | printk(KERN_ERR PREFIX "Unknown addr space %d\n", |
@@ -874,7 +912,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) | |||
874 | */ | 912 | */ |
875 | cpumask_copy(saved_mask, ¤t->cpus_allowed); | 913 | cpumask_copy(saved_mask, ¤t->cpus_allowed); |
876 | /* FIXME: use work_on_cpu() */ | 914 | /* FIXME: use work_on_cpu() */ |
877 | set_cpus_allowed_ptr(current, cpumask_of(pr->id)); | 915 | if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { |
916 | /* Can't migrate to the target pr->id CPU. Exit */ | ||
917 | free_cpumask_var(saved_mask); | ||
918 | return -ENODEV; | ||
919 | } | ||
878 | ret = pr->throttling.acpi_processor_get_throttling(pr); | 920 | ret = pr->throttling.acpi_processor_get_throttling(pr); |
879 | /* restore the previous state */ | 921 | /* restore the previous state */ |
880 | set_cpus_allowed_ptr(current, saved_mask); | 922 | set_cpus_allowed_ptr(current, saved_mask); |
@@ -1049,6 +1091,14 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1049 | return -ENOMEM; | 1091 | return -ENOMEM; |
1050 | } | 1092 | } |
1051 | 1093 | ||
1094 | if (cpu_is_offline(pr->id)) { | ||
1095 | /* | ||
1096 | * the cpu pointed by pr->id is offline. Unnecessary to change | ||
1097 | * the throttling state any more. | ||
1098 | */ | ||
1099 | return -ENODEV; | ||
1100 | } | ||
1101 | |||
1052 | cpumask_copy(saved_mask, ¤t->cpus_allowed); | 1102 | cpumask_copy(saved_mask, ¤t->cpus_allowed); |
1053 | t_state.target_state = state; | 1103 | t_state.target_state = state; |
1054 | p_throttling = &(pr->throttling); | 1104 | p_throttling = &(pr->throttling); |
@@ -1072,7 +1122,11 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1072 | */ | 1122 | */ |
1073 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { | 1123 | if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { |
1074 | /* FIXME: use work_on_cpu() */ | 1124 | /* FIXME: use work_on_cpu() */ |
1075 | set_cpus_allowed_ptr(current, cpumask_of(pr->id)); | 1125 | if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { |
1126 | /* Can't migrate to the pr->id CPU. Exit */ | ||
1127 | ret = -ENODEV; | ||
1128 | goto exit; | ||
1129 | } | ||
1076 | ret = p_throttling->acpi_processor_set_throttling(pr, | 1130 | ret = p_throttling->acpi_processor_set_throttling(pr, |
1077 | t_state.target_state, force); | 1131 | t_state.target_state, force); |
1078 | } else { | 1132 | } else { |
@@ -1098,13 +1152,14 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1098 | */ | 1152 | */ |
1099 | if (!match_pr->flags.throttling) { | 1153 | if (!match_pr->flags.throttling) { |
1100 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 1154 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
1101 | "Throttling Controll is unsupported " | 1155 | "Throttling Control is unsupported " |
1102 | "on CPU %d\n", i)); | 1156 | "on CPU %d\n", i)); |
1103 | continue; | 1157 | continue; |
1104 | } | 1158 | } |
1105 | t_state.cpu = i; | 1159 | t_state.cpu = i; |
1106 | /* FIXME: use work_on_cpu() */ | 1160 | /* FIXME: use work_on_cpu() */ |
1107 | set_cpus_allowed_ptr(current, cpumask_of(i)); | 1161 | if (set_cpus_allowed_ptr(current, cpumask_of(i))) |
1162 | continue; | ||
1108 | ret = match_pr->throttling. | 1163 | ret = match_pr->throttling. |
1109 | acpi_processor_set_throttling( | 1164 | acpi_processor_set_throttling( |
1110 | match_pr, t_state.target_state, force); | 1165 | match_pr, t_state.target_state, force); |
@@ -1124,6 +1179,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, | |||
1124 | /* restore the previous state */ | 1179 | /* restore the previous state */ |
1125 | /* FIXME: use work_on_cpu() */ | 1180 | /* FIXME: use work_on_cpu() */ |
1126 | set_cpus_allowed_ptr(current, saved_mask); | 1181 | set_cpus_allowed_ptr(current, saved_mask); |
1182 | exit: | ||
1127 | free_cpumask_var(online_throttling_cpus); | 1183 | free_cpumask_var(online_throttling_cpus); |
1128 | free_cpumask_var(saved_mask); | 1184 | free_cpumask_var(saved_mask); |
1129 | return ret; | 1185 | return ret; |
@@ -1214,111 +1270,3 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) | |||
1214 | return result; | 1270 | return result; |
1215 | } | 1271 | } |
1216 | 1272 | ||
1217 | /* proc interface */ | ||
1218 | static int acpi_processor_throttling_seq_show(struct seq_file *seq, | ||
1219 | void *offset) | ||
1220 | { | ||
1221 | struct acpi_processor *pr = seq->private; | ||
1222 | int i = 0; | ||
1223 | int result = 0; | ||
1224 | |||
1225 | if (!pr) | ||
1226 | goto end; | ||
1227 | |||
1228 | if (!(pr->throttling.state_count > 0)) { | ||
1229 | seq_puts(seq, "<not supported>\n"); | ||
1230 | goto end; | ||
1231 | } | ||
1232 | |||
1233 | result = acpi_processor_get_throttling(pr); | ||
1234 | |||
1235 | if (result) { | ||
1236 | seq_puts(seq, | ||
1237 | "Could not determine current throttling state.\n"); | ||
1238 | goto end; | ||
1239 | } | ||
1240 | |||
1241 | seq_printf(seq, "state count: %d\n" | ||
1242 | "active state: T%d\n" | ||
1243 | "state available: T%d to T%d\n", | ||
1244 | pr->throttling.state_count, pr->throttling.state, | ||
1245 | pr->throttling_platform_limit, | ||
1246 | pr->throttling.state_count - 1); | ||
1247 | |||
1248 | seq_puts(seq, "states:\n"); | ||
1249 | if (pr->throttling.acpi_processor_get_throttling == | ||
1250 | acpi_processor_get_throttling_fadt) { | ||
1251 | for (i = 0; i < pr->throttling.state_count; i++) | ||
1252 | seq_printf(seq, " %cT%d: %02d%%\n", | ||
1253 | (i == pr->throttling.state ? '*' : ' '), i, | ||
1254 | (pr->throttling.states[i].performance ? pr-> | ||
1255 | throttling.states[i].performance / 10 : 0)); | ||
1256 | } else { | ||
1257 | for (i = 0; i < pr->throttling.state_count; i++) | ||
1258 | seq_printf(seq, " %cT%d: %02d%%\n", | ||
1259 | (i == pr->throttling.state ? '*' : ' '), i, | ||
1260 | (int)pr->throttling.states_tss[i]. | ||
1261 | freqpercentage); | ||
1262 | } | ||
1263 | |||
1264 | end: | ||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1268 | static int acpi_processor_throttling_open_fs(struct inode *inode, | ||
1269 | struct file *file) | ||
1270 | { | ||
1271 | return single_open(file, acpi_processor_throttling_seq_show, | ||
1272 | PDE(inode)->data); | ||
1273 | } | ||
1274 | |||
1275 | static ssize_t acpi_processor_write_throttling(struct file *file, | ||
1276 | const char __user * buffer, | ||
1277 | size_t count, loff_t * data) | ||
1278 | { | ||
1279 | int result = 0; | ||
1280 | struct seq_file *m = file->private_data; | ||
1281 | struct acpi_processor *pr = m->private; | ||
1282 | char state_string[5] = ""; | ||
1283 | char *charp = NULL; | ||
1284 | size_t state_val = 0; | ||
1285 | char tmpbuf[5] = ""; | ||
1286 | |||
1287 | if (!pr || (count > sizeof(state_string) - 1)) | ||
1288 | return -EINVAL; | ||
1289 | |||
1290 | if (copy_from_user(state_string, buffer, count)) | ||
1291 | return -EFAULT; | ||
1292 | |||
1293 | state_string[count] = '\0'; | ||
1294 | if ((count > 0) && (state_string[count-1] == '\n')) | ||
1295 | state_string[count-1] = '\0'; | ||
1296 | |||
1297 | charp = state_string; | ||
1298 | if ((state_string[0] == 't') || (state_string[0] == 'T')) | ||
1299 | charp++; | ||
1300 | |||
1301 | state_val = simple_strtoul(charp, NULL, 0); | ||
1302 | if (state_val >= pr->throttling.state_count) | ||
1303 | return -EINVAL; | ||
1304 | |||
1305 | snprintf(tmpbuf, 5, "%zu", state_val); | ||
1306 | |||
1307 | if (strcmp(tmpbuf, charp) != 0) | ||
1308 | return -EINVAL; | ||
1309 | |||
1310 | result = acpi_processor_set_throttling(pr, state_val, false); | ||
1311 | if (result) | ||
1312 | return result; | ||
1313 | |||
1314 | return count; | ||
1315 | } | ||
1316 | |||
1317 | const struct file_operations acpi_processor_throttling_fops = { | ||
1318 | .owner = THIS_MODULE, | ||
1319 | .open = acpi_processor_throttling_open_fs, | ||
1320 | .read = seq_read, | ||
1321 | .write = acpi_processor_write_throttling, | ||
1322 | .llseek = seq_lseek, | ||
1323 | .release = single_release, | ||
1324 | }; | ||