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