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