1
2
3
4
5
6
7
8
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
36struct msr_hwp_cap {
37 unsigned char highest;
38 unsigned char guaranteed;
39 unsigned char efficient;
40 unsigned char lowest;
41};
42
43struct 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
52unsigned int debug;
53unsigned int verbose;
54unsigned int force;
55char *progname;
56int base_cpu;
57unsigned char update_epb;
58unsigned long long new_epb;
59unsigned char turbo_is_enabled;
60unsigned char update_turbo;
61unsigned char turbo_update_value;
62unsigned char update_hwp_epp;
63unsigned char update_hwp_min;
64unsigned char update_hwp_max;
65unsigned char update_hwp_desired;
66unsigned char update_hwp_window;
67unsigned char update_hwp_use_pkg;
68unsigned 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)
70int max_cpu_num;
71int max_pkg_num;
72#define MAX_PACKAGES 64
73unsigned int first_cpu_in_pkg[MAX_PACKAGES];
74unsigned long long pkg_present_set;
75unsigned long long pkg_selected_set;
76cpu_set_t *cpu_present_set;
77cpu_set_t *cpu_selected_set;
78int genuine_intel;
79
80size_t cpu_setsize;
81
82char *proc_stat = "/proc/stat";
83
84unsigned int has_epb;
85unsigned int has_hwp;
86
87unsigned int has_hwp_notify;
88unsigned int has_hwp_activity_window;
89unsigned int has_hwp_epp;
90unsigned int has_hwp_request_pkg;
91
92unsigned int bdx_highest_ratio;
93
94
95
96
97void 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
115
116
117
118int 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}
132int 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;
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}
149int 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
178
179
180int 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
197
198
199int 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
216
217
218int 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;
229 }
230 return i;
231}
232
233int 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}
265int 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}
286int 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
306int 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
345void 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
359void 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
373void 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
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
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
456void 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
505void 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
515void print_version(void)
516{
517 printf("x86_energy_perf_policy 17.05.11 (C) Len Brown <len.brown@intel.com>\n");
518}
519
520void 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
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
614
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
626int get_msr(int cpu, int offset, unsigned long long *msr)
627{
628 int retval;
629 char pathname[32];
630 int fd;
631
632 sprintf(pathname, "/dev/cpu/%d/msr", cpu);
633 fd = open(pathname, O_RDONLY);
634 if (fd < 0)
635 err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
636
637 retval = pread(fd, msr, sizeof(*msr), offset);
638 if (retval != sizeof(*msr))
639 err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset);
640
641 if (debug > 1)
642 fprintf(stderr, "get_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, *msr);
643
644 close(fd);
645 return 0;
646}
647
648int put_msr(int cpu, int offset, unsigned long long new_msr)
649{
650 char pathname[32];
651 int retval;
652 int fd;
653
654 sprintf(pathname, "/dev/cpu/%d/msr", cpu);
655 fd = open(pathname, O_RDWR);
656 if (fd < 0)
657 err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
658
659 retval = pwrite(fd, &new_msr, sizeof(new_msr), offset);
660 if (retval != sizeof(new_msr))
661 err(-2, "pwrite(cpu%d, offset 0x%x, 0x%llx) = %d", cpu, offset, new_msr, retval);
662
663 close(fd);
664
665 if (debug > 1)
666 fprintf(stderr, "put_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, new_msr);
667
668 return 0;
669}
670
671void print_hwp_cap(int cpu, struct msr_hwp_cap *cap, char *str)
672{
673 if (cpu != -1)
674 printf("cpu%d: ", cpu);
675
676 printf("HWP_CAP: low %d eff %d guar %d high %d\n",
677 cap->lowest, cap->efficient, cap->guaranteed, cap->highest);
678}
679void read_hwp_cap(int cpu, struct msr_hwp_cap *cap, unsigned int msr_offset)
680{
681 unsigned long long msr;
682
683 get_msr(cpu, msr_offset, &msr);
684
685 cap->highest = msr_perf_2_ratio(HWP_HIGHEST_PERF(msr));
686 cap->guaranteed = msr_perf_2_ratio(HWP_GUARANTEED_PERF(msr));
687 cap->efficient = msr_perf_2_ratio(HWP_MOSTEFFICIENT_PERF(msr));
688 cap->lowest = msr_perf_2_ratio(HWP_LOWEST_PERF(msr));
689}
690
691void print_hwp_request(int cpu, struct msr_hwp_request *h, char *str)
692{
693 if (cpu != -1)
694 printf("cpu%d: ", cpu);
695
696 if (str)
697 printf("%s", str);
698
699 printf("HWP_REQ: min %d max %d des %d epp %d window 0x%x (%d*10^%dus) use_pkg %d\n",
700 h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp,
701 h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7, h->hwp_use_pkg);
702}
703void print_hwp_request_pkg(int pkg, struct msr_hwp_request *h, char *str)
704{
705 printf("pkg%d: ", pkg);
706
707 if (str)
708 printf("%s", str);
709
710 printf("HWP_REQ_PKG: min %d max %d des %d epp %d window 0x%x (%d*10^%dus)\n",
711 h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp,
712 h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7);
713}
714void read_hwp_request(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset)
715{
716 unsigned long long msr;
717
718 get_msr(cpu, msr_offset, &msr);
719
720 hwp_req->hwp_min = msr_perf_2_ratio((((msr) >> 0) & 0xff));
721 hwp_req->hwp_max = msr_perf_2_ratio((((msr) >> 8) & 0xff));
722 hwp_req->hwp_desired = msr_perf_2_ratio((((msr) >> 16) & 0xff));
723 hwp_req->hwp_epp = (((msr) >> 24) & 0xff);
724 hwp_req->hwp_window = (((msr) >> 32) & 0x3ff);
725 hwp_req->hwp_use_pkg = (((msr) >> 42) & 0x1);
726}
727
728void write_hwp_request(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset)
729{
730 unsigned long long msr = 0;
731
732 if (debug > 1)
733 printf("cpu%d: requesting min %d max %d des %d epp %d window 0x%0x use_pkg %d\n",
734 cpu, hwp_req->hwp_min, hwp_req->hwp_max,
735 hwp_req->hwp_desired, hwp_req->hwp_epp,
736 hwp_req->hwp_window, hwp_req->hwp_use_pkg);
737
738 msr |= HWP_MIN_PERF(ratio_2_msr_perf(hwp_req->hwp_min));
739 msr |= HWP_MAX_PERF(ratio_2_msr_perf(hwp_req->hwp_max));
740 msr |= HWP_DESIRED_PERF(ratio_2_msr_perf(hwp_req->hwp_desired));
741 msr |= HWP_ENERGY_PERF_PREFERENCE(hwp_req->hwp_epp);
742 msr |= HWP_ACTIVITY_WINDOW(hwp_req->hwp_window);
743 msr |= HWP_PACKAGE_CONTROL(hwp_req->hwp_use_pkg);
744
745 put_msr(cpu, msr_offset, msr);
746}
747
748int print_cpu_msrs(int cpu)
749{
750 unsigned long long msr;
751 struct msr_hwp_request req;
752 struct msr_hwp_cap cap;
753
754 if (has_epb) {
755 get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr);
756
757 printf("cpu%d: EPB %u\n", cpu, (unsigned int) msr);
758 }
759
760 if (!has_hwp)
761 return 0;
762
763 read_hwp_request(cpu, &req, MSR_HWP_REQUEST);
764 print_hwp_request(cpu, &req, "");
765
766 read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES);
767 print_hwp_cap(cpu, &cap, "");
768
769 return 0;
770}
771
772int print_pkg_msrs(int pkg)
773{
774 struct msr_hwp_request req;
775 unsigned long long msr;
776
777 if (!has_hwp)
778 return 0;
779
780 read_hwp_request(first_cpu_in_pkg[pkg], &req, MSR_HWP_REQUEST_PKG);
781 print_hwp_request_pkg(pkg, &req, "");
782
783 if (has_hwp_notify) {
784 get_msr(first_cpu_in_pkg[pkg], MSR_HWP_INTERRUPT, &msr);
785 fprintf(stderr,
786 "pkg%d: MSR_HWP_INTERRUPT: 0x%08llx (Excursion_Min-%sabled, Guaranteed_Perf_Change-%sabled)\n",
787 pkg, msr,
788 ((msr) & 0x2) ? "EN" : "Dis",
789 ((msr) & 0x1) ? "EN" : "Dis");
790 }
791 get_msr(first_cpu_in_pkg[pkg], MSR_HWP_STATUS, &msr);
792 fprintf(stderr,
793 "pkg%d: MSR_HWP_STATUS: 0x%08llx (%sExcursion_Min, %sGuaranteed_Perf_Change)\n",
794 pkg, msr,
795 ((msr) & 0x4) ? "" : "No-",
796 ((msr) & 0x1) ? "" : "No-");
797
798 return 0;
799}
800
801
802
803
804int ratio_2_sysfs_khz(int ratio)
805{
806 int bclk_khz = 100 * 1000;
807
808 return ratio * bclk_khz;
809}
810
811
812
813
814
815
816
817void update_cpufreq_scaling_freq(int is_max, int cpu, unsigned int ratio)
818{
819 char pathname[64];
820 FILE *fp;
821 int retval;
822 int khz;
823
824 sprintf(pathname, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_%s_freq",
825 cpu, is_max ? "max" : "min");
826
827 fp = fopen(pathname, "w");
828 if (!fp) {
829 if (debug)
830 perror(pathname);
831 return;
832 }
833
834 khz = ratio_2_sysfs_khz(ratio);
835 retval = fprintf(fp, "%d", khz);
836 if (retval < 0)
837 if (debug)
838 perror("fprintf");
839 if (debug)
840 printf("echo %d > %s\n", khz, pathname);
841
842 fclose(fp);
843}
844
845
846
847
848
849
850
851int update_sysfs(int cpu)
852{
853 if (!has_hwp)
854 return 0;
855
856 if (!hwp_update_enabled())
857 return 0;
858
859 if (access("/sys/devices/system/cpu/cpu0/cpufreq", F_OK))
860 return 0;
861
862 if (update_hwp_min)
863 update_cpufreq_scaling_freq(0, cpu, req_update.hwp_min);
864
865 if (update_hwp_max)
866 update_cpufreq_scaling_freq(1, cpu, req_update.hwp_max);
867
868 return 0;
869}
870
871int verify_hwp_req_self_consistency(int cpu, struct msr_hwp_request *req)
872{
873
874 if (req->hwp_min > req->hwp_max) {
875 errx(1, "cpu%d: requested hwp-min %d > hwp_max %d",
876 cpu, req->hwp_min, req->hwp_max);
877 }
878
879
880 if (req->hwp_desired && (req->hwp_desired > req->hwp_max)) {
881 errx(1, "cpu%d: requested hwp-desired %d > hwp_max %d",
882 cpu, req->hwp_desired, req->hwp_max);
883 }
884
885 if (req->hwp_desired && (req->hwp_desired < req->hwp_min)) {
886 errx(1, "cpu%d: requested hwp-desired %d < requested hwp_min %d",
887 cpu, req->hwp_desired, req->hwp_min);
888 }
889
890 return 0;
891}
892
893int check_hwp_request_v_hwp_capabilities(int cpu, struct msr_hwp_request *req, struct msr_hwp_cap *cap)
894{
895 if (update_hwp_max) {
896 if (req->hwp_max > cap->highest)
897 errx(1, "cpu%d: requested max %d > capabilities highest %d, use --force?",
898 cpu, req->hwp_max, cap->highest);
899 if (req->hwp_max < cap->lowest)
900 errx(1, "cpu%d: requested max %d < capabilities lowest %d, use --force?",
901 cpu, req->hwp_max, cap->lowest);
902 }
903
904 if (update_hwp_min) {
905 if (req->hwp_min > cap->highest)
906 errx(1, "cpu%d: requested min %d > capabilities highest %d, use --force?",
907 cpu, req->hwp_min, cap->highest);
908 if (req->hwp_min < cap->lowest)
909 errx(1, "cpu%d: requested min %d < capabilities lowest %d, use --force?",
910 cpu, req->hwp_min, cap->lowest);
911 }
912
913 if (update_hwp_min && update_hwp_max && (req->hwp_min > req->hwp_max))
914 errx(1, "cpu%d: requested min %d > requested max %d",
915 cpu, req->hwp_min, req->hwp_max);
916
917 if (update_hwp_desired && req->hwp_desired) {
918 if (req->hwp_desired > req->hwp_max)
919 errx(1, "cpu%d: requested desired %d > requested max %d, use --force?",
920 cpu, req->hwp_desired, req->hwp_max);
921 if (req->hwp_desired < req->hwp_min)
922 errx(1, "cpu%d: requested desired %d < requested min %d, use --force?",
923 cpu, req->hwp_desired, req->hwp_min);
924 if (req->hwp_desired < cap->lowest)
925 errx(1, "cpu%d: requested desired %d < capabilities lowest %d, use --force?",
926 cpu, req->hwp_desired, cap->lowest);
927 if (req->hwp_desired > cap->highest)
928 errx(1, "cpu%d: requested desired %d > capabilities highest %d, use --force?",
929 cpu, req->hwp_desired, cap->highest);
930 }
931
932 return 0;
933}
934
935int update_hwp_request(int cpu)
936{
937 struct msr_hwp_request req;
938 struct msr_hwp_cap cap;
939
940 int msr_offset = MSR_HWP_REQUEST;
941
942 read_hwp_request(cpu, &req, msr_offset);
943 if (debug)
944 print_hwp_request(cpu, &req, "old: ");
945
946 if (update_hwp_min)
947 req.hwp_min = req_update.hwp_min;
948
949 if (update_hwp_max)
950 req.hwp_max = req_update.hwp_max;
951
952 if (update_hwp_desired)
953 req.hwp_desired = req_update.hwp_desired;
954
955 if (update_hwp_window)
956 req.hwp_window = req_update.hwp_window;
957
958 if (update_hwp_epp)
959 req.hwp_epp = req_update.hwp_epp;
960
961 req.hwp_use_pkg = req_update.hwp_use_pkg;
962
963 read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES);
964 if (debug)
965 print_hwp_cap(cpu, &cap, "");
966
967 if (!force)
968 check_hwp_request_v_hwp_capabilities(cpu, &req, &cap);
969
970 verify_hwp_req_self_consistency(cpu, &req);
971
972 write_hwp_request(cpu, &req, msr_offset);
973
974 if (debug) {
975 read_hwp_request(cpu, &req, msr_offset);
976 print_hwp_request(cpu, &req, "new: ");
977 }
978 return 0;
979}
980int update_hwp_request_pkg(int pkg)
981{
982 struct msr_hwp_request req;
983 struct msr_hwp_cap cap;
984 int cpu = first_cpu_in_pkg[pkg];
985
986 int msr_offset = MSR_HWP_REQUEST_PKG;
987
988 read_hwp_request(cpu, &req, msr_offset);
989 if (debug)
990 print_hwp_request_pkg(pkg, &req, "old: ");
991
992 if (update_hwp_min)
993 req.hwp_min = req_update.hwp_min;
994
995 if (update_hwp_max)
996 req.hwp_max = req_update.hwp_max;
997
998 if (update_hwp_desired)
999 req.hwp_desired = req_update.hwp_desired;
1000
1001 if (update_hwp_window)
1002 req.hwp_window = req_update.hwp_window;
1003
1004 if (update_hwp_epp)
1005 req.hwp_epp = req_update.hwp_epp;
1006
1007 read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES);
1008 if (debug)
1009 print_hwp_cap(cpu, &cap, "");
1010
1011 if (!force)
1012 check_hwp_request_v_hwp_capabilities(cpu, &req, &cap);
1013
1014 verify_hwp_req_self_consistency(cpu, &req);
1015
1016 write_hwp_request(cpu, &req, msr_offset);
1017
1018 if (debug) {
1019 read_hwp_request(cpu, &req, msr_offset);
1020 print_hwp_request_pkg(pkg, &req, "new: ");
1021 }
1022 return 0;
1023}
1024
1025int enable_hwp_on_cpu(int cpu)
1026{
1027 unsigned long long msr;
1028
1029 get_msr(cpu, MSR_PM_ENABLE, &msr);
1030 put_msr(cpu, MSR_PM_ENABLE, 1);
1031
1032 if (verbose)
1033 printf("cpu%d: MSR_PM_ENABLE old: %d new: %d\n", cpu, (unsigned int) msr, 1);
1034
1035 return 0;
1036}
1037
1038int update_cpu_msrs(int cpu)
1039{
1040 unsigned long long msr;
1041
1042
1043 if (update_epb) {
1044 get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr);
1045 put_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, new_epb);
1046
1047 if (verbose)
1048 printf("cpu%d: ENERGY_PERF_BIAS old: %d new: %d\n",
1049 cpu, (unsigned int) msr, (unsigned int) new_epb);
1050 }
1051
1052 if (update_turbo) {
1053 int turbo_is_present_and_disabled;
1054
1055 get_msr(cpu, MSR_IA32_MISC_ENABLE, &msr);
1056
1057 turbo_is_present_and_disabled = ((msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE) != 0);
1058
1059 if (turbo_update_value == 1) {
1060 if (turbo_is_present_and_disabled) {
1061 msr &= ~MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
1062 put_msr(cpu, MSR_IA32_MISC_ENABLE, msr);
1063 if (verbose)
1064 printf("cpu%d: turbo ENABLE\n", cpu);
1065 }
1066 } else {
1067
1068
1069
1070
1071
1072 msr |= MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
1073 put_msr(cpu, MSR_IA32_MISC_ENABLE, msr);
1074 if (verbose)
1075 printf("cpu%d: turbo DISABLE\n", cpu);
1076 }
1077 }
1078
1079 if (!has_hwp)
1080 return 0;
1081
1082 if (!hwp_update_enabled())
1083 return 0;
1084
1085 update_hwp_request(cpu);
1086 return 0;
1087}
1088
1089
1090
1091
1092FILE *fopen_or_die(const char *path, const char *mode)
1093{
1094 FILE *filep = fopen(path, "r");
1095
1096 if (!filep)
1097 err(1, "%s: open failed", path);
1098 return filep;
1099}
1100
1101unsigned int get_pkg_num(int cpu)
1102{
1103 FILE *fp;
1104 char pathname[128];
1105 unsigned int pkg;
1106 int retval;
1107
1108 sprintf(pathname, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
1109
1110 fp = fopen_or_die(pathname, "r");
1111 retval = fscanf(fp, "%d\n", &pkg);
1112 if (retval != 1)
1113 errx(1, "%s: failed to parse", pathname);
1114 return pkg;
1115}
1116
1117int set_max_cpu_pkg_num(int cpu)
1118{
1119 unsigned int pkg;
1120
1121 if (max_cpu_num < cpu)
1122 max_cpu_num = cpu;
1123
1124 pkg = get_pkg_num(cpu);
1125
1126 if (pkg >= MAX_PACKAGES)
1127 errx(1, "cpu%d: %d >= MAX_PACKAGES (%d)", cpu, pkg, MAX_PACKAGES);
1128
1129 if (pkg > max_pkg_num)
1130 max_pkg_num = pkg;
1131
1132 if ((pkg_present_set & (1ULL << pkg)) == 0) {
1133 pkg_present_set |= (1ULL << pkg);
1134 first_cpu_in_pkg[pkg] = cpu;
1135 }
1136
1137 return 0;
1138}
1139int mark_cpu_present(int cpu)
1140{
1141 CPU_SET_S(cpu, cpu_setsize, cpu_present_set);
1142 return 0;
1143}
1144
1145
1146
1147
1148
1149int for_all_proc_cpus(int (func)(int))
1150{
1151 FILE *fp;
1152 int cpu_num;
1153 int retval;
1154
1155 fp = fopen_or_die(proc_stat, "r");
1156
1157 retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
1158 if (retval != 0)
1159 err(1, "%s: failed to parse format", proc_stat);
1160
1161 while (1) {
1162 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num);
1163 if (retval != 1)
1164 break;
1165
1166 retval = func(cpu_num);
1167 if (retval) {
1168 fclose(fp);
1169 return retval;
1170 }
1171 }
1172 fclose(fp);
1173 return 0;
1174}
1175
1176void for_all_cpus_in_set(size_t set_size, cpu_set_t *cpu_set, int (func)(int))
1177{
1178 int cpu_num;
1179
1180 for (cpu_num = 0; cpu_num <= max_cpu_num; ++cpu_num)
1181 if (CPU_ISSET_S(cpu_num, set_size, cpu_set))
1182 func(cpu_num);
1183}
1184
1185void init_data_structures(void)
1186{
1187 for_all_proc_cpus(set_max_cpu_pkg_num);
1188
1189 cpu_setsize = CPU_ALLOC_SIZE((max_cpu_num + 1));
1190
1191 cpu_present_set = CPU_ALLOC((max_cpu_num + 1));
1192 if (cpu_present_set == NULL)
1193 err(3, "CPU_ALLOC");
1194 CPU_ZERO_S(cpu_setsize, cpu_present_set);
1195 for_all_proc_cpus(mark_cpu_present);
1196}
1197
1198
1199
1200void verify_hwp_is_enabled(void)
1201{
1202 unsigned long long msr;
1203
1204 if (!has_hwp)
1205 return;
1206
1207
1208 get_msr(base_cpu, MSR_PM_ENABLE, &msr);
1209 if ((msr & 1) == 0) {
1210 fprintf(stderr, "HWP can be enabled using '--hwp-enable'\n");
1211 has_hwp = 0;
1212 return;
1213 }
1214}
1215
1216int req_update_bounds_check(void)
1217{
1218 if (!hwp_update_enabled())
1219 return 0;
1220
1221
1222 if ((update_hwp_max && update_hwp_min) &&
1223 (req_update.hwp_min > req_update.hwp_max)) {
1224 printf("hwp-min %d > hwp_max %d\n", req_update.hwp_min, req_update.hwp_max);
1225 return -EINVAL;
1226 }
1227
1228
1229 if (req_update.hwp_desired && update_hwp_max &&
1230 (req_update.hwp_desired > req_update.hwp_max)) {
1231 printf("hwp-desired cannot be greater than hwp_max\n");
1232 return -EINVAL;
1233 }
1234
1235 if (req_update.hwp_desired && update_hwp_min &&
1236 (req_update.hwp_desired < req_update.hwp_min)) {
1237 printf("hwp-desired cannot be less than hwp_min\n");
1238 return -EINVAL;
1239 }
1240
1241 return 0;
1242}
1243
1244void set_base_cpu(void)
1245{
1246 base_cpu = sched_getcpu();
1247 if (base_cpu < 0)
1248 err(-ENODEV, "No valid cpus found");
1249}
1250
1251
1252void probe_dev_msr(void)
1253{
1254 struct stat sb;
1255 char pathname[32];
1256
1257 sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
1258 if (stat(pathname, &sb))
1259 if (system("/sbin/modprobe msr > /dev/null 2>&1"))
1260 err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
1261}
1262
1263static void get_cpuid_or_exit(unsigned int leaf,
1264 unsigned int *eax, unsigned int *ebx,
1265 unsigned int *ecx, unsigned int *edx)
1266{
1267 if (!__get_cpuid(leaf, eax, ebx, ecx, edx))
1268 errx(1, "Processor not supported\n");
1269}
1270
1271
1272
1273
1274
1275
1276void early_cpuid(void)
1277{
1278 unsigned int eax, ebx, ecx, edx;
1279 unsigned int fms, family, model;
1280
1281 get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
1282 family = (fms >> 8) & 0xf;
1283 model = (fms >> 4) & 0xf;
1284 if (family == 6 || family == 0xf)
1285 model += ((fms >> 16) & 0xf) << 4;
1286
1287 if (model == 0x4F) {
1288 unsigned long long msr;
1289
1290 get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
1291
1292 bdx_highest_ratio = msr & 0xFF;
1293 }
1294
1295 get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
1296 turbo_is_enabled = (eax >> 1) & 1;
1297 has_hwp = (eax >> 7) & 1;
1298 has_epb = (ecx >> 3) & 1;
1299}
1300
1301
1302
1303
1304
1305
1306void parse_cpuid(void)
1307{
1308 unsigned int eax, ebx, ecx, edx, max_level;
1309 unsigned int fms, family, model, stepping;
1310
1311 eax = ebx = ecx = edx = 0;
1312
1313 get_cpuid_or_exit(0, &max_level, &ebx, &ecx, &edx);
1314
1315 if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
1316 genuine_intel = 1;
1317
1318 if (debug)
1319 fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ",
1320 (char *)&ebx, (char *)&edx, (char *)&ecx);
1321
1322 get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
1323 family = (fms >> 8) & 0xf;
1324 model = (fms >> 4) & 0xf;
1325 stepping = fms & 0xf;
1326 if (family == 6 || family == 0xf)
1327 model += ((fms >> 16) & 0xf) << 4;
1328
1329 if (debug) {
1330 fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
1331 max_level, family, model, stepping, family, model, stepping);
1332 fprintf(stderr, "CPUID(1): %s %s %s %s %s %s %s %s\n",
1333 ecx & (1 << 0) ? "SSE3" : "-",
1334 ecx & (1 << 3) ? "MONITOR" : "-",
1335 ecx & (1 << 7) ? "EIST" : "-",
1336 ecx & (1 << 8) ? "TM2" : "-",
1337 edx & (1 << 4) ? "TSC" : "-",
1338 edx & (1 << 5) ? "MSR" : "-",
1339 edx & (1 << 22) ? "ACPI-TM" : "-",
1340 edx & (1 << 29) ? "TM" : "-");
1341 }
1342
1343 if (!(edx & (1 << 5)))
1344 errx(1, "CPUID: no MSR");
1345
1346
1347 get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
1348
1349
1350 has_hwp_notify = eax & (1 << 8);
1351 has_hwp_activity_window = eax & (1 << 9);
1352 has_hwp_epp = eax & (1 << 10);
1353 has_hwp_request_pkg = eax & (1 << 11);
1354
1355 if (!has_hwp_request_pkg && update_hwp_use_pkg)
1356 errx(1, "--hwp-use-pkg is not available on this hardware");
1357
1358
1359
1360 if (debug)
1361 fprintf(stderr,
1362 "CPUID(6): %sTURBO, %sHWP, %sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n",
1363 turbo_is_enabled ? "" : "No-",
1364 has_hwp ? "" : "No-",
1365 has_hwp_notify ? "" : "No-",
1366 has_hwp_activity_window ? "" : "No-",
1367 has_hwp_epp ? "" : "No-",
1368 has_hwp_request_pkg ? "" : "No-",
1369 has_epb ? "" : "No-");
1370
1371 return;
1372}
1373
1374int main(int argc, char **argv)
1375{
1376 set_base_cpu();
1377 probe_dev_msr();
1378 init_data_structures();
1379
1380 early_cpuid();
1381
1382 cmdline(argc, argv);
1383
1384 if (debug)
1385 print_version();
1386
1387 parse_cpuid();
1388
1389
1390 if ((cpu_selected_set == 0) && (pkg_selected_set == 0))
1391 cpu_selected_set = cpu_present_set;
1392
1393
1394
1395
1396
1397 if (update_hwp_enable)
1398 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, enable_hwp_on_cpu);
1399
1400
1401 verify_hwp_is_enabled();
1402
1403 if (req_update_bounds_check())
1404 return -EINVAL;
1405
1406
1407 if (!update_epb && !update_turbo && !hwp_update_enabled()) {
1408 if (cpu_selected_set)
1409 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, print_cpu_msrs);
1410
1411 if (has_hwp_request_pkg) {
1412 if (pkg_selected_set == 0)
1413 pkg_selected_set = pkg_present_set;
1414
1415 for_packages(pkg_selected_set, print_pkg_msrs);
1416 }
1417
1418 return 0;
1419 }
1420
1421
1422 if (cpu_selected_set) {
1423 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_sysfs);
1424 for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_cpu_msrs);
1425 } else if (pkg_selected_set)
1426 for_packages(pkg_selected_set, update_hwp_request_pkg);
1427
1428 return 0;
1429}
1430