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