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