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