Merge tag 'block-5.11-2021-01-16' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / tools / power / x86 / intel-speed-select / isst-config.c
blob5390158cdb401ebbfa7940118827c58382559a2c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Intel Speed Select -- Enumerate and control features
4 * Copyright (c) 2019 Intel Corporation.
5 */
7 #include <linux/isst_if.h>
9 #include "isst.h"
11 struct process_cmd_struct {
12 char *feature;
13 char *command;
14 void (*process_fn)(int arg);
15 int arg;
18 static const char *version_str = "v1.7";
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;
25 static int cpu_model;
26 static int cpu_stepping;
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];
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;
47 static int mbox_delay;
48 static int mbox_retries = 3;
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;
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;
66 struct _cpu_map *cpu_map;
68 struct cpu_topology {
69 short cpu;
70 short core_id;
71 short pkg_id;
72 short die_id;
75 FILE *get_output_file(void)
77 return outf;
80 void debug_printf(const char *format, ...)
82 va_list args;
84 va_start(args, format);
86 if (debug_flag)
87 vprintf(format, args);
89 va_end(args);
93 int is_clx_n_platform(void)
95 if (cpu_model == 0x55)
96 if (cpu_stepping == 0x6 || cpu_stepping == 0x7)
97 return 1;
98 return 0;
101 int is_skx_based_platform(void)
103 if (cpu_model == 0x55)
104 return 1;
106 return 0;
109 static int update_cpu_model(void)
111 unsigned int ebx, ecx, edx;
112 unsigned int fms, family;
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;
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;
128 fp = fopen("/proc/cpuinfo", "r");
129 if (!fp)
130 err(-1, "cannot open /proc/cpuinfo\n");
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;
141 free(line);
142 fclose(fp);
143 return ret;
145 return 0;
148 /* Open a file, and exit on failure */
149 static FILE *fopen_or_exit(const char *path, const char *mode)
151 FILE *filep = fopen(path, mode);
153 if (!filep)
154 err(1, "%s: open failed", path);
156 return filep;
159 /* Parse a file containing a single int */
160 static int parse_int_file(int fatal, const char *fmt, ...)
162 va_list args;
163 char path[PATH_MAX];
164 FILE *filep;
165 int value;
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;
177 if (fscanf(filep, "%d", &value) != 1)
178 err(1, "%s: failed to parse number from file", path);
179 fclose(filep);
181 return value;
184 int cpufreq_sysfs_present(void)
186 DIR *dir;
188 dir = opendir("/sys/devices/system/cpu/cpu0/cpufreq");
189 if (dir) {
190 closedir(dir);
191 return 1;
194 return 0;
197 int out_format_is_json(void)
199 return out_format_json;
202 static int get_stored_topology_info(int cpu, int *core_id, int *pkg_id, int *die_id)
204 const char *pathname = "/var/run/isst_cpu_topology.dat";
205 struct cpu_topology cpu_top;
206 FILE *fp;
207 int ret;
209 fp = fopen(pathname, "rb");
210 if (!fp)
211 return -1;
213 ret = fseek(fp, cpu * sizeof(cpu_top), SEEK_SET);
214 if (ret)
215 goto err_ret;
217 ret = fread(&cpu_top, sizeof(cpu_top), 1, fp);
218 if (ret != 1) {
219 ret = -1;
220 goto err_ret;
223 *pkg_id = cpu_top.pkg_id;
224 *core_id = cpu_top.core_id;
225 *die_id = cpu_top.die_id;
226 ret = 0;
228 err_ret:
229 fclose(fp);
231 return ret;
234 static void store_cpu_topology(void)
236 const char *pathname = "/var/run/isst_cpu_topology.dat";
237 FILE *fp;
238 int i;
240 fp = fopen(pathname, "rb");
241 if (fp) {
242 /* Mapping already exists */
243 fclose(fp);
244 return;
247 fp = fopen(pathname, "wb");
248 if (!fp) {
249 fprintf(stderr, "Can't create file:%s\n", pathname);
250 return;
253 fprintf(stderr, "Caching topology information\n");
255 for (i = 0; i < topo_max_cpus; ++i) {
256 struct cpu_topology cpu_top;
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;
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;
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;
273 cpu_top.cpu = i;
275 if (fwrite(&cpu_top, sizeof(cpu_top), 1, fp) != 1) {
276 fprintf(stderr, "Can't write to:%s\n", pathname);
277 break;
281 fclose(fp);
284 int get_physical_package_id(int cpu)
286 int ret;
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;
294 ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
295 if (!ret)
296 return pkg_id;
299 return ret;
302 int get_physical_core_id(int cpu)
304 int ret;
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;
312 ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
313 if (!ret)
314 return core_id;
317 return ret;
320 int get_physical_die_id(int cpu)
322 int ret;
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;
330 ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
331 if (!ret) {
332 if (die_id < 0)
333 die_id = 0;
335 return die_id;
339 if (ret < 0)
340 ret = 0;
342 return ret;
345 int get_cpufreq_base_freq(int cpu)
347 return parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", cpu);
350 int get_topo_max_cpus(void)
352 return topo_max_cpus;
355 static void set_cpu_online_offline(int cpu, int state)
357 char buffer[128];
358 int fd, ret;
360 snprintf(buffer, sizeof(buffer),
361 "/sys/devices/system/cpu/cpu%d/online", cpu);
363 fd = open(buffer, O_WRONLY);
364 if (fd < 0) {
365 if (!cpu && state) {
366 fprintf(stderr, "This system is not configured for CPU 0 online/offline\n");
367 fprintf(stderr, "Ignoring online request for CPU 0 as this is already online\n");
368 return;
370 err(-1, "%s open failed", buffer);
373 if (state)
374 ret = write(fd, "1\n", 2);
375 else
376 ret = write(fd, "0\n", 2);
378 if (ret == -1)
379 perror("Online/Offline: Operation failed\n");
381 close(fd);
384 #define MAX_PACKAGE_COUNT 8
385 #define MAX_DIE_PER_PACKAGE 2
386 static void for_each_online_package_in_set(void (*callback)(int, void *, void *,
387 void *, void *),
388 void *arg1, void *arg2, void *arg3,
389 void *arg4)
391 int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
392 int pkg_index = 0, i;
394 memset(max_packages, 0xff, sizeof(max_packages));
395 for (i = 0; i < topo_max_cpus; ++i) {
396 int j, online, pkg_id, die_id = 0, skip = 0;
398 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
399 continue;
400 if (i)
401 online = parse_int_file(
402 1, "/sys/devices/system/cpu/cpu%d/online", i);
403 else
404 online =
405 1; /* online entry for CPU 0 needs some special configs */
407 die_id = get_physical_die_id(i);
408 if (die_id < 0)
409 die_id = 0;
411 pkg_id = parse_int_file(0,
412 "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i);
413 if (pkg_id < 0)
414 continue;
416 /* Create an unique id for package, die combination to store */
417 pkg_id = (MAX_PACKAGE_COUNT * pkg_id + die_id);
419 for (j = 0; j < pkg_index; ++j) {
420 if (max_packages[j] == pkg_id) {
421 skip = 1;
422 break;
426 if (!skip && online && callback) {
427 callback(i, arg1, arg2, arg3, arg4);
428 max_packages[pkg_index++] = pkg_id;
433 static void for_each_online_target_cpu_in_set(
434 void (*callback)(int, void *, void *, void *, void *), void *arg1,
435 void *arg2, void *arg3, void *arg4)
437 int i, found = 0;
439 for (i = 0; i < topo_max_cpus; ++i) {
440 int online;
442 if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
443 continue;
444 if (i)
445 online = parse_int_file(
446 1, "/sys/devices/system/cpu/cpu%d/online", i);
447 else
448 online =
449 1; /* online entry for CPU 0 needs some special configs */
451 if (online && callback) {
452 callback(i, arg1, arg2, arg3, arg4);
453 found = 1;
457 if (!found)
458 fprintf(stderr, "No valid CPU in the list\n");
461 #define BITMASK_SIZE 32
462 static void set_max_cpu_num(void)
464 FILE *filep;
465 unsigned long dummy;
466 int i;
468 topo_max_cpus = 0;
469 for (i = 0; i < 256; ++i) {
470 char path[256];
472 snprintf(path, sizeof(path),
473 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", i);
474 filep = fopen(path, "r");
475 if (filep)
476 break;
479 if (!filep) {
480 fprintf(stderr, "Can't get max cpu number\n");
481 exit(0);
484 while (fscanf(filep, "%lx,", &dummy) == 1)
485 topo_max_cpus += BITMASK_SIZE;
486 fclose(filep);
488 debug_printf("max cpus %d\n", topo_max_cpus);
491 size_t alloc_cpu_set(cpu_set_t **cpu_set)
493 cpu_set_t *_cpu_set;
494 size_t size;
496 _cpu_set = CPU_ALLOC((topo_max_cpus + 1));
497 if (_cpu_set == NULL)
498 err(3, "CPU_ALLOC");
499 size = CPU_ALLOC_SIZE((topo_max_cpus + 1));
500 CPU_ZERO_S(size, _cpu_set);
502 *cpu_set = _cpu_set;
503 return size;
506 void free_cpu_set(cpu_set_t *cpu_set)
508 CPU_FREE(cpu_set);
511 static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
512 static long long core_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
513 static void set_cpu_present_cpu_mask(void)
515 size_t size;
516 DIR *dir;
517 int i;
519 size = alloc_cpu_set(&present_cpumask);
520 present_cpumask_size = size;
521 for (i = 0; i < topo_max_cpus; ++i) {
522 char buffer[256];
524 snprintf(buffer, sizeof(buffer),
525 "/sys/devices/system/cpu/cpu%d", i);
526 dir = opendir(buffer);
527 if (dir) {
528 int pkg_id, die_id;
530 CPU_SET_S(i, size, present_cpumask);
531 die_id = get_physical_die_id(i);
532 if (die_id < 0)
533 die_id = 0;
535 pkg_id = get_physical_package_id(i);
536 if (pkg_id < 0) {
537 fprintf(stderr, "Failed to get package id, CPU %d may be offline\n", i);
538 continue;
540 if (pkg_id < MAX_PACKAGE_COUNT &&
541 die_id < MAX_DIE_PER_PACKAGE) {
542 int core_id = get_physical_core_id(i);
544 cpu_cnt[pkg_id][die_id]++;
545 core_mask[pkg_id][die_id] |= (1ULL << core_id);
548 closedir(dir);
552 int get_max_punit_core_id(int pkg_id, int die_id)
554 int max_id = 0;
555 int i;
557 for (i = 0; i < topo_max_cpus; ++i)
559 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
560 continue;
562 if (cpu_map[i].pkg_id == pkg_id &&
563 cpu_map[i].die_id == die_id &&
564 cpu_map[i].punit_cpu_core > max_id)
565 max_id = cpu_map[i].punit_cpu_core;
568 return max_id;
571 int get_cpu_count(int pkg_id, int die_id)
573 if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE)
574 return cpu_cnt[pkg_id][die_id];
576 return 0;
579 static void set_cpu_target_cpu_mask(void)
581 size_t size;
582 int i;
584 size = alloc_cpu_set(&target_cpumask);
585 target_cpumask_size = size;
586 for (i = 0; i < max_target_cpus; ++i) {
587 if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
588 present_cpumask))
589 continue;
591 CPU_SET_S(target_cpus[i], size, target_cpumask);
595 static void create_cpu_map(void)
597 const char *pathname = "/dev/isst_interface";
598 int i, fd = 0;
599 struct isst_if_cpu_maps map;
601 cpu_map = malloc(sizeof(*cpu_map) * topo_max_cpus);
602 if (!cpu_map)
603 err(3, "cpumap");
605 fd = open(pathname, O_RDWR);
606 if (fd < 0)
607 err(-1, "%s open failed", pathname);
609 for (i = 0; i < topo_max_cpus; ++i) {
610 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
611 continue;
613 map.cmd_count = 1;
614 map.cpu_map[0].logical_cpu = i;
616 debug_printf(" map logical_cpu:%d\n",
617 map.cpu_map[0].logical_cpu);
618 if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
619 perror("ISST_IF_GET_PHY_ID");
620 fprintf(outf, "Error: map logical_cpu:%d\n",
621 map.cpu_map[0].logical_cpu);
622 continue;
624 cpu_map[i].core_id = get_physical_core_id(i);
625 cpu_map[i].pkg_id = get_physical_package_id(i);
626 cpu_map[i].die_id = get_physical_die_id(i);
627 cpu_map[i].punit_cpu = map.cpu_map[0].physical_cpu;
628 cpu_map[i].punit_cpu_core = (map.cpu_map[0].physical_cpu >>
629 1); // shift to get core id
631 debug_printf(
632 "map logical_cpu:%d core: %d die:%d pkg:%d punit_cpu:%d punit_core:%d\n",
633 i, cpu_map[i].core_id, cpu_map[i].die_id,
634 cpu_map[i].pkg_id, cpu_map[i].punit_cpu,
635 cpu_map[i].punit_cpu_core);
638 if (fd)
639 close(fd);
642 int find_logical_cpu(int pkg_id, int die_id, int punit_core_id)
644 int i;
646 for (i = 0; i < topo_max_cpus; ++i) {
647 if (cpu_map[i].pkg_id == pkg_id &&
648 cpu_map[i].die_id == die_id &&
649 cpu_map[i].punit_cpu_core == punit_core_id)
650 return i;
653 return -EINVAL;
656 void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask,
657 size_t core_cpumask_size,
658 cpu_set_t *core_cpumask, int *cpu_cnt)
660 int i, cnt = 0;
661 int die_id, pkg_id;
663 *cpu_cnt = 0;
664 die_id = get_physical_die_id(cpu);
665 pkg_id = get_physical_package_id(cpu);
667 for (i = 0; i < 64; ++i) {
668 if (core_mask & BIT_ULL(i)) {
669 int j;
671 for (j = 0; j < topo_max_cpus; ++j) {
672 if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask))
673 continue;
675 if (cpu_map[j].pkg_id == pkg_id &&
676 cpu_map[j].die_id == die_id &&
677 cpu_map[j].punit_cpu_core == i) {
678 CPU_SET_S(j, core_cpumask_size,
679 core_cpumask);
680 ++cnt;
686 *cpu_cnt = cnt;
689 int find_phy_core_num(int logical_cpu)
691 if (logical_cpu < topo_max_cpus)
692 return cpu_map[logical_cpu].punit_cpu_core;
694 return -EINVAL;
697 static int isst_send_mmio_command(unsigned int cpu, unsigned int reg, int write,
698 unsigned int *value)
700 struct isst_if_io_regs io_regs;
701 const char *pathname = "/dev/isst_interface";
702 int cmd;
703 int fd;
705 debug_printf("mmio_cmd cpu:%d reg:%d write:%d\n", cpu, reg, write);
707 fd = open(pathname, O_RDWR);
708 if (fd < 0)
709 err(-1, "%s open failed", pathname);
711 io_regs.req_count = 1;
712 io_regs.io_reg[0].logical_cpu = cpu;
713 io_regs.io_reg[0].reg = reg;
714 cmd = ISST_IF_IO_CMD;
715 if (write) {
716 io_regs.io_reg[0].read_write = 1;
717 io_regs.io_reg[0].value = *value;
718 } else {
719 io_regs.io_reg[0].read_write = 0;
722 if (ioctl(fd, cmd, &io_regs) == -1) {
723 if (errno == ENOTTY) {
724 perror("ISST_IF_IO_COMMAND\n");
725 fprintf(stderr, "Check presence of kernel modules: isst_if_mmio\n");
726 exit(0);
728 fprintf(outf, "Error: mmio_cmd cpu:%d reg:%x read_write:%x\n",
729 cpu, reg, write);
730 } else {
731 if (!write)
732 *value = io_regs.io_reg[0].value;
734 debug_printf(
735 "mmio_cmd response: cpu:%d reg:%x rd_write:%x resp:%x\n",
736 cpu, reg, write, *value);
739 close(fd);
741 return 0;
744 int isst_send_mbox_command(unsigned int cpu, unsigned char command,
745 unsigned char sub_command, unsigned int parameter,
746 unsigned int req_data, unsigned int *resp)
748 const char *pathname = "/dev/isst_interface";
749 int fd, retry;
750 struct isst_if_mbox_cmds mbox_cmds = { 0 };
752 debug_printf(
753 "mbox_send: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
754 cpu, command, sub_command, parameter, req_data);
756 if (!is_skx_based_platform() && command == CONFIG_CLOS &&
757 sub_command != CLOS_PM_QOS_CONFIG) {
758 unsigned int value;
759 int write = 0;
760 int clos_id, core_id, ret = 0;
762 debug_printf("CPU %d\n", cpu);
764 if (parameter & BIT(MBOX_CMD_WRITE_BIT)) {
765 value = req_data;
766 write = 1;
769 switch (sub_command) {
770 case CLOS_PQR_ASSOC:
771 core_id = parameter & 0xff;
772 ret = isst_send_mmio_command(
773 cpu, PQR_ASSOC_OFFSET + core_id * 4, write,
774 &value);
775 if (!ret && !write)
776 *resp = value;
777 break;
778 case CLOS_PM_CLOS:
779 clos_id = parameter & 0x03;
780 ret = isst_send_mmio_command(
781 cpu, PM_CLOS_OFFSET + clos_id * 4, write,
782 &value);
783 if (!ret && !write)
784 *resp = value;
785 break;
786 case CLOS_STATUS:
787 break;
788 default:
789 break;
791 return ret;
794 mbox_cmds.cmd_count = 1;
795 mbox_cmds.mbox_cmd[0].logical_cpu = cpu;
796 mbox_cmds.mbox_cmd[0].command = command;
797 mbox_cmds.mbox_cmd[0].sub_command = sub_command;
798 mbox_cmds.mbox_cmd[0].parameter = parameter;
799 mbox_cmds.mbox_cmd[0].req_data = req_data;
801 if (mbox_delay)
802 usleep(mbox_delay * 1000);
804 fd = open(pathname, O_RDWR);
805 if (fd < 0)
806 err(-1, "%s open failed", pathname);
808 retry = mbox_retries;
810 do {
811 if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
812 if (errno == ENOTTY) {
813 perror("ISST_IF_MBOX_COMMAND\n");
814 fprintf(stderr, "Check presence of kernel modules: isst_if_mbox_pci or isst_if_mbox_msr\n");
815 exit(0);
817 debug_printf(
818 "Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x errorno:%d\n",
819 cpu, command, sub_command, parameter, req_data, errno);
820 --retry;
821 } else {
822 *resp = mbox_cmds.mbox_cmd[0].resp_data;
823 debug_printf(
824 "mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
825 cpu, command, sub_command, parameter, req_data, *resp);
826 break;
828 } while (retry);
830 close(fd);
832 if (!retry) {
833 debug_printf("Failed mbox command even after retries\n");
834 return -1;
837 return 0;
840 int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
841 unsigned long long *req_resp)
843 struct isst_if_msr_cmds msr_cmds;
844 const char *pathname = "/dev/isst_interface";
845 int fd;
847 fd = open(pathname, O_RDWR);
848 if (fd < 0)
849 err(-1, "%s open failed", pathname);
851 msr_cmds.cmd_count = 1;
852 msr_cmds.msr_cmd[0].logical_cpu = cpu;
853 msr_cmds.msr_cmd[0].msr = msr;
854 msr_cmds.msr_cmd[0].read_write = write;
855 if (write)
856 msr_cmds.msr_cmd[0].data = *req_resp;
858 if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
859 perror("ISST_IF_MSR_COMMAND");
860 fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
861 cpu, msr, write);
862 } else {
863 if (!write)
864 *req_resp = msr_cmds.msr_cmd[0].data;
866 debug_printf(
867 "msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
868 cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
871 close(fd);
873 return 0;
876 static int isst_fill_platform_info(void)
878 const char *pathname = "/dev/isst_interface";
879 int fd;
881 fd = open(pathname, O_RDWR);
882 if (fd < 0)
883 err(-1, "%s open failed", pathname);
885 if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) {
886 perror("ISST_IF_GET_PLATFORM_INFO");
887 close(fd);
888 return -1;
891 close(fd);
893 if (isst_platform_info.api_version > supported_api_ver) {
894 printf("Incompatible API versions; Upgrade of tool is required\n");
895 return -1;
897 return 0;
900 static void isst_print_extended_platform_info(void)
902 int cp_state, cp_cap, fact_support = 0, pbf_support = 0;
903 struct isst_pkg_ctdp_level_info ctdp_level;
904 struct isst_pkg_ctdp pkg_dev;
905 int ret, i, j;
906 FILE *filep;
908 for (i = 0; i < 256; ++i) {
909 char path[256];
911 snprintf(path, sizeof(path),
912 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", i);
913 filep = fopen(path, "r");
914 if (filep)
915 break;
918 if (!filep)
919 return;
921 fclose(filep);
923 ret = isst_get_ctdp_levels(i, &pkg_dev);
924 if (ret)
925 return;
927 if (pkg_dev.enabled) {
928 fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is supported\n");
929 } else {
930 fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is not supported\n");
931 fprintf(outf, "Only performance level 0 (base level) is present\n");
934 if (pkg_dev.locked)
935 fprintf(outf, "TDP level change control is locked\n");
936 else
937 fprintf(outf, "TDP level change control is unlocked, max level: %d \n", pkg_dev.levels);
939 for (j = 0; j <= pkg_dev.levels; ++j) {
940 ret = isst_get_ctdp_control(i, j, &ctdp_level);
941 if (ret)
942 continue;
944 if (!fact_support && ctdp_level.fact_support)
945 fact_support = 1;
947 if (!pbf_support && ctdp_level.pbf_support)
948 pbf_support = 1;
951 if (fact_support)
952 fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is supported\n");
953 else
954 fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is not supported\n");
956 if (pbf_support)
957 fprintf(outf, "Intel(R) SST-BF (feature base-freq) is supported\n");
958 else
959 fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n");
961 ret = isst_read_pm_config(i, &cp_state, &cp_cap);
962 if (cp_cap)
963 fprintf(outf, "Intel(R) SST-CP (feature core-power) is supported\n");
964 else
965 fprintf(outf, "Intel(R) SST-CP (feature core-power) is not supported\n");
968 static void isst_print_platform_information(void)
970 struct isst_if_platform_info platform_info;
971 const char *pathname = "/dev/isst_interface";
972 int fd;
974 if (is_clx_n_platform()) {
975 fprintf(stderr, "\nThis option in not supported on this platform\n");
976 exit(0);
979 fd = open(pathname, O_RDWR);
980 if (fd < 0)
981 err(-1, "%s open failed", pathname);
983 if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &platform_info) == -1) {
984 perror("ISST_IF_GET_PLATFORM_INFO");
985 } else {
986 fprintf(outf, "Platform: API version : %d\n",
987 platform_info.api_version);
988 fprintf(outf, "Platform: Driver version : %d\n",
989 platform_info.driver_version);
990 fprintf(outf, "Platform: mbox supported : %d\n",
991 platform_info.mbox_supported);
992 fprintf(outf, "Platform: mmio supported : %d\n",
993 platform_info.mmio_supported);
994 isst_print_extended_platform_info();
997 close(fd);
999 exit(0);
1002 static char *local_str0, *local_str1;
1003 static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1004 void *arg4)
1006 int (*fn_ptr)(int cpu, void *arg);
1007 int ret;
1009 fn_ptr = arg1;
1010 ret = fn_ptr(cpu, arg2);
1011 if (ret)
1012 isst_display_error_info_message(1, "get_tdp_* failed", 0, 0);
1013 else
1014 isst_ctdp_display_core_info(cpu, outf, arg3,
1015 *(unsigned int *)arg4,
1016 local_str0, local_str1);
1019 #define _get_tdp_level(desc, suffix, object, help, str0, str1) \
1020 static void get_tdp_##object(int arg) \
1022 struct isst_pkg_ctdp ctdp; \
1024 if (cmd_help) { \
1025 fprintf(stderr, \
1026 "Print %s [No command arguments are required]\n", \
1027 help); \
1028 exit(0); \
1030 local_str0 = str0; \
1031 local_str1 = str1; \
1032 isst_ctdp_display_information_start(outf); \
1033 if (max_target_cpus) \
1034 for_each_online_target_cpu_in_set( \
1035 exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix, \
1036 &ctdp, desc, &ctdp.object); \
1037 else \
1038 for_each_online_package_in_set(exec_on_get_ctdp_cpu, \
1039 isst_get_ctdp_##suffix, \
1040 &ctdp, desc, \
1041 &ctdp.object); \
1042 isst_ctdp_display_information_end(outf); \
1045 _get_tdp_level("get-config-levels", levels, levels, "Max TDP level", NULL, NULL);
1046 _get_tdp_level("get-config-version", levels, version, "TDP version", NULL, NULL);
1047 _get_tdp_level("get-config-enabled", levels, enabled, "perf-profile enable status", "disabled", "enabled");
1048 _get_tdp_level("get-config-current_level", levels, current_level,
1049 "Current TDP Level", NULL, NULL);
1050 _get_tdp_level("get-lock-status", levels, locked, "TDP lock status", "unlocked", "locked");
1052 struct isst_pkg_ctdp clx_n_pkg_dev;
1054 static int clx_n_get_base_ratio(void)
1056 FILE *fp;
1057 char *begin, *end, *line = NULL;
1058 char number[5];
1059 float value = 0;
1060 size_t n = 0;
1062 fp = fopen("/proc/cpuinfo", "r");
1063 if (!fp)
1064 err(-1, "cannot open /proc/cpuinfo\n");
1066 while (getline(&line, &n, fp) > 0) {
1067 if (strstr(line, "model name")) {
1068 /* this is true for CascadeLake-N */
1069 begin = strstr(line, "@ ") + 2;
1070 end = strstr(line, "GHz");
1071 strncpy(number, begin, end - begin);
1072 value = atof(number) * 10;
1073 break;
1076 free(line);
1077 fclose(fp);
1079 return (int)(value);
1082 static int clx_n_config(int cpu)
1084 int i, ret, pkg_id, die_id;
1085 unsigned long cpu_bf;
1086 struct isst_pkg_ctdp_level_info *ctdp_level;
1087 struct isst_pbf_info *pbf_info;
1089 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1090 pbf_info = &ctdp_level->pbf_info;
1091 ctdp_level->core_cpumask_size =
1092 alloc_cpu_set(&ctdp_level->core_cpumask);
1094 /* find the frequency base ratio */
1095 ctdp_level->tdp_ratio = clx_n_get_base_ratio();
1096 if (ctdp_level->tdp_ratio == 0) {
1097 debug_printf("CLX: cn base ratio is zero\n");
1098 ret = -1;
1099 goto error_ret;
1102 /* find the high and low priority frequencies */
1103 pbf_info->p1_high = 0;
1104 pbf_info->p1_low = ~0;
1106 pkg_id = get_physical_package_id(cpu);
1107 die_id = get_physical_die_id(cpu);
1109 for (i = 0; i < topo_max_cpus; i++) {
1110 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1111 continue;
1113 if (pkg_id != get_physical_package_id(i) ||
1114 die_id != get_physical_die_id(i))
1115 continue;
1117 CPU_SET_S(i, ctdp_level->core_cpumask_size,
1118 ctdp_level->core_cpumask);
1120 cpu_bf = parse_int_file(1,
1121 "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1123 if (cpu_bf > pbf_info->p1_high)
1124 pbf_info->p1_high = cpu_bf;
1125 if (cpu_bf < pbf_info->p1_low)
1126 pbf_info->p1_low = cpu_bf;
1129 if (pbf_info->p1_high == ~0UL) {
1130 debug_printf("CLX: maximum base frequency not set\n");
1131 ret = -1;
1132 goto error_ret;
1135 if (pbf_info->p1_low == 0) {
1136 debug_printf("CLX: minimum base frequency not set\n");
1137 ret = -1;
1138 goto error_ret;
1141 /* convert frequencies back to ratios */
1142 pbf_info->p1_high = pbf_info->p1_high / 100000;
1143 pbf_info->p1_low = pbf_info->p1_low / 100000;
1145 /* create high priority cpu mask */
1146 pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
1147 for (i = 0; i < topo_max_cpus; i++) {
1148 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1149 continue;
1151 if (pkg_id != get_physical_package_id(i) ||
1152 die_id != get_physical_die_id(i))
1153 continue;
1155 cpu_bf = parse_int_file(1,
1156 "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1158 cpu_bf = cpu_bf / 100000;
1159 if (cpu_bf == pbf_info->p1_high)
1160 CPU_SET_S(i, pbf_info->core_cpumask_size,
1161 pbf_info->core_cpumask);
1164 /* extra ctdp & pbf struct parameters */
1165 ctdp_level->processed = 1;
1166 ctdp_level->pbf_support = 1; /* PBF is always supported and enabled */
1167 ctdp_level->pbf_enabled = 1;
1168 ctdp_level->fact_support = 0; /* FACT is never supported */
1169 ctdp_level->fact_enabled = 0;
1171 return 0;
1173 error_ret:
1174 free_cpu_set(ctdp_level->core_cpumask);
1175 return ret;
1178 static void dump_clx_n_config_for_cpu(int cpu, void *arg1, void *arg2,
1179 void *arg3, void *arg4)
1181 int ret;
1183 if (tdp_level != 0xff && tdp_level != 0) {
1184 isst_display_error_info_message(1, "Invalid level", 1, tdp_level);
1185 exit(0);
1188 ret = clx_n_config(cpu);
1189 if (ret) {
1190 debug_printf("clx_n_config failed");
1191 } else {
1192 struct isst_pkg_ctdp_level_info *ctdp_level;
1193 struct isst_pbf_info *pbf_info;
1195 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1196 pbf_info = &ctdp_level->pbf_info;
1197 clx_n_pkg_dev.processed = 1;
1198 isst_ctdp_display_information(cpu, outf, tdp_level, &clx_n_pkg_dev);
1199 free_cpu_set(ctdp_level->core_cpumask);
1200 free_cpu_set(pbf_info->core_cpumask);
1204 static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2,
1205 void *arg3, void *arg4)
1207 struct isst_pkg_ctdp pkg_dev;
1208 int ret;
1210 memset(&pkg_dev, 0, sizeof(pkg_dev));
1211 ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev);
1212 if (ret) {
1213 isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, cpu);
1214 isst_ctdp_display_information_end(outf);
1215 exit(1);
1216 } else {
1217 isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev);
1218 isst_get_process_ctdp_complete(cpu, &pkg_dev);
1222 static void dump_isst_config(int arg)
1224 void *fn;
1226 if (cmd_help) {
1227 fprintf(stderr,
1228 "Print Intel(R) Speed Select Technology Performance profile configuration\n");
1229 fprintf(stderr,
1230 "including base frequency and turbo frequency configurations\n");
1231 fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
1232 fprintf(stderr,
1233 "\tIf no arguments, dump information for all TDP levels\n");
1234 exit(0);
1237 if (!is_clx_n_platform())
1238 fn = dump_isst_config_for_cpu;
1239 else
1240 fn = dump_clx_n_config_for_cpu;
1242 isst_ctdp_display_information_start(outf);
1244 if (max_target_cpus)
1245 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1246 else
1247 for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL);
1249 isst_ctdp_display_information_end(outf);
1252 static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1253 void *arg4)
1255 int ret;
1257 ret = isst_set_tdp_level(cpu, tdp_level);
1258 if (ret) {
1259 isst_display_error_info_message(1, "Set TDP level failed", 0, 0);
1260 isst_ctdp_display_information_end(outf);
1261 exit(1);
1262 } else {
1263 isst_display_result(cpu, outf, "perf-profile", "set_tdp_level",
1264 ret);
1265 if (force_online_offline) {
1266 struct isst_pkg_ctdp_level_info ctdp_level;
1267 int pkg_id = get_physical_package_id(cpu);
1268 int die_id = get_physical_die_id(cpu);
1270 fprintf(stderr, "Option is set to online/offline\n");
1271 ctdp_level.core_cpumask_size =
1272 alloc_cpu_set(&ctdp_level.core_cpumask);
1273 ret = isst_get_coremask_info(cpu, tdp_level, &ctdp_level);
1274 if (ret) {
1275 isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
1276 return;
1278 if (ctdp_level.cpu_count) {
1279 int i, max_cpus = get_topo_max_cpus();
1280 for (i = 0; i < max_cpus; ++i) {
1281 if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
1282 continue;
1283 if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
1284 fprintf(stderr, "online cpu %d\n", i);
1285 set_cpu_online_offline(i, 1);
1286 } else {
1287 fprintf(stderr, "offline cpu %d\n", i);
1288 set_cpu_online_offline(i, 0);
1296 static void set_tdp_level(int arg)
1298 if (cmd_help) {
1299 fprintf(stderr, "Set Config TDP level\n");
1300 fprintf(stderr,
1301 "\t Arguments: -l|--level : Specify tdp level\n");
1302 fprintf(stderr,
1303 "\t Optional Arguments: -o | online : online/offline for the tdp level\n");
1304 fprintf(stderr,
1305 "\t online/offline operation has limitations, refer to Linux hotplug documentation\n");
1306 exit(0);
1309 if (tdp_level == 0xff) {
1310 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1311 exit(1);
1313 isst_ctdp_display_information_start(outf);
1314 if (max_target_cpus)
1315 for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
1316 NULL, NULL, NULL);
1317 else
1318 for_each_online_package_in_set(set_tdp_level_for_cpu, NULL,
1319 NULL, NULL, NULL);
1320 isst_ctdp_display_information_end(outf);
1323 static void clx_n_dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2,
1324 void *arg3, void *arg4)
1326 int ret;
1328 ret = clx_n_config(cpu);
1329 if (ret) {
1330 isst_display_error_info_message(1, "clx_n_config failed", 0, 0);
1331 } else {
1332 struct isst_pkg_ctdp_level_info *ctdp_level;
1333 struct isst_pbf_info *pbf_info;
1335 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1336 pbf_info = &ctdp_level->pbf_info;
1337 isst_pbf_display_information(cpu, outf, tdp_level, pbf_info);
1338 free_cpu_set(ctdp_level->core_cpumask);
1339 free_cpu_set(pbf_info->core_cpumask);
1343 static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1344 void *arg4)
1346 struct isst_pbf_info pbf_info;
1347 int ret;
1349 ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info);
1350 if (ret) {
1351 isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level);
1352 isst_ctdp_display_information_end(outf);
1353 exit(1);
1354 } else {
1355 isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info);
1356 isst_get_pbf_info_complete(&pbf_info);
1360 static void dump_pbf_config(int arg)
1362 void *fn;
1364 if (cmd_help) {
1365 fprintf(stderr,
1366 "Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
1367 fprintf(stderr,
1368 "\tArguments: -l|--level : Specify tdp level\n");
1369 exit(0);
1372 if (tdp_level == 0xff) {
1373 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1374 exit(1);
1377 if (!is_clx_n_platform())
1378 fn = dump_pbf_config_for_cpu;
1379 else
1380 fn = clx_n_dump_pbf_config_for_cpu;
1382 isst_ctdp_display_information_start(outf);
1384 if (max_target_cpus)
1385 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1386 else
1387 for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL);
1389 isst_ctdp_display_information_end(outf);
1392 static int set_clos_param(int cpu, int clos, int epp, int wt, int min, int max)
1394 struct isst_clos_config clos_config;
1395 int ret;
1397 ret = isst_pm_get_clos(cpu, clos, &clos_config);
1398 if (ret) {
1399 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
1400 return ret;
1402 clos_config.clos_min = min;
1403 clos_config.clos_max = max;
1404 clos_config.epp = epp;
1405 clos_config.clos_prop_prio = wt;
1406 ret = isst_set_clos(cpu, clos, &clos_config);
1407 if (ret) {
1408 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
1409 return ret;
1412 return 0;
1415 static int set_cpufreq_scaling_min_max(int cpu, int max, int freq)
1417 char buffer[128], freq_str[16];
1418 int fd, ret, len;
1420 if (max)
1421 snprintf(buffer, sizeof(buffer),
1422 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1423 else
1424 snprintf(buffer, sizeof(buffer),
1425 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1427 fd = open(buffer, O_WRONLY);
1428 if (fd < 0)
1429 return fd;
1431 snprintf(freq_str, sizeof(freq_str), "%d", freq);
1432 len = strlen(freq_str);
1433 ret = write(fd, freq_str, len);
1434 if (ret == -1) {
1435 close(fd);
1436 return ret;
1438 close(fd);
1440 return 0;
1443 static int set_clx_pbf_cpufreq_scaling_min_max(int cpu)
1445 struct isst_pkg_ctdp_level_info *ctdp_level;
1446 struct isst_pbf_info *pbf_info;
1447 int i, pkg_id, die_id, freq, freq_high, freq_low;
1448 int ret;
1450 ret = clx_n_config(cpu);
1451 if (ret) {
1452 debug_printf("cpufreq_scaling_min_max failed for CLX");
1453 return ret;
1456 ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1457 pbf_info = &ctdp_level->pbf_info;
1458 freq_high = pbf_info->p1_high * 100000;
1459 freq_low = pbf_info->p1_low * 100000;
1461 pkg_id = get_physical_package_id(cpu);
1462 die_id = get_physical_die_id(cpu);
1463 for (i = 0; i < get_topo_max_cpus(); ++i) {
1464 if (pkg_id != get_physical_package_id(i) ||
1465 die_id != get_physical_die_id(i))
1466 continue;
1468 if (CPU_ISSET_S(i, pbf_info->core_cpumask_size,
1469 pbf_info->core_cpumask))
1470 freq = freq_high;
1471 else
1472 freq = freq_low;
1474 set_cpufreq_scaling_min_max(i, 1, freq);
1475 set_cpufreq_scaling_min_max(i, 0, freq);
1478 return 0;
1481 static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, int scaling_max)
1483 char buffer[128], min_freq[16];
1484 int fd, ret, len;
1486 if (!CPU_ISSET_S(cpu, present_cpumask_size, present_cpumask))
1487 return -1;
1489 if (cpuinfo_max)
1490 snprintf(buffer, sizeof(buffer),
1491 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu);
1492 else
1493 snprintf(buffer, sizeof(buffer),
1494 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpu);
1496 fd = open(buffer, O_RDONLY);
1497 if (fd < 0)
1498 return fd;
1500 len = read(fd, min_freq, sizeof(min_freq));
1501 close(fd);
1503 if (len < 0)
1504 return len;
1506 if (scaling_max)
1507 snprintf(buffer, sizeof(buffer),
1508 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1509 else
1510 snprintf(buffer, sizeof(buffer),
1511 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1513 fd = open(buffer, O_WRONLY);
1514 if (fd < 0)
1515 return fd;
1517 len = strlen(min_freq);
1518 ret = write(fd, min_freq, len);
1519 if (ret == -1) {
1520 close(fd);
1521 return ret;
1523 close(fd);
1525 return 0;
1528 static void set_scaling_min_to_cpuinfo_max(int cpu)
1530 int i, pkg_id, die_id;
1532 pkg_id = get_physical_package_id(cpu);
1533 die_id = get_physical_die_id(cpu);
1534 for (i = 0; i < get_topo_max_cpus(); ++i) {
1535 if (pkg_id != get_physical_package_id(i) ||
1536 die_id != get_physical_die_id(i))
1537 continue;
1539 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0);
1543 static void set_scaling_min_to_cpuinfo_min(int cpu)
1545 int i, pkg_id, die_id;
1547 pkg_id = get_physical_package_id(cpu);
1548 die_id = get_physical_die_id(cpu);
1549 for (i = 0; i < get_topo_max_cpus(); ++i) {
1550 if (pkg_id != get_physical_package_id(i) ||
1551 die_id != get_physical_die_id(i))
1552 continue;
1554 set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0);
1558 static void set_scaling_max_to_cpuinfo_max(int cpu)
1560 int i, pkg_id, die_id;
1562 pkg_id = get_physical_package_id(cpu);
1563 die_id = get_physical_die_id(cpu);
1564 for (i = 0; i < get_topo_max_cpus(); ++i) {
1565 if (pkg_id != get_physical_package_id(i) ||
1566 die_id != get_physical_die_id(i))
1567 continue;
1569 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1);
1573 static int set_core_priority_and_min(int cpu, int mask_size,
1574 cpu_set_t *cpu_mask, int min_high,
1575 int min_low)
1577 int pkg_id, die_id, ret, i;
1579 if (!CPU_COUNT_S(mask_size, cpu_mask))
1580 return -1;
1582 ret = set_clos_param(cpu, 0, 0, 0, min_high, 0xff);
1583 if (ret)
1584 return ret;
1586 ret = set_clos_param(cpu, 1, 15, 15, min_low, 0xff);
1587 if (ret)
1588 return ret;
1590 ret = set_clos_param(cpu, 2, 15, 15, min_low, 0xff);
1591 if (ret)
1592 return ret;
1594 ret = set_clos_param(cpu, 3, 15, 15, min_low, 0xff);
1595 if (ret)
1596 return ret;
1598 pkg_id = get_physical_package_id(cpu);
1599 die_id = get_physical_die_id(cpu);
1600 for (i = 0; i < get_topo_max_cpus(); ++i) {
1601 int clos;
1603 if (pkg_id != get_physical_package_id(i) ||
1604 die_id != get_physical_die_id(i))
1605 continue;
1607 if (CPU_ISSET_S(i, mask_size, cpu_mask))
1608 clos = 0;
1609 else
1610 clos = 3;
1612 debug_printf("Associate cpu: %d clos: %d\n", i, clos);
1613 ret = isst_clos_associate(i, clos);
1614 if (ret) {
1615 isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0);
1616 return ret;
1620 return 0;
1623 static int set_pbf_core_power(int cpu)
1625 struct isst_pbf_info pbf_info;
1626 struct isst_pkg_ctdp pkg_dev;
1627 int ret;
1629 ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1630 if (ret) {
1631 debug_printf("isst_get_ctdp_levels failed");
1632 return ret;
1634 debug_printf("Current_level: %d\n", pkg_dev.current_level);
1636 ret = isst_get_pbf_info(cpu, pkg_dev.current_level, &pbf_info);
1637 if (ret) {
1638 debug_printf("isst_get_pbf_info failed");
1639 return ret;
1641 debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high,
1642 pbf_info.p1_low);
1644 ret = set_core_priority_and_min(cpu, pbf_info.core_cpumask_size,
1645 pbf_info.core_cpumask,
1646 pbf_info.p1_high, pbf_info.p1_low);
1647 if (ret) {
1648 debug_printf("set_core_priority_and_min failed");
1649 return ret;
1652 ret = isst_pm_qos_config(cpu, 1, 1);
1653 if (ret) {
1654 debug_printf("isst_pm_qos_config failed");
1655 return ret;
1658 return 0;
1661 static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1662 void *arg4)
1664 struct isst_pkg_ctdp_level_info ctdp_level;
1665 struct isst_pkg_ctdp pkg_dev;
1666 int ret;
1667 int status = *(int *)arg4;
1669 if (is_clx_n_platform()) {
1670 ret = 0;
1671 if (status) {
1672 set_clx_pbf_cpufreq_scaling_min_max(cpu);
1674 } else {
1675 set_scaling_max_to_cpuinfo_max(cpu);
1676 set_scaling_min_to_cpuinfo_min(cpu);
1678 goto disp_result;
1681 ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1682 if (ret) {
1683 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
1684 goto disp_result;
1687 ret = isst_get_ctdp_control(cpu, pkg_dev.current_level, &ctdp_level);
1688 if (ret) {
1689 isst_display_error_info_message(1, "Failed to get current level", 0, 0);
1690 goto disp_result;
1693 if (!ctdp_level.pbf_support) {
1694 isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, pkg_dev.current_level);
1695 ret = -1;
1696 goto disp_result;
1699 if (auto_mode && status) {
1700 ret = set_pbf_core_power(cpu);
1701 if (ret)
1702 goto disp_result;
1705 ret = isst_set_pbf_fact_status(cpu, 1, status);
1706 if (ret) {
1707 debug_printf("isst_set_pbf_fact_status failed");
1708 if (auto_mode)
1709 isst_pm_qos_config(cpu, 0, 0);
1710 } else {
1711 if (auto_mode) {
1712 if (status)
1713 set_scaling_min_to_cpuinfo_max(cpu);
1714 else
1715 set_scaling_min_to_cpuinfo_min(cpu);
1719 if (auto_mode && !status)
1720 isst_pm_qos_config(cpu, 0, 1);
1722 disp_result:
1723 if (status)
1724 isst_display_result(cpu, outf, "base-freq", "enable",
1725 ret);
1726 else
1727 isst_display_result(cpu, outf, "base-freq", "disable",
1728 ret);
1731 static void set_pbf_enable(int arg)
1733 int enable = arg;
1735 if (cmd_help) {
1736 if (enable) {
1737 fprintf(stderr,
1738 "Enable Intel Speed Select Technology base frequency feature\n");
1739 if (is_clx_n_platform()) {
1740 fprintf(stderr,
1741 "\tOn this platform this command doesn't enable feature in the hardware.\n");
1742 fprintf(stderr,
1743 "\tIt updates the cpufreq scaling_min_freq to match cpufreq base_frequency.\n");
1744 exit(0);
1747 fprintf(stderr,
1748 "\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n");
1749 } else {
1751 if (is_clx_n_platform()) {
1752 fprintf(stderr,
1753 "\tOn this platform this command doesn't disable feature in the hardware.\n");
1754 fprintf(stderr,
1755 "\tIt updates the cpufreq scaling_min_freq to match cpuinfo_min_freq\n");
1756 exit(0);
1758 fprintf(stderr,
1759 "Disable Intel Speed Select Technology base frequency feature\n");
1760 fprintf(stderr,
1761 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
1763 exit(0);
1766 isst_ctdp_display_information_start(outf);
1767 if (max_target_cpus)
1768 for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
1769 NULL, &enable);
1770 else
1771 for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
1772 NULL, &enable);
1773 isst_ctdp_display_information_end(outf);
1776 static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2,
1777 void *arg3, void *arg4)
1779 struct isst_fact_info fact_info;
1780 int ret;
1782 ret = isst_get_fact_info(cpu, tdp_level, fact_bucket, &fact_info);
1783 if (ret) {
1784 isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level);
1785 isst_ctdp_display_information_end(outf);
1786 exit(1);
1787 } else {
1788 isst_fact_display_information(cpu, outf, tdp_level, fact_bucket,
1789 fact_avx, &fact_info);
1793 static void dump_fact_config(int arg)
1795 if (cmd_help) {
1796 fprintf(stderr,
1797 "Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
1798 fprintf(stderr,
1799 "\tArguments: -l|--level : Specify tdp level\n");
1800 fprintf(stderr,
1801 "\tArguments: -b|--bucket : Bucket index to dump\n");
1802 fprintf(stderr,
1803 "\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
1804 exit(0);
1807 if (tdp_level == 0xff) {
1808 isst_display_error_info_message(1, "Invalid command: specify tdp_level\n", 0, 0);
1809 exit(1);
1812 isst_ctdp_display_information_start(outf);
1813 if (max_target_cpus)
1814 for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
1815 NULL, NULL, NULL, NULL);
1816 else
1817 for_each_online_package_in_set(dump_fact_config_for_cpu, NULL,
1818 NULL, NULL, NULL);
1819 isst_ctdp_display_information_end(outf);
1822 static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1823 void *arg4)
1825 struct isst_pkg_ctdp_level_info ctdp_level;
1826 struct isst_pkg_ctdp pkg_dev;
1827 int ret;
1828 int status = *(int *)arg4;
1830 ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1831 if (ret) {
1832 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
1833 goto disp_results;
1836 ret = isst_get_ctdp_control(cpu, pkg_dev.current_level, &ctdp_level);
1837 if (ret) {
1838 isst_display_error_info_message(1, "Failed to get current level", 0, 0);
1839 goto disp_results;
1842 if (!ctdp_level.fact_support) {
1843 isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, pkg_dev.current_level);
1844 ret = -1;
1845 goto disp_results;
1848 if (status) {
1849 ret = isst_pm_qos_config(cpu, 1, 1);
1850 if (ret)
1851 goto disp_results;
1854 ret = isst_set_pbf_fact_status(cpu, 0, status);
1855 if (ret) {
1856 debug_printf("isst_set_pbf_fact_status failed");
1857 if (auto_mode)
1858 isst_pm_qos_config(cpu, 0, 0);
1860 goto disp_results;
1863 /* Set TRL */
1864 if (status) {
1865 struct isst_pkg_ctdp pkg_dev;
1867 ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1868 if (!ret)
1869 ret = isst_set_trl(cpu, fact_trl);
1870 if (ret && auto_mode)
1871 isst_pm_qos_config(cpu, 0, 0);
1872 } else {
1873 if (auto_mode)
1874 isst_pm_qos_config(cpu, 0, 0);
1877 disp_results:
1878 if (status) {
1879 isst_display_result(cpu, outf, "turbo-freq", "enable", ret);
1880 if (ret)
1881 fact_enable_fail = ret;
1882 } else {
1883 /* Since we modified TRL during Fact enable, restore it */
1884 isst_set_trl_from_current_tdp(cpu, fact_trl);
1885 isst_display_result(cpu, outf, "turbo-freq", "disable", ret);
1889 static void set_fact_enable(int arg)
1891 int i, ret, enable = arg;
1893 if (cmd_help) {
1894 if (enable) {
1895 fprintf(stderr,
1896 "Enable Intel Speed Select Technology Turbo frequency feature\n");
1897 fprintf(stderr,
1898 "Optional: -t|--trl : Specify turbo ratio limit\n");
1899 fprintf(stderr,
1900 "\tOptional Arguments: -a|--auto : Designate specified target CPUs with");
1901 fprintf(stderr,
1902 "-C|--cpu option as as high priority using core-power feature\n");
1903 } else {
1904 fprintf(stderr,
1905 "Disable Intel Speed Select Technology turbo frequency feature\n");
1906 fprintf(stderr,
1907 "Optional: -t|--trl : Specify turbo ratio limit\n");
1908 fprintf(stderr,
1909 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
1911 exit(0);
1914 isst_ctdp_display_information_start(outf);
1915 if (max_target_cpus)
1916 for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
1917 NULL, &enable);
1918 else
1919 for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
1920 NULL, &enable);
1921 isst_ctdp_display_information_end(outf);
1923 if (!fact_enable_fail && enable && auto_mode) {
1925 * When we adjust CLOS param, we have to set for siblings also.
1926 * So for the each user specified CPU, also add the sibling
1927 * in the present_cpu_mask.
1929 for (i = 0; i < get_topo_max_cpus(); ++i) {
1930 char buffer[128], sibling_list[128], *cpu_str;
1931 int fd, len;
1933 if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
1934 continue;
1936 snprintf(buffer, sizeof(buffer),
1937 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i);
1939 fd = open(buffer, O_RDONLY);
1940 if (fd < 0)
1941 continue;
1943 len = read(fd, sibling_list, sizeof(sibling_list));
1944 close(fd);
1946 if (len < 0)
1947 continue;
1949 cpu_str = strtok(sibling_list, ",");
1950 while (cpu_str != NULL) {
1951 int cpu;
1953 sscanf(cpu_str, "%d", &cpu);
1954 CPU_SET_S(cpu, target_cpumask_size, target_cpumask);
1955 cpu_str = strtok(NULL, ",");
1959 for (i = 0; i < get_topo_max_cpus(); ++i) {
1960 int clos;
1962 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1963 continue;
1965 ret = set_clos_param(i, 0, 0, 0, 0, 0xff);
1966 if (ret)
1967 goto error_disp;
1969 ret = set_clos_param(i, 1, 15, 15, 0, 0xff);
1970 if (ret)
1971 goto error_disp;
1973 ret = set_clos_param(i, 2, 15, 15, 0, 0xff);
1974 if (ret)
1975 goto error_disp;
1977 ret = set_clos_param(i, 3, 15, 15, 0, 0xff);
1978 if (ret)
1979 goto error_disp;
1981 if (CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
1982 clos = 0;
1983 else
1984 clos = 3;
1986 debug_printf("Associate cpu: %d clos: %d\n", i, clos);
1987 ret = isst_clos_associate(i, clos);
1988 if (ret)
1989 goto error_disp;
1991 isst_display_result(-1, outf, "turbo-freq --auto", "enable", 0);
1994 return;
1996 error_disp:
1997 isst_display_result(i, outf, "turbo-freq --auto", "enable", ret);
2001 static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
2002 void *arg4)
2004 int ret;
2005 int status = *(int *)arg4;
2007 if (is_skx_based_platform())
2008 clos_priority_type = 1;
2010 ret = isst_pm_qos_config(cpu, status, clos_priority_type);
2011 if (ret)
2012 isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0);
2014 if (status)
2015 isst_display_result(cpu, outf, "core-power", "enable",
2016 ret);
2017 else
2018 isst_display_result(cpu, outf, "core-power", "disable",
2019 ret);
2022 static void set_clos_enable(int arg)
2024 int enable = arg;
2026 if (cmd_help) {
2027 if (enable) {
2028 fprintf(stderr,
2029 "Enable core-power for a package/die\n");
2030 if (!is_skx_based_platform()) {
2031 fprintf(stderr,
2032 "\tClos Enable: Specify priority type with [--priority|-p]\n");
2033 fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
2035 } else {
2036 fprintf(stderr,
2037 "Disable core-power: [No command arguments are required]\n");
2039 exit(0);
2042 if (enable && cpufreq_sysfs_present()) {
2043 fprintf(stderr,
2044 "cpufreq subsystem and core-power enable will interfere with each other!\n");
2047 isst_ctdp_display_information_start(outf);
2048 if (max_target_cpus)
2049 for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
2050 NULL, NULL, &enable);
2051 else
2052 for_each_online_package_in_set(enable_clos_qos_config, NULL,
2053 NULL, NULL, &enable);
2054 isst_ctdp_display_information_end(outf);
2057 static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2,
2058 void *arg3, void *arg4)
2060 struct isst_clos_config clos_config;
2061 int ret;
2063 ret = isst_pm_get_clos(cpu, current_clos, &clos_config);
2064 if (ret)
2065 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
2066 else
2067 isst_clos_display_information(cpu, outf, current_clos,
2068 &clos_config);
2071 static void dump_clos_config(int arg)
2073 if (cmd_help) {
2074 fprintf(stderr,
2075 "Print Intel Speed Select Technology core power configuration\n");
2076 fprintf(stderr,
2077 "\tArguments: [-c | --clos]: Specify clos id\n");
2078 exit(0);
2080 if (current_clos < 0 || current_clos > 3) {
2081 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2082 isst_ctdp_display_information_end(outf);
2083 exit(0);
2086 isst_ctdp_display_information_start(outf);
2087 if (max_target_cpus)
2088 for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
2089 NULL, NULL, NULL, NULL);
2090 else
2091 for_each_online_package_in_set(dump_clos_config_for_cpu, NULL,
2092 NULL, NULL, NULL);
2093 isst_ctdp_display_information_end(outf);
2096 static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2097 void *arg4)
2099 int enable, ret, prio_type;
2101 ret = isst_clos_get_clos_information(cpu, &enable, &prio_type);
2102 if (ret)
2103 isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0);
2104 else {
2105 int cp_state, cp_cap;
2107 isst_read_pm_config(cpu, &cp_state, &cp_cap);
2108 isst_clos_display_clos_information(cpu, outf, enable, prio_type,
2109 cp_state, cp_cap);
2113 static void dump_clos_info(int arg)
2115 if (cmd_help) {
2116 fprintf(stderr,
2117 "Print Intel Speed Select Technology core power information\n");
2118 fprintf(stderr, "\t Optionally specify targeted cpu id with [--cpu|-c]\n");
2119 exit(0);
2122 isst_ctdp_display_information_start(outf);
2123 if (max_target_cpus)
2124 for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL,
2125 NULL, NULL, NULL);
2126 else
2127 for_each_online_package_in_set(get_clos_info_for_cpu, NULL,
2128 NULL, NULL, NULL);
2129 isst_ctdp_display_information_end(outf);
2133 static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2134 void *arg4)
2136 struct isst_clos_config clos_config;
2137 int ret;
2139 clos_config.pkg_id = get_physical_package_id(cpu);
2140 clos_config.die_id = get_physical_die_id(cpu);
2142 clos_config.epp = clos_epp;
2143 clos_config.clos_prop_prio = clos_prop_prio;
2144 clos_config.clos_min = clos_min;
2145 clos_config.clos_max = clos_max;
2146 clos_config.clos_desired = clos_desired;
2147 ret = isst_set_clos(cpu, current_clos, &clos_config);
2148 if (ret)
2149 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
2150 else
2151 isst_display_result(cpu, outf, "core-power", "config", ret);
2154 static void set_clos_config(int arg)
2156 if (cmd_help) {
2157 fprintf(stderr,
2158 "Set core-power configuration for one of the four clos ids\n");
2159 fprintf(stderr,
2160 "\tSpecify targeted clos id with [--clos|-c]\n");
2161 if (!is_skx_based_platform()) {
2162 fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
2163 fprintf(stderr,
2164 "\tSpecify clos Proportional Priority [--weight|-w]\n");
2166 fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n");
2167 fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n");
2168 exit(0);
2171 if (current_clos < 0 || current_clos > 3) {
2172 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2173 exit(0);
2175 if (!is_skx_based_platform() && (clos_epp < 0 || clos_epp > 0x0F)) {
2176 fprintf(stderr, "clos epp is not specified or invalid, default: 0\n");
2177 clos_epp = 0;
2179 if (!is_skx_based_platform() && (clos_prop_prio < 0 || clos_prop_prio > 0x0F)) {
2180 fprintf(stderr,
2181 "clos frequency weight is not specified or invalid, default: 0\n");
2182 clos_prop_prio = 0;
2184 if (clos_min < 0) {
2185 fprintf(stderr, "clos min is not specified, default: 0\n");
2186 clos_min = 0;
2188 if (clos_max < 0) {
2189 fprintf(stderr, "clos max is not specified, default: Max frequency (ratio 0xff)\n");
2190 clos_max = 0xff;
2192 if (clos_desired) {
2193 fprintf(stderr, "clos desired is not supported on this platform\n");
2194 clos_desired = 0x00;
2197 isst_ctdp_display_information_start(outf);
2198 if (max_target_cpus)
2199 for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
2200 NULL, NULL, NULL);
2201 else
2202 for_each_online_package_in_set(set_clos_config_for_cpu, NULL,
2203 NULL, NULL, NULL);
2204 isst_ctdp_display_information_end(outf);
2207 static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2208 void *arg4)
2210 int ret;
2212 ret = isst_clos_associate(cpu, current_clos);
2213 if (ret)
2214 debug_printf("isst_clos_associate failed");
2215 else
2216 isst_display_result(cpu, outf, "core-power", "assoc", ret);
2219 static void set_clos_assoc(int arg)
2221 if (cmd_help) {
2222 fprintf(stderr, "Associate a clos id to a CPU\n");
2223 fprintf(stderr,
2224 "\tSpecify targeted clos id with [--clos|-c]\n");
2225 fprintf(stderr,
2226 "\tFor example to associate clos 1 to CPU 0: issue\n");
2227 fprintf(stderr,
2228 "\tintel-speed-select --cpu 0 core-power assoc --clos 1\n");
2229 exit(0);
2232 if (current_clos < 0 || current_clos > 3) {
2233 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2234 exit(0);
2236 if (max_target_cpus)
2237 for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
2238 NULL, NULL, NULL);
2239 else {
2240 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2244 static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2245 void *arg4)
2247 int clos, ret;
2249 ret = isst_clos_get_assoc_status(cpu, &clos);
2250 if (ret)
2251 isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0);
2252 else
2253 isst_clos_display_assoc_information(cpu, outf, clos);
2256 static void get_clos_assoc(int arg)
2258 if (cmd_help) {
2259 fprintf(stderr, "Get associate clos id to a CPU\n");
2260 fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
2261 exit(0);
2264 if (!max_target_cpus) {
2265 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2266 exit(0);
2269 isst_ctdp_display_information_start(outf);
2270 for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
2271 NULL, NULL, NULL);
2272 isst_ctdp_display_information_end(outf);
2275 static struct process_cmd_struct clx_n_cmds[] = {
2276 { "perf-profile", "info", dump_isst_config, 0 },
2277 { "base-freq", "info", dump_pbf_config, 0 },
2278 { "base-freq", "enable", set_pbf_enable, 1 },
2279 { "base-freq", "disable", set_pbf_enable, 0 },
2280 { NULL, NULL, NULL, 0 }
2283 static struct process_cmd_struct isst_cmds[] = {
2284 { "perf-profile", "get-lock-status", get_tdp_locked, 0 },
2285 { "perf-profile", "get-config-levels", get_tdp_levels, 0 },
2286 { "perf-profile", "get-config-version", get_tdp_version, 0 },
2287 { "perf-profile", "get-config-enabled", get_tdp_enabled, 0 },
2288 { "perf-profile", "get-config-current-level", get_tdp_current_level,
2289 0 },
2290 { "perf-profile", "set-config-level", set_tdp_level, 0 },
2291 { "perf-profile", "info", dump_isst_config, 0 },
2292 { "base-freq", "info", dump_pbf_config, 0 },
2293 { "base-freq", "enable", set_pbf_enable, 1 },
2294 { "base-freq", "disable", set_pbf_enable, 0 },
2295 { "turbo-freq", "info", dump_fact_config, 0 },
2296 { "turbo-freq", "enable", set_fact_enable, 1 },
2297 { "turbo-freq", "disable", set_fact_enable, 0 },
2298 { "core-power", "info", dump_clos_info, 0 },
2299 { "core-power", "enable", set_clos_enable, 1 },
2300 { "core-power", "disable", set_clos_enable, 0 },
2301 { "core-power", "config", set_clos_config, 0 },
2302 { "core-power", "get-config", dump_clos_config, 0 },
2303 { "core-power", "assoc", set_clos_assoc, 0 },
2304 { "core-power", "get-assoc", get_clos_assoc, 0 },
2305 { NULL, NULL, NULL }
2309 * parse cpuset with following syntax
2310 * 1,2,4..6,8-10 and set bits in cpu_subset
2312 void parse_cpu_command(char *optarg)
2314 unsigned int start, end;
2315 char *next;
2317 next = optarg;
2319 while (next && *next) {
2320 if (*next == '-') /* no negative cpu numbers */
2321 goto error;
2323 start = strtoul(next, &next, 10);
2325 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2326 target_cpus[max_target_cpus++] = start;
2328 if (*next == '\0')
2329 break;
2331 if (*next == ',') {
2332 next += 1;
2333 continue;
2336 if (*next == '-') {
2337 next += 1; /* start range */
2338 } else if (*next == '.') {
2339 next += 1;
2340 if (*next == '.')
2341 next += 1; /* start range */
2342 else
2343 goto error;
2346 end = strtoul(next, &next, 10);
2347 if (end <= start)
2348 goto error;
2350 while (++start <= end) {
2351 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2352 target_cpus[max_target_cpus++] = start;
2355 if (*next == ',')
2356 next += 1;
2357 else if (*next != '\0')
2358 goto error;
2361 #ifdef DEBUG
2363 int i;
2365 for (i = 0; i < max_target_cpus; ++i)
2366 printf("cpu [%d] in arg\n", target_cpus[i]);
2368 #endif
2369 return;
2371 error:
2372 fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
2373 exit(-1);
2376 static void parse_cmd_args(int argc, int start, char **argv)
2378 int opt;
2379 int option_index;
2381 static struct option long_options[] = {
2382 { "bucket", required_argument, 0, 'b' },
2383 { "level", required_argument, 0, 'l' },
2384 { "online", required_argument, 0, 'o' },
2385 { "trl-type", required_argument, 0, 'r' },
2386 { "trl", required_argument, 0, 't' },
2387 { "help", no_argument, 0, 'h' },
2388 { "clos", required_argument, 0, 'c' },
2389 { "desired", required_argument, 0, 'd' },
2390 { "epp", required_argument, 0, 'e' },
2391 { "min", required_argument, 0, 'n' },
2392 { "max", required_argument, 0, 'm' },
2393 { "priority", required_argument, 0, 'p' },
2394 { "weight", required_argument, 0, 'w' },
2395 { "auto", no_argument, 0, 'a' },
2396 { 0, 0, 0, 0 }
2399 option_index = start;
2401 optind = start + 1;
2402 while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:r:hoa",
2403 long_options, &option_index)) != -1) {
2404 switch (opt) {
2405 case 'a':
2406 auto_mode = 1;
2407 break;
2408 case 'b':
2409 fact_bucket = atoi(optarg);
2410 break;
2411 case 'h':
2412 cmd_help = 1;
2413 break;
2414 case 'l':
2415 tdp_level = atoi(optarg);
2416 break;
2417 case 'o':
2418 force_online_offline = 1;
2419 break;
2420 case 't':
2421 sscanf(optarg, "0x%llx", &fact_trl);
2422 break;
2423 case 'r':
2424 if (!strncmp(optarg, "sse", 3)) {
2425 fact_avx = 0x01;
2426 } else if (!strncmp(optarg, "avx2", 4)) {
2427 fact_avx = 0x02;
2428 } else if (!strncmp(optarg, "avx512", 6)) {
2429 fact_avx = 0x04;
2430 } else {
2431 fprintf(outf, "Invalid sse,avx options\n");
2432 exit(1);
2434 break;
2435 /* CLOS related */
2436 case 'c':
2437 current_clos = atoi(optarg);
2438 break;
2439 case 'd':
2440 clos_desired = atoi(optarg);
2441 clos_desired /= DISP_FREQ_MULTIPLIER;
2442 break;
2443 case 'e':
2444 clos_epp = atoi(optarg);
2445 if (is_skx_based_platform()) {
2446 isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0);
2447 exit(0);
2449 break;
2450 case 'n':
2451 clos_min = atoi(optarg);
2452 clos_min /= DISP_FREQ_MULTIPLIER;
2453 break;
2454 case 'm':
2455 clos_max = atoi(optarg);
2456 clos_max /= DISP_FREQ_MULTIPLIER;
2457 break;
2458 case 'p':
2459 clos_priority_type = atoi(optarg);
2460 if (is_skx_based_platform() && !clos_priority_type) {
2461 isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0);
2462 exit(0);
2464 break;
2465 case 'w':
2466 clos_prop_prio = atoi(optarg);
2467 if (is_skx_based_platform()) {
2468 isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0);
2469 exit(0);
2471 break;
2472 default:
2473 printf("Unknown option: ignore\n");
2477 if (argv[optind])
2478 printf("Garbage at the end of command: ignore\n");
2481 static void isst_help(void)
2483 printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
2484 performance profiles per system via static and/or dynamic\n\
2485 adjustment of core count, workload, Tjmax, and\n\
2486 TDP, etc.\n");
2487 printf("\nCommands : For feature=perf-profile\n");
2488 printf("\tinfo\n");
2490 if (!is_clx_n_platform()) {
2491 printf("\tget-lock-status\n");
2492 printf("\tget-config-levels\n");
2493 printf("\tget-config-version\n");
2494 printf("\tget-config-enabled\n");
2495 printf("\tget-config-current-level\n");
2496 printf("\tset-config-level\n");
2500 static void pbf_help(void)
2502 printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
2503 on certain cores (high priority cores) in exchange for lower\n\
2504 base frequency on remaining cores (low priority cores).\n");
2505 printf("\tcommand : info\n");
2506 printf("\tcommand : enable\n");
2507 printf("\tcommand : disable\n");
2510 static void fact_help(void)
2512 printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
2513 limits to cores based on priority.\n");
2514 printf("\nCommand: For feature=turbo-freq\n");
2515 printf("\tcommand : info\n");
2516 printf("\tcommand : enable\n");
2517 printf("\tcommand : disable\n");
2520 static void core_power_help(void)
2522 printf("core-power:\tInterface that allows user to define per core/tile\n\
2523 priority.\n");
2524 printf("\nCommands : For feature=core-power\n");
2525 printf("\tinfo\n");
2526 printf("\tenable\n");
2527 printf("\tdisable\n");
2528 printf("\tconfig\n");
2529 printf("\tget-config\n");
2530 printf("\tassoc\n");
2531 printf("\tget-assoc\n");
2534 struct process_cmd_help_struct {
2535 char *feature;
2536 void (*process_fn)(void);
2539 static struct process_cmd_help_struct isst_help_cmds[] = {
2540 { "perf-profile", isst_help },
2541 { "base-freq", pbf_help },
2542 { "turbo-freq", fact_help },
2543 { "core-power", core_power_help },
2544 { NULL, NULL }
2547 static struct process_cmd_help_struct clx_n_help_cmds[] = {
2548 { "perf-profile", isst_help },
2549 { "base-freq", pbf_help },
2550 { NULL, NULL }
2553 void process_command(int argc, char **argv,
2554 struct process_cmd_help_struct *help_cmds,
2555 struct process_cmd_struct *cmds)
2557 int i = 0, matched = 0;
2558 char *feature = argv[optind];
2559 char *cmd = argv[optind + 1];
2561 if (!feature || !cmd)
2562 return;
2564 debug_printf("feature name [%s] command [%s]\n", feature, cmd);
2565 if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
2566 while (help_cmds[i].feature) {
2567 if (!strcmp(help_cmds[i].feature, feature)) {
2568 help_cmds[i].process_fn();
2569 exit(0);
2571 ++i;
2575 if (!is_clx_n_platform())
2576 create_cpu_map();
2578 i = 0;
2579 while (cmds[i].feature) {
2580 if (!strcmp(cmds[i].feature, feature) &&
2581 !strcmp(cmds[i].command, cmd)) {
2582 parse_cmd_args(argc, optind + 1, argv);
2583 cmds[i].process_fn(cmds[i].arg);
2584 matched = 1;
2585 break;
2587 ++i;
2590 if (!matched)
2591 fprintf(stderr, "Invalid command\n");
2594 static void usage(void)
2596 if (is_clx_n_platform()) {
2597 fprintf(stderr, "\nThere is limited support of Intel Speed Select features on this platform.\n");
2598 fprintf(stderr, "Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware.\n\n");
2601 printf("\nUsage:\n");
2602 printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
2603 printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features:\n");
2604 if (is_clx_n_platform())
2605 printf("\nFEATURE : [perf-profile|base-freq]\n");
2606 else
2607 printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power]\n");
2608 printf("\nFor help on each feature, use -h|--help\n");
2609 printf("\tFor example: intel-speed-select perf-profile -h\n");
2611 printf("\nFor additional help on each command for a feature, use --h|--help\n");
2612 printf("\tFor example: intel-speed-select perf-profile get-lock-status -h\n");
2613 printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
2615 printf("\nOPTIONS\n");
2616 printf("\t[-c|--cpu] : logical cpu number\n");
2617 printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
2618 printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
2619 printf("\t[-d|--debug] : Debug mode\n");
2620 printf("\t[-f|--format] : output format [json|text]. Default: text\n");
2621 printf("\t[-h|--help] : Print help\n");
2622 printf("\t[-i|--info] : Print platform information\n");
2623 printf("\t[-o|--out] : Output file\n");
2624 printf("\t\t\tDefault : stderr\n");
2625 printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n");
2626 printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n");
2627 printf("\t[-v|--version] : Print version\n");
2629 printf("\nResult format\n");
2630 printf("\tResult display uses a common format for each command:\n");
2631 printf("\tResults are formatted in text/JSON with\n");
2632 printf("\t\tPackage, Die, CPU, and command specific results.\n");
2634 printf("\nExamples\n");
2635 printf("\tTo get platform information:\n");
2636 printf("\t\tintel-speed-select --info\n");
2637 printf("\tTo get full perf-profile information dump:\n");
2638 printf("\t\tintel-speed-select perf-profile info\n");
2639 printf("\tTo get full base-freq information dump:\n");
2640 printf("\t\tintel-speed-select base-freq info -l 0\n");
2641 if (!is_clx_n_platform()) {
2642 printf("\tTo get full turbo-freq information dump:\n");
2643 printf("\t\tintel-speed-select turbo-freq info -l 0\n");
2645 exit(1);
2648 static void print_version(void)
2650 fprintf(outf, "Version %s\n", version_str);
2651 fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__);
2652 exit(0);
2655 static void cmdline(int argc, char **argv)
2657 const char *pathname = "/dev/isst_interface";
2658 char *ptr;
2659 FILE *fp;
2660 int opt;
2661 int option_index = 0;
2662 int ret;
2664 static struct option long_options[] = {
2665 { "cpu", required_argument, 0, 'c' },
2666 { "debug", no_argument, 0, 'd' },
2667 { "format", required_argument, 0, 'f' },
2668 { "help", no_argument, 0, 'h' },
2669 { "info", no_argument, 0, 'i' },
2670 { "pause", required_argument, 0, 'p' },
2671 { "out", required_argument, 0, 'o' },
2672 { "retry", required_argument, 0, 'r' },
2673 { "version", no_argument, 0, 'v' },
2674 { 0, 0, 0, 0 }
2677 if (geteuid() != 0) {
2678 fprintf(stderr, "Must run as root\n");
2679 exit(0);
2682 ret = update_cpu_model();
2683 if (ret)
2684 err(-1, "Invalid CPU model (%d)\n", cpu_model);
2685 printf("Intel(R) Speed Select Technology\n");
2686 printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
2688 if (!is_clx_n_platform()) {
2689 fp = fopen(pathname, "rb");
2690 if (!fp) {
2691 fprintf(stderr, "Intel speed select drivers are not loaded on this system.\n");
2692 fprintf(stderr, "Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE.\n");
2693 fprintf(stderr, "If the config is included then this is not a supported platform.\n");
2694 exit(0);
2696 fclose(fp);
2699 progname = argv[0];
2700 while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options,
2701 &option_index)) != -1) {
2702 switch (opt) {
2703 case 'c':
2704 parse_cpu_command(optarg);
2705 break;
2706 case 'd':
2707 debug_flag = 1;
2708 printf("Debug Mode ON\n");
2709 break;
2710 case 'f':
2711 if (!strncmp(optarg, "json", 4))
2712 out_format_json = 1;
2713 break;
2714 case 'h':
2715 usage();
2716 break;
2717 case 'i':
2718 isst_print_platform_information();
2719 break;
2720 case 'o':
2721 if (outf)
2722 fclose(outf);
2723 outf = fopen_or_exit(optarg, "w");
2724 break;
2725 case 'p':
2726 ret = strtol(optarg, &ptr, 10);
2727 if (!ret)
2728 fprintf(stderr, "Invalid pause interval, ignore\n");
2729 else
2730 mbox_delay = ret;
2731 break;
2732 case 'r':
2733 ret = strtol(optarg, &ptr, 10);
2734 if (!ret)
2735 fprintf(stderr, "Invalid retry count, ignore\n");
2736 else
2737 mbox_retries = ret;
2738 break;
2739 case 'v':
2740 print_version();
2741 break;
2742 default:
2743 usage();
2747 if (optind > (argc - 2)) {
2748 usage();
2749 exit(0);
2751 set_max_cpu_num();
2752 store_cpu_topology();
2753 set_cpu_present_cpu_mask();
2754 set_cpu_target_cpu_mask();
2756 if (!is_clx_n_platform()) {
2757 ret = isst_fill_platform_info();
2758 if (ret)
2759 goto out;
2760 process_command(argc, argv, isst_help_cmds, isst_cmds);
2761 } else {
2762 process_command(argc, argv, clx_n_help_cmds, clx_n_cmds);
2764 out:
2765 free_cpu_set(present_cpumask);
2766 free_cpu_set(target_cpumask);
2769 int main(int argc, char **argv)
2771 outf = stderr;
2772 cmdline(argc, argv);
2773 return 0;