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