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