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