1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Intel Speed Select -- Enumerate and control features
4 * Copyright (c) 2019 Intel Corporation.
5 */
6
7 #include <ctype.h>
8 #include <linux/isst_if.h>
9
10 #include "isst.h"
11
12 struct process_cmd_struct {
13 char *feature;
14 char *command;
15 void (*process_fn)(int arg);
16 int arg;
17 };
18
19 static const char *version_str = "v1.25";
20
21 static const int supported_api_ver = 3;
22 static struct isst_if_platform_info isst_platform_info;
23 static char *progname;
24 static int debug_flag;
25 static FILE *outf;
26
27 static int cpu_model;
28 static int cpu_stepping;
29 static int extended_family;
30
31 #define MAX_CPUS_IN_ONE_REQ 512
32 static short max_target_cpus;
33 static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ];
34
35 static int topo_max_cpus;
36 static size_t present_cpumask_size;
37 static cpu_set_t *present_cpumask;
38 static size_t target_cpumask_size;
39 static cpu_set_t *target_cpumask;
40 static int tdp_level = 0xFF;
41 static int fact_bucket = 0xFF;
42 static int fact_avx = 0xFF;
43 static unsigned long long fact_trl;
44 static int out_format_json;
45 static int cmd_help;
46 static int force_online_offline;
47 static int auto_mode;
48 static int fact_enable_fail;
49 static int cgroupv2;
50 static int max_pkg_id;
51 static int max_die_id;
52 static int max_die_id_package_0;
53
54 /* clos related */
55 static int current_clos = -1;
56 static int clos_epp = -1;
57 static int clos_prop_prio = -1;
58 static int clos_min = -1;
59 static int clos_max = -1;
60 static int clos_desired = -1;
61 static int clos_priority_type;
62 static int cpu_0_cgroupv2;
63 static int cpu_0_workaround(int isolate);
64
65 struct _cpu_map {
66 unsigned short core_id;
67 unsigned short pkg_id;
68 unsigned short die_id;
69 unsigned short punit_id;
70 unsigned short punit_cpu;
71 unsigned short punit_cpu_core;
72 unsigned short initialized;
73 };
74 struct _cpu_map *cpu_map;
75
76 struct cpu_topology {
77 short cpu;
78 short core_id;
79 short pkg_id;
80 short die_id;
81 };
82
83 static int read_only;
84
check_privilege(void)85 static void check_privilege(void)
86 {
87 if (!read_only)
88 return;
89
90 isst_display_error_info_message(1, "Insufficient privileges", 0, 0);
91 isst_ctdp_display_information_end(outf);
92 exit(1);
93 }
94
get_output_file(void)95 FILE *get_output_file(void)
96 {
97 return outf;
98 }
99
is_debug_enabled(void)100 int is_debug_enabled(void)
101 {
102 return debug_flag;
103 }
104
debug_printf(const char * format,...)105 void debug_printf(const char *format, ...)
106 {
107 va_list args;
108
109 va_start(args, format);
110
111 if (debug_flag)
112 vprintf(format, args);
113
114 va_end(args);
115 }
116
117
is_clx_n_platform(void)118 int is_clx_n_platform(void)
119 {
120 if (cpu_model == 0x55)
121 if (cpu_stepping == 0x6 || cpu_stepping == 0x7)
122 return 1;
123 return 0;
124 }
125
is_skx_based_platform(void)126 int is_skx_based_platform(void)
127 {
128 if (cpu_model == 0x55)
129 return 1;
130
131 return 0;
132 }
133
is_spr_platform(void)134 int is_spr_platform(void)
135 {
136 if (cpu_model == 0x8F)
137 return 1;
138
139 return 0;
140 }
141
is_emr_platform(void)142 int is_emr_platform(void)
143 {
144 if (cpu_model == 0xCF)
145 return 1;
146
147 return 0;
148 }
149
150
is_icx_platform(void)151 int is_icx_platform(void)
152 {
153 if (cpu_model == 0x6A || cpu_model == 0x6C)
154 return 1;
155
156 return 0;
157 }
158
is_dmr_plus_platform(void)159 static int is_dmr_plus_platform(void)
160 {
161 if (extended_family == 0x04)
162 return 1;
163
164 return 0;
165 }
166
update_cpu_model(void)167 static int update_cpu_model(void)
168 {
169 unsigned int ebx, ecx, edx;
170 unsigned int fms, family;
171
172 __cpuid(1, fms, ebx, ecx, edx);
173 family = (fms >> 8) & 0xf;
174 extended_family = (fms >> 20) & 0x0f;
175 cpu_model = (fms >> 4) & 0xf;
176 if (family == 6 || family == 0xf)
177 cpu_model += ((fms >> 16) & 0xf) << 4;
178
179 cpu_stepping = fms & 0xf;
180 /* only three CascadeLake-N models are supported */
181 if (is_clx_n_platform()) {
182 FILE *fp;
183 size_t n = 0;
184 char *line = NULL;
185 int ret = 1;
186
187 fp = fopen("/proc/cpuinfo", "r");
188 if (!fp)
189 err(-1, "cannot open /proc/cpuinfo\n");
190
191 while (getline(&line, &n, fp) > 0) {
192 if (strstr(line, "model name")) {
193 if (strstr(line, "6252N") ||
194 strstr(line, "6230N") ||
195 strstr(line, "5218N"))
196 ret = 0;
197 break;
198 }
199 }
200 free(line);
201 fclose(fp);
202 return ret;
203 }
204 return 0;
205 }
206
api_version(void)207 int api_version(void)
208 {
209 return isst_platform_info.api_version;
210 }
211
212 /* Open a file, and exit on failure */
fopen_or_exit(const char * path,const char * mode)213 static FILE *fopen_or_exit(const char *path, const char *mode)
214 {
215 FILE *filep = fopen(path, mode);
216
217 if (!filep)
218 err(1, "%s: open failed", path);
219
220 return filep;
221 }
222
223 /* Parse a file containing a single int */
parse_int_file(int fatal,const char * fmt,...)224 static int parse_int_file(int fatal, const char *fmt, ...)
225 {
226 va_list args;
227 char path[PATH_MAX];
228 FILE *filep;
229 int value;
230
231 va_start(args, fmt);
232 vsnprintf(path, sizeof(path), fmt, args);
233 va_end(args);
234 if (fatal) {
235 filep = fopen_or_exit(path, "r");
236 } else {
237 filep = fopen(path, "r");
238 if (!filep)
239 return -1;
240 }
241 if (fscanf(filep, "%d", &value) != 1)
242 err(1, "%s: failed to parse number from file", path);
243 fclose(filep);
244
245 return value;
246 }
247
cpufreq_sysfs_present(void)248 int cpufreq_sysfs_present(void)
249 {
250 DIR *dir;
251
252 dir = opendir("/sys/devices/system/cpu/cpu0/cpufreq");
253 if (dir) {
254 closedir(dir);
255 return 1;
256 }
257
258 return 0;
259 }
260
out_format_is_json(void)261 int out_format_is_json(void)
262 {
263 return out_format_json;
264 }
265
get_stored_topology_info(int cpu,int * core_id,int * pkg_id,int * die_id)266 static int get_stored_topology_info(int cpu, int *core_id, int *pkg_id, int *die_id)
267 {
268 const char *pathname = "/var/run/isst_cpu_topology.dat";
269 struct cpu_topology cpu_top;
270 FILE *fp;
271 int ret;
272
273 fp = fopen(pathname, "rb");
274 if (!fp)
275 return -1;
276
277 ret = fseek(fp, cpu * sizeof(cpu_top), SEEK_SET);
278 if (ret)
279 goto err_ret;
280
281 ret = fread(&cpu_top, sizeof(cpu_top), 1, fp);
282 if (ret != 1) {
283 ret = -1;
284 goto err_ret;
285 }
286
287 *pkg_id = cpu_top.pkg_id;
288 *core_id = cpu_top.core_id;
289 *die_id = cpu_top.die_id;
290 ret = 0;
291
292 err_ret:
293 fclose(fp);
294
295 return ret;
296 }
297
store_cpu_topology(void)298 static void store_cpu_topology(void)
299 {
300 const char *pathname = "/var/run/isst_cpu_topology.dat";
301 FILE *fp;
302 int i;
303
304 fp = fopen(pathname, "rb");
305 if (fp) {
306 /* Mapping already exists */
307 fclose(fp);
308 return;
309 }
310
311 fp = fopen(pathname, "wb");
312 if (!fp) {
313 fprintf(stderr, "Can't create file:%s\n", pathname);
314 return;
315 }
316
317 fprintf(stderr, "Caching topology information\n");
318
319 for (i = 0; i < topo_max_cpus; ++i) {
320 struct cpu_topology cpu_top;
321
322 cpu_top.core_id = parse_int_file(0,
323 "/sys/devices/system/cpu/cpu%d/topology/core_id", i);
324 if (cpu_top.core_id < 0)
325 cpu_top.core_id = -1;
326
327 cpu_top.pkg_id = parse_int_file(0,
328 "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i);
329 if (cpu_top.pkg_id < 0)
330 cpu_top.pkg_id = -1;
331
332 cpu_top.die_id = parse_int_file(0,
333 "/sys/devices/system/cpu/cpu%d/topology/die_id", i);
334 if (cpu_top.die_id < 0)
335 cpu_top.die_id = -1;
336
337 cpu_top.cpu = i;
338
339 if (fwrite(&cpu_top, sizeof(cpu_top), 1, fp) != 1) {
340 fprintf(stderr, "Can't write to:%s\n", pathname);
341 break;
342 }
343 }
344
345 fclose(fp);
346 }
347
get_physical_package_id(int cpu)348 static int get_physical_package_id(int cpu)
349 {
350 int ret;
351
352 if (cpu < 0)
353 return -1;
354
355 if (cpu_map && cpu_map[cpu].initialized)
356 return cpu_map[cpu].pkg_id;
357
358 ret = parse_int_file(0,
359 "/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
360 cpu);
361 if (ret < 0) {
362 int core_id, pkg_id, die_id;
363
364 ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
365 if (!ret)
366 return pkg_id;
367 }
368
369 return ret;
370 }
371
get_physical_core_id(int cpu)372 static int get_physical_core_id(int cpu)
373 {
374 int ret;
375
376 if (cpu < 0)
377 return -1;
378
379 if (cpu_map && cpu_map[cpu].initialized)
380 return cpu_map[cpu].core_id;
381
382 ret = parse_int_file(0,
383 "/sys/devices/system/cpu/cpu%d/topology/core_id",
384 cpu);
385 if (ret < 0) {
386 int core_id, pkg_id, die_id;
387
388 ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
389 if (!ret)
390 return core_id;
391 }
392
393 return ret;
394 }
395
get_physical_die_id(int cpu)396 static int get_physical_die_id(int cpu)
397 {
398 int ret;
399
400 if (cpu < 0)
401 return -1;
402
403 if (cpu_map && cpu_map[cpu].initialized)
404 return cpu_map[cpu].die_id;
405
406 ret = parse_int_file(0,
407 "/sys/devices/system/cpu/cpu%d/topology/die_id",
408 cpu);
409 if (ret < 0) {
410 int core_id, pkg_id, die_id;
411
412 ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
413 if (!ret) {
414 if (die_id < 0)
415 die_id = 0;
416
417 return die_id;
418 }
419 }
420
421 if (ret < 0)
422 ret = 0;
423
424 return ret;
425 }
426
get_physical_punit_id(int cpu)427 static int get_physical_punit_id(int cpu)
428 {
429 if (cpu < 0)
430 return -1;
431
432 if (cpu_map && cpu_map[cpu].initialized)
433 return cpu_map[cpu].punit_id;
434
435 return -1;
436 }
437
set_isst_id(struct isst_id * id,int cpu)438 void set_isst_id(struct isst_id *id, int cpu)
439 {
440 id->cpu = cpu;
441
442 id->pkg = get_physical_package_id(cpu);
443 if (id->pkg >= MAX_PACKAGE_COUNT)
444 id->pkg = -1;
445
446 id->die = get_physical_die_id(cpu);
447 if (id->die >= MAX_DIE_PER_PACKAGE)
448 id->die = -1;
449
450 id->punit = get_physical_punit_id(cpu);
451 if (id->punit >= MAX_PUNIT_PER_DIE)
452 id->punit = -1;
453 }
454
is_cpu_in_power_domain(int cpu,struct isst_id * id)455 int is_cpu_in_power_domain(int cpu, struct isst_id *id)
456 {
457 struct isst_id tid;
458
459 set_isst_id(&tid, cpu);
460
461 if (id->pkg == tid.pkg && id->die == tid.die && id->punit == tid.punit)
462 return 1;
463
464 return 0;
465 }
466
get_cpufreq_base_freq(int cpu)467 int get_cpufreq_base_freq(int cpu)
468 {
469 return parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", cpu);
470 }
471
get_topo_max_cpus(void)472 int get_topo_max_cpus(void)
473 {
474 return topo_max_cpus;
475 }
476
is_cpu_online(int cpu)477 static unsigned int is_cpu_online(int cpu)
478 {
479 char buffer[128];
480 int fd, ret;
481 unsigned char online;
482
483 snprintf(buffer, sizeof(buffer),
484 "/sys/devices/system/cpu/cpu%d/online", cpu);
485
486 fd = open(buffer, O_RDONLY);
487 if (fd < 0)
488 return fd;
489
490 ret = read(fd, &online, sizeof(online));
491 close(fd);
492
493 if (ret == -1)
494 return ret;
495
496 if (online == '1')
497 online = 1;
498 else
499 online = 0;
500
501 return online;
502 }
503
set_cpu_online_offline(int cpu,int state)504 void set_cpu_online_offline(int cpu, int state)
505 {
506 char buffer[128];
507 int fd, ret;
508
509 if (cpu_0_cgroupv2 && !cpu) {
510 fprintf(stderr, "Will use cgroup v2 for CPU 0\n");
511 cpu_0_workaround(!state);
512 return;
513 }
514
515 snprintf(buffer, sizeof(buffer),
516 "/sys/devices/system/cpu/cpu%d/online", cpu);
517
518 fd = open(buffer, O_WRONLY);
519 if (fd < 0) {
520 if (!cpu) {
521 fprintf(stderr, "This system is not configured for CPU 0 online/offline\n");
522 fprintf(stderr, "Will use cgroup v2\n");
523 cpu_0_workaround(!state);
524 return;
525 }
526 err(-1, "%s open failed", buffer);
527 }
528
529 if (state)
530 ret = write(fd, "1\n", 2);
531 else
532 ret = write(fd, "0\n", 2);
533
534 if (ret == -1)
535 perror("Online/Offline: Operation failed\n");
536
537 close(fd);
538 }
539
force_all_cpus_online(void)540 static void force_all_cpus_online(void)
541 {
542 int i;
543
544 fprintf(stderr, "Forcing all CPUs online\n");
545
546 for (i = 0; i < topo_max_cpus; ++i)
547 set_cpu_online_offline(i, 1);
548
549 unlink("/var/run/isst_cpu_topology.dat");
550 }
551
for_each_online_power_domain_in_set(void (* callback)(struct isst_id *,void *,void *,void *,void *),void * arg1,void * arg2,void * arg3,void * arg4)552 void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void *, void *,
553 void *, void *),
554 void *arg1, void *arg2, void *arg3,
555 void *arg4)
556 {
557 struct isst_id id;
558 int cpus[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
559 int valid_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE] = {0};
560 int i, j, k;
561
562 memset(cpus, -1, sizeof(cpus));
563
564 for (i = 0; i < topo_max_cpus; ++i) {
565 int online;
566
567 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
568 continue;
569
570 online = parse_int_file(
571 i != 0, "/sys/devices/system/cpu/cpu%d/online", i);
572 if (online < 0)
573 online = 1; /* online entry for CPU 0 needs some special configs */
574
575 if (!online)
576 continue;
577
578 set_isst_id(&id, i);
579
580 if (id.pkg < 0 || id.die < 0 || id.punit < 0)
581 continue;
582
583 id.die = id.die % (max_die_id_package_0 + 1);
584
585 valid_mask[id.pkg][id.die] = 1;
586
587 if (cpus[id.pkg][id.die][id.punit] == -1)
588 cpus[id.pkg][id.die][id.punit] = i;
589 }
590
591 for (i = 0; i < MAX_PACKAGE_COUNT; i++) {
592 if (max_die_id > max_pkg_id) {
593 for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) {
594 id.cpu = cpus[i][k][k];
595 id.pkg = i;
596 id.die = get_physical_die_id(id.cpu);
597 id.punit = k;
598 if (isst_is_punit_valid(&id))
599 callback(&id, arg1, arg2, arg3, arg4);
600 }
601 continue;
602 }
603
604 for (j = 0; j < MAX_DIE_PER_PACKAGE; j++) {
605 /*
606 * Fix me:
607 * How to check a non-cpu die for a package/die with all cpu offlined?
608 */
609 if (!valid_mask[i][j])
610 continue;
611 for (k = 0; k < MAX_PUNIT_PER_DIE; k++) {
612 id.cpu = cpus[i][j][k];
613 id.pkg = i;
614 if (id.cpu >= 0)
615 id.die = get_physical_die_id(id.cpu);
616 else
617 id.die = id.pkg;
618 id.punit = k;
619 if (isst_is_punit_valid(&id))
620 callback(&id, arg1, arg2, arg3, arg4);
621 }
622 }
623 }
624 }
625
for_each_online_target_cpu_in_set(void (* callback)(struct isst_id *,void *,void *,void *,void *),void * arg1,void * arg2,void * arg3,void * arg4)626 static void for_each_online_target_cpu_in_set(
627 void (*callback)(struct isst_id *, void *, void *, void *, void *), void *arg1,
628 void *arg2, void *arg3, void *arg4)
629 {
630 int i, found = 0;
631 struct isst_id id;
632
633 for (i = 0; i < topo_max_cpus; ++i) {
634 int online;
635
636 if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
637 continue;
638 if (i)
639 online = parse_int_file(
640 1, "/sys/devices/system/cpu/cpu%d/online", i);
641 else
642 online =
643 1; /* online entry for CPU 0 needs some special configs */
644
645 set_isst_id(&id, i);
646 if (online && callback) {
647 callback(&id, arg1, arg2, arg3, arg4);
648 found = 1;
649 }
650 }
651
652 if (!found)
653 fprintf(stderr, "No valid CPU in the list\n");
654 }
655
656 #define BITMASK_SIZE 32
set_max_cpu_num(void)657 static void set_max_cpu_num(void)
658 {
659 FILE *filep;
660 unsigned long dummy;
661 int i;
662
663 topo_max_cpus = 0;
664 for (i = 0; i < 256; ++i) {
665 char path[256];
666
667 snprintf(path, sizeof(path),
668 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", i);
669 filep = fopen(path, "r");
670 if (filep)
671 break;
672 }
673
674 if (!filep) {
675 fprintf(stderr, "Can't get max cpu number\n");
676 exit(0);
677 }
678
679 while (fscanf(filep, "%lx,", &dummy) == 1)
680 topo_max_cpus += BITMASK_SIZE;
681 fclose(filep);
682
683 debug_printf("max cpus %d\n", topo_max_cpus);
684 }
685
alloc_cpu_set(cpu_set_t ** cpu_set)686 size_t alloc_cpu_set(cpu_set_t **cpu_set)
687 {
688 cpu_set_t *_cpu_set;
689 size_t size;
690
691 _cpu_set = CPU_ALLOC((topo_max_cpus + 1));
692 if (_cpu_set == NULL)
693 err(3, "CPU_ALLOC");
694 size = CPU_ALLOC_SIZE((topo_max_cpus + 1));
695 CPU_ZERO_S(size, _cpu_set);
696
697 *cpu_set = _cpu_set;
698 return size;
699 }
700
free_cpu_set(cpu_set_t * cpu_set)701 void free_cpu_set(cpu_set_t *cpu_set)
702 {
703 CPU_FREE(cpu_set);
704 }
705
706 static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
707
get_max_punit_core_id(struct isst_id * id)708 int get_max_punit_core_id(struct isst_id *id)
709 {
710 int max_id = 0;
711 int i;
712
713 for (i = 0; i < topo_max_cpus; ++i)
714 {
715 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
716 continue;
717
718 if (is_cpu_in_power_domain(i, id) &&
719 cpu_map[i].punit_cpu_core > max_id)
720 max_id = cpu_map[i].punit_cpu_core;
721 }
722
723 return max_id;
724 }
725
get_cpu_count(struct isst_id * id)726 int get_cpu_count(struct isst_id *id)
727 {
728 if (id->pkg < 0 || id->die < 0 || id->punit < 0)
729 return 0;
730
731 return cpu_cnt[id->pkg][id->die][id->punit];
732 }
733
update_punit_cpu_info(__u32 physical_cpu,struct _cpu_map * cpu_map)734 static void update_punit_cpu_info(__u32 physical_cpu, struct _cpu_map *cpu_map)
735 {
736 if (api_version() > 1) {
737 /*
738 * MSR 0x54 format
739 * [15:11] PM_DOMAIN_ID
740 * [10:3] MODULE_ID (aka IDI_AGENT_ID)
741 * [2:0] LP_ID (We don't care about these bits we only
742 * care die and core id
743 * For Atom:
744 * [2] Always 0
745 * [1:0] core ID within module
746 * For Core
747 * [2:1] Always 0
748 * [0] thread ID
749 */
750 cpu_map->punit_id = (physical_cpu >> 11) & 0x1f;
751 cpu_map->punit_cpu_core = (physical_cpu >> 3) & 0xff;
752 cpu_map->punit_cpu = physical_cpu & 0x7ff;
753 } else {
754 int punit_id;
755
756 /*
757 * MSR 0x53 format
758 * Format
759 * Bit 0 – thread ID
760 * Bit 8:1 – core ID
761 * Bit 13:9 – punit ID
762 */
763 cpu_map->punit_cpu = physical_cpu & 0x1ff;
764 cpu_map->punit_cpu_core = (cpu_map->punit_cpu >> 1); // shift to get core id
765 punit_id = (physical_cpu >> 9) & 0x1f;
766
767 if (punit_id >= MAX_PUNIT_PER_DIE)
768 punit_id = 0;
769
770 cpu_map->punit_id = punit_id;
771 }
772 }
773
create_cpu_map(void)774 static void create_cpu_map(void)
775 {
776 const char *pathname = "/dev/isst_interface";
777 size_t size;
778 DIR *dir;
779 int i, fd = 0;
780 struct isst_if_cpu_maps map;
781
782 /* Use calloc to make sure the memory is initialized to Zero */
783 cpu_map = calloc(topo_max_cpus, sizeof(*cpu_map));
784 if (!cpu_map)
785 err(3, "cpumap");
786
787 fd = open(pathname, O_RDWR);
788 if (fd < 0 && !is_clx_n_platform())
789 err(-1, "%s open failed", pathname);
790
791 size = alloc_cpu_set(&present_cpumask);
792 present_cpumask_size = size;
793
794 for (i = 0; i < topo_max_cpus; ++i) {
795 char buffer[256];
796 int pkg_id, die_id, core_id, punit_id;
797
798 /* check if CPU is online */
799 snprintf(buffer, sizeof(buffer),
800 "/sys/devices/system/cpu/cpu%d", i);
801 dir = opendir(buffer);
802 if (!dir)
803 continue;
804 closedir(dir);
805
806 CPU_SET_S(i, size, present_cpumask);
807
808 pkg_id = get_physical_package_id(i);
809 die_id = get_physical_die_id(i);
810 core_id = get_physical_core_id(i);
811
812 if (pkg_id < 0 || die_id < 0 || core_id < 0)
813 continue;
814
815 cpu_map[i].pkg_id = pkg_id;
816 cpu_map[i].die_id = die_id;
817 cpu_map[i].core_id = core_id;
818
819 if (max_pkg_id < pkg_id)
820 max_pkg_id = pkg_id;
821
822 punit_id = 0;
823
824 if (fd >= 0) {
825 map.cmd_count = 1;
826 map.cpu_map[0].logical_cpu = i;
827 debug_printf(" map logical_cpu:%d\n",
828 map.cpu_map[0].logical_cpu);
829 if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
830 perror("ISST_IF_GET_PHY_ID");
831 fprintf(outf, "Error: map logical_cpu:%d\n",
832 map.cpu_map[0].logical_cpu);
833 } else {
834 update_punit_cpu_info(map.cpu_map[0].physical_cpu, &cpu_map[i]);
835 punit_id = cpu_map[i].punit_id;
836 }
837 }
838 cpu_map[i].initialized = 1;
839
840 cpu_cnt[pkg_id][die_id][punit_id]++;
841
842 if (max_die_id < die_id)
843 max_die_id = die_id;
844
845 if (!pkg_id && max_die_id_package_0 < die_id)
846 max_die_id_package_0 = die_id;
847
848 debug_printf(
849 "map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d\n",
850 i, cpu_map[i].core_id, cpu_map[i].die_id,
851 cpu_map[i].pkg_id, cpu_map[i].punit_id,
852 cpu_map[i].punit_cpu, cpu_map[i].punit_cpu_core);
853 }
854 if (fd >= 0)
855 close(fd);
856
857 size = alloc_cpu_set(&target_cpumask);
858 target_cpumask_size = size;
859 for (i = 0; i < max_target_cpus; ++i) {
860 if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
861 present_cpumask))
862 continue;
863
864 CPU_SET_S(target_cpus[i], size, target_cpumask);
865 }
866 }
867
set_cpu_mask_from_punit_coremask(struct isst_id * id,unsigned long long core_mask,size_t core_cpumask_size,cpu_set_t * core_cpumask,int * cpu_cnt)868 void set_cpu_mask_from_punit_coremask(struct isst_id *id, unsigned long long core_mask,
869 size_t core_cpumask_size,
870 cpu_set_t *core_cpumask, int *cpu_cnt)
871 {
872 int i, cnt = 0;
873
874 if (id->cpu < 0)
875 return;
876
877 *cpu_cnt = 0;
878
879 for (i = 0; i < 64; ++i) {
880 if (core_mask & BIT_ULL(i)) {
881 int j;
882
883 for (j = 0; j < topo_max_cpus; ++j) {
884 if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask))
885 continue;
886
887 if (is_cpu_in_power_domain(j, id) &&
888 cpu_map[j].punit_cpu_core == i) {
889 CPU_SET_S(j, core_cpumask_size,
890 core_cpumask);
891 ++cnt;
892 }
893 }
894 }
895 }
896
897 *cpu_cnt = cnt;
898 }
899
find_phy_core_num(int logical_cpu)900 int find_phy_core_num(int logical_cpu)
901 {
902 if (logical_cpu < topo_max_cpus)
903 return cpu_map[logical_cpu].punit_cpu_core;
904
905 return -EINVAL;
906 }
907
use_cgroupv2(void)908 int use_cgroupv2(void)
909 {
910 return cgroupv2;
911 }
912
enable_cpuset_controller(void)913 int enable_cpuset_controller(void)
914 {
915 int fd, ret;
916
917 fd = open("/sys/fs/cgroup/cgroup.subtree_control", O_RDWR, 0);
918 if (fd < 0) {
919 debug_printf("Can't activate cpuset controller\n");
920 debug_printf("Either you are not root user or CGroup v2 is not supported\n");
921 return fd;
922 }
923
924 ret = write(fd, " +cpuset", strlen(" +cpuset"));
925 close(fd);
926
927 if (ret == -1) {
928 debug_printf("Can't activate cpuset controller: Write failed\n");
929 return ret;
930 }
931
932 return 0;
933 }
934
isolate_cpus(struct isst_id * id,int mask_size,cpu_set_t * cpu_mask,int level,int cpu_0_only)935 int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level, int cpu_0_only)
936 {
937 int i, first, curr_index, index, ret, fd;
938 static char str[512], dir_name[64];
939 static char cpuset_cpus[128];
940 int str_len = sizeof(str);
941 DIR *dir;
942
943 snprintf(dir_name, sizeof(dir_name), "/sys/fs/cgroup/%d-%d-%d", id->pkg, id->die, id->punit);
944 dir = opendir(dir_name);
945 if (!dir) {
946 ret = mkdir(dir_name, 0744);
947 if (ret) {
948 debug_printf("Can't create dir:%s errno:%d\n", dir_name, errno);
949 return ret;
950 }
951 }
952 closedir(dir);
953
954 if (!level) {
955 sprintf(cpuset_cpus, "%s/cpuset.cpus.partition", dir_name);
956
957 fd = open(cpuset_cpus, O_RDWR, 0);
958 if (fd < 0) {
959 return fd;
960 }
961
962 ret = write(fd, "member", strlen("member"));
963 if (ret == -1) {
964 printf("Can't update to member\n");
965 close(fd);
966 return ret;
967 }
968
969 close(fd);
970 return 0;
971 }
972
973 if (!CPU_COUNT_S(mask_size, cpu_mask)) {
974 return -1;
975 }
976
977 curr_index = 0;
978 first = 1;
979 str[0] = '\0';
980
981 if (cpu_0_only) {
982 snprintf(str, str_len, "0");
983 goto create_partition;
984 }
985
986 for (i = 0; i < get_topo_max_cpus(); ++i) {
987 if (!is_cpu_in_power_domain(i, id))
988 continue;
989
990 if (CPU_ISSET_S(i, mask_size, cpu_mask))
991 continue;
992
993 if (!first) {
994 index = snprintf(&str[curr_index],
995 str_len - curr_index, ",");
996 curr_index += index;
997 if (curr_index >= str_len)
998 break;
999 }
1000 index = snprintf(&str[curr_index], str_len - curr_index, "%d",
1001 i);
1002 curr_index += index;
1003 if (curr_index >= str_len)
1004 break;
1005 first = 0;
1006 }
1007
1008 create_partition:
1009 debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str);
1010
1011 snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name);
1012
1013 fd = open(cpuset_cpus, O_RDWR, 0);
1014 if (fd < 0) {
1015 return fd;
1016 }
1017
1018 ret = write(fd, str, strlen(str));
1019 close(fd);
1020
1021 if (ret == -1) {
1022 debug_printf("Can't activate cpuset controller: Write failed\n");
1023 return ret;
1024 }
1025
1026 snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus.partition", dir_name);
1027
1028 fd = open(cpuset_cpus, O_RDWR, 0);
1029 if (fd < 0) {
1030 return fd;
1031 }
1032
1033 ret = write(fd, "isolated", strlen("isolated"));
1034 if (ret == -1) {
1035 debug_printf("Can't update to isolated\n");
1036 ret = write(fd, "root", strlen("root"));
1037 if (ret == -1)
1038 debug_printf("Can't update to root\n");
1039 }
1040
1041 close(fd);
1042
1043 if (ret < 0)
1044 return ret;
1045
1046 return 0;
1047 }
1048
cpu_0_workaround(int isolate)1049 static int cpu_0_workaround(int isolate)
1050 {
1051 int fd, fd1, len, ret;
1052 cpu_set_t cpu_mask;
1053 struct isst_id id;
1054 char str[2];
1055
1056 debug_printf("isolate CPU 0 state: %d\n", isolate);
1057
1058 if (isolate)
1059 goto isolate;
1060
1061 /* First check if CPU 0 was isolated to remove isolation. */
1062
1063 /* If the cpuset.cpus doesn't exist, that means that none of the CPUs are isolated*/
1064 fd = open("/sys/fs/cgroup/0-0-0/cpuset.cpus", O_RDONLY, 0);
1065 if (fd < 0)
1066 return 0;
1067
1068 len = read(fd, str, sizeof(str));
1069 /* Error check, but unlikely to fail. If fails that means that not isolated */
1070 if (len == -1)
1071 return 0;
1072
1073
1074 /* Is CPU 0 is in isolate list, the display is sorted so first element will be CPU 0*/
1075 if (str[0] != '0') {
1076 close(fd);
1077 return 0;
1078 }
1079
1080 fd1 = open("/sys/fs/cgroup/0-0-0/cpuset.cpus.partition", O_RDONLY, 0);
1081 /* Unlikely that, this attribute is not present, but handle error */
1082 if (fd1 < 0) {
1083 close(fd);
1084 return 0;
1085 }
1086
1087 /* Is CPU 0 already changed partition to "member" */
1088 len = read(fd1, str, sizeof(str));
1089 if (len != -1 && str[0] == 'm') {
1090 close(fd1);
1091 close(fd);
1092 return 0;
1093 }
1094
1095 close(fd1);
1096 close(fd);
1097
1098 debug_printf("CPU 0 was isolated before, so remove isolation\n");
1099
1100 isolate:
1101 ret = enable_cpuset_controller();
1102 if (ret)
1103 goto isolate_fail;
1104
1105 CPU_ZERO(&cpu_mask);
1106 memset(&id, 0, sizeof(struct isst_id));
1107 CPU_SET(0, &cpu_mask);
1108
1109 ret = isolate_cpus(&id, sizeof(cpu_mask), &cpu_mask, isolate, 1);
1110 isolate_fail:
1111 if (ret)
1112 fprintf(stderr, "Can't isolate CPU 0\n");
1113
1114 return ret;
1115 }
1116
isst_fill_platform_info(void)1117 static int isst_fill_platform_info(void)
1118 {
1119 const char *pathname = "/dev/isst_interface";
1120 int fd;
1121
1122 if (is_clx_n_platform()) {
1123 isst_platform_info.api_version = 1;
1124 goto set_platform_ops;
1125 }
1126
1127 fd = open(pathname, O_RDWR);
1128 if (fd < 0)
1129 err(-1, "%s open failed", pathname);
1130
1131 if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) {
1132 perror("ISST_IF_GET_PLATFORM_INFO");
1133 close(fd);
1134 return -1;
1135 }
1136
1137 close(fd);
1138
1139 if (isst_platform_info.api_version > supported_api_ver) {
1140 printf("Incompatible API versions; Upgrade of tool is required\n");
1141 return -1;
1142 }
1143
1144 set_platform_ops:
1145 if (isst_set_platform_ops(isst_platform_info.api_version)) {
1146 fprintf(stderr, "Failed to set platform callbacks\n");
1147 exit(0);
1148 }
1149 return 0;
1150 }
1151
get_isst_status(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1152 void get_isst_status(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4)
1153 {
1154 struct isst_pkg_ctdp pkg_dev;
1155 struct isst_id *tid = (struct isst_id *)arg2;
1156 int *mask = (int *)arg3;
1157 int *max_level = (int *)arg4;
1158 int j, ret;
1159
1160 /* Only check the first cpu power domain */
1161 if (id->cpu < 0 || tid->cpu >= 0)
1162 return;
1163
1164 ret = isst_get_ctdp_levels(id, &pkg_dev);
1165 if (ret)
1166 return;
1167
1168 if (pkg_dev.enabled)
1169 *mask |= BIT(0);
1170
1171 if (pkg_dev.locked)
1172 *mask |= BIT(1);
1173
1174 if (*max_level < pkg_dev.levels)
1175 *max_level = pkg_dev.levels;
1176
1177 for (j = 0; j <= pkg_dev.levels; ++j) {
1178 struct isst_pkg_ctdp_level_info ctdp_level;
1179
1180 ret = isst_get_ctdp_control(id, j, &ctdp_level);
1181 if (ret)
1182 continue;
1183
1184 if (ctdp_level.fact_support)
1185 *mask |= BIT(2);
1186
1187 if (ctdp_level.pbf_support)
1188 *mask |= BIT(3);
1189 }
1190
1191 tid->cpu = id->cpu;
1192 tid->pkg = id->pkg;
1193 tid->die = id->die;
1194 tid->punit = id->punit;
1195 }
1196
isst_print_extended_platform_info(void)1197 static void isst_print_extended_platform_info(void)
1198 {
1199 int cp_state, cp_cap;
1200 struct isst_id id;
1201 int mask = 0, max_level = 0;
1202
1203 id.cpu = -1;
1204 for_each_online_power_domain_in_set(get_isst_status, NULL, &id, &mask, &max_level);
1205
1206 if (mask & BIT(0)) {
1207 fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is supported\n");
1208 } else {
1209 fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is not supported\n");
1210 fprintf(outf, "Only performance level 0 (base level) is present\n");
1211 }
1212
1213 if (mask & BIT(1))
1214 fprintf(outf, "TDP level change control is locked\n");
1215 else
1216 fprintf(outf, "TDP level change control is unlocked, max level: %d\n", max_level);
1217
1218 if (mask & BIT(2))
1219 fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is supported\n");
1220 else
1221 fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is not supported\n");
1222
1223 if (mask & BIT(3))
1224 fprintf(outf, "Intel(R) SST-BF (feature base-freq) is supported\n");
1225 else
1226 fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n");
1227
1228 if (isst_read_pm_config(&id, &cp_state, &cp_cap)) {
1229 fprintf(outf, "Intel(R) SST-CP (feature core-power) status is unknown\n");
1230 return;
1231 }
1232
1233 if (cp_cap)
1234 fprintf(outf, "Intel(R) SST-CP (feature core-power) is supported\n");
1235 else
1236 fprintf(outf, "Intel(R) SST-CP (feature core-power) is not supported\n");
1237 }
1238
isst_print_platform_information(void)1239 static void isst_print_platform_information(void)
1240 {
1241 if (is_clx_n_platform()) {
1242 fprintf(stderr, "\nThis option in not supported on this platform\n");
1243 exit(0);
1244 }
1245
1246 /* Early initialization to create working cpu_map */
1247 set_max_cpu_num();
1248 create_cpu_map();
1249
1250 fprintf(outf, "Platform: API version : %d\n",
1251 isst_platform_info.api_version);
1252 fprintf(outf, "Platform: Driver version : %d\n",
1253 isst_platform_info.driver_version);
1254 fprintf(outf, "Platform: mbox supported : %d\n",
1255 isst_platform_info.mbox_supported);
1256 fprintf(outf, "Platform: mmio supported : %d\n",
1257 isst_platform_info.mmio_supported);
1258 isst_print_extended_platform_info();
1259
1260 exit(0);
1261 }
1262
1263 static char *local_str0, *local_str1;
exec_on_get_ctdp_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1264 static void exec_on_get_ctdp_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1265 void *arg4)
1266 {
1267 int (*fn_ptr)(struct isst_id *id, void *arg);
1268 int ret;
1269
1270 fn_ptr = arg1;
1271 ret = fn_ptr(id, arg2);
1272 if (ret)
1273 isst_display_error_info_message(1, "get_tdp_* failed", 0, 0);
1274 else
1275 isst_ctdp_display_core_info(id, outf, arg3,
1276 *(unsigned int *)arg4,
1277 local_str0, local_str1);
1278 }
1279
1280 #define _get_tdp_level(desc, suffix, object, help, str0, str1) \
1281 static void get_tdp_##object(int arg) \
1282 { \
1283 struct isst_pkg_ctdp ctdp; \
1284 \
1285 if (cmd_help) { \
1286 fprintf(stderr, \
1287 "Print %s [No command arguments are required]\n", \
1288 help); \
1289 exit(0); \
1290 } \
1291 local_str0 = str0; \
1292 local_str1 = str1; \
1293 isst_ctdp_display_information_start(outf); \
1294 if (max_target_cpus) \
1295 for_each_online_target_cpu_in_set( \
1296 exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix, \
1297 &ctdp, desc, &ctdp.object); \
1298 else \
1299 for_each_online_power_domain_in_set(exec_on_get_ctdp_cpu, \
1300 isst_get_ctdp_##suffix, \
1301 &ctdp, desc, \
1302 &ctdp.object); \
1303 isst_ctdp_display_information_end(outf); \
1304 }
1305
1306 _get_tdp_level("get-config-levels", levels, levels, "Max TDP level", NULL, NULL);
1307 _get_tdp_level("get-config-version", levels, version, "TDP version", NULL, NULL);
1308 _get_tdp_level("get-config-enabled", levels, enabled, "perf-profile enable status", "disabled", "enabled");
1309 _get_tdp_level("get-config-current_level", levels, current_level,
1310 "Current TDP Level", NULL, NULL);
1311 _get_tdp_level("get-lock-status", levels, locked, "TDP lock status", "unlocked", "locked");
1312
1313 struct isst_pkg_ctdp clx_n_pkg_dev;
1314
clx_n_get_base_ratio(void)1315 static int clx_n_get_base_ratio(void)
1316 {
1317 FILE *fp;
1318 char *begin, *end, *line = NULL;
1319 char number[5];
1320 float value = 0;
1321 size_t n = 0;
1322
1323 fp = fopen("/proc/cpuinfo", "r");
1324 if (!fp)
1325 err(-1, "cannot open /proc/cpuinfo\n");
1326
1327 while (getline(&line, &n, fp) > 0) {
1328 if (strstr(line, "model name")) {
1329 /* this is true for CascadeLake-N */
1330 begin = strstr(line, "@ ") + 2;
1331 end = strstr(line, "GHz");
1332 strncpy(number, begin, end - begin);
1333 value = atof(number) * 10;
1334 break;
1335 }
1336 }
1337 free(line);
1338 fclose(fp);
1339
1340 return (int)(value);
1341 }
1342
clx_n_config(struct isst_id * id)1343 static int clx_n_config(struct isst_id *id)
1344 {
1345 int i, ret;
1346 unsigned long cpu_bf;
1347 struct isst_pkg_ctdp_level_info *ctdp_level;
1348 struct isst_pbf_info *pbf_info;
1349
1350 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1351 pbf_info = &ctdp_level->pbf_info;
1352 ctdp_level->core_cpumask_size =
1353 alloc_cpu_set(&ctdp_level->core_cpumask);
1354
1355 /* find the frequency base ratio */
1356 ctdp_level->tdp_ratio = clx_n_get_base_ratio();
1357 if (ctdp_level->tdp_ratio == 0) {
1358 debug_printf("CLX: cn base ratio is zero\n");
1359 ret = -1;
1360 goto error_ret;
1361 }
1362
1363 /* find the high and low priority frequencies */
1364 pbf_info->p1_high = 0;
1365 pbf_info->p1_low = ~0;
1366
1367 for (i = 0; i < topo_max_cpus; i++) {
1368 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1369 continue;
1370
1371 if (!is_cpu_in_power_domain(i, id))
1372 continue;
1373
1374 CPU_SET_S(i, ctdp_level->core_cpumask_size,
1375 ctdp_level->core_cpumask);
1376
1377 cpu_bf = parse_int_file(1,
1378 "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1379 i);
1380 if (cpu_bf > pbf_info->p1_high)
1381 pbf_info->p1_high = cpu_bf;
1382 if (cpu_bf < pbf_info->p1_low)
1383 pbf_info->p1_low = cpu_bf;
1384 }
1385
1386 if (pbf_info->p1_high == ~0UL) {
1387 debug_printf("CLX: maximum base frequency not set\n");
1388 ret = -1;
1389 goto error_ret;
1390 }
1391
1392 if (pbf_info->p1_low == 0) {
1393 debug_printf("CLX: minimum base frequency not set\n");
1394 ret = -1;
1395 goto error_ret;
1396 }
1397
1398 /* convert frequencies back to ratios */
1399 pbf_info->p1_high = pbf_info->p1_high / 100000;
1400 pbf_info->p1_low = pbf_info->p1_low / 100000;
1401
1402 /* create high priority cpu mask */
1403 pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
1404 for (i = 0; i < topo_max_cpus; i++) {
1405 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1406 continue;
1407
1408 if (!is_cpu_in_power_domain(i, id))
1409 continue;
1410
1411 cpu_bf = parse_int_file(1,
1412 "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1413 i);
1414 cpu_bf = cpu_bf / 100000;
1415 if (cpu_bf == pbf_info->p1_high)
1416 CPU_SET_S(i, pbf_info->core_cpumask_size,
1417 pbf_info->core_cpumask);
1418 }
1419
1420 /* extra ctdp & pbf struct parameters */
1421 ctdp_level->processed = 1;
1422 ctdp_level->pbf_support = 1; /* PBF is always supported and enabled */
1423 ctdp_level->pbf_enabled = 1;
1424 ctdp_level->fact_support = 0; /* FACT is never supported */
1425 ctdp_level->fact_enabled = 0;
1426
1427 return 0;
1428
1429 error_ret:
1430 free_cpu_set(ctdp_level->core_cpumask);
1431 return ret;
1432 }
1433
dump_clx_n_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1434 static void dump_clx_n_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
1435 void *arg3, void *arg4)
1436 {
1437 int ret;
1438
1439 if (tdp_level != 0xff && tdp_level != 0) {
1440 isst_display_error_info_message(1, "Invalid level", 1, tdp_level);
1441 exit(0);
1442 }
1443
1444 ret = clx_n_config(id);
1445 if (ret) {
1446 debug_printf("clx_n_config failed");
1447 } else {
1448 struct isst_pkg_ctdp_level_info *ctdp_level;
1449 struct isst_pbf_info *pbf_info;
1450
1451 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1452 pbf_info = &ctdp_level->pbf_info;
1453 clx_n_pkg_dev.processed = 1;
1454 isst_ctdp_display_information(id, outf, tdp_level, &clx_n_pkg_dev);
1455 free_cpu_set(ctdp_level->core_cpumask);
1456 free_cpu_set(pbf_info->core_cpumask);
1457 }
1458 }
1459
dump_isst_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1460 static void dump_isst_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
1461 void *arg3, void *arg4)
1462 {
1463 struct isst_pkg_ctdp pkg_dev;
1464 int ret;
1465
1466 memset(&pkg_dev, 0, sizeof(pkg_dev));
1467 ret = isst_get_process_ctdp(id, tdp_level, &pkg_dev);
1468 if (ret) {
1469 isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, id->cpu);
1470 isst_ctdp_display_information_end(outf);
1471 exit(1);
1472 } else {
1473 isst_ctdp_display_information(id, outf, tdp_level, &pkg_dev);
1474 isst_get_process_ctdp_complete(id, &pkg_dev);
1475 }
1476 }
1477
dump_isst_config(int arg)1478 static void dump_isst_config(int arg)
1479 {
1480 void *fn;
1481
1482 if (cmd_help) {
1483 fprintf(stderr,
1484 "Print Intel(R) Speed Select Technology Performance profile configuration\n");
1485 fprintf(stderr,
1486 "including base frequency and turbo frequency configurations\n");
1487 fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
1488 fprintf(stderr,
1489 "\tIf no arguments, dump information for all TDP levels\n");
1490 exit(0);
1491 }
1492
1493 if (!is_clx_n_platform())
1494 fn = dump_isst_config_for_cpu;
1495 else
1496 fn = dump_clx_n_config_for_cpu;
1497
1498 isst_ctdp_display_information_start(outf);
1499
1500 if (max_target_cpus)
1501 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1502 else
1503 for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL);
1504
1505 isst_ctdp_display_information_end(outf);
1506 }
1507
1508 static void adjust_scaling_max_from_base_freq(int cpu);
1509
set_tdp_level_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1510 static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1511 void *arg4)
1512 {
1513 struct isst_pkg_ctdp pkg_dev;
1514 int ret;
1515
1516 ret = isst_get_ctdp_levels(id, &pkg_dev);
1517 if (ret) {
1518 isst_display_error_info_message(1, "Get TDP level failed", 0, 0);
1519 isst_ctdp_display_information_end(outf);
1520 exit(1);
1521 }
1522
1523 if (pkg_dev.current_level == tdp_level) {
1524 debug_printf("TDP level already set. Skipped\n");
1525 goto display_result;
1526 }
1527
1528 ret = isst_set_tdp_level(id, tdp_level);
1529 if (ret) {
1530 isst_display_error_info_message(1, "Set TDP level failed", 0, 0);
1531 isst_ctdp_display_information_end(outf);
1532 exit(1);
1533 }
1534
1535 display_result:
1536 isst_display_result(id, outf, "perf-profile", "set_tdp_level", ret);
1537 if (force_online_offline && id->cpu >= 0) {
1538 struct isst_pkg_ctdp_level_info ctdp_level;
1539
1540 /* Wait for updated base frequencies */
1541 usleep(2000);
1542
1543 /* Adjusting uncore freq */
1544 if (!is_dmr_plus_platform())
1545 isst_adjust_uncore_freq(id, tdp_level, &ctdp_level);
1546
1547 fprintf(stderr, "Option is set to online/offline\n");
1548 ctdp_level.core_cpumask_size =
1549 alloc_cpu_set(&ctdp_level.core_cpumask);
1550 ret = isst_get_coremask_info(id, tdp_level, &ctdp_level);
1551 if (ret) {
1552 isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
1553 goto free_mask;
1554 }
1555
1556 if (use_cgroupv2()) {
1557 int ret;
1558
1559 fprintf(stderr, "Using cgroup v2 in lieu of online/offline\n");
1560 ret = enable_cpuset_controller();
1561 if (ret)
1562 goto use_offline;
1563
1564 ret = isolate_cpus(id, ctdp_level.core_cpumask_size,
1565 ctdp_level.core_cpumask, tdp_level, 0);
1566 if (ret)
1567 goto use_offline;
1568
1569 goto free_mask;
1570 }
1571
1572 use_offline:
1573 if (ctdp_level.cpu_count) {
1574 int i, max_cpus = get_topo_max_cpus();
1575 for (i = 0; i < max_cpus; ++i) {
1576 if (!is_cpu_in_power_domain(i, id))
1577 continue;
1578 if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
1579 fprintf(stderr, "online cpu %d\n", i);
1580 set_cpu_online_offline(i, 1);
1581 adjust_scaling_max_from_base_freq(i);
1582 } else {
1583 fprintf(stderr, "offline cpu %d\n", i);
1584 set_cpu_online_offline(i, 0);
1585 }
1586 }
1587 }
1588 free_mask:
1589 free_cpu_set(ctdp_level.core_cpumask);
1590 }
1591 }
1592
set_tdp_level(int arg)1593 static void set_tdp_level(int arg)
1594 {
1595 check_privilege();
1596
1597 if (cmd_help) {
1598 fprintf(stderr, "Set Config TDP level\n");
1599 fprintf(stderr,
1600 "\t Arguments: -l|--level : Specify tdp level\n");
1601 fprintf(stderr,
1602 "\t Optional Arguments: -o | online : online/offline for the tdp level\n");
1603 fprintf(stderr,
1604 "\t online/offline operation has limitations, refer to Linux hotplug documentation\n");
1605 exit(0);
1606 }
1607
1608 if (tdp_level == 0xff) {
1609 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1610 exit(1);
1611 }
1612 isst_ctdp_display_information_start(outf);
1613 if (max_target_cpus)
1614 for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
1615 NULL, NULL, NULL);
1616 else
1617 for_each_online_power_domain_in_set(set_tdp_level_for_cpu, NULL,
1618 NULL, NULL, NULL);
1619 isst_ctdp_display_information_end(outf);
1620 }
1621
clx_n_dump_pbf_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1622 static void clx_n_dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
1623 void *arg3, void *arg4)
1624 {
1625 int ret;
1626
1627 ret = clx_n_config(id);
1628 if (ret) {
1629 isst_display_error_info_message(1, "clx_n_config failed", 0, 0);
1630 } else {
1631 struct isst_pkg_ctdp_level_info *ctdp_level;
1632 struct isst_pbf_info *pbf_info;
1633
1634 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1635 pbf_info = &ctdp_level->pbf_info;
1636 isst_pbf_display_information(id, outf, tdp_level, pbf_info);
1637 free_cpu_set(ctdp_level->core_cpumask);
1638 free_cpu_set(pbf_info->core_cpumask);
1639 }
1640 }
1641
dump_pbf_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1642 static void dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1643 void *arg4)
1644 {
1645 struct isst_pbf_info pbf_info;
1646 int ret;
1647
1648 ret = isst_get_pbf_info(id, tdp_level, &pbf_info);
1649 if (ret) {
1650 isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level);
1651 isst_ctdp_display_information_end(outf);
1652 exit(1);
1653 } else {
1654 isst_pbf_display_information(id, outf, tdp_level, &pbf_info);
1655 free_cpu_set(pbf_info.core_cpumask);
1656 }
1657 }
1658
dump_pbf_config(int arg)1659 static void dump_pbf_config(int arg)
1660 {
1661 void *fn;
1662
1663 if (cmd_help) {
1664 fprintf(stderr,
1665 "Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
1666 fprintf(stderr,
1667 "\tArguments: -l|--level : Specify tdp level\n");
1668 exit(0);
1669 }
1670
1671 if (tdp_level == 0xff) {
1672 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1673 exit(1);
1674 }
1675
1676 if (!is_clx_n_platform())
1677 fn = dump_pbf_config_for_cpu;
1678 else
1679 fn = clx_n_dump_pbf_config_for_cpu;
1680
1681 isst_ctdp_display_information_start(outf);
1682
1683 if (max_target_cpus)
1684 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1685 else
1686 for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL);
1687
1688 isst_ctdp_display_information_end(outf);
1689 }
1690
set_clos_param(struct isst_id * id,int clos,int epp,int wt,int min,int max)1691 static int set_clos_param(struct isst_id *id, int clos, int epp, int wt, int min, int max)
1692 {
1693 struct isst_clos_config clos_config;
1694 int ret;
1695
1696 ret = isst_pm_get_clos(id, clos, &clos_config);
1697 if (ret) {
1698 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
1699 return ret;
1700 }
1701 clos_config.clos_min = min;
1702 clos_config.clos_max = max;
1703 clos_config.epp = epp;
1704 clos_config.clos_prop_prio = wt;
1705 ret = isst_set_clos(id, clos, &clos_config);
1706 if (ret) {
1707 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
1708 return ret;
1709 }
1710
1711 return 0;
1712 }
1713
set_cpufreq_scaling_min_max(int cpu,int max,int freq)1714 static int set_cpufreq_scaling_min_max(int cpu, int max, int freq)
1715 {
1716 char buffer[128], freq_str[16];
1717 int fd, ret, len;
1718
1719 if (max)
1720 snprintf(buffer, sizeof(buffer),
1721 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1722 else
1723 snprintf(buffer, sizeof(buffer),
1724 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1725
1726 fd = open(buffer, O_WRONLY);
1727 if (fd < 0)
1728 return fd;
1729
1730 snprintf(freq_str, sizeof(freq_str), "%d", freq);
1731 len = strlen(freq_str);
1732 ret = write(fd, freq_str, len);
1733 if (ret == -1) {
1734 close(fd);
1735 return ret;
1736 }
1737 close(fd);
1738
1739 return 0;
1740 }
1741
no_turbo(void)1742 static int no_turbo(void)
1743 {
1744 return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo");
1745 }
1746
adjust_scaling_max_from_base_freq(int cpu)1747 static void adjust_scaling_max_from_base_freq(int cpu)
1748 {
1749 int base_freq, scaling_max_freq;
1750
1751 scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1752 base_freq = get_cpufreq_base_freq(cpu);
1753 if (scaling_max_freq < base_freq || no_turbo())
1754 set_cpufreq_scaling_min_max(cpu, 1, base_freq);
1755 }
1756
adjust_scaling_min_from_base_freq(int cpu)1757 static void adjust_scaling_min_from_base_freq(int cpu)
1758 {
1759 int base_freq, scaling_min_freq;
1760
1761 scaling_min_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1762 base_freq = get_cpufreq_base_freq(cpu);
1763 if (scaling_min_freq < base_freq)
1764 set_cpufreq_scaling_min_max(cpu, 0, base_freq);
1765 }
1766
set_clx_pbf_cpufreq_scaling_min_max(struct isst_id * id)1767 static int set_clx_pbf_cpufreq_scaling_min_max(struct isst_id *id)
1768 {
1769 struct isst_pkg_ctdp_level_info *ctdp_level;
1770 struct isst_pbf_info *pbf_info;
1771 int i, freq, freq_high, freq_low;
1772 int ret;
1773
1774 ret = clx_n_config(id);
1775 if (ret) {
1776 debug_printf("cpufreq_scaling_min_max failed for CLX");
1777 return ret;
1778 }
1779
1780 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1781 pbf_info = &ctdp_level->pbf_info;
1782 freq_high = pbf_info->p1_high * 100000;
1783 freq_low = pbf_info->p1_low * 100000;
1784
1785 for (i = 0; i < get_topo_max_cpus(); ++i) {
1786 if (!is_cpu_in_power_domain(i, id))
1787 continue;
1788
1789 if (CPU_ISSET_S(i, pbf_info->core_cpumask_size,
1790 pbf_info->core_cpumask))
1791 freq = freq_high;
1792 else
1793 freq = freq_low;
1794
1795 set_cpufreq_scaling_min_max(i, 1, freq);
1796 set_cpufreq_scaling_min_max(i, 0, freq);
1797 }
1798
1799 return 0;
1800 }
1801
set_cpufreq_scaling_min_max_from_cpuinfo(int cpu,int cpuinfo_max,int scaling_max)1802 static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, int scaling_max)
1803 {
1804 char buffer[128], min_freq[16];
1805 int fd, ret, len;
1806
1807 if (!CPU_ISSET_S(cpu, present_cpumask_size, present_cpumask))
1808 return -1;
1809
1810 if (cpuinfo_max)
1811 snprintf(buffer, sizeof(buffer),
1812 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu);
1813 else
1814 snprintf(buffer, sizeof(buffer),
1815 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpu);
1816
1817 fd = open(buffer, O_RDONLY);
1818 if (fd < 0)
1819 return fd;
1820
1821 len = read(fd, min_freq, sizeof(min_freq));
1822 close(fd);
1823
1824 if (len < 0)
1825 return len;
1826
1827 if (scaling_max)
1828 snprintf(buffer, sizeof(buffer),
1829 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1830 else
1831 snprintf(buffer, sizeof(buffer),
1832 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1833
1834 fd = open(buffer, O_WRONLY);
1835 if (fd < 0)
1836 return fd;
1837
1838 min_freq[15] = '\0';
1839 len = strlen(min_freq);
1840 ret = write(fd, min_freq, len);
1841 if (ret == -1) {
1842 close(fd);
1843 return ret;
1844 }
1845 close(fd);
1846
1847 return 0;
1848 }
1849
set_scaling_min_to_cpuinfo_max(struct isst_id * id)1850 static void set_scaling_min_to_cpuinfo_max(struct isst_id *id)
1851 {
1852 int i;
1853
1854 if (id->cpu < 0)
1855 return;
1856
1857 for (i = 0; i < get_topo_max_cpus(); ++i) {
1858 if (!is_cpu_in_power_domain(i, id))
1859 continue;
1860
1861 if (is_cpu_online(i) != 1)
1862 continue;
1863
1864 adjust_scaling_max_from_base_freq(i);
1865 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0);
1866 adjust_scaling_min_from_base_freq(i);
1867 }
1868 }
1869
set_scaling_min_to_cpuinfo_min(struct isst_id * id)1870 static void set_scaling_min_to_cpuinfo_min(struct isst_id *id)
1871 {
1872 int i;
1873
1874 if (id->cpu < 0)
1875 return;
1876
1877 for (i = 0; i < get_topo_max_cpus(); ++i) {
1878 if (!is_cpu_in_power_domain(i, id))
1879 continue;
1880
1881 if (is_cpu_online(i) != 1)
1882 continue;
1883
1884 adjust_scaling_max_from_base_freq(i);
1885 set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0);
1886 }
1887 }
1888
set_scaling_max_to_cpuinfo_max(struct isst_id * id)1889 static void set_scaling_max_to_cpuinfo_max(struct isst_id *id)
1890 {
1891 int i;
1892
1893 for (i = 0; i < get_topo_max_cpus(); ++i) {
1894 if (!is_cpu_in_power_domain(i, id))
1895 continue;
1896
1897 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1);
1898 }
1899 }
1900
set_core_priority_and_min(struct isst_id * id,int mask_size,cpu_set_t * cpu_mask,int min_high,int min_low)1901 static int set_core_priority_and_min(struct isst_id *id, int mask_size,
1902 cpu_set_t *cpu_mask, int min_high,
1903 int min_low)
1904 {
1905 int ret, i;
1906
1907 if (!CPU_COUNT_S(mask_size, cpu_mask))
1908 return -1;
1909
1910 ret = set_clos_param(id, 0, 0, 0, min_high, 0xff);
1911 if (ret)
1912 return ret;
1913
1914 ret = set_clos_param(id, 1, 15, 15, min_low, 0xff);
1915 if (ret)
1916 return ret;
1917
1918 ret = set_clos_param(id, 2, 15, 15, min_low, 0xff);
1919 if (ret)
1920 return ret;
1921
1922 ret = set_clos_param(id, 3, 15, 15, min_low, 0xff);
1923 if (ret)
1924 return ret;
1925
1926 for (i = 0; i < get_topo_max_cpus(); ++i) {
1927 int clos;
1928 struct isst_id tid;
1929
1930 if (!is_cpu_in_power_domain(i, id))
1931 continue;
1932
1933 if (CPU_ISSET_S(i, mask_size, cpu_mask))
1934 clos = 0;
1935 else
1936 clos = 3;
1937
1938 debug_printf("Associate cpu: %d clos: %d\n", i, clos);
1939 set_isst_id(&tid, i);
1940 ret = isst_clos_associate(&tid, clos);
1941 if (ret) {
1942 isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0);
1943 return ret;
1944 }
1945 }
1946
1947 return 0;
1948 }
1949
set_pbf_core_power(struct isst_id * id)1950 static int set_pbf_core_power(struct isst_id *id)
1951 {
1952 struct isst_pbf_info pbf_info;
1953 struct isst_pkg_ctdp pkg_dev;
1954 int ret;
1955
1956 if (id->cpu < 0)
1957 return 0;
1958
1959 ret = isst_get_ctdp_levels(id, &pkg_dev);
1960 if (ret) {
1961 debug_printf("isst_get_ctdp_levels failed");
1962 return ret;
1963 }
1964 debug_printf("Current_level: %d\n", pkg_dev.current_level);
1965
1966 ret = isst_get_pbf_info(id, pkg_dev.current_level, &pbf_info);
1967 if (ret) {
1968 debug_printf("isst_get_pbf_info failed");
1969 return ret;
1970 }
1971 debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high,
1972 pbf_info.p1_low);
1973
1974 ret = set_core_priority_and_min(id, pbf_info.core_cpumask_size,
1975 pbf_info.core_cpumask,
1976 pbf_info.p1_high, pbf_info.p1_low);
1977 if (ret) {
1978 debug_printf("set_core_priority_and_min failed");
1979 return ret;
1980 }
1981
1982 ret = isst_pm_qos_config(id, 1, 1);
1983 if (ret) {
1984 debug_printf("isst_pm_qos_config failed");
1985 return ret;
1986 }
1987
1988 return 0;
1989 }
1990
set_pbf_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)1991 static void set_pbf_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1992 void *arg4)
1993 {
1994 struct isst_pkg_ctdp_level_info ctdp_level;
1995 struct isst_pkg_ctdp pkg_dev;
1996 int ret;
1997 int status = *(int *)arg4;
1998
1999 if (is_clx_n_platform()) {
2000 ret = 0;
2001 if (status) {
2002 set_clx_pbf_cpufreq_scaling_min_max(id);
2003
2004 } else {
2005 set_scaling_max_to_cpuinfo_max(id);
2006 set_scaling_min_to_cpuinfo_min(id);
2007 }
2008 goto disp_result;
2009 }
2010
2011 ret = isst_get_ctdp_levels(id, &pkg_dev);
2012 if (ret) {
2013 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
2014 goto disp_result;
2015 }
2016
2017 ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level);
2018 if (ret) {
2019 isst_display_error_info_message(1, "Failed to get current level", 0, 0);
2020 goto disp_result;
2021 }
2022
2023 if (!ctdp_level.pbf_support) {
2024 isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, pkg_dev.current_level);
2025 ret = -1;
2026 goto disp_result;
2027 }
2028
2029 if (auto_mode && status) {
2030 ret = set_pbf_core_power(id);
2031 if (ret)
2032 goto disp_result;
2033 }
2034
2035 ret = isst_set_pbf_fact_status(id, 1, status);
2036 if (ret) {
2037 debug_printf("isst_set_pbf_fact_status failed");
2038 if (auto_mode)
2039 isst_pm_qos_config(id, 0, 0);
2040 } else {
2041 if (auto_mode) {
2042 if (status)
2043 set_scaling_min_to_cpuinfo_max(id);
2044 else
2045 set_scaling_min_to_cpuinfo_min(id);
2046 }
2047 }
2048
2049 if (auto_mode && !status)
2050 isst_pm_qos_config(id, 0, 1);
2051
2052 disp_result:
2053 if (status)
2054 isst_display_result(id, outf, "base-freq", "enable",
2055 ret);
2056 else
2057 isst_display_result(id, outf, "base-freq", "disable",
2058 ret);
2059 }
2060
set_pbf_enable(int arg)2061 static void set_pbf_enable(int arg)
2062 {
2063 int enable = arg;
2064
2065 check_privilege();
2066
2067 if (cmd_help) {
2068 if (enable) {
2069 fprintf(stderr,
2070 "Enable Intel Speed Select Technology base frequency feature\n");
2071 if (is_clx_n_platform()) {
2072 fprintf(stderr,
2073 "\tOn this platform this command doesn't enable feature in the hardware.\n");
2074 fprintf(stderr,
2075 "\tIt updates the cpufreq scaling_min_freq to match cpufreq base_frequency.\n");
2076 exit(0);
2077
2078 }
2079 fprintf(stderr,
2080 "\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n");
2081 } else {
2082
2083 if (is_clx_n_platform()) {
2084 fprintf(stderr,
2085 "\tOn this platform this command doesn't disable feature in the hardware.\n");
2086 fprintf(stderr,
2087 "\tIt updates the cpufreq scaling_min_freq to match cpuinfo_min_freq\n");
2088 exit(0);
2089 }
2090 fprintf(stderr,
2091 "Disable Intel Speed Select Technology base frequency feature\n");
2092 fprintf(stderr,
2093 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
2094 }
2095 exit(0);
2096 }
2097
2098 isst_ctdp_display_information_start(outf);
2099 if (max_target_cpus)
2100 for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
2101 NULL, &enable);
2102 else
2103 for_each_online_power_domain_in_set(set_pbf_for_cpu, NULL, NULL,
2104 NULL, &enable);
2105 isst_ctdp_display_information_end(outf);
2106 }
2107
dump_fact_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2108 static void dump_fact_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
2109 void *arg3, void *arg4)
2110 {
2111 struct isst_fact_info fact_info;
2112 int ret;
2113
2114 memset(&fact_info, 0, sizeof(fact_info));
2115 ret = isst_get_fact_info(id, tdp_level, fact_bucket, &fact_info);
2116 if (ret) {
2117 isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level);
2118 isst_ctdp_display_information_end(outf);
2119 exit(1);
2120 } else {
2121 isst_fact_display_information(id, outf, tdp_level, fact_bucket,
2122 fact_avx, &fact_info);
2123 }
2124 }
2125
dump_fact_config(int arg)2126 static void dump_fact_config(int arg)
2127 {
2128 if (cmd_help) {
2129 fprintf(stderr,
2130 "Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
2131 fprintf(stderr,
2132 "\tArguments: -l|--level : Specify tdp level\n");
2133 fprintf(stderr,
2134 "\tArguments: -b|--bucket : Bucket index to dump\n");
2135 fprintf(stderr,
2136 "\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
2137 exit(0);
2138 }
2139
2140 if (tdp_level == 0xff) {
2141 isst_display_error_info_message(1, "Invalid command: specify tdp_level\n", 0, 0);
2142 exit(1);
2143 }
2144
2145 isst_ctdp_display_information_start(outf);
2146 if (max_target_cpus)
2147 for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
2148 NULL, NULL, NULL, NULL);
2149 else
2150 for_each_online_power_domain_in_set(dump_fact_config_for_cpu, NULL,
2151 NULL, NULL, NULL);
2152 isst_ctdp_display_information_end(outf);
2153 }
2154
set_fact_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2155 static void set_fact_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2156 void *arg4)
2157 {
2158 struct isst_pkg_ctdp_level_info ctdp_level;
2159 struct isst_pkg_ctdp pkg_dev;
2160 int ret;
2161 int status = *(int *)arg4;
2162
2163 if (status && no_turbo()) {
2164 isst_display_error_info_message(1, "Turbo mode is disabled", 0, 0);
2165 ret = -1;
2166 goto disp_results;
2167 }
2168
2169 ret = isst_get_ctdp_levels(id, &pkg_dev);
2170 if (ret) {
2171 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
2172 goto disp_results;
2173 }
2174
2175 ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level);
2176 if (ret) {
2177 isst_display_error_info_message(1, "Failed to get current level", 0, 0);
2178 goto disp_results;
2179 }
2180
2181 if (!ctdp_level.fact_support) {
2182 isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, pkg_dev.current_level);
2183 ret = -1;
2184 goto disp_results;
2185 }
2186
2187 if (status) {
2188 ret = isst_pm_qos_config(id, 1, 1);
2189 if (ret)
2190 goto disp_results;
2191 }
2192
2193 ret = isst_set_pbf_fact_status(id, 0, status);
2194 if (ret) {
2195 debug_printf("isst_set_pbf_fact_status failed");
2196 if (auto_mode)
2197 isst_pm_qos_config(id, 0, 0);
2198
2199 goto disp_results;
2200 }
2201
2202 /* Set TRL */
2203 if (status) {
2204 struct isst_pkg_ctdp pkg_dev;
2205
2206 ret = isst_get_ctdp_levels(id, &pkg_dev);
2207 if (!ret && id->cpu >= 0)
2208 ret = isst_set_trl(id, fact_trl);
2209 if (ret && auto_mode)
2210 isst_pm_qos_config(id, 0, 0);
2211 } else {
2212 if (auto_mode)
2213 isst_pm_qos_config(id, 0, 0);
2214 }
2215
2216 disp_results:
2217 if (status) {
2218 isst_display_result(id, outf, "turbo-freq", "enable", ret);
2219 if (ret)
2220 fact_enable_fail = ret;
2221 } else {
2222 /* Since we modified TRL during Fact enable, restore it */
2223 isst_set_trl_from_current_tdp(id, fact_trl);
2224 isst_display_result(id, outf, "turbo-freq", "disable", ret);
2225 }
2226 }
2227
set_fact_enable(int arg)2228 static void set_fact_enable(int arg)
2229 {
2230 int i, ret, enable = arg;
2231 struct isst_id id;
2232
2233 check_privilege();
2234
2235 if (cmd_help) {
2236 if (enable) {
2237 fprintf(stderr,
2238 "Enable Intel Speed Select Technology Turbo frequency feature\n");
2239 fprintf(stderr,
2240 "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n");
2241 fprintf(stderr,
2242 "\tOptional Arguments: -a|--auto : Designate specified target CPUs with");
2243 fprintf(stderr,
2244 "-C|--cpu option as as high priority using core-power feature\n");
2245 } else {
2246 fprintf(stderr,
2247 "Disable Intel Speed Select Technology turbo frequency feature\n");
2248 fprintf(stderr,
2249 "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n");
2250 fprintf(stderr,
2251 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
2252 }
2253 exit(0);
2254 }
2255
2256 isst_ctdp_display_information_start(outf);
2257 if (max_target_cpus)
2258 for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
2259 NULL, &enable);
2260 else
2261 for_each_online_power_domain_in_set(set_fact_for_cpu, NULL, NULL,
2262 NULL, &enable);
2263
2264 if (!fact_enable_fail && enable && auto_mode) {
2265 /*
2266 * When we adjust CLOS param, we have to set for siblings also.
2267 * So for the each user specified CPU, also add the sibling
2268 * in the present_cpu_mask.
2269 */
2270 for (i = 0; i < get_topo_max_cpus(); ++i) {
2271 char buffer[128], sibling_list[128], *cpu_str;
2272 int fd, len;
2273
2274 if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
2275 continue;
2276
2277 snprintf(buffer, sizeof(buffer),
2278 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i);
2279
2280 fd = open(buffer, O_RDONLY);
2281 if (fd < 0)
2282 continue;
2283
2284 len = read(fd, sibling_list, sizeof(sibling_list));
2285 close(fd);
2286
2287 if (len < 0)
2288 continue;
2289
2290 sibling_list[127] = '\0';
2291 cpu_str = strtok(sibling_list, ",");
2292 while (cpu_str != NULL) {
2293 int cpu;
2294
2295 sscanf(cpu_str, "%d", &cpu);
2296 CPU_SET_S(cpu, target_cpumask_size, target_cpumask);
2297 cpu_str = strtok(NULL, ",");
2298 }
2299 }
2300
2301 for (i = 0; i < get_topo_max_cpus(); ++i) {
2302 int clos;
2303
2304 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
2305 continue;
2306
2307 if (is_cpu_online(i) != 1)
2308 continue;
2309
2310 set_isst_id(&id, i);
2311 ret = set_clos_param(&id, 0, 0, 0, 0, 0xff);
2312 if (ret)
2313 goto error_disp;
2314
2315 ret = set_clos_param(&id, 1, 15, 15, 0, 0xff);
2316 if (ret)
2317 goto error_disp;
2318
2319 ret = set_clos_param(&id, 2, 15, 15, 0, 0xff);
2320 if (ret)
2321 goto error_disp;
2322
2323 ret = set_clos_param(&id, 3, 15, 15, 0, 0xff);
2324 if (ret)
2325 goto error_disp;
2326
2327 if (CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
2328 clos = 0;
2329 else
2330 clos = 3;
2331
2332 debug_printf("Associate cpu: %d clos: %d\n", i, clos);
2333 ret = isst_clos_associate(&id, clos);
2334 if (ret)
2335 goto error_disp;
2336 }
2337 set_isst_id(&id, -1);
2338 isst_display_result(&id, outf, "turbo-freq --auto", "enable", 0);
2339 }
2340
2341 isst_ctdp_display_information_end(outf);
2342
2343 return;
2344
2345 error_disp:
2346 isst_display_result(&id, outf, "turbo-freq --auto", "enable", ret);
2347 isst_ctdp_display_information_end(outf);
2348
2349 }
2350
enable_clos_qos_config(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2351 static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2352 void *arg4)
2353 {
2354 int ret;
2355 int status = *(int *)arg4;
2356 int cp_state, cp_cap;
2357
2358 if (!isst_read_pm_config(id, &cp_state, &cp_cap)) {
2359 if (!cp_cap) {
2360 isst_display_error_info_message(1, "core-power not supported", 0, 0);
2361 return;
2362 }
2363 }
2364
2365 if (is_skx_based_platform())
2366 clos_priority_type = 1;
2367
2368 ret = isst_pm_qos_config(id, status, clos_priority_type);
2369 if (ret)
2370 isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0);
2371
2372 if (status)
2373 isst_display_result(id, outf, "core-power", "enable",
2374 ret);
2375 else
2376 isst_display_result(id, outf, "core-power", "disable",
2377 ret);
2378 }
2379
set_clos_enable(int arg)2380 static void set_clos_enable(int arg)
2381 {
2382 int enable = arg;
2383
2384 check_privilege();
2385
2386 if (cmd_help) {
2387 if (enable) {
2388 fprintf(stderr,
2389 "Enable core-power for a package/die\n");
2390 if (!is_skx_based_platform()) {
2391 fprintf(stderr,
2392 "\tClos Enable: Specify priority type with [--priority|-p]\n");
2393 fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
2394 }
2395 } else {
2396 fprintf(stderr,
2397 "Disable core-power: [No command arguments are required]\n");
2398 }
2399 exit(0);
2400 }
2401
2402 if (enable && cpufreq_sysfs_present()) {
2403 fprintf(stderr,
2404 "cpufreq subsystem and core-power enable will interfere with each other!\n");
2405 }
2406
2407 isst_ctdp_display_information_start(outf);
2408 if (max_target_cpus)
2409 for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
2410 NULL, NULL, &enable);
2411 else
2412 for_each_online_power_domain_in_set(enable_clos_qos_config, NULL,
2413 NULL, NULL, &enable);
2414 isst_ctdp_display_information_end(outf);
2415 }
2416
dump_clos_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2417 static void dump_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
2418 void *arg3, void *arg4)
2419 {
2420 struct isst_clos_config clos_config;
2421 int ret;
2422
2423 ret = isst_pm_get_clos(id, current_clos, &clos_config);
2424 if (ret)
2425 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
2426 else
2427 isst_clos_display_information(id, outf, current_clos,
2428 &clos_config);
2429 }
2430
dump_clos_config(int arg)2431 static void dump_clos_config(int arg)
2432 {
2433 if (cmd_help) {
2434 fprintf(stderr,
2435 "Print Intel Speed Select Technology core power configuration\n");
2436 fprintf(stderr,
2437 "\tArguments: [-c | --clos]: Specify clos id\n");
2438 exit(0);
2439 }
2440 if (current_clos < 0 || current_clos > 3) {
2441 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2442 isst_ctdp_display_information_end(outf);
2443 exit(0);
2444 }
2445
2446 isst_ctdp_display_information_start(outf);
2447 if (max_target_cpus)
2448 for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
2449 NULL, NULL, NULL, NULL);
2450 else
2451 for_each_online_power_domain_in_set(dump_clos_config_for_cpu, NULL,
2452 NULL, NULL, NULL);
2453 isst_ctdp_display_information_end(outf);
2454 }
2455
get_clos_info_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2456 static void get_clos_info_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2457 void *arg4)
2458 {
2459 int enable, ret, prio_type;
2460
2461 ret = isst_clos_get_clos_information(id, &enable, &prio_type);
2462 if (ret)
2463 isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0);
2464 else {
2465 int cp_state, cp_cap;
2466
2467 isst_read_pm_config(id, &cp_state, &cp_cap);
2468 isst_clos_display_clos_information(id, outf, enable, prio_type,
2469 cp_state, cp_cap);
2470 }
2471 }
2472
dump_clos_info(int arg)2473 static void dump_clos_info(int arg)
2474 {
2475 if (cmd_help) {
2476 fprintf(stderr,
2477 "Print Intel Speed Select Technology core power information\n");
2478 fprintf(stderr, "\t Optionally specify targeted cpu id with [--cpu|-c]\n");
2479 exit(0);
2480 }
2481
2482 isst_ctdp_display_information_start(outf);
2483 if (max_target_cpus)
2484 for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL,
2485 NULL, NULL, NULL);
2486 else
2487 for_each_online_power_domain_in_set(get_clos_info_for_cpu, NULL,
2488 NULL, NULL, NULL);
2489 isst_ctdp_display_information_end(outf);
2490
2491 }
2492
set_clos_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2493 static void set_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2494 void *arg4)
2495 {
2496 struct isst_clos_config clos_config;
2497 int ret;
2498
2499 if (id->cpu < 0)
2500 return;
2501
2502 clos_config.epp = clos_epp;
2503 clos_config.clos_prop_prio = clos_prop_prio;
2504 clos_config.clos_min = clos_min;
2505 clos_config.clos_max = clos_max;
2506 clos_config.clos_desired = clos_desired;
2507 ret = isst_set_clos(id, current_clos, &clos_config);
2508 if (ret)
2509 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
2510 else
2511 isst_display_result(id, outf, "core-power", "config", ret);
2512 }
2513
set_clos_config(int arg)2514 static void set_clos_config(int arg)
2515 {
2516 check_privilege();
2517
2518 if (cmd_help) {
2519 fprintf(stderr,
2520 "Set core-power configuration for one of the four clos ids\n");
2521 fprintf(stderr,
2522 "\tSpecify targeted clos id with [--clos|-c]\n");
2523 if (!is_skx_based_platform()) {
2524 fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
2525 fprintf(stderr,
2526 "\tSpecify clos Proportional Priority [--weight|-w]\n");
2527 }
2528 fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n");
2529 fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n");
2530 exit(0);
2531 }
2532
2533 if (current_clos < 0 || current_clos > 3) {
2534 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2535 exit(0);
2536 }
2537 if (!is_skx_based_platform() && (clos_epp < 0 || clos_epp > 0x0F)) {
2538 fprintf(stderr, "clos epp is not specified or invalid, default: 0\n");
2539 clos_epp = 0;
2540 }
2541 if (!is_skx_based_platform() && (clos_prop_prio < 0 || clos_prop_prio > 0x0F)) {
2542 fprintf(stderr,
2543 "clos frequency weight is not specified or invalid, default: 0\n");
2544 clos_prop_prio = 0;
2545 }
2546 if (clos_min < 0) {
2547 fprintf(stderr, "clos min is not specified, default: 0\n");
2548 clos_min = 0;
2549 }
2550 if (clos_max < 0) {
2551 fprintf(stderr, "clos max is not specified, default: Max frequency (ratio 0xff)\n");
2552 clos_max = 0xff;
2553 }
2554 if (clos_desired) {
2555 fprintf(stderr, "clos desired is not supported on this platform\n");
2556 clos_desired = 0x00;
2557 }
2558
2559 isst_ctdp_display_information_start(outf);
2560 if (max_target_cpus)
2561 for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
2562 NULL, NULL, NULL);
2563 else
2564 for_each_online_power_domain_in_set(set_clos_config_for_cpu, NULL,
2565 NULL, NULL, NULL);
2566 isst_ctdp_display_information_end(outf);
2567 }
2568
set_clos_assoc_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2569 static void set_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2570 void *arg4)
2571 {
2572 int ret;
2573
2574 ret = isst_clos_associate(id, current_clos);
2575 if (ret)
2576 debug_printf("isst_clos_associate failed");
2577 else
2578 isst_display_result(id, outf, "core-power", "assoc", ret);
2579 }
2580
set_clos_assoc(int arg)2581 static void set_clos_assoc(int arg)
2582 {
2583 check_privilege();
2584
2585 if (cmd_help) {
2586 fprintf(stderr, "Associate a clos id to a CPU\n");
2587 fprintf(stderr,
2588 "\tSpecify targeted clos id with [--clos|-c]\n");
2589 fprintf(stderr,
2590 "\tFor example to associate clos 1 to CPU 0: issue\n");
2591 fprintf(stderr,
2592 "\tintel-speed-select --cpu 0 core-power assoc --clos 1\n");
2593 exit(0);
2594 }
2595
2596 if (current_clos < 0 || current_clos > 3) {
2597 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2598 exit(0);
2599 }
2600
2601 isst_ctdp_display_information_start(outf);
2602
2603 if (max_target_cpus)
2604 for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
2605 NULL, NULL, NULL);
2606 else {
2607 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2608 }
2609 isst_ctdp_display_information_end(outf);
2610 }
2611
get_clos_assoc_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2612 static void get_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2613 void *arg4)
2614 {
2615 int clos, ret;
2616
2617 ret = isst_clos_get_assoc_status(id, &clos);
2618 if (ret)
2619 isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0);
2620 else
2621 isst_clos_display_assoc_information(id, outf, clos);
2622 }
2623
get_clos_assoc(int arg)2624 static void get_clos_assoc(int arg)
2625 {
2626 if (cmd_help) {
2627 fprintf(stderr, "Get associate clos id to a CPU\n");
2628 fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
2629 exit(0);
2630 }
2631
2632 if (!max_target_cpus) {
2633 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2634 exit(0);
2635 }
2636
2637 isst_ctdp_display_information_start(outf);
2638 for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
2639 NULL, NULL, NULL);
2640 isst_ctdp_display_information_end(outf);
2641 }
2642
set_turbo_mode_for_cpu(struct isst_id * id,int status)2643 static void set_turbo_mode_for_cpu(struct isst_id *id, int status)
2644 {
2645 int base_freq;
2646
2647 if (status) {
2648 base_freq = get_cpufreq_base_freq(id->cpu);
2649 set_cpufreq_scaling_min_max(id->cpu, 1, base_freq);
2650 } else {
2651 set_scaling_max_to_cpuinfo_max(id);
2652 }
2653
2654 if (status) {
2655 isst_display_result(id, outf, "turbo-mode", "disable", 0);
2656 } else {
2657 isst_display_result(id, outf, "turbo-mode", "enable", 0);
2658 }
2659 }
2660
set_turbo_mode(int arg)2661 static void set_turbo_mode(int arg)
2662 {
2663 int i, disable = arg;
2664 struct isst_id id;
2665
2666 check_privilege();
2667
2668 if (cmd_help) {
2669 if (disable)
2670 fprintf(stderr, "Set turbo mode disable\n");
2671 else
2672 fprintf(stderr, "Set turbo mode enable\n");
2673 exit(0);
2674 }
2675
2676 isst_ctdp_display_information_start(outf);
2677
2678 for (i = 0; i < topo_max_cpus; ++i) {
2679 int online;
2680
2681 if (i)
2682 online = parse_int_file(
2683 1, "/sys/devices/system/cpu/cpu%d/online", i);
2684 else
2685 online =
2686 1; /* online entry for CPU 0 needs some special configs */
2687
2688 if (online) {
2689 set_isst_id(&id, i);
2690 set_turbo_mode_for_cpu(&id, disable);
2691 }
2692
2693 }
2694 isst_ctdp_display_information_end(outf);
2695 }
2696
get_set_trl(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)2697 static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2698 void *arg4)
2699 {
2700 unsigned long long trl;
2701 int set = *(int *)arg4;
2702 int ret;
2703
2704 if (id->cpu < 0)
2705 return;
2706
2707 if (set && !fact_trl) {
2708 isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0);
2709 exit(0);
2710 }
2711
2712 if (set) {
2713 check_privilege();
2714 ret = isst_set_trl(id, fact_trl);
2715 isst_display_result(id, outf, "turbo-mode", "set-trl", ret);
2716 return;
2717 }
2718
2719 ret = isst_get_trl(id, &trl);
2720 if (ret)
2721 isst_display_result(id, outf, "turbo-mode", "get-trl", ret);
2722 else
2723 isst_trl_display_information(id, outf, trl);
2724 }
2725
process_trl(int arg)2726 static void process_trl(int arg)
2727 {
2728 if (cmd_help) {
2729 if (arg) {
2730 fprintf(stderr, "Set TRL (turbo ratio limits)\n");
2731 fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL in hex starting with 0x\n");
2732 } else {
2733 fprintf(stderr, "Get TRL (turbo ratio limits)\n");
2734 }
2735 exit(0);
2736 }
2737
2738 isst_ctdp_display_information_start(outf);
2739 if (max_target_cpus)
2740 for_each_online_target_cpu_in_set(get_set_trl, NULL,
2741 NULL, NULL, &arg);
2742 else
2743 for_each_online_power_domain_in_set(get_set_trl, NULL,
2744 NULL, NULL, &arg);
2745 isst_ctdp_display_information_end(outf);
2746 }
2747
2748 static struct process_cmd_struct clx_n_cmds[] = {
2749 { "perf-profile", "info", dump_isst_config, 0 },
2750 { "base-freq", "info", dump_pbf_config, 0 },
2751 { "base-freq", "enable", set_pbf_enable, 1 },
2752 { "base-freq", "disable", set_pbf_enable, 0 },
2753 { NULL, NULL, NULL, 0 }
2754 };
2755
2756 static struct process_cmd_struct isst_cmds[] = {
2757 { "perf-profile", "get-lock-status", get_tdp_locked, 0 },
2758 { "perf-profile", "get-config-levels", get_tdp_levels, 0 },
2759 { "perf-profile", "get-config-version", get_tdp_version, 0 },
2760 { "perf-profile", "get-config-enabled", get_tdp_enabled, 0 },
2761 { "perf-profile", "get-config-current-level", get_tdp_current_level,
2762 0 },
2763 { "perf-profile", "set-config-level", set_tdp_level, 0 },
2764 { "perf-profile", "info", dump_isst_config, 0 },
2765 { "base-freq", "info", dump_pbf_config, 0 },
2766 { "base-freq", "enable", set_pbf_enable, 1 },
2767 { "base-freq", "disable", set_pbf_enable, 0 },
2768 { "turbo-freq", "info", dump_fact_config, 0 },
2769 { "turbo-freq", "enable", set_fact_enable, 1 },
2770 { "turbo-freq", "disable", set_fact_enable, 0 },
2771 { "core-power", "info", dump_clos_info, 0 },
2772 { "core-power", "enable", set_clos_enable, 1 },
2773 { "core-power", "disable", set_clos_enable, 0 },
2774 { "core-power", "config", set_clos_config, 0 },
2775 { "core-power", "get-config", dump_clos_config, 0 },
2776 { "core-power", "assoc", set_clos_assoc, 0 },
2777 { "core-power", "get-assoc", get_clos_assoc, 0 },
2778 { "turbo-mode", "enable", set_turbo_mode, 0 },
2779 { "turbo-mode", "disable", set_turbo_mode, 1 },
2780 { "turbo-mode", "get-trl", process_trl, 0 },
2781 { "turbo-mode", "set-trl", process_trl, 1 },
2782 { NULL, NULL, NULL }
2783 };
2784
2785 /*
2786 * parse cpuset with following syntax
2787 * 1,2,4..6,8-10 and set bits in cpu_subset
2788 */
parse_cpu_command(char * optarg)2789 void parse_cpu_command(char *optarg)
2790 {
2791 unsigned int start, end, invalid_count;
2792 char *next;
2793
2794 next = optarg;
2795 invalid_count = 0;
2796
2797 while (next && *next) {
2798 if (*next == '-') /* no negative cpu numbers */
2799 goto error;
2800
2801 start = strtoul(next, &next, 10);
2802
2803 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2804 target_cpus[max_target_cpus++] = start;
2805 else
2806 invalid_count = 1;
2807
2808 if (*next == '\0')
2809 break;
2810
2811 if (*next == ',') {
2812 next += 1;
2813 continue;
2814 }
2815
2816 if (*next == '-') {
2817 next += 1; /* start range */
2818 } else if (*next == '.') {
2819 next += 1;
2820 if (*next == '.')
2821 next += 1; /* start range */
2822 else
2823 goto error;
2824 }
2825
2826 end = strtoul(next, &next, 10);
2827 if (end <= start)
2828 goto error;
2829
2830 while (++start <= end) {
2831 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2832 target_cpus[max_target_cpus++] = start;
2833 else
2834 invalid_count = 1;
2835 }
2836
2837 if (*next == ',')
2838 next += 1;
2839 else if (*next != '\0')
2840 goto error;
2841 }
2842
2843 if (invalid_count) {
2844 isst_ctdp_display_information_start(outf);
2845 isst_display_error_info_message(1, "Too many CPUs in one request: max is", 1, MAX_CPUS_IN_ONE_REQ - 1);
2846 isst_ctdp_display_information_end(outf);
2847 exit(-1);
2848 }
2849
2850 #ifdef DEBUG
2851 {
2852 int i;
2853
2854 for (i = 0; i < max_target_cpus; ++i)
2855 printf("cpu [%d] in arg\n", target_cpus[i]);
2856 }
2857 #endif
2858 return;
2859
2860 error:
2861 fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
2862 exit(-1);
2863 }
2864
check_optarg(char * option,int hex)2865 static void check_optarg(char *option, int hex)
2866 {
2867 if (optarg) {
2868 char *start = optarg;
2869 int i;
2870
2871 if (hex && strlen(optarg) < 3) {
2872 /* At least 0x plus one character must be present */
2873 fprintf(stderr, "malformed arguments for:%s [%s]\n", option, optarg);
2874 exit(0);
2875 }
2876
2877 if (hex) {
2878 if (optarg[0] != '0' || tolower(optarg[1]) != 'x') {
2879 fprintf(stderr, "malformed arguments for:%s [%s]\n",
2880 option, optarg);
2881 exit(0);
2882 }
2883 start = &optarg[2];
2884 }
2885
2886 for (i = 0; i < strlen(start); ++i) {
2887 if (hex) {
2888 if (!isxdigit(start[i])) {
2889 fprintf(stderr, "malformed arguments for:%s [%s]\n",
2890 option, optarg);
2891 exit(0);
2892 }
2893 } else if (!isdigit(start[i])) {
2894 fprintf(stderr, "malformed arguments for:%s [%s]\n",
2895 option, optarg);
2896 exit(0);
2897 }
2898 }
2899 }
2900 }
2901
parse_cmd_args(int argc,int start,char ** argv)2902 static void parse_cmd_args(int argc, int start, char **argv)
2903 {
2904 int opt;
2905 int option_index;
2906
2907 static struct option long_options[] = {
2908 { "bucket", required_argument, 0, 'b' },
2909 { "level", required_argument, 0, 'l' },
2910 { "online", required_argument, 0, 'o' },
2911 { "trl-type", required_argument, 0, 'r' },
2912 { "trl", required_argument, 0, 't' },
2913 { "help", no_argument, 0, 'h' },
2914 { "clos", required_argument, 0, 'c' },
2915 { "desired", required_argument, 0, 'd' },
2916 { "epp", required_argument, 0, 'e' },
2917 { "min", required_argument, 0, 'n' },
2918 { "max", required_argument, 0, 'm' },
2919 { "priority", required_argument, 0, 'p' },
2920 { "weight", required_argument, 0, 'w' },
2921 { "auto", no_argument, 0, 'a' },
2922 { 0, 0, 0, 0 }
2923 };
2924
2925 option_index = start;
2926
2927 optind = start + 1;
2928 while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:r:hoa",
2929 long_options, &option_index)) != -1) {
2930 switch (opt) {
2931 case 'a':
2932 auto_mode = 1;
2933 break;
2934 case 'b':
2935 check_optarg("bucket", 0);
2936 fact_bucket = atoi(optarg);
2937 break;
2938 case 'h':
2939 cmd_help = 1;
2940 break;
2941 case 'l':
2942 check_optarg("level", 0);
2943 tdp_level = atoi(optarg);
2944 break;
2945 case 'o':
2946 force_online_offline = 1;
2947 break;
2948 case 't':
2949 check_optarg("trl", 1);
2950 sscanf(optarg, "0x%llx", &fact_trl);
2951 break;
2952 case 'r':
2953 if (!strncmp(optarg, "sse", 3)) {
2954 fact_avx = 0x01;
2955 } else if (!strncmp(optarg, "avx2", 4)) {
2956 fact_avx = 0x02;
2957 } else if (!strncmp(optarg, "avx512", 6)) {
2958 fact_avx = 0x04;
2959 } else {
2960 fprintf(outf, "Invalid sse,avx options\n");
2961 exit(1);
2962 }
2963 break;
2964 /* CLOS related */
2965 case 'c':
2966 check_optarg("clos", 0);
2967 current_clos = atoi(optarg);
2968 break;
2969 case 'd':
2970 check_optarg("desired", 0);
2971 clos_desired = atoi(optarg);
2972 clos_desired /= isst_get_disp_freq_multiplier();
2973 break;
2974 case 'e':
2975 check_optarg("epp", 0);
2976 clos_epp = atoi(optarg);
2977 if (is_skx_based_platform()) {
2978 isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0);
2979 exit(0);
2980 }
2981 break;
2982 case 'n':
2983 check_optarg("min", 0);
2984 clos_min = atoi(optarg);
2985 clos_min /= isst_get_disp_freq_multiplier();
2986 break;
2987 case 'm':
2988 check_optarg("max", 0);
2989 clos_max = atoi(optarg);
2990 clos_max /= isst_get_disp_freq_multiplier();
2991 break;
2992 case 'p':
2993 check_optarg("priority", 0);
2994 clos_priority_type = atoi(optarg);
2995 if (is_skx_based_platform() && !clos_priority_type) {
2996 isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0);
2997 exit(0);
2998 }
2999 break;
3000 case 'w':
3001 check_optarg("weight", 0);
3002 clos_prop_prio = atoi(optarg);
3003 if (is_skx_based_platform()) {
3004 isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0);
3005 exit(0);
3006 }
3007 break;
3008 default:
3009 printf("Unknown option: ignore\n");
3010 }
3011 }
3012
3013 if (argv[optind])
3014 printf("Garbage at the end of command: ignore\n");
3015 }
3016
isst_help(void)3017 static void isst_help(void)
3018 {
3019 printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
3020 performance profiles per system via static and/or dynamic\n\
3021 adjustment of core count, workload, Tjmax, and\n\
3022 TDP, etc.\n");
3023 printf("\nCommands : For feature=perf-profile\n");
3024 printf("\tinfo\n");
3025
3026 if (!is_clx_n_platform()) {
3027 printf("\tget-lock-status\n");
3028 printf("\tget-config-levels\n");
3029 printf("\tget-config-version\n");
3030 printf("\tget-config-enabled\n");
3031 printf("\tget-config-current-level\n");
3032 printf("\tset-config-level\n");
3033 }
3034 }
3035
pbf_help(void)3036 static void pbf_help(void)
3037 {
3038 printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
3039 on certain cores (high priority cores) in exchange for lower\n\
3040 base frequency on remaining cores (low priority cores).\n");
3041 printf("\tcommand : info\n");
3042 printf("\tcommand : enable\n");
3043 printf("\tcommand : disable\n");
3044 }
3045
fact_help(void)3046 static void fact_help(void)
3047 {
3048 printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
3049 limits to cores based on priority.\n");
3050 printf("\nCommand: For feature=turbo-freq\n");
3051 printf("\tcommand : info\n");
3052 printf("\tcommand : enable\n");
3053 printf("\tcommand : disable\n");
3054 }
3055
turbo_mode_help(void)3056 static void turbo_mode_help(void)
3057 {
3058 printf("turbo-mode:\tEnables users to enable/disable turbo mode by adjusting frequency settings. Also allows to get and set turbo ratio limits (TRL).\n");
3059 printf("\tcommand : enable\n");
3060 printf("\tcommand : disable\n");
3061 printf("\tcommand : get-trl\n");
3062 printf("\tcommand : set-trl\n");
3063 }
3064
3065
core_power_help(void)3066 static void core_power_help(void)
3067 {
3068 printf("core-power:\tInterface that allows user to define per core/tile\n\
3069 priority.\n");
3070 printf("\nCommands : For feature=core-power\n");
3071 printf("\tinfo\n");
3072 printf("\tenable\n");
3073 printf("\tdisable\n");
3074 printf("\tconfig\n");
3075 printf("\tget-config\n");
3076 printf("\tassoc\n");
3077 printf("\tget-assoc\n");
3078 }
3079
3080 struct process_cmd_help_struct {
3081 char *feature;
3082 void (*process_fn)(void);
3083 };
3084
3085 static struct process_cmd_help_struct isst_help_cmds[] = {
3086 { "perf-profile", isst_help },
3087 { "base-freq", pbf_help },
3088 { "turbo-freq", fact_help },
3089 { "core-power", core_power_help },
3090 { "turbo-mode", turbo_mode_help },
3091 { NULL, NULL }
3092 };
3093
3094 static struct process_cmd_help_struct clx_n_help_cmds[] = {
3095 { "perf-profile", isst_help },
3096 { "base-freq", pbf_help },
3097 { NULL, NULL }
3098 };
3099
process_command(int argc,char ** argv,struct process_cmd_help_struct * help_cmds,struct process_cmd_struct * cmds)3100 void process_command(int argc, char **argv,
3101 struct process_cmd_help_struct *help_cmds,
3102 struct process_cmd_struct *cmds)
3103 {
3104 int i = 0, matched = 0;
3105 char *feature = argv[optind];
3106 char *cmd = argv[optind + 1];
3107
3108 if (!feature || !cmd)
3109 return;
3110
3111 debug_printf("feature name [%s] command [%s]\n", feature, cmd);
3112 if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
3113 while (help_cmds[i].feature) {
3114 if (!strcmp(help_cmds[i].feature, feature)) {
3115 help_cmds[i].process_fn();
3116 exit(0);
3117 }
3118 ++i;
3119 }
3120 }
3121
3122 i = 0;
3123 while (cmds[i].feature) {
3124 if (!strcmp(cmds[i].feature, feature) &&
3125 !strcmp(cmds[i].command, cmd)) {
3126 parse_cmd_args(argc, optind + 1, argv);
3127 cmds[i].process_fn(cmds[i].arg);
3128 matched = 1;
3129 break;
3130 }
3131 ++i;
3132 }
3133
3134 if (!matched)
3135 fprintf(stderr, "Invalid command\n");
3136 }
3137
usage(void)3138 static void usage(void)
3139 {
3140 if (is_clx_n_platform()) {
3141 fprintf(stderr, "\nThere is limited support of Intel Speed Select features on this platform.\n");
3142 fprintf(stderr, "Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware.\n\n");
3143 }
3144
3145 printf("\nUsage:\n");
3146 printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
3147 printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features:\n");
3148 if (is_clx_n_platform())
3149 printf("\nFEATURE : [perf-profile|base-freq]\n");
3150 else
3151 printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power|turbo-mode]\n");
3152 printf("\nFor help on each feature, use -h|--help\n");
3153 printf("\tFor example: intel-speed-select perf-profile -h\n");
3154
3155 printf("\nFor additional help on each command for a feature, use --h|--help\n");
3156 printf("\tFor example: intel-speed-select perf-profile get-lock-status -h\n");
3157 printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
3158
3159 printf("\nOPTIONS\n");
3160 printf("\t[-c|--cpu] : logical cpu number\n");
3161 printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
3162 printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
3163 printf("\t[-d|--debug] : Debug mode\n");
3164 printf("\t[-f|--format] : output format [json|text]. Default: text\n");
3165 printf("\t[-h|--help] : Print help\n");
3166 printf("\t[-i|--info] : Print platform information\n");
3167 printf("\t[-a|--all-cpus-online] : Force online every CPU in the system\n");
3168 printf("\t[-o|--out] : Output file\n");
3169 printf("\t\t\tDefault : stderr\n");
3170 printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n");
3171 printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n");
3172 printf("\t[-v|--version] : Print version\n");
3173 printf("\t[-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent.\n");
3174 printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n");
3175 printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n");
3176 printf("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n");
3177 printf("\t[-u|--cpu0-workaround : Don't try to online/offline CPU0 instead use cgroup v2.\n");
3178 printf("\nResult format\n");
3179 printf("\tResult display uses a common format for each command:\n");
3180 printf("\tResults are formatted in text/JSON with\n");
3181 printf("\t\tPackage, Die, CPU, and command specific results.\n");
3182
3183 printf("\nExamples\n");
3184 printf("\tTo get platform information:\n");
3185 printf("\t\tintel-speed-select --info\n");
3186 printf("\tTo get full perf-profile information dump:\n");
3187 printf("\t\tintel-speed-select perf-profile info\n");
3188 printf("\tTo get full base-freq information dump:\n");
3189 printf("\t\tintel-speed-select base-freq info -l 0\n");
3190 if (!is_clx_n_platform()) {
3191 printf("\tTo get full turbo-freq information dump:\n");
3192 printf("\t\tintel-speed-select turbo-freq info -l 0\n");
3193 }
3194 exit(1);
3195 }
3196
print_version(void)3197 static void print_version(void)
3198 {
3199 fprintf(outf, "Version %s\n", version_str);
3200 exit(0);
3201 }
3202
cmdline(int argc,char ** argv)3203 static void cmdline(int argc, char **argv)
3204 {
3205 const char *pathname = "/dev/isst_interface";
3206 char *ptr;
3207 FILE *fp;
3208 int opt, force_cpus_online = 0;
3209 int option_index = 0;
3210 int ret;
3211 int oob_mode = 0;
3212 int poll_interval = -1;
3213 int no_daemon = 0;
3214 int mbox_delay = 0, mbox_retries = 3;
3215
3216 static struct option long_options[] = {
3217 { "all-cpus-online", no_argument, 0, 'a' },
3218 { "cpu", required_argument, 0, 'c' },
3219 { "debug", no_argument, 0, 'd' },
3220 { "format", required_argument, 0, 'f' },
3221 { "help", no_argument, 0, 'h' },
3222 { "info", no_argument, 0, 'i' },
3223 { "pause", required_argument, 0, 'p' },
3224 { "out", required_argument, 0, 'o' },
3225 { "retry", required_argument, 0, 'r' },
3226 { "version", no_argument, 0, 'v' },
3227 { "oob", no_argument, 0, 'b' },
3228 { "no-daemon", no_argument, 0, 'n' },
3229 { "poll-interval", required_argument, 0, 'w' },
3230 { "cgroupv2", required_argument, 0, 'g' },
3231 { "cpu0-workaround", required_argument, 0, 'u' },
3232 { 0, 0, 0, 0 }
3233 };
3234
3235 if (geteuid() != 0) {
3236 int fd;
3237
3238 fd = open(pathname, O_RDWR);
3239 if (fd < 0) {
3240 fprintf(stderr, "Must run as root\n");
3241 exit(0);
3242 }
3243 fprintf(stderr, "\nNot running as root, Only read only operations are supported\n");
3244 close(fd);
3245 read_only = 1;
3246 }
3247
3248 ret = update_cpu_model();
3249 if (ret)
3250 err(-1, "Invalid CPU model (%d)\n", cpu_model);
3251 printf("Intel(R) Speed Select Technology\n");
3252 printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
3253
3254 if (!is_clx_n_platform()) {
3255 fp = fopen(pathname, "rb");
3256 if (!fp) {
3257 fprintf(stderr, "Intel speed select drivers are not loaded on this system.\n");
3258 fprintf(stderr, "Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE.\n");
3259 fprintf(stderr, "If the config is included then this is not a supported platform.\n");
3260 exit(0);
3261 }
3262 fclose(fp);
3263 }
3264
3265 ret = isst_fill_platform_info();
3266 if (ret)
3267 goto out;
3268
3269 progname = argv[0];
3270 while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ngu", long_options,
3271 &option_index)) != -1) {
3272 switch (opt) {
3273 case 'a':
3274 force_cpus_online = 1;
3275 break;
3276 case 'c':
3277 parse_cpu_command(optarg);
3278 break;
3279 case 'd':
3280 debug_flag = 1;
3281 printf("Debug Mode ON\n");
3282 break;
3283 case 'f':
3284 if (!strncmp(optarg, "json", 4))
3285 out_format_json = 1;
3286 break;
3287 case 'h':
3288 usage();
3289 break;
3290 case 'i':
3291 isst_print_platform_information();
3292 break;
3293 case 'o':
3294 if (outf)
3295 fclose(outf);
3296 outf = fopen_or_exit(optarg, "w");
3297 break;
3298 case 'p':
3299 ret = strtol(optarg, &ptr, 10);
3300 if (!ret)
3301 fprintf(stderr, "Invalid pause interval, ignore\n");
3302 else
3303 mbox_delay = ret;
3304 break;
3305 case 'r':
3306 ret = strtol(optarg, &ptr, 10);
3307 if (!ret)
3308 fprintf(stderr, "Invalid retry count, ignore\n");
3309 else
3310 mbox_retries = ret;
3311 break;
3312 case 'v':
3313 print_version();
3314 break;
3315 case 'b':
3316 oob_mode = 1;
3317 break;
3318 case 'n':
3319 no_daemon = 1;
3320 break;
3321 case 'w':
3322 ret = strtol(optarg, &ptr, 10);
3323 if (!ret) {
3324 fprintf(stderr, "Invalid poll interval count\n");
3325 exit(0);
3326 }
3327 poll_interval = ret;
3328 break;
3329 case 'g':
3330 cgroupv2 = 1;
3331 break;
3332 case 'u':
3333 cpu_0_cgroupv2 = 1;
3334 break;
3335 default:
3336 usage();
3337 }
3338 }
3339
3340 if (optind > (argc - 2) && !oob_mode) {
3341 usage();
3342 exit(0);
3343 }
3344
3345 isst_update_platform_param(ISST_PARAM_MBOX_DELAY, mbox_delay);
3346 isst_update_platform_param(ISST_PARAM_MBOX_RETRIES, mbox_retries);
3347
3348 set_max_cpu_num();
3349 if (force_cpus_online)
3350 force_all_cpus_online();
3351 store_cpu_topology();
3352 create_cpu_map();
3353
3354 if (oob_mode) {
3355 if (debug_flag)
3356 fprintf(stderr, "OOB mode is enabled in debug mode\n");
3357
3358 ret = isst_daemon(debug_flag, poll_interval, no_daemon);
3359 if (ret)
3360 fprintf(stderr, "OOB mode enable failed\n");
3361 goto out;
3362 }
3363
3364 if (!is_clx_n_platform()) {
3365 process_command(argc, argv, isst_help_cmds, isst_cmds);
3366 } else {
3367 process_command(argc, argv, clx_n_help_cmds, clx_n_cmds);
3368 }
3369 out:
3370 free_cpu_set(present_cpumask);
3371 free_cpu_set(target_cpumask);
3372 }
3373
main(int argc,char ** argv)3374 int main(int argc, char **argv)
3375 {
3376 outf = stderr;
3377 cmdline(argc, argv);
3378 return 0;
3379 }
3380