1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * x86_energy_perf_policy -- set the energy versus performance
4 * policy preference bias on recent X86 processors.
5 */
6 /*
7 * Copyright (c) 2010 - 2026 Intel Corporation.
8 * Len Brown <len.brown@intel.com>
9 */
10
11 #define _GNU_SOURCE
12 #include MSRHEADER
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <sys/types.h>
16 #include <sched.h>
17 #include <sys/stat.h>
18 #include <sys/resource.h>
19 #include <getopt.h>
20 #include <err.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <sys/time.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <cpuid.h>
28 #include <errno.h>
29
30 #define OPTARG_NORMAL (INT_MAX - 1)
31 #define OPTARG_POWER (INT_MAX - 2)
32 #define OPTARG_BALANCE_POWER (INT_MAX - 3)
33 #define OPTARG_BALANCE_PERFORMANCE (INT_MAX - 4)
34 #define OPTARG_PERFORMANCE (INT_MAX - 5)
35
36 struct msr_hwp_cap {
37 unsigned char highest;
38 unsigned char guaranteed;
39 unsigned char efficient;
40 unsigned char lowest;
41 };
42
43 struct msr_hwp_request {
44 unsigned char hwp_min;
45 unsigned char hwp_max;
46 unsigned char hwp_desired;
47 unsigned char hwp_epp;
48 unsigned int hwp_window;
49 unsigned char hwp_use_pkg;
50 } req_update;
51
52 unsigned int debug;
53 unsigned int verbose;
54 unsigned int force;
55 char *progname;
56 int base_cpu;
57 unsigned char update_epb;
58 unsigned long long new_epb;
59 unsigned char turbo_is_enabled;
60 unsigned char update_turbo;
61 unsigned char turbo_update_value;
62 unsigned char update_hwp_epp;
63 unsigned char update_hwp_min;
64 unsigned char update_hwp_max;
65 unsigned char hwp_limits_done_via_sysfs;
66 unsigned char update_hwp_desired;
67 unsigned char update_hwp_window;
68 unsigned char update_hwp_use_pkg;
69 unsigned char update_hwp_enable;
70 #define hwp_update_enabled() (update_hwp_enable | update_hwp_epp | update_hwp_max | update_hwp_min | update_hwp_desired | update_hwp_window | update_hwp_use_pkg)
71 int max_cpu_num;
72 int max_pkg_num;
73 #define MAX_PACKAGES 64
74 unsigned int first_cpu_in_pkg[MAX_PACKAGES];
75 unsigned long long pkg_present_set;
76 unsigned long long pkg_selected_set;
77 cpu_set_t *cpu_present_set;
78 cpu_set_t *cpu_selected_set;
79 int genuine_intel;
80
81 size_t cpu_setsize;
82
83 char *proc_stat = "/proc/stat";
84
85 unsigned int has_epb; /* MSR_IA32_ENERGY_PERF_BIAS */
86 unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */
87 /* IA32_HWP_REQUEST, IA32_HWP_STATUS */
88 unsigned int has_hwp_notify; /* IA32_HWP_INTERRUPT */
89 unsigned int has_hwp_activity_window; /* IA32_HWP_REQUEST[bits 41:32] */
90 unsigned int has_hwp_epp; /* IA32_HWP_REQUEST[bits 31:24] */
91 unsigned int has_hwp_request_pkg; /* IA32_HWP_REQUEST_PKG */
92
93 unsigned int bdx_highest_ratio;
94
95 unsigned char update_soc_slider_balance;
96 unsigned char update_soc_slider_offset;
97 unsigned char update_platform_profile;
98 int soc_slider_balance;
99 int soc_slider_offset;
100 char platform_profile[64];
101
102 #define PATH_TO_CPU "/sys/devices/system/cpu/"
103 #define SYSFS_PATH_MAX 255
104 #define PATH_SOC_SLIDER_BALANCE "/sys/module/processor_thermal_soc_slider/parameters/slider_balance"
105 #define PATH_SOC_SLIDER_OFFSET "/sys/module/processor_thermal_soc_slider/parameters/slider_offset"
106 #define PATH_PLATFORM_PROFILE "/sys/class/platform-profile/platform-profile-0/profile"
107 #define PATH_PLATFORM_PROFILE_NAME "/sys/class/platform-profile/platform-profile-0/name"
108 #define POWER_SLIDER_NAME "SoC Power Slider"
109
110 static int use_android_msr_path;
111
112 static unsigned int read_sysfs(const char *, char *, size_t);
113 static int sysfs_read_string(const char *, char *, size_t);
114
115 /*
116 * maintain compatibility with original implementation, but don't document it:
117 */
usage(void)118 void usage(void)
119 {
120 fprintf(stderr, "%s [options] [scope][field value]\n", progname);
121 fprintf(stderr, "scope: --cpu cpu-list [--hwp-use-pkg #] | --pkg pkg-list\n");
122 fprintf(stderr, "field: --all | --epb | --hwp-epp | --hwp-min | --hwp-max | --hwp-desired\n");
123 fprintf(stderr, "other: --hwp-enable | --turbo-enable (0 | 1) | --help | --force\n");
124 fprintf(stderr, "soc-slider: --soc-slider-balance # | --soc-slider-offset # | --platform-profile <name>\n");
125 fprintf(stderr, "value: ( # | \"normal\" | \"performance\" | \"balance-performance\" | \"balance-power\"| \"power\")\n");
126 fprintf(stderr, "--hwp-window usec\n");
127
128 fprintf(stderr, "Specify only Energy Performance BIAS (legacy usage):\n");
129 fprintf(stderr, "%s: [-c cpu] [-v] (-r | policy-value )\n", progname);
130
131 exit(1);
132 }
133
134 /*
135 * If bdx_highest_ratio is set,
136 * then we must translate between MSR format and simple ratio
137 * used on the cmdline.
138 */
ratio_2_msr_perf(int ratio)139 int ratio_2_msr_perf(int ratio)
140 {
141 int msr_perf;
142
143 if (!bdx_highest_ratio)
144 return ratio;
145
146 msr_perf = ratio * 255 / bdx_highest_ratio;
147
148 if (debug)
149 fprintf(stderr, "%d = ratio_to_msr_perf(%d)\n", msr_perf, ratio);
150
151 return msr_perf;
152 }
153
msr_perf_2_ratio(int msr_perf)154 int msr_perf_2_ratio(int msr_perf)
155 {
156 int ratio;
157 double d;
158
159 if (!bdx_highest_ratio)
160 return msr_perf;
161
162 d = (double)msr_perf * (double)bdx_highest_ratio / 255.0;
163 d = d + 0.5; /* round */
164 ratio = (int)d;
165
166 if (debug)
167 fprintf(stderr, "%d = msr_perf_ratio(%d) {%f}\n", ratio, msr_perf, d);
168
169 return ratio;
170 }
171
parse_cmdline_epb(int i)172 int parse_cmdline_epb(int i)
173 {
174 if (!has_epb)
175 errx(1, "EPB not enabled on this platform");
176
177 update_epb = 1;
178
179 switch (i) {
180 case OPTARG_POWER:
181 return ENERGY_PERF_BIAS_POWERSAVE;
182 case OPTARG_BALANCE_POWER:
183 return ENERGY_PERF_BIAS_BALANCE_POWERSAVE;
184 case OPTARG_NORMAL:
185 return ENERGY_PERF_BIAS_NORMAL;
186 case OPTARG_BALANCE_PERFORMANCE:
187 return ENERGY_PERF_BIAS_BALANCE_PERFORMANCE;
188 case OPTARG_PERFORMANCE:
189 return ENERGY_PERF_BIAS_PERFORMANCE;
190 }
191 if (i < 0 || i > ENERGY_PERF_BIAS_POWERSAVE)
192 errx(1, "--epb must be from 0 to 15");
193 return i;
194 }
195
196 #define HWP_CAP_LOWEST 0
197 #define HWP_CAP_HIGHEST 255
198
199 /*
200 * "performance" changes hwp_min to cap.highest
201 * All others leave it at cap.lowest
202 */
parse_cmdline_hwp_min(int i)203 int parse_cmdline_hwp_min(int i)
204 {
205 update_hwp_min = 1;
206
207 switch (i) {
208 case OPTARG_POWER:
209 case OPTARG_BALANCE_POWER:
210 case OPTARG_NORMAL:
211 case OPTARG_BALANCE_PERFORMANCE:
212 return HWP_CAP_LOWEST;
213 case OPTARG_PERFORMANCE:
214 return HWP_CAP_HIGHEST;
215 }
216 return i;
217 }
218
219 /*
220 * "power" changes hwp_max to cap.lowest
221 * All others leave it at cap.highest
222 */
parse_cmdline_hwp_max(int i)223 int parse_cmdline_hwp_max(int i)
224 {
225 update_hwp_max = 1;
226
227 switch (i) {
228 case OPTARG_POWER:
229 return HWP_CAP_LOWEST;
230 case OPTARG_NORMAL:
231 case OPTARG_BALANCE_POWER:
232 case OPTARG_BALANCE_PERFORMANCE:
233 case OPTARG_PERFORMANCE:
234 return HWP_CAP_HIGHEST;
235 }
236 return i;
237 }
238
239 /*
240 * for --hwp-des, all strings leave it in autonomous mode
241 * If you want to change it, you need to explicitly pick a value
242 */
parse_cmdline_hwp_desired(int i)243 int parse_cmdline_hwp_desired(int i)
244 {
245 update_hwp_desired = 1;
246
247 switch (i) {
248 case OPTARG_POWER:
249 case OPTARG_BALANCE_POWER:
250 case OPTARG_BALANCE_PERFORMANCE:
251 case OPTARG_NORMAL:
252 case OPTARG_PERFORMANCE:
253 return 0; /* autonomous */
254 }
255 return i;
256 }
257
parse_cmdline_hwp_window(int i)258 int parse_cmdline_hwp_window(int i)
259 {
260 unsigned int exponent;
261
262 update_hwp_window = 1;
263
264 switch (i) {
265 case OPTARG_POWER:
266 case OPTARG_BALANCE_POWER:
267 case OPTARG_NORMAL:
268 case OPTARG_BALANCE_PERFORMANCE:
269 case OPTARG_PERFORMANCE:
270 return 0;
271 }
272 if (i < 0 || i > 1270000000) {
273 fprintf(stderr, "--hwp-window: 0 for auto; 1 - 1270000000 usec for window duration\n");
274 usage();
275 }
276 for (exponent = 0;; ++exponent) {
277 if (debug)
278 printf("%d 10^%d\n", i, exponent);
279
280 if (i <= 127)
281 break;
282
283 i = i / 10;
284 }
285 if (debug)
286 fprintf(stderr, "%d*10^%d: 0x%x\n", i, exponent, (exponent << 7) | i);
287
288 return (exponent << 7) | i;
289 }
290
parse_cmdline_hwp_epp(int i)291 int parse_cmdline_hwp_epp(int i)
292 {
293 update_hwp_epp = 1;
294
295 switch (i) {
296 case OPTARG_POWER:
297 return HWP_EPP_POWERSAVE;
298 case OPTARG_BALANCE_POWER:
299 return HWP_EPP_BALANCE_POWERSAVE;
300 case OPTARG_NORMAL:
301 case OPTARG_BALANCE_PERFORMANCE:
302 return HWP_EPP_BALANCE_PERFORMANCE;
303 case OPTARG_PERFORMANCE:
304 return HWP_EPP_PERFORMANCE;
305 }
306 if (i < 0 || i > 0xff) {
307 fprintf(stderr, "--hwp-epp must be from 0 to 0xff\n");
308 usage();
309 }
310 return i;
311 }
312
parse_cmdline_turbo(int i)313 int parse_cmdline_turbo(int i)
314 {
315 update_turbo = 1;
316
317 switch (i) {
318 case OPTARG_POWER:
319 return 0;
320 case OPTARG_NORMAL:
321 case OPTARG_BALANCE_POWER:
322 case OPTARG_BALANCE_PERFORMANCE:
323 case OPTARG_PERFORMANCE:
324 return 1;
325 }
326 if (i < 0 || i > 1) {
327 fprintf(stderr, "--turbo-enable: 1 to enable, 0 to disable\n");
328 usage();
329 }
330 return i;
331 }
332
parse_optarg_string(char * s)333 int parse_optarg_string(char *s)
334 {
335 int i;
336 char *endptr;
337
338 if (!strncmp(s, "default", 7))
339 return OPTARG_NORMAL;
340
341 if (!strncmp(s, "normal", 6))
342 return OPTARG_NORMAL;
343
344 if (!strncmp(s, "power", 9))
345 return OPTARG_POWER;
346
347 if (!strncmp(s, "balance-power", 17))
348 return OPTARG_BALANCE_POWER;
349
350 if (!strncmp(s, "balance-performance", 19))
351 return OPTARG_BALANCE_PERFORMANCE;
352
353 if (!strncmp(s, "performance", 11))
354 return OPTARG_PERFORMANCE;
355
356 i = strtol(s, &endptr, 0);
357 if (s == endptr) {
358 fprintf(stderr, "no digits in \"%s\"\n", s);
359 usage();
360 }
361 if (i == LONG_MIN || i == LONG_MAX)
362 errx(-1, "%s", s);
363
364 if (i > 0xFF)
365 errx(-1, "%d (0x%x) must be < 256", i, i);
366
367 if (i < 0)
368 errx(-1, "%d (0x%x) must be >= 0", i, i);
369 return i;
370 }
371
parse_cmdline_all(char * s)372 void parse_cmdline_all(char *s)
373 {
374 force++;
375 update_hwp_enable = 1;
376 req_update.hwp_min = parse_cmdline_hwp_min(parse_optarg_string(s));
377 req_update.hwp_max = parse_cmdline_hwp_max(parse_optarg_string(s));
378 req_update.hwp_epp = parse_cmdline_hwp_epp(parse_optarg_string(s));
379 if (has_epb)
380 new_epb = parse_cmdline_epb(parse_optarg_string(s));
381 turbo_update_value = parse_cmdline_turbo(parse_optarg_string(s));
382 req_update.hwp_desired = parse_cmdline_hwp_desired(parse_optarg_string(s));
383 req_update.hwp_window = parse_cmdline_hwp_window(parse_optarg_string(s));
384 }
385
validate_cpu_selected_set(void)386 void validate_cpu_selected_set(void)
387 {
388 int cpu;
389
390 if (CPU_COUNT_S(cpu_setsize, cpu_selected_set) == 0)
391 errx(0, "no CPUs requested");
392
393 for (cpu = 0; cpu <= max_cpu_num; ++cpu) {
394 if (CPU_ISSET_S(cpu, cpu_setsize, cpu_selected_set))
395 if (!CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set))
396 errx(1, "Requested cpu%d is not present", cpu);
397 }
398 }
399
parse_cmdline_cpu(char * s)400 void parse_cmdline_cpu(char *s)
401 {
402 char *startp, *endp;
403 int cpu = 0;
404
405 if (pkg_selected_set) {
406 usage();
407 errx(1, "--cpu | --pkg");
408 }
409 cpu_selected_set = CPU_ALLOC((max_cpu_num + 1));
410 if (cpu_selected_set == NULL)
411 err(1, "cpu_selected_set");
412 CPU_ZERO_S(cpu_setsize, cpu_selected_set);
413
414 for (startp = s; startp && *startp;) {
415
416 if (*startp == ',') {
417 startp++;
418 continue;
419 }
420
421 if (*startp == '-') {
422 int end_cpu;
423
424 startp++;
425 end_cpu = strtol(startp, &endp, 10);
426 if (startp == endp)
427 continue;
428
429 while (cpu <= end_cpu) {
430 if (cpu > max_cpu_num)
431 errx(1, "Requested cpu%d exceeds max cpu%d", cpu, max_cpu_num);
432 CPU_SET_S(cpu, cpu_setsize, cpu_selected_set);
433 cpu++;
434 }
435 startp = endp;
436 continue;
437 }
438
439 if (strncmp(startp, "all", 3) == 0) {
440 for (cpu = 0; cpu <= max_cpu_num; cpu += 1) {
441 if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set))
442 CPU_SET_S(cpu, cpu_setsize, cpu_selected_set);
443 }
444 startp += 3;
445 if (*startp == 0)
446 break;
447 }
448 /* "--cpu even" is not documented */
449 if (strncmp(startp, "even", 4) == 0) {
450 for (cpu = 0; cpu <= max_cpu_num; cpu += 2) {
451 if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set))
452 CPU_SET_S(cpu, cpu_setsize, cpu_selected_set);
453 }
454 startp += 4;
455 if (*startp == 0)
456 break;
457 }
458
459 /* "--cpu odd" is not documented */
460 if (strncmp(startp, "odd", 3) == 0) {
461 for (cpu = 1; cpu <= max_cpu_num; cpu += 2) {
462 if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set))
463 CPU_SET_S(cpu, cpu_setsize, cpu_selected_set);
464 }
465 startp += 3;
466 if (*startp == 0)
467 break;
468 }
469
470 cpu = strtol(startp, &endp, 10);
471 if (startp == endp)
472 errx(1, "--cpu cpu-set: confused by '%s'", startp);
473 if (cpu > max_cpu_num)
474 errx(1, "Requested cpu%d exceeds max cpu%d", cpu, max_cpu_num);
475 CPU_SET_S(cpu, cpu_setsize, cpu_selected_set);
476 startp = endp;
477 }
478
479 validate_cpu_selected_set();
480
481 }
482
parse_cmdline_pkg(char * s)483 void parse_cmdline_pkg(char *s)
484 {
485 char *startp, *endp;
486 int pkg = 0;
487
488 if (cpu_selected_set) {
489 usage();
490 errx(1, "--pkg | --cpu");
491 }
492 pkg_selected_set = 0;
493
494 for (startp = s; startp && *startp;) {
495
496 if (*startp == ',') {
497 startp++;
498 continue;
499 }
500
501 if (*startp == '-') {
502 int end_pkg;
503
504 startp++;
505 end_pkg = strtol(startp, &endp, 10);
506 if (startp == endp)
507 continue;
508
509 while (pkg <= end_pkg) {
510 if (pkg > max_pkg_num)
511 errx(1, "Requested pkg%d exceeds max pkg%d", pkg, max_pkg_num);
512 pkg_selected_set |= 1 << pkg;
513 pkg++;
514 }
515 startp = endp;
516 continue;
517 }
518
519 if (strncmp(startp, "all", 3) == 0) {
520 pkg_selected_set = pkg_present_set;
521 return;
522 }
523
524 pkg = strtol(startp, &endp, 10);
525 if (pkg > max_pkg_num)
526 errx(1, "Requested pkg%d Exceeds max pkg%d", pkg, max_pkg_num);
527 pkg_selected_set |= 1 << pkg;
528 startp = endp;
529 }
530 }
531
for_packages(unsigned long long pkg_set,int (func)(int))532 void for_packages(unsigned long long pkg_set, int (func) (int))
533 {
534 int pkg_num;
535
536 for (pkg_num = 0; pkg_num <= max_pkg_num; ++pkg_num) {
537 if (pkg_set & (1UL << pkg_num))
538 func(pkg_num);
539 }
540 }
541
parse_cmdline_int(const char * s,int * out)542 static int parse_cmdline_int(const char *s, int *out)
543 {
544 char *endp;
545 long val;
546
547 val = strtol(s, &endp, 0);
548 if (endp == s || errno == ERANGE)
549 return -1;
550 if (*endp != '\0')
551 return -1;
552 if (val < INT_MIN || val > INT_MAX)
553 return -1;
554
555 *out = (int)val;
556 return 0;
557 }
558
print_version(void)559 void print_version(void)
560 {
561 printf("x86_energy_perf_policy 2026.04.25 Len Brown <lenb@kernel.org>\n");
562 }
563
platform_profile_access(int mode)564 static int platform_profile_access(int mode)
565 {
566 if (access(PATH_PLATFORM_PROFILE, mode)) {
567 if (debug)
568 fprintf(stderr, "Can not access %s\n", PATH_PLATFORM_PROFILE);
569 return 0;
570 }
571
572 return 1;
573 }
574
platform_profile_name_is(char * name)575 static int platform_profile_name_is(char *name)
576 {
577 char buf[64];
578
579 if (sysfs_read_string(PATH_PLATFORM_PROFILE_NAME, buf, sizeof(buf)) != 0) {
580 if (debug)
581 fprintf(stderr, "Can not read %s\n", PATH_PLATFORM_PROFILE_NAME);
582 return 0;
583 }
584
585 if (strncmp(buf, name, 16)) {
586 if (debug)
587 fprintf(stderr, "%s does not match '%s'\n", PATH_PLATFORM_PROFILE_NAME, name);
588 return 0;
589 }
590
591 return 1;
592 }
593
soc_slider_access(int mode)594 static int soc_slider_access(int mode)
595 {
596 if (!platform_profile_access(R_OK))
597 return 0;
598
599 if (!platform_profile_name_is(POWER_SLIDER_NAME))
600 return 0;
601
602 if (access(PATH_SOC_SLIDER_BALANCE, mode)) {
603 if (debug)
604 fprintf(stderr, "Can not access %s\n", PATH_SOC_SLIDER_BALANCE);
605 return 0;
606 }
607
608 if (access(PATH_SOC_SLIDER_OFFSET, mode)) {
609 if (debug)
610 fprintf(stderr, "Can not access %s\n", PATH_SOC_SLIDER_OFFSET);
611 return 0;
612 }
613
614 return 1;
615 }
616
cmdline(int argc,char ** argv)617 void cmdline(int argc, char **argv)
618 {
619 int opt;
620 int option_index = 0;
621
622 static struct option long_options[] = {
623 { "all", required_argument, 0, 'a' },
624 { "cpu", required_argument, 0, 'c' },
625 { "pkg", required_argument, 0, 'p' },
626 { "debug", no_argument, 0, 'd' },
627 { "hwp-desired", required_argument, 0, 'D' },
628 { "epb", required_argument, 0, 'B' },
629 { "force", no_argument, 0, 'f' },
630 { "hwp-enable", no_argument, 0, 'e' },
631 { "help", no_argument, 0, 'h' },
632 { "hwp-epp", required_argument, 0, 'P' },
633 { "hwp-min", required_argument, 0, 'm' },
634 { "hwp-max", required_argument, 0, 'M' },
635 { "read", no_argument, 0, 'r' },
636 { "turbo-enable", required_argument, 0, 't' },
637 { "hwp-use-pkg", required_argument, 0, 'u' },
638 { "version", no_argument, 0, 'v' },
639 { "hwp-window", required_argument, 0, 'w' },
640 { "soc-slider-balance", required_argument, 0, 'S' },
641 { "soc-slider-offset", required_argument, 0, 'O' },
642 { "platform-profile", required_argument, 0, 'F' },
643 { 0, 0, 0, 0 }
644 };
645
646 progname = argv[0];
647
648 while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw::S:O:F:", long_options, &option_index)) != -1) {
649 switch (opt) {
650 case 'a':
651 parse_cmdline_all(optarg);
652 break;
653 case 'B':
654 new_epb = parse_cmdline_epb(parse_optarg_string(optarg));
655 break;
656 case 'c':
657 parse_cmdline_cpu(optarg);
658 break;
659 case 'e':
660 update_hwp_enable = 1;
661 break;
662 case 'h':
663 usage();
664 break;
665 case 'd':
666 debug++;
667 verbose++;
668 break;
669 case 'f':
670 force++;
671 break;
672 case 'D':
673 req_update.hwp_desired = parse_cmdline_hwp_desired(parse_optarg_string(optarg));
674 break;
675 case 'F':
676 if (strlen(optarg) >= sizeof(platform_profile))
677 errx(1, "--platform-profile: value too long");
678 if (!platform_profile_access(W_OK))
679 errx(1, "Can not update platform-profile in '%s'", PATH_PLATFORM_PROFILE);
680 strcpy(platform_profile, optarg);
681 update_platform_profile = 1;
682 break;
683 case 'm':
684 req_update.hwp_min = parse_cmdline_hwp_min(parse_optarg_string(optarg));
685 break;
686 case 'M':
687 req_update.hwp_max = parse_cmdline_hwp_max(parse_optarg_string(optarg));
688 break;
689 case 'O':
690 if (parse_cmdline_int(optarg, &soc_slider_offset))
691 errx(1, "--soc-slider-offset: invalid value");
692 if (!soc_slider_access(W_OK))
693 errx(1, "Unable to write SOC Slider Offset");
694 update_soc_slider_offset = 1;
695 break;
696 case 'p':
697 parse_cmdline_pkg(optarg);
698 break;
699 case 'P':
700 req_update.hwp_epp = parse_cmdline_hwp_epp(parse_optarg_string(optarg));
701 break;
702 case 'r':
703 /* v1 used -r to specify read-only mode, now the default */
704 break;
705 case 'S':
706 if (parse_cmdline_int(optarg, &soc_slider_balance))
707 errx(1, "--soc-slider-balance: invalid value");
708 if (!soc_slider_access(W_OK))
709 errx(1, "Unable to write SOC Slider-Balance in '%s'", PATH_SOC_SLIDER_BALANCE);
710 update_soc_slider_balance = 1;
711 break;
712 case 't':
713 turbo_update_value = parse_cmdline_turbo(parse_optarg_string(optarg));
714 break;
715 case 'u':
716 update_hwp_use_pkg++;
717 if (atoi(optarg) == 0)
718 req_update.hwp_use_pkg = 0;
719 else
720 req_update.hwp_use_pkg = 1;
721 break;
722 case 'v':
723 print_version();
724 exit(0);
725 break;
726 case 'w':
727 req_update.hwp_window = parse_cmdline_hwp_window(parse_optarg_string(optarg));
728 break;
729 default:
730 usage();
731 }
732 }
733 /*
734 * v1 allowed "performance"|"normal"|"power" with no policy specifier
735 * to update BIAS. Continue to support that, even though no longer documented.
736 */
737 if (argc == optind + 1)
738 new_epb = parse_cmdline_epb(parse_optarg_string(argv[optind]));
739
740 if (argc > optind + 1) {
741 fprintf(stderr, "stray parameter '%s'\n", argv[optind + 1]);
742 usage();
743 }
744 }
745
746 /*
747 * Open a file, and exit on failure
748 */
fopen_or_die(const char * path,const char * mode)749 FILE *fopen_or_die(const char *path, const char *mode)
750 {
751 FILE *filep = fopen(path, mode);
752
753 if (!filep)
754 err(1, "%s: open failed", path);
755 return filep;
756 }
757
err_on_hypervisor(void)758 void err_on_hypervisor(void)
759 {
760 FILE *cpuinfo;
761 char *flags, *hypervisor;
762 char *buffer;
763
764 /* On VMs /proc/cpuinfo contains a "flags" entry for hypervisor */
765 cpuinfo = fopen_or_die("/proc/cpuinfo", "r");
766
767 buffer = malloc(4096);
768 if (!buffer) {
769 fclose(cpuinfo);
770 err(-ENOMEM, "buffer malloc fail");
771 }
772
773 if (!fread(buffer, 1024, 1, cpuinfo)) {
774 fclose(cpuinfo);
775 free(buffer);
776 err(1, "Reading /proc/cpuinfo failed");
777 }
778
779 flags = strstr(buffer, "flags");
780 if (!flags) {
781 fclose(cpuinfo);
782 free(buffer);
783 err(1, "Failed to find 'flags' in /proc/cpuinfo");
784 }
785 rewind(cpuinfo);
786 fseek(cpuinfo, flags - buffer, SEEK_SET);
787 if (!fgets(buffer, 4096, cpuinfo)) {
788 fclose(cpuinfo);
789 free(buffer);
790 err(1, "Reading /proc/cpuinfo failed");
791 }
792 fclose(cpuinfo);
793
794 hypervisor = strstr(buffer, "hypervisor");
795
796 free(buffer);
797
798 if (hypervisor)
799 err(-1, "not supported on this virtual machine");
800 }
801
get_msr(int cpu,int offset,unsigned long long * msr)802 int get_msr(int cpu, int offset, unsigned long long *msr)
803 {
804 int retval;
805 char pathname[32];
806 int fd;
807
808 sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", cpu);
809 fd = open(pathname, O_RDONLY);
810 if (fd < 0)
811 err(-1, "%s open failed, try chown or chmod +r %s, or run as root", pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr");
812
813 retval = pread(fd, msr, sizeof(*msr), offset);
814 if (retval != sizeof(*msr)) {
815 err_on_hypervisor();
816 err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset);
817 }
818
819 if (debug > 1)
820 fprintf(stderr, "get_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, *msr);
821
822 close(fd);
823 return 0;
824 }
825
put_msr(int cpu,int offset,unsigned long long new_msr)826 int put_msr(int cpu, int offset, unsigned long long new_msr)
827 {
828 char pathname[32];
829 int retval;
830 int fd;
831
832 sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", cpu);
833 fd = open(pathname, O_RDWR);
834 if (fd < 0)
835 err(-1, "%s open failed, try chown or chmod +r %s, or run as root", pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr");
836
837 retval = pwrite(fd, &new_msr, sizeof(new_msr), offset);
838 if (retval != sizeof(new_msr))
839 err(-2, "pwrite(cpu%d, offset 0x%x, 0x%llx) = %d", cpu, offset, new_msr, retval);
840
841 close(fd);
842
843 if (debug > 1)
844 fprintf(stderr, "put_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, new_msr);
845
846 return 0;
847 }
848
read_sysfs(const char * path,char * buf,size_t buflen)849 static unsigned int read_sysfs(const char *path, char *buf, size_t buflen)
850 {
851 ssize_t numread;
852 int fd;
853
854 fd = open(path, O_RDONLY);
855 if (fd == -1)
856 return 0;
857
858 numread = read(fd, buf, buflen - 1);
859 if (numread < 1) {
860 close(fd);
861 return 0;
862 }
863
864 buf[numread] = '\0';
865 close(fd);
866
867 return (unsigned int)numread;
868 }
869
write_sysfs(const char * path,char * buf,size_t buflen)870 static unsigned int write_sysfs(const char *path, char *buf, size_t buflen)
871 {
872 ssize_t numwritten;
873 int fd;
874
875 fd = open(path, O_WRONLY);
876 if (fd == -1)
877 return 0;
878
879 numwritten = write(fd, buf, buflen - 1);
880 if (numwritten < 1) {
881 buf[strcspn(buf, "\n")] = '\0';
882 warn("Write '%s' to '%s' failed", buf, path);
883 close(fd);
884 return -1;
885 }
886
887 close(fd);
888
889 return (unsigned int)numwritten;
890 }
891
sysfs_read_string(const char * path,char * buf,size_t buflen)892 static int sysfs_read_string(const char *path, char *buf, size_t buflen)
893 {
894 unsigned int len;
895 size_t n;
896
897 len = read_sysfs(path, buf, buflen);
898 if (!len)
899 return -1;
900
901 n = strcspn(buf, "\n");
902 buf[n] = '\0';
903 return 0;
904 }
905
sysfs_write_string(const char * path,const char * buf)906 static int sysfs_write_string(const char *path, const char *buf)
907 {
908 char tmp[128];
909 int len;
910
911 len = snprintf(tmp, sizeof(tmp), "%s\n", buf);
912 if (len < 0 || len >= (int)sizeof(tmp))
913 return -1;
914 return write_sysfs(path, tmp, (size_t)len + 1) ? 0 : -1;
915 }
916
print_hwp_cap(int cpu,struct msr_hwp_cap * cap,char * str)917 void print_hwp_cap(int cpu, struct msr_hwp_cap *cap, char *str)
918 {
919 if (cpu != -1)
920 printf("cpu%d: ", cpu);
921
922 printf("HWP_CAP: low %d eff %d guar %d high %d\n", cap->lowest, cap->efficient, cap->guaranteed, cap->highest);
923 }
924
read_hwp_cap(int cpu,struct msr_hwp_cap * cap,unsigned int msr_offset)925 void read_hwp_cap(int cpu, struct msr_hwp_cap *cap, unsigned int msr_offset)
926 {
927 unsigned long long msr;
928
929 get_msr(cpu, msr_offset, &msr);
930
931 cap->highest = msr_perf_2_ratio(HWP_HIGHEST_PERF(msr));
932 cap->guaranteed = msr_perf_2_ratio(HWP_GUARANTEED_PERF(msr));
933 cap->efficient = msr_perf_2_ratio(HWP_MOSTEFFICIENT_PERF(msr));
934 cap->lowest = msr_perf_2_ratio(HWP_LOWEST_PERF(msr));
935 }
936
print_hwp_request(int cpu,struct msr_hwp_request * h,char * str)937 void print_hwp_request(int cpu, struct msr_hwp_request *h, char *str)
938 {
939 if (cpu != -1)
940 printf("cpu%d: ", cpu);
941
942 if (str)
943 printf("%s", str);
944
945 printf("HWP_REQ: min %d max %d des %d epp %d window 0x%x (%d*10^%dus) use_pkg %d\n",
946 h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7, h->hwp_use_pkg);
947 }
948
print_hwp_request_pkg(int pkg,struct msr_hwp_request * h,char * str)949 void print_hwp_request_pkg(int pkg, struct msr_hwp_request *h, char *str)
950 {
951 printf("pkg%d: ", pkg);
952
953 if (str)
954 printf("%s", str);
955
956 printf("HWP_REQ_PKG: min %d max %d des %d epp %d window 0x%x (%d*10^%dus)\n",
957 h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7);
958 }
959
read_hwp_request_msr(int cpu,struct msr_hwp_request * hwp_req,unsigned int msr_offset)960 void read_hwp_request_msr(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset)
961 {
962 unsigned long long msr;
963
964 get_msr(cpu, msr_offset, &msr);
965
966 hwp_req->hwp_min = msr_perf_2_ratio((((msr) >> 0) & 0xff));
967 hwp_req->hwp_max = msr_perf_2_ratio((((msr) >> 8) & 0xff));
968 hwp_req->hwp_desired = msr_perf_2_ratio((((msr) >> 16) & 0xff));
969 hwp_req->hwp_epp = (((msr) >> 24) & 0xff);
970 hwp_req->hwp_window = (((msr) >> 32) & 0x3ff);
971 hwp_req->hwp_use_pkg = (((msr) >> 42) & 0x1);
972 }
973
write_hwp_request_msr(int cpu,struct msr_hwp_request * hwp_req,unsigned int msr_offset)974 void write_hwp_request_msr(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset)
975 {
976 unsigned long long msr = 0;
977
978 if (debug > 1)
979 printf("cpu%d: requesting min %d max %d des %d epp %d window 0x%0x use_pkg %d\n",
980 cpu, hwp_req->hwp_min, hwp_req->hwp_max, hwp_req->hwp_desired, hwp_req->hwp_epp, hwp_req->hwp_window, hwp_req->hwp_use_pkg);
981
982 msr |= HWP_MIN_PERF(ratio_2_msr_perf(hwp_req->hwp_min));
983 msr |= HWP_MAX_PERF(ratio_2_msr_perf(hwp_req->hwp_max));
984 msr |= HWP_DESIRED_PERF(ratio_2_msr_perf(hwp_req->hwp_desired));
985 msr |= HWP_ENERGY_PERF_PREFERENCE(hwp_req->hwp_epp);
986 msr |= HWP_ACTIVITY_WINDOW(hwp_req->hwp_window);
987 msr |= HWP_PACKAGE_CONTROL(hwp_req->hwp_use_pkg);
988
989 put_msr(cpu, msr_offset, msr);
990 }
991
get_epb_sysfs(int cpu)992 static int get_epb_sysfs(int cpu)
993 {
994 char path[SYSFS_PATH_MAX];
995 char linebuf[3];
996 char *endp;
997 long val;
998
999 if (!has_epb)
1000 return -1;
1001
1002 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/power/energy_perf_bias", cpu);
1003
1004 if (!read_sysfs(path, linebuf, 3))
1005 return -1;
1006
1007 val = strtol(linebuf, &endp, 0);
1008 if (endp == linebuf || errno == ERANGE)
1009 return -1;
1010
1011 return (int)val;
1012 }
1013
set_epb_sysfs(int cpu,int val)1014 static int set_epb_sysfs(int cpu, int val)
1015 {
1016 char path[SYSFS_PATH_MAX];
1017 char linebuf[3];
1018 char *endp;
1019 int ret;
1020
1021 if (!has_epb)
1022 return -1;
1023
1024 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/power/energy_perf_bias", cpu);
1025 snprintf(linebuf, sizeof(linebuf), "%d", val);
1026
1027 ret = write_sysfs(path, linebuf, 3);
1028 if (ret <= 0)
1029 return -1;
1030
1031 val = strtol(linebuf, &endp, 0);
1032 if (endp == linebuf || errno == ERANGE)
1033 return -1;
1034
1035 return (int)val;
1036 }
1037
print_soc_slider(void)1038 static void print_soc_slider(void)
1039 {
1040 char buf[64];
1041
1042 if (!soc_slider_access(R_OK))
1043 return;
1044
1045 if (sysfs_read_string(PATH_SOC_SLIDER_BALANCE, buf, sizeof(buf)) == 0)
1046 printf("soc-slider-balance: %s\n", buf);
1047
1048 if (sysfs_read_string(PATH_SOC_SLIDER_OFFSET, buf, sizeof(buf)) == 0)
1049 printf("soc-slider-offset: %s\n", buf);
1050 }
1051
print_platform_profile(void)1052 static void print_platform_profile(void)
1053 {
1054 char buf[64];
1055
1056 if (!platform_profile_access(R_OK))
1057 return;
1058
1059 if (sysfs_read_string(PATH_PLATFORM_PROFILE_NAME, buf, sizeof(buf)) == 0)
1060 printf("platform-profile-name: %s\n", buf);
1061
1062 if (sysfs_read_string(PATH_PLATFORM_PROFILE, buf, sizeof(buf)) == 0)
1063 printf("platform-profile: %s\n", buf);
1064 }
1065
update_soc_slider(void)1066 static int update_soc_slider(void)
1067 {
1068 char tmp[32];
1069
1070 if (update_soc_slider_balance) {
1071 snprintf(tmp, sizeof(tmp), "%d", soc_slider_balance);
1072 if (sysfs_write_string(PATH_SOC_SLIDER_BALANCE, tmp))
1073 err(1, "soc-slider-balance write failed");
1074 }
1075
1076 if (update_soc_slider_offset) {
1077 snprintf(tmp, sizeof(tmp), "%d", soc_slider_offset);
1078 if (sysfs_write_string(PATH_SOC_SLIDER_OFFSET, tmp))
1079 err(1, "soc-slider-offset write failed");
1080 }
1081
1082 if (update_platform_profile) {
1083 if (sysfs_write_string(PATH_PLATFORM_PROFILE, platform_profile))
1084 err(1, "platform-profile write failed");
1085 }
1086
1087 return 0;
1088 }
1089
print_cpu_msrs(int cpu)1090 int print_cpu_msrs(int cpu)
1091 {
1092 struct msr_hwp_request req;
1093 struct msr_hwp_cap cap;
1094 int epb;
1095
1096 epb = get_epb_sysfs(cpu);
1097 if (epb >= 0)
1098 printf("cpu%d: EPB %u\n", cpu, (unsigned int)epb);
1099
1100 if (!has_hwp)
1101 return 0;
1102
1103 read_hwp_request_msr(cpu, &req, MSR_HWP_REQUEST);
1104 print_hwp_request(cpu, &req, "");
1105
1106 read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES);
1107 print_hwp_cap(cpu, &cap, "");
1108
1109 return 0;
1110 }
1111
print_pkg_msrs(int pkg)1112 int print_pkg_msrs(int pkg)
1113 {
1114 struct msr_hwp_request req;
1115 unsigned long long msr;
1116
1117 if (!has_hwp)
1118 return 0;
1119
1120 read_hwp_request_msr(first_cpu_in_pkg[pkg], &req, MSR_HWP_REQUEST_PKG);
1121 print_hwp_request_pkg(pkg, &req, "");
1122
1123 if (has_hwp_notify) {
1124 get_msr(first_cpu_in_pkg[pkg], MSR_HWP_INTERRUPT, &msr);
1125 fprintf(stderr,
1126 "pkg%d: MSR_HWP_INTERRUPT: 0x%08llx (Excursion_Min-%sabled, Guaranteed_Perf_Change-%sabled)\n",
1127 pkg, msr, ((msr) & 0x2) ? "EN" : "Dis", ((msr) & 0x1) ? "EN" : "Dis");
1128 }
1129 get_msr(first_cpu_in_pkg[pkg], MSR_HWP_STATUS, &msr);
1130 fprintf(stderr,
1131 "pkg%d: MSR_HWP_STATUS: 0x%08llx (%sExcursion_Min, %sGuaranteed_Perf_Change)\n",
1132 pkg, msr, ((msr) & 0x4) ? "" : "No-", ((msr) & 0x1) ? "" : "No-");
1133
1134 return 0;
1135 }
1136
1137 /*
1138 * Assumption: All HWP systems have 100 MHz bus clock
1139 */
ratio_2_sysfs_khz(int ratio)1140 int ratio_2_sysfs_khz(int ratio)
1141 {
1142 int bclk_khz = 100 * 1000; /* 100,000 KHz = 100 MHz */
1143
1144 return ratio * bclk_khz;
1145 }
1146
1147 /*
1148 * If HWP is enabled and cpufreq sysfs attribtes are present,
1149 * then update via sysfs. The intel_pstate driver may modify (clip)
1150 * this request, say, when HWP_CAP is outside of PLATFORM_INFO limits,
1151 * and the driver-chosen value takes precidence.
1152 *
1153 * (intel_pstate's max_perf_pct and min_perf_pct will follow cpufreq,
1154 * so we don't have to touch that.)
1155 */
update_cpufreq_scaling_freq(int is_max,int cpu,unsigned int ratio)1156 void update_cpufreq_scaling_freq(int is_max, int cpu, unsigned int ratio)
1157 {
1158 char pathname[64];
1159 FILE *fp;
1160 int retval;
1161 int khz;
1162
1163 sprintf(pathname, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_%s_freq", cpu, is_max ? "max" : "min");
1164
1165 fp = fopen(pathname, "w");
1166 if (!fp) {
1167 if (debug)
1168 perror(pathname);
1169 return;
1170 }
1171
1172 khz = ratio_2_sysfs_khz(ratio);
1173 retval = fprintf(fp, "%d", khz);
1174 if (retval < 0)
1175 if (debug)
1176 perror("fprintf");
1177 if (debug)
1178 printf("echo %d > %s\n", khz, pathname);
1179
1180 fclose(fp);
1181 }
1182
1183 /*
1184 * We update all sysfs before updating any MSRs because of
1185 * bugs in cpufreq/intel_pstate where the sysfs writes
1186 * for a CPU may change the min/max values on other CPUS.
1187 */
1188
update_sysfs(int cpu)1189 int update_sysfs(int cpu)
1190 {
1191 if (!has_hwp)
1192 return 0;
1193
1194 if (!hwp_update_enabled())
1195 return 0;
1196
1197 if (access("/sys/devices/system/cpu/cpu0/cpufreq", F_OK))
1198 return 0;
1199
1200 if (update_hwp_min)
1201 update_cpufreq_scaling_freq(0, cpu, req_update.hwp_min);
1202
1203 if (update_hwp_max)
1204 update_cpufreq_scaling_freq(1, cpu, req_update.hwp_max);
1205
1206 hwp_limits_done_via_sysfs = 1;
1207
1208 return 0;
1209 }
1210
verify_hwp_req_self_consistency(int cpu,struct msr_hwp_request * req)1211 int verify_hwp_req_self_consistency(int cpu, struct msr_hwp_request *req)
1212 {
1213 /* fail if min > max requested */
1214 if (req->hwp_min > req->hwp_max) {
1215 errx(1, "cpu%d: requested hwp-min %d > hwp_max %d", cpu, req->hwp_min, req->hwp_max);
1216 }
1217
1218 /* fail if desired > max requestd */
1219 if (req->hwp_desired && (req->hwp_desired > req->hwp_max)) {
1220 errx(1, "cpu%d: requested hwp-desired %d > hwp_max %d", cpu, req->hwp_desired, req->hwp_max);
1221 }
1222 /* fail if desired < min requestd */
1223 if (req->hwp_desired && (req->hwp_desired < req->hwp_min)) {
1224 errx(1, "cpu%d: requested hwp-desired %d < requested hwp_min %d", cpu, req->hwp_desired, req->hwp_min);
1225 }
1226
1227 return 0;
1228 }
1229
check_hwp_request_v_hwp_capabilities(int cpu,struct msr_hwp_request * req,struct msr_hwp_cap * cap)1230 int check_hwp_request_v_hwp_capabilities(int cpu, struct msr_hwp_request *req, struct msr_hwp_cap *cap)
1231 {
1232 if (update_hwp_max) {
1233 if (req->hwp_max > cap->highest)
1234 errx(1, "cpu%d: requested max %d > capabilities highest %d, use --force?", cpu, req->hwp_max, cap->highest);
1235 if (req->hwp_max < cap->lowest)
1236 errx(1, "cpu%d: requested max %d < capabilities lowest %d, use --force?", cpu, req->hwp_max, cap->lowest);
1237 }
1238
1239 if (update_hwp_min) {
1240 if (req->hwp_min > cap->highest)
1241 errx(1, "cpu%d: requested min %d > capabilities highest %d, use --force?", cpu, req->hwp_min, cap->highest);
1242 if (req->hwp_min < cap->lowest)
1243 errx(1, "cpu%d: requested min %d < capabilities lowest %d, use --force?", cpu, req->hwp_min, cap->lowest);
1244 }
1245
1246 if (update_hwp_min && update_hwp_max && (req->hwp_min > req->hwp_max))
1247 errx(1, "cpu%d: requested min %d > requested max %d", cpu, req->hwp_min, req->hwp_max);
1248
1249 if (update_hwp_desired && req->hwp_desired) {
1250 if (req->hwp_desired > req->hwp_max)
1251 errx(1, "cpu%d: requested desired %d > requested max %d, use --force?", cpu, req->hwp_desired, req->hwp_max);
1252 if (req->hwp_desired < req->hwp_min)
1253 errx(1, "cpu%d: requested desired %d < requested min %d, use --force?", cpu, req->hwp_desired, req->hwp_min);
1254 if (req->hwp_desired < cap->lowest)
1255 errx(1, "cpu%d: requested desired %d < capabilities lowest %d, use --force?", cpu, req->hwp_desired, cap->lowest);
1256 if (req->hwp_desired > cap->highest)
1257 errx(1, "cpu%d: requested desired %d > capabilities highest %d, use --force?", cpu, req->hwp_desired, cap->highest);
1258 }
1259
1260 return 0;
1261 }
1262
update_hwp_request_msr(int cpu)1263 int update_hwp_request_msr(int cpu)
1264 {
1265 struct msr_hwp_request req;
1266 struct msr_hwp_cap cap;
1267
1268 int msr_offset = MSR_HWP_REQUEST;
1269
1270 read_hwp_request_msr(cpu, &req, msr_offset);
1271 if (debug)
1272 print_hwp_request(cpu, &req, "old: ");
1273
1274 if (update_hwp_min && !hwp_limits_done_via_sysfs)
1275 req.hwp_min = req_update.hwp_min;
1276
1277 if (update_hwp_max && !hwp_limits_done_via_sysfs)
1278 req.hwp_max = req_update.hwp_max;
1279
1280 if (update_hwp_desired)
1281 req.hwp_desired = req_update.hwp_desired;
1282
1283 if (update_hwp_window)
1284 req.hwp_window = req_update.hwp_window;
1285
1286 if (update_hwp_epp)
1287 req.hwp_epp = req_update.hwp_epp;
1288
1289 req.hwp_use_pkg = req_update.hwp_use_pkg;
1290
1291 read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES);
1292 if (debug)
1293 print_hwp_cap(cpu, &cap, "");
1294
1295 if (!force)
1296 check_hwp_request_v_hwp_capabilities(cpu, &req, &cap);
1297
1298 verify_hwp_req_self_consistency(cpu, &req);
1299
1300 write_hwp_request_msr(cpu, &req, msr_offset);
1301
1302 if (debug) {
1303 read_hwp_request_msr(cpu, &req, msr_offset);
1304 print_hwp_request(cpu, &req, "new: ");
1305 }
1306 return 0;
1307 }
1308
update_hwp_request_pkg_msr(int pkg)1309 int update_hwp_request_pkg_msr(int pkg)
1310 {
1311 struct msr_hwp_request req;
1312 struct msr_hwp_cap cap;
1313 int cpu = first_cpu_in_pkg[pkg];
1314
1315 int msr_offset = MSR_HWP_REQUEST_PKG;
1316
1317 read_hwp_request_msr(cpu, &req, msr_offset);
1318 if (debug)
1319 print_hwp_request_pkg(pkg, &req, "old: ");
1320
1321 if (update_hwp_min)
1322 req.hwp_min = req_update.hwp_min;
1323
1324 if (update_hwp_max)
1325 req.hwp_max = req_update.hwp_max;
1326
1327 if (update_hwp_desired)
1328 req.hwp_desired = req_update.hwp_desired;
1329
1330 if (update_hwp_window)
1331 req.hwp_window = req_update.hwp_window;
1332
1333 if (update_hwp_epp)
1334 req.hwp_epp = req_update.hwp_epp;
1335
1336 read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES);
1337 if (debug)
1338 print_hwp_cap(cpu, &cap, "");
1339
1340 if (!force)
1341 check_hwp_request_v_hwp_capabilities(cpu, &req, &cap);
1342
1343 verify_hwp_req_self_consistency(cpu, &req);
1344
1345 write_hwp_request_msr(cpu, &req, msr_offset);
1346
1347 if (debug) {
1348 read_hwp_request_msr(cpu, &req, msr_offset);
1349 print_hwp_request_pkg(pkg, &req, "new: ");
1350 }
1351 return 0;
1352 }
1353
enable_hwp_on_cpu(int cpu)1354 int enable_hwp_on_cpu(int cpu)
1355 {
1356 unsigned long long old_msr, new_msr;
1357
1358 get_msr(cpu, MSR_PM_ENABLE, &old_msr);
1359
1360 if (old_msr & 1)
1361 return 0; /* already enabled */
1362
1363 new_msr = old_msr | 1;
1364 put_msr(cpu, MSR_PM_ENABLE, new_msr);
1365
1366 if (verbose)
1367 printf("cpu%d: MSR_PM_ENABLE old: %llX new: %llX\n", cpu, old_msr, new_msr);
1368
1369 return 0;
1370 }
1371
update_cpu_epb_sysfs(int cpu)1372 int update_cpu_epb_sysfs(int cpu)
1373 {
1374 int epb;
1375
1376 epb = get_epb_sysfs(cpu);
1377 set_epb_sysfs(cpu, new_epb);
1378
1379 if (verbose)
1380 printf("cpu%d: ENERGY_PERF_BIAS old: %d new: %d\n", cpu, epb, (unsigned int)new_epb);
1381
1382 return 0;
1383 }
1384
update_cpu_msrs(int cpu)1385 int update_cpu_msrs(int cpu)
1386 {
1387 unsigned long long msr;
1388
1389 if (update_turbo) {
1390 int turbo_is_present_and_disabled;
1391
1392 get_msr(cpu, MSR_IA32_MISC_ENABLE, &msr);
1393
1394 turbo_is_present_and_disabled = ((msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE) != 0);
1395
1396 if (turbo_update_value == 1) {
1397 if (turbo_is_present_and_disabled) {
1398 msr &= ~MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
1399 put_msr(cpu, MSR_IA32_MISC_ENABLE, msr);
1400 if (verbose)
1401 printf("cpu%d: turbo ENABLE\n", cpu);
1402 }
1403 } else {
1404 /*
1405 * if "turbo_is_enabled" were known to be describe this cpu
1406 * then we could use it here to skip redundant disable requests.
1407 * but cpu may be in a different package, so we always write.
1408 */
1409 msr |= MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
1410 put_msr(cpu, MSR_IA32_MISC_ENABLE, msr);
1411 if (verbose)
1412 printf("cpu%d: turbo DISABLE\n", cpu);
1413 }
1414 }
1415
1416 if (!has_hwp)
1417 return 0;
1418
1419 if (!hwp_update_enabled())
1420 return 0;
1421
1422 update_hwp_request_msr(cpu);
1423 return 0;
1424 }
1425
get_pkg_num(int cpu)1426 unsigned int get_pkg_num(int cpu)
1427 {
1428 FILE *fp;
1429 char pathname[128];
1430 unsigned int pkg;
1431 int retval;
1432
1433 sprintf(pathname, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
1434
1435 fp = fopen_or_die(pathname, "r");
1436 retval = fscanf(fp, "%d\n", &pkg);
1437 if (retval != 1)
1438 errx(1, "%s: failed to parse", pathname);
1439 fclose(fp);
1440 return pkg;
1441 }
1442
set_max_cpu_pkg_num(int cpu)1443 int set_max_cpu_pkg_num(int cpu)
1444 {
1445 unsigned int pkg;
1446
1447 if (max_cpu_num < cpu)
1448 max_cpu_num = cpu;
1449
1450 pkg = get_pkg_num(cpu);
1451
1452 if (pkg >= MAX_PACKAGES)
1453 errx(1, "cpu%d: %d >= MAX_PACKAGES (%d)", cpu, pkg, MAX_PACKAGES);
1454
1455 if (pkg > max_pkg_num)
1456 max_pkg_num = pkg;
1457
1458 if ((pkg_present_set & (1ULL << pkg)) == 0) {
1459 pkg_present_set |= (1ULL << pkg);
1460 first_cpu_in_pkg[pkg] = cpu;
1461 }
1462
1463 return 0;
1464 }
1465
mark_cpu_present(int cpu)1466 int mark_cpu_present(int cpu)
1467 {
1468 CPU_SET_S(cpu, cpu_setsize, cpu_present_set);
1469 return 0;
1470 }
1471
1472 /*
1473 * run func(cpu) on every cpu in /proc/stat
1474 * return max_cpu number
1475 */
for_all_proc_cpus(int (func)(int))1476 int for_all_proc_cpus(int (func) (int))
1477 {
1478 FILE *fp;
1479 int cpu_num;
1480 int retval;
1481
1482 fp = fopen_or_die(proc_stat, "r");
1483
1484 retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
1485 if (retval != 0)
1486 err(1, "%s: failed to parse format", proc_stat);
1487
1488 while (1) {
1489 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num);
1490 if (retval != 1)
1491 break;
1492
1493 retval = func(cpu_num);
1494 if (retval) {
1495 fclose(fp);
1496 return retval;
1497 }
1498 }
1499 fclose(fp);
1500 return 0;
1501 }
1502
for_all_cpus_in_set(size_t set_size,cpu_set_t * cpu_set,int (func)(int))1503 void for_all_cpus_in_set(size_t set_size, cpu_set_t *cpu_set, int (func) (int))
1504 {
1505 int cpu_num;
1506
1507 for (cpu_num = 0; cpu_num <= max_cpu_num; ++cpu_num)
1508 if (CPU_ISSET_S(cpu_num, set_size, cpu_set))
1509 func(cpu_num);
1510 }
1511
for_all_cpus_in_set_and(size_t set_size,cpu_set_t * cpu_set,int (func)(int))1512 int for_all_cpus_in_set_and(size_t set_size, cpu_set_t *cpu_set, int (func) (int))
1513 {
1514 int cpu_num;
1515 int retval = 1;
1516
1517 for (cpu_num = 0; cpu_num <= max_cpu_num; ++cpu_num)
1518 if (CPU_ISSET_S(cpu_num, set_size, cpu_set))
1519 retval &= func(cpu_num);
1520
1521 return retval;
1522 }
1523
init_data_structures(void)1524 void init_data_structures(void)
1525 {
1526 for_all_proc_cpus(set_max_cpu_pkg_num);
1527
1528 cpu_setsize = CPU_ALLOC_SIZE((max_cpu_num + 1));
1529
1530 cpu_present_set = CPU_ALLOC((max_cpu_num + 1));
1531 if (cpu_present_set == NULL)
1532 err(3, "CPU_ALLOC");
1533 CPU_ZERO_S(cpu_setsize, cpu_present_set);
1534 for_all_proc_cpus(mark_cpu_present);
1535 }
1536
is_hwp_enabled_on_cpu(int cpu_num)1537 int is_hwp_enabled_on_cpu(int cpu_num)
1538 {
1539 unsigned long long msr;
1540 int retval;
1541
1542 /* MSR_PM_ENABLE[1] == 1 if HWP is enabled and MSRs visible */
1543 get_msr(cpu_num, MSR_PM_ENABLE, &msr);
1544 retval = (msr & 1);
1545
1546 if (verbose)
1547 fprintf(stderr, "cpu%d: %sHWP\n", cpu_num, retval ? "" : "No-");
1548
1549 return retval;
1550 }
1551
1552 /*
1553 * verify_hwp_is_enabled()
1554 *
1555 * Set (has_hwp=0) if no HWP feature or any of selected CPU set does not have HWP enabled
1556 */
verify_hwp_is_enabled(void)1557 void verify_hwp_is_enabled(void)
1558 {
1559 int retval;
1560
1561 if (!has_hwp) /* set in early_cpuid() */
1562 return;
1563
1564 retval = for_all_cpus_in_set_and(cpu_setsize, cpu_selected_set, is_hwp_enabled_on_cpu);
1565
1566 if (retval == 0) {
1567 fprintf(stderr, "HWP can be enabled using '--hwp-enable'\n");
1568 has_hwp = 0;
1569 }
1570 }
1571
req_update_bounds_check(void)1572 int req_update_bounds_check(void)
1573 {
1574 if (!hwp_update_enabled())
1575 return 0;
1576
1577 /* fail if min > max requested */
1578 if ((update_hwp_max && update_hwp_min) && (req_update.hwp_min > req_update.hwp_max)) {
1579 printf("hwp-min %d > hwp_max %d\n", req_update.hwp_min, req_update.hwp_max);
1580 return -EINVAL;
1581 }
1582
1583 /* fail if desired > max requestd */
1584 if (req_update.hwp_desired && update_hwp_max && (req_update.hwp_desired > req_update.hwp_max)) {
1585 printf("hwp-desired cannot be greater than hwp_max\n");
1586 return -EINVAL;
1587 }
1588 /* fail if desired < min requestd */
1589 if (req_update.hwp_desired && update_hwp_min && (req_update.hwp_desired < req_update.hwp_min)) {
1590 printf("hwp-desired cannot be less than hwp_min\n");
1591 return -EINVAL;
1592 }
1593
1594 return 0;
1595 }
1596
set_base_cpu(void)1597 void set_base_cpu(void)
1598 {
1599 base_cpu = sched_getcpu();
1600 if (base_cpu < 0)
1601 err(-ENODEV, "No valid cpus found");
1602 }
1603
probe_android_msr_path(void)1604 static void probe_android_msr_path(void)
1605 {
1606 struct stat sb;
1607 char test_path[32];
1608
1609 sprintf(test_path, "/dev/msr%d", base_cpu);
1610 if (stat(test_path, &sb) == 0)
1611 use_android_msr_path = 1;
1612 }
1613
probe_dev_msr(void)1614 void probe_dev_msr(void)
1615 {
1616 struct stat sb;
1617 char pathname[32];
1618
1619 probe_android_msr_path();
1620
1621 sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", base_cpu);
1622 if (stat(pathname, &sb)) {
1623 if (system("/sbin/modprobe msr > /dev/null 2>&1")) {
1624 if (use_android_msr_path)
1625 err(-5, "no /dev/msr0, Try \"# modprobe msr\" ");
1626 else
1627 err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
1628 }
1629 }
1630 }
1631
get_cpuid_or_exit(unsigned int leaf,unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)1632 static void get_cpuid_or_exit(unsigned int leaf, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
1633 {
1634 if (!__get_cpuid(leaf, eax, ebx, ecx, edx))
1635 errx(1, "Processor not supported\n");
1636 }
1637
1638 /*
1639 * early_cpuid()
1640 * initialize turbo_is_enabled, has_hwp, has_epb
1641 * before cmdline is parsed
1642 */
early_cpuid(void)1643 void early_cpuid(void)
1644 {
1645 unsigned int eax, ebx, ecx, edx;
1646 unsigned int fms, family, model;
1647
1648 get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
1649 family = (fms >> 8) & 0xf;
1650 model = (fms >> 4) & 0xf;
1651 if (family == 6 || family == 0xf)
1652 model += ((fms >> 16) & 0xf) << 4;
1653
1654 if (model == 0x4F) {
1655 unsigned long long msr;
1656
1657 get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
1658
1659 bdx_highest_ratio = msr & 0xFF;
1660 }
1661
1662 get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
1663 turbo_is_enabled = (eax >> 1) & 1;
1664 has_hwp = (eax >> 7) & 1;
1665 has_epb = (ecx >> 3) & 1;
1666 }
1667
1668 /*
1669 * parse_cpuid()
1670 * set
1671 * has_hwp, has_hwp_notify, has_hwp_activity_window, has_hwp_epp, has_hwp_request_pkg, has_epb
1672 */
parse_cpuid(void)1673 void parse_cpuid(void)
1674 {
1675 unsigned int eax, ebx, ecx, edx, max_level;
1676 unsigned int fms, family, model, stepping;
1677
1678 eax = ebx = ecx = edx = 0;
1679
1680 get_cpuid_or_exit(0, &max_level, &ebx, &ecx, &edx);
1681
1682 if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
1683 genuine_intel = 1;
1684
1685 if (debug)
1686 fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", (char *)&ebx, (char *)&edx, (char *)&ecx);
1687
1688 get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
1689 family = (fms >> 8) & 0xf;
1690 model = (fms >> 4) & 0xf;
1691 stepping = fms & 0xf;
1692 if (family == 6 || family == 0xf)
1693 model += ((fms >> 16) & 0xf) << 4;
1694
1695 if (debug) {
1696 fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", max_level, family, model, stepping, family, model, stepping);
1697 fprintf(stderr, "CPUID(1): %s %s %s %s %s %s %s %s\n",
1698 ecx & (1 << 0) ? "SSE3" : "-",
1699 ecx & (1 << 3) ? "MONITOR" : "-",
1700 ecx & (1 << 7) ? "EIST" : "-",
1701 ecx & (1 << 8) ? "TM2" : "-",
1702 edx & (1 << 4) ? "TSC" : "-", edx & (1 << 5) ? "MSR" : "-", edx & (1 << 22) ? "ACPI-TM" : "-", edx & (1 << 29) ? "TM" : "-");
1703 }
1704
1705 if (!(edx & (1 << 5)))
1706 errx(1, "CPUID: no MSR");
1707
1708 get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
1709 /* turbo_is_enabled already set */
1710 /* has_hwp already set */
1711 has_hwp_notify = eax & (1 << 8);
1712 has_hwp_activity_window = eax & (1 << 9);
1713 has_hwp_epp = eax & (1 << 10);
1714 has_hwp_request_pkg = eax & (1 << 11);
1715
1716 if (!has_hwp_request_pkg && update_hwp_use_pkg)
1717 errx(1, "--hwp-use-pkg is not available on this hardware");
1718
1719 /* has_epb already set */
1720
1721 if (debug)
1722 fprintf(stderr,
1723 "CPUID(6): %sTURBO, %sHWP, %sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n",
1724 turbo_is_enabled ? "" : "No-",
1725 has_hwp ? "" : "No-",
1726 has_hwp_notify ? "" : "No-",
1727 has_hwp_activity_window ? "" : "No-", has_hwp_epp ? "" : "No-", has_hwp_request_pkg ? "" : "No-", has_epb ? "" : "No-");
1728
1729 return; /* success */
1730 }
1731
main(int argc,char ** argv)1732 int main(int argc, char **argv)
1733 {
1734 set_base_cpu();
1735
1736 probe_dev_msr();
1737 init_data_structures();
1738
1739 early_cpuid(); /* initial cpuid parse before cmdline */
1740
1741 cmdline(argc, argv);
1742
1743 if (debug)
1744 print_version();
1745
1746 parse_cpuid();
1747
1748 /* If CPU-set and PKG-set are not initialized, default to all CPUs */
1749 if ((cpu_selected_set == 0) && (pkg_selected_set == 0))
1750 cpu_selected_set = cpu_present_set;
1751
1752 /*
1753 * If HWP is being enabled, do it now, so that subsequent operations
1754 * that access HWP registers can work.
1755 */
1756 if (update_hwp_enable)
1757 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, enable_hwp_on_cpu);
1758
1759 /* If HWP present, but disabled, warn and ignore from here forward */
1760 verify_hwp_is_enabled();
1761
1762 if (req_update_bounds_check())
1763 return -EINVAL;
1764
1765 /* display information only, no updates to settings */
1766 if (!update_epb && !update_turbo && !hwp_update_enabled() && !update_soc_slider_balance && !update_soc_slider_offset && !update_platform_profile) {
1767 if (cpu_selected_set)
1768 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, print_cpu_msrs);
1769
1770 print_soc_slider();
1771 print_platform_profile();
1772
1773 if (has_hwp_request_pkg) {
1774 if (pkg_selected_set == 0)
1775 pkg_selected_set = pkg_present_set;
1776
1777 for_packages(pkg_selected_set, print_pkg_msrs);
1778 }
1779
1780 return 0;
1781 }
1782
1783 /* update CPU set */
1784 if (cpu_selected_set) {
1785 if (update_epb)
1786 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_cpu_epb_sysfs);
1787 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_sysfs);
1788 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_cpu_msrs);
1789
1790 } else if (pkg_selected_set)
1791 for_packages(pkg_selected_set, update_hwp_request_pkg_msr);
1792
1793 if (update_soc_slider_balance || update_soc_slider_offset || update_platform_profile)
1794 update_soc_slider();
1795
1796 return 0;
1797 }
1798