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