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