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