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