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