Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Intel Speed Select -- Enumerate and control features
0004  * Copyright (c) 2019 Intel Corporation.
0005  */
0006 
0007 #include <linux/isst_if.h>
0008 
0009 #include "isst.h"
0010 
0011 struct process_cmd_struct {
0012     char *feature;
0013     char *command;
0014     void (*process_fn)(int arg);
0015     int arg;
0016 };
0017 
0018 static const char *version_str = "v1.12";
0019 
0020 static const int supported_api_ver = 1;
0021 static struct isst_if_platform_info isst_platform_info;
0022 static char *progname;
0023 static int debug_flag;
0024 static FILE *outf;
0025 
0026 static int cpu_model;
0027 static int cpu_stepping;
0028 
0029 #define MAX_CPUS_IN_ONE_REQ 256
0030 static short max_target_cpus;
0031 static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ];
0032 
0033 static int topo_max_cpus;
0034 static size_t present_cpumask_size;
0035 static cpu_set_t *present_cpumask;
0036 static size_t target_cpumask_size;
0037 static cpu_set_t *target_cpumask;
0038 static int tdp_level = 0xFF;
0039 static int fact_bucket = 0xFF;
0040 static int fact_avx = 0xFF;
0041 static unsigned long long fact_trl;
0042 static int out_format_json;
0043 static int cmd_help;
0044 static int force_online_offline;
0045 static int auto_mode;
0046 static int fact_enable_fail;
0047 
0048 static int mbox_delay;
0049 static int mbox_retries = 3;
0050 
0051 /* clos related */
0052 static int current_clos = -1;
0053 static int clos_epp = -1;
0054 static int clos_prop_prio = -1;
0055 static int clos_min = -1;
0056 static int clos_max = -1;
0057 static int clos_desired = -1;
0058 static int clos_priority_type;
0059 
0060 struct _cpu_map {
0061     unsigned short core_id;
0062     unsigned short pkg_id;
0063     unsigned short die_id;
0064     unsigned short punit_cpu;
0065     unsigned short punit_cpu_core;
0066 };
0067 struct _cpu_map *cpu_map;
0068 
0069 struct cpu_topology {
0070     short cpu;
0071     short core_id;
0072     short pkg_id;
0073     short die_id;
0074 };
0075 
0076 FILE *get_output_file(void)
0077 {
0078     return outf;
0079 }
0080 
0081 void debug_printf(const char *format, ...)
0082 {
0083     va_list args;
0084 
0085     va_start(args, format);
0086 
0087     if (debug_flag)
0088         vprintf(format, args);
0089 
0090     va_end(args);
0091 }
0092 
0093 
0094 int is_clx_n_platform(void)
0095 {
0096     if (cpu_model == 0x55)
0097         if (cpu_stepping == 0x6 || cpu_stepping == 0x7)
0098             return 1;
0099     return 0;
0100 }
0101 
0102 int is_skx_based_platform(void)
0103 {
0104     if (cpu_model == 0x55)
0105         return 1;
0106 
0107     return 0;
0108 }
0109 
0110 int is_spr_platform(void)
0111 {
0112     if (cpu_model == 0x8F)
0113         return 1;
0114 
0115     return 0;
0116 }
0117 
0118 int is_icx_platform(void)
0119 {
0120     if (cpu_model == 0x6A || cpu_model == 0x6C)
0121         return 1;
0122 
0123     return 0;
0124 }
0125 
0126 static int update_cpu_model(void)
0127 {
0128     unsigned int ebx, ecx, edx;
0129     unsigned int fms, family;
0130 
0131     __cpuid(1, fms, ebx, ecx, edx);
0132     family = (fms >> 8) & 0xf;
0133     cpu_model = (fms >> 4) & 0xf;
0134     if (family == 6 || family == 0xf)
0135         cpu_model += ((fms >> 16) & 0xf) << 4;
0136 
0137     cpu_stepping = fms & 0xf;
0138     /* only three CascadeLake-N models are supported */
0139     if (is_clx_n_platform()) {
0140         FILE *fp;
0141         size_t n = 0;
0142         char *line = NULL;
0143         int ret = 1;
0144 
0145         fp = fopen("/proc/cpuinfo", "r");
0146         if (!fp)
0147             err(-1, "cannot open /proc/cpuinfo\n");
0148 
0149         while (getline(&line, &n, fp) > 0) {
0150             if (strstr(line, "model name")) {
0151                 if (strstr(line, "6252N") ||
0152                     strstr(line, "6230N") ||
0153                     strstr(line, "5218N"))
0154                     ret = 0;
0155                 break;
0156             }
0157         }
0158         free(line);
0159         fclose(fp);
0160         return ret;
0161     }
0162     return 0;
0163 }
0164 
0165 /* Open a file, and exit on failure */
0166 static FILE *fopen_or_exit(const char *path, const char *mode)
0167 {
0168     FILE *filep = fopen(path, mode);
0169 
0170     if (!filep)
0171         err(1, "%s: open failed", path);
0172 
0173     return filep;
0174 }
0175 
0176 /* Parse a file containing a single int */
0177 static int parse_int_file(int fatal, const char *fmt, ...)
0178 {
0179     va_list args;
0180     char path[PATH_MAX];
0181     FILE *filep;
0182     int value;
0183 
0184     va_start(args, fmt);
0185     vsnprintf(path, sizeof(path), fmt, args);
0186     va_end(args);
0187     if (fatal) {
0188         filep = fopen_or_exit(path, "r");
0189     } else {
0190         filep = fopen(path, "r");
0191         if (!filep)
0192             return -1;
0193     }
0194     if (fscanf(filep, "%d", &value) != 1)
0195         err(1, "%s: failed to parse number from file", path);
0196     fclose(filep);
0197 
0198     return value;
0199 }
0200 
0201 int cpufreq_sysfs_present(void)
0202 {
0203     DIR *dir;
0204 
0205     dir = opendir("/sys/devices/system/cpu/cpu0/cpufreq");
0206     if (dir) {
0207         closedir(dir);
0208         return 1;
0209     }
0210 
0211     return 0;
0212 }
0213 
0214 int out_format_is_json(void)
0215 {
0216     return out_format_json;
0217 }
0218 
0219 static int get_stored_topology_info(int cpu, int *core_id, int *pkg_id, int *die_id)
0220 {
0221     const char *pathname = "/var/run/isst_cpu_topology.dat";
0222     struct cpu_topology cpu_top;
0223     FILE *fp;
0224     int ret;
0225 
0226     fp = fopen(pathname, "rb");
0227     if (!fp)
0228         return -1;
0229 
0230     ret = fseek(fp, cpu * sizeof(cpu_top), SEEK_SET);
0231     if (ret)
0232         goto err_ret;
0233 
0234     ret = fread(&cpu_top, sizeof(cpu_top), 1, fp);
0235     if (ret != 1) {
0236         ret = -1;
0237         goto err_ret;
0238     }
0239 
0240     *pkg_id = cpu_top.pkg_id;
0241     *core_id = cpu_top.core_id;
0242     *die_id = cpu_top.die_id;
0243     ret = 0;
0244 
0245 err_ret:
0246     fclose(fp);
0247 
0248     return ret;
0249 }
0250 
0251 static void store_cpu_topology(void)
0252 {
0253     const char *pathname = "/var/run/isst_cpu_topology.dat";
0254     FILE *fp;
0255     int i;
0256 
0257     fp = fopen(pathname, "rb");
0258     if (fp) {
0259         /* Mapping already exists */
0260         fclose(fp);
0261         return;
0262     }
0263 
0264     fp = fopen(pathname, "wb");
0265     if (!fp) {
0266         fprintf(stderr, "Can't create file:%s\n", pathname);
0267         return;
0268     }
0269 
0270     fprintf(stderr, "Caching topology information\n");
0271 
0272     for (i = 0; i < topo_max_cpus; ++i) {
0273         struct cpu_topology cpu_top;
0274 
0275         cpu_top.core_id = parse_int_file(0,
0276             "/sys/devices/system/cpu/cpu%d/topology/core_id", i);
0277         if (cpu_top.core_id < 0)
0278             cpu_top.core_id = -1;
0279 
0280         cpu_top.pkg_id = parse_int_file(0,
0281             "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i);
0282         if (cpu_top.pkg_id < 0)
0283             cpu_top.pkg_id = -1;
0284 
0285         cpu_top.die_id = parse_int_file(0,
0286             "/sys/devices/system/cpu/cpu%d/topology/die_id", i);
0287         if (cpu_top.die_id < 0)
0288             cpu_top.die_id = -1;
0289 
0290         cpu_top.cpu = i;
0291 
0292         if (fwrite(&cpu_top, sizeof(cpu_top), 1, fp) != 1) {
0293             fprintf(stderr, "Can't write to:%s\n", pathname);
0294             break;
0295         }
0296     }
0297 
0298     fclose(fp);
0299 }
0300 
0301 int get_physical_package_id(int cpu)
0302 {
0303     int ret;
0304 
0305     ret = parse_int_file(0,
0306             "/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
0307             cpu);
0308     if (ret < 0) {
0309         int core_id, pkg_id, die_id;
0310 
0311         ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
0312         if (!ret)
0313             return pkg_id;
0314     }
0315 
0316     return ret;
0317 }
0318 
0319 int get_physical_core_id(int cpu)
0320 {
0321     int ret;
0322 
0323     ret = parse_int_file(0,
0324             "/sys/devices/system/cpu/cpu%d/topology/core_id",
0325             cpu);
0326     if (ret < 0) {
0327         int core_id, pkg_id, die_id;
0328 
0329         ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
0330         if (!ret)
0331             return core_id;
0332     }
0333 
0334     return ret;
0335 }
0336 
0337 int get_physical_die_id(int cpu)
0338 {
0339     int ret;
0340 
0341     ret = parse_int_file(0,
0342             "/sys/devices/system/cpu/cpu%d/topology/die_id",
0343             cpu);
0344     if (ret < 0) {
0345         int core_id, pkg_id, die_id;
0346 
0347         ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
0348         if (!ret) {
0349             if (die_id < 0)
0350                 die_id = 0;
0351 
0352             return die_id;
0353         }
0354     }
0355 
0356     if (ret < 0)
0357         ret = 0;
0358 
0359     return ret;
0360 }
0361 
0362 int get_cpufreq_base_freq(int cpu)
0363 {
0364     return parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", cpu);
0365 }
0366 
0367 int get_topo_max_cpus(void)
0368 {
0369     return topo_max_cpus;
0370 }
0371 
0372 void set_cpu_online_offline(int cpu, int state)
0373 {
0374     char buffer[128];
0375     int fd, ret;
0376 
0377     snprintf(buffer, sizeof(buffer),
0378          "/sys/devices/system/cpu/cpu%d/online", cpu);
0379 
0380     fd = open(buffer, O_WRONLY);
0381     if (fd < 0) {
0382         if (!cpu && state) {
0383             fprintf(stderr, "This system is not configured for CPU 0 online/offline\n");
0384             fprintf(stderr, "Ignoring online request for CPU 0 as this is already online\n");
0385             return;
0386         }
0387         err(-1, "%s open failed", buffer);
0388     }
0389 
0390     if (state)
0391         ret = write(fd, "1\n", 2);
0392     else
0393         ret = write(fd, "0\n", 2);
0394 
0395     if (ret == -1)
0396         perror("Online/Offline: Operation failed\n");
0397 
0398     close(fd);
0399 }
0400 
0401 static void force_all_cpus_online(void)
0402 {
0403     int i;
0404 
0405     fprintf(stderr, "Forcing all CPUs online\n");
0406 
0407     for (i = 0; i < topo_max_cpus; ++i)
0408         set_cpu_online_offline(i, 1);
0409 
0410     unlink("/var/run/isst_cpu_topology.dat");
0411 }
0412 
0413 void for_each_online_package_in_set(void (*callback)(int, void *, void *,
0414                              void *, void *),
0415                     void *arg1, void *arg2, void *arg3,
0416                     void *arg4)
0417 {
0418     int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
0419     int pkg_index = 0, i;
0420 
0421     memset(max_packages, 0xff, sizeof(max_packages));
0422     for (i = 0; i < topo_max_cpus; ++i) {
0423         int j, online, pkg_id, die_id = 0, skip = 0;
0424 
0425         if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
0426             continue;
0427         if (i)
0428             online = parse_int_file(
0429                 1, "/sys/devices/system/cpu/cpu%d/online", i);
0430         else
0431             online =
0432                 1; /* online entry for CPU 0 needs some special configs */
0433 
0434         die_id = get_physical_die_id(i);
0435         if (die_id < 0)
0436             die_id = 0;
0437 
0438         pkg_id = parse_int_file(0,
0439             "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i);
0440         if (pkg_id < 0)
0441             continue;
0442 
0443         /* Create an unique id for package, die combination to store */
0444         pkg_id = (MAX_PACKAGE_COUNT * pkg_id + die_id);
0445 
0446         for (j = 0; j < pkg_index; ++j) {
0447             if (max_packages[j] == pkg_id) {
0448                 skip = 1;
0449                 break;
0450             }
0451         }
0452 
0453         if (!skip && online && callback) {
0454             callback(i, arg1, arg2, arg3, arg4);
0455             max_packages[pkg_index++] = pkg_id;
0456         }
0457     }
0458 }
0459 
0460 static void for_each_online_target_cpu_in_set(
0461     void (*callback)(int, void *, void *, void *, void *), void *arg1,
0462     void *arg2, void *arg3, void *arg4)
0463 {
0464     int i, found = 0;
0465 
0466     for (i = 0; i < topo_max_cpus; ++i) {
0467         int online;
0468 
0469         if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
0470             continue;
0471         if (i)
0472             online = parse_int_file(
0473                 1, "/sys/devices/system/cpu/cpu%d/online", i);
0474         else
0475             online =
0476                 1; /* online entry for CPU 0 needs some special configs */
0477 
0478         if (online && callback) {
0479             callback(i, arg1, arg2, arg3, arg4);
0480             found = 1;
0481         }
0482     }
0483 
0484     if (!found)
0485         fprintf(stderr, "No valid CPU in the list\n");
0486 }
0487 
0488 #define BITMASK_SIZE 32
0489 static void set_max_cpu_num(void)
0490 {
0491     FILE *filep;
0492     unsigned long dummy;
0493     int i;
0494 
0495     topo_max_cpus = 0;
0496     for (i = 0; i < 256; ++i) {
0497         char path[256];
0498 
0499         snprintf(path, sizeof(path),
0500              "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", i);
0501         filep = fopen(path, "r");
0502         if (filep)
0503             break;
0504     }
0505 
0506     if (!filep) {
0507         fprintf(stderr, "Can't get max cpu number\n");
0508         exit(0);
0509     }
0510 
0511     while (fscanf(filep, "%lx,", &dummy) == 1)
0512         topo_max_cpus += BITMASK_SIZE;
0513     fclose(filep);
0514 
0515     debug_printf("max cpus %d\n", topo_max_cpus);
0516 }
0517 
0518 size_t alloc_cpu_set(cpu_set_t **cpu_set)
0519 {
0520     cpu_set_t *_cpu_set;
0521     size_t size;
0522 
0523     _cpu_set = CPU_ALLOC((topo_max_cpus + 1));
0524     if (_cpu_set == NULL)
0525         err(3, "CPU_ALLOC");
0526     size = CPU_ALLOC_SIZE((topo_max_cpus + 1));
0527     CPU_ZERO_S(size, _cpu_set);
0528 
0529     *cpu_set = _cpu_set;
0530     return size;
0531 }
0532 
0533 void free_cpu_set(cpu_set_t *cpu_set)
0534 {
0535     CPU_FREE(cpu_set);
0536 }
0537 
0538 static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
0539 static long long core_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
0540 static void set_cpu_present_cpu_mask(void)
0541 {
0542     size_t size;
0543     DIR *dir;
0544     int i;
0545 
0546     size = alloc_cpu_set(&present_cpumask);
0547     present_cpumask_size = size;
0548     for (i = 0; i < topo_max_cpus; ++i) {
0549         char buffer[256];
0550 
0551         snprintf(buffer, sizeof(buffer),
0552              "/sys/devices/system/cpu/cpu%d", i);
0553         dir = opendir(buffer);
0554         if (dir) {
0555             int pkg_id, die_id;
0556 
0557             CPU_SET_S(i, size, present_cpumask);
0558             die_id = get_physical_die_id(i);
0559             if (die_id < 0)
0560                 die_id = 0;
0561 
0562             pkg_id = get_physical_package_id(i);
0563             if (pkg_id < 0) {
0564                 fprintf(stderr, "Failed to get package id, CPU %d may be offline\n", i);
0565                 continue;
0566             }
0567             if (pkg_id < MAX_PACKAGE_COUNT &&
0568                 die_id < MAX_DIE_PER_PACKAGE) {
0569                 int core_id = get_physical_core_id(i);
0570 
0571                 cpu_cnt[pkg_id][die_id]++;
0572                 core_mask[pkg_id][die_id] |= (1ULL << core_id);
0573             }
0574         }
0575         closedir(dir);
0576     }
0577 }
0578 
0579 int get_max_punit_core_id(int pkg_id, int die_id)
0580 {
0581     int max_id = 0;
0582     int i;
0583 
0584     for (i = 0; i < topo_max_cpus; ++i)
0585     {
0586         if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
0587             continue;
0588 
0589         if (cpu_map[i].pkg_id == pkg_id &&
0590             cpu_map[i].die_id == die_id &&
0591             cpu_map[i].punit_cpu_core > max_id)
0592             max_id = cpu_map[i].punit_cpu_core;
0593     }
0594 
0595     return max_id;
0596 }
0597 
0598 int get_cpu_count(int pkg_id, int die_id)
0599 {
0600     if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE)
0601         return cpu_cnt[pkg_id][die_id];
0602 
0603     return 0;
0604 }
0605 
0606 static void set_cpu_target_cpu_mask(void)
0607 {
0608     size_t size;
0609     int i;
0610 
0611     size = alloc_cpu_set(&target_cpumask);
0612     target_cpumask_size = size;
0613     for (i = 0; i < max_target_cpus; ++i) {
0614         if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
0615                  present_cpumask))
0616             continue;
0617 
0618         CPU_SET_S(target_cpus[i], size, target_cpumask);
0619     }
0620 }
0621 
0622 static void create_cpu_map(void)
0623 {
0624     const char *pathname = "/dev/isst_interface";
0625     int i, fd = 0;
0626     struct isst_if_cpu_maps map;
0627 
0628     cpu_map = malloc(sizeof(*cpu_map) * topo_max_cpus);
0629     if (!cpu_map)
0630         err(3, "cpumap");
0631 
0632     fd = open(pathname, O_RDWR);
0633     if (fd < 0)
0634         err(-1, "%s open failed", pathname);
0635 
0636     for (i = 0; i < topo_max_cpus; ++i) {
0637         if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
0638             continue;
0639 
0640         map.cmd_count = 1;
0641         map.cpu_map[0].logical_cpu = i;
0642 
0643         debug_printf(" map logical_cpu:%d\n",
0644                  map.cpu_map[0].logical_cpu);
0645         if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
0646             perror("ISST_IF_GET_PHY_ID");
0647             fprintf(outf, "Error: map logical_cpu:%d\n",
0648                 map.cpu_map[0].logical_cpu);
0649             continue;
0650         }
0651         cpu_map[i].core_id = get_physical_core_id(i);
0652         cpu_map[i].pkg_id = get_physical_package_id(i);
0653         cpu_map[i].die_id = get_physical_die_id(i);
0654         cpu_map[i].punit_cpu = map.cpu_map[0].physical_cpu;
0655         cpu_map[i].punit_cpu_core = (map.cpu_map[0].physical_cpu >>
0656                          1); // shift to get core id
0657 
0658         debug_printf(
0659             "map logical_cpu:%d core: %d die:%d pkg:%d punit_cpu:%d punit_core:%d\n",
0660             i, cpu_map[i].core_id, cpu_map[i].die_id,
0661             cpu_map[i].pkg_id, cpu_map[i].punit_cpu,
0662             cpu_map[i].punit_cpu_core);
0663     }
0664 
0665     if (fd)
0666         close(fd);
0667 }
0668 
0669 int find_logical_cpu(int pkg_id, int die_id, int punit_core_id)
0670 {
0671     int i;
0672 
0673     for (i = 0; i < topo_max_cpus; ++i) {
0674         if (cpu_map[i].pkg_id == pkg_id &&
0675             cpu_map[i].die_id == die_id &&
0676             cpu_map[i].punit_cpu_core == punit_core_id)
0677             return i;
0678     }
0679 
0680     return -EINVAL;
0681 }
0682 
0683 void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask,
0684                       size_t core_cpumask_size,
0685                       cpu_set_t *core_cpumask, int *cpu_cnt)
0686 {
0687     int i, cnt = 0;
0688     int die_id, pkg_id;
0689 
0690     *cpu_cnt = 0;
0691     die_id = get_physical_die_id(cpu);
0692     pkg_id = get_physical_package_id(cpu);
0693 
0694     for (i = 0; i < 64; ++i) {
0695         if (core_mask & BIT_ULL(i)) {
0696             int j;
0697 
0698             for (j = 0; j < topo_max_cpus; ++j) {
0699                 if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask))
0700                     continue;
0701 
0702                 if (cpu_map[j].pkg_id == pkg_id &&
0703                     cpu_map[j].die_id == die_id &&
0704                     cpu_map[j].punit_cpu_core == i) {
0705                     CPU_SET_S(j, core_cpumask_size,
0706                           core_cpumask);
0707                     ++cnt;
0708                 }
0709             }
0710         }
0711     }
0712 
0713     *cpu_cnt = cnt;
0714 }
0715 
0716 int find_phy_core_num(int logical_cpu)
0717 {
0718     if (logical_cpu < topo_max_cpus)
0719         return cpu_map[logical_cpu].punit_cpu_core;
0720 
0721     return -EINVAL;
0722 }
0723 
0724 static int isst_send_mmio_command(unsigned int cpu, unsigned int reg, int write,
0725                   unsigned int *value)
0726 {
0727     struct isst_if_io_regs io_regs;
0728     const char *pathname = "/dev/isst_interface";
0729     int cmd;
0730     int fd;
0731 
0732     debug_printf("mmio_cmd cpu:%d reg:%d write:%d\n", cpu, reg, write);
0733 
0734     fd = open(pathname, O_RDWR);
0735     if (fd < 0)
0736         err(-1, "%s open failed", pathname);
0737 
0738     io_regs.req_count = 1;
0739     io_regs.io_reg[0].logical_cpu = cpu;
0740     io_regs.io_reg[0].reg = reg;
0741     cmd = ISST_IF_IO_CMD;
0742     if (write) {
0743         io_regs.io_reg[0].read_write = 1;
0744         io_regs.io_reg[0].value = *value;
0745     } else {
0746         io_regs.io_reg[0].read_write = 0;
0747     }
0748 
0749     if (ioctl(fd, cmd, &io_regs) == -1) {
0750         if (errno == ENOTTY) {
0751             perror("ISST_IF_IO_COMMAND\n");
0752             fprintf(stderr, "Check presence of kernel modules: isst_if_mmio\n");
0753             exit(0);
0754         }
0755         fprintf(outf, "Error: mmio_cmd cpu:%d reg:%x read_write:%x\n",
0756             cpu, reg, write);
0757     } else {
0758         if (!write)
0759             *value = io_regs.io_reg[0].value;
0760 
0761         debug_printf(
0762             "mmio_cmd response: cpu:%d reg:%x rd_write:%x resp:%x\n",
0763             cpu, reg, write, *value);
0764     }
0765 
0766     close(fd);
0767 
0768     return 0;
0769 }
0770 
0771 int isst_send_mbox_command(unsigned int cpu, unsigned char command,
0772                unsigned char sub_command, unsigned int parameter,
0773                unsigned int req_data, unsigned int *resp)
0774 {
0775     const char *pathname = "/dev/isst_interface";
0776     int fd, retry;
0777     struct isst_if_mbox_cmds mbox_cmds = { 0 };
0778 
0779     debug_printf(
0780         "mbox_send: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
0781         cpu, command, sub_command, parameter, req_data);
0782 
0783     if (!is_skx_based_platform() && command == CONFIG_CLOS &&
0784         sub_command != CLOS_PM_QOS_CONFIG) {
0785         unsigned int value;
0786         int write = 0;
0787         int clos_id, core_id, ret = 0;
0788 
0789         debug_printf("CPU %d\n", cpu);
0790 
0791         if (parameter & BIT(MBOX_CMD_WRITE_BIT)) {
0792             value = req_data;
0793             write = 1;
0794         }
0795 
0796         switch (sub_command) {
0797         case CLOS_PQR_ASSOC:
0798             core_id = parameter & 0xff;
0799             ret = isst_send_mmio_command(
0800                 cpu, PQR_ASSOC_OFFSET + core_id * 4, write,
0801                 &value);
0802             if (!ret && !write)
0803                 *resp = value;
0804             break;
0805         case CLOS_PM_CLOS:
0806             clos_id = parameter & 0x03;
0807             ret = isst_send_mmio_command(
0808                 cpu, PM_CLOS_OFFSET + clos_id * 4, write,
0809                 &value);
0810             if (!ret && !write)
0811                 *resp = value;
0812             break;
0813         case CLOS_STATUS:
0814             break;
0815         default:
0816             break;
0817         }
0818         return ret;
0819     }
0820 
0821     mbox_cmds.cmd_count = 1;
0822     mbox_cmds.mbox_cmd[0].logical_cpu = cpu;
0823     mbox_cmds.mbox_cmd[0].command = command;
0824     mbox_cmds.mbox_cmd[0].sub_command = sub_command;
0825     mbox_cmds.mbox_cmd[0].parameter = parameter;
0826     mbox_cmds.mbox_cmd[0].req_data = req_data;
0827 
0828     if (mbox_delay)
0829         usleep(mbox_delay * 1000);
0830 
0831     fd = open(pathname, O_RDWR);
0832     if (fd < 0)
0833         err(-1, "%s open failed", pathname);
0834 
0835     retry = mbox_retries;
0836 
0837     do {
0838         if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
0839             if (errno == ENOTTY) {
0840                 perror("ISST_IF_MBOX_COMMAND\n");
0841                 fprintf(stderr, "Check presence of kernel modules: isst_if_mbox_pci or isst_if_mbox_msr\n");
0842                 exit(0);
0843             }
0844             debug_printf(
0845                 "Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x errorno:%d\n",
0846                 cpu, command, sub_command, parameter, req_data, errno);
0847             --retry;
0848         } else {
0849             *resp = mbox_cmds.mbox_cmd[0].resp_data;
0850             debug_printf(
0851                 "mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
0852                 cpu, command, sub_command, parameter, req_data, *resp);
0853             break;
0854         }
0855     } while (retry);
0856 
0857     close(fd);
0858 
0859     if (!retry) {
0860         debug_printf("Failed mbox command even after retries\n");
0861         return -1;
0862 
0863     }
0864     return 0;
0865 }
0866 
0867 int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
0868               unsigned long long *req_resp)
0869 {
0870     struct isst_if_msr_cmds msr_cmds;
0871     const char *pathname = "/dev/isst_interface";
0872     int fd;
0873 
0874     fd = open(pathname, O_RDWR);
0875     if (fd < 0)
0876         err(-1, "%s open failed", pathname);
0877 
0878     msr_cmds.cmd_count = 1;
0879     msr_cmds.msr_cmd[0].logical_cpu = cpu;
0880     msr_cmds.msr_cmd[0].msr = msr;
0881     msr_cmds.msr_cmd[0].read_write = write;
0882     if (write)
0883         msr_cmds.msr_cmd[0].data = *req_resp;
0884 
0885     if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
0886         perror("ISST_IF_MSR_COMMAND");
0887         fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
0888             cpu, msr, write);
0889     } else {
0890         if (!write)
0891             *req_resp = msr_cmds.msr_cmd[0].data;
0892 
0893         debug_printf(
0894             "msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
0895             cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
0896     }
0897 
0898     close(fd);
0899 
0900     return 0;
0901 }
0902 
0903 static int isst_fill_platform_info(void)
0904 {
0905     const char *pathname = "/dev/isst_interface";
0906     int fd;
0907 
0908     fd = open(pathname, O_RDWR);
0909     if (fd < 0)
0910         err(-1, "%s open failed", pathname);
0911 
0912     if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) {
0913         perror("ISST_IF_GET_PLATFORM_INFO");
0914         close(fd);
0915         return -1;
0916     }
0917 
0918     close(fd);
0919 
0920     if (isst_platform_info.api_version > supported_api_ver) {
0921         printf("Incompatible API versions; Upgrade of tool is required\n");
0922         return -1;
0923     }
0924     return 0;
0925 }
0926 
0927 static void isst_print_extended_platform_info(void)
0928 {
0929     int cp_state, cp_cap, fact_support = 0, pbf_support = 0;
0930     struct isst_pkg_ctdp_level_info ctdp_level;
0931     struct isst_pkg_ctdp pkg_dev;
0932     int ret, i, j;
0933     FILE *filep;
0934 
0935     for (i = 0; i < 256; ++i) {
0936         char path[256];
0937 
0938         snprintf(path, sizeof(path),
0939              "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", i);
0940         filep = fopen(path, "r");
0941         if (filep)
0942             break;
0943     }
0944 
0945     if (!filep)
0946         return;
0947 
0948     fclose(filep);
0949 
0950     ret = isst_get_ctdp_levels(i, &pkg_dev);
0951     if (ret)
0952         return;
0953 
0954     if (pkg_dev.enabled) {
0955         fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is supported\n");
0956     } else {
0957         fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is not supported\n");
0958         fprintf(outf, "Only performance level 0 (base level) is present\n");
0959     }
0960 
0961     if (pkg_dev.locked)
0962         fprintf(outf, "TDP level change control is locked\n");
0963     else
0964         fprintf(outf, "TDP level change control is unlocked, max level: %d \n", pkg_dev.levels);
0965 
0966     for (j = 0; j <= pkg_dev.levels; ++j) {
0967         ret = isst_get_ctdp_control(i, j, &ctdp_level);
0968         if (ret)
0969             continue;
0970 
0971         if (!fact_support && ctdp_level.fact_support)
0972             fact_support = 1;
0973 
0974         if (!pbf_support && ctdp_level.pbf_support)
0975             pbf_support = 1;
0976     }
0977 
0978     if (fact_support)
0979         fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is supported\n");
0980     else
0981         fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is not supported\n");
0982 
0983     if (pbf_support)
0984         fprintf(outf, "Intel(R) SST-BF (feature base-freq) is supported\n");
0985     else
0986         fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n");
0987 
0988     ret = isst_read_pm_config(i, &cp_state, &cp_cap);
0989     if (ret) {
0990         fprintf(outf, "Intel(R) SST-CP (feature core-power) status is unknown\n");
0991         return;
0992     }
0993     if (cp_cap)
0994         fprintf(outf, "Intel(R) SST-CP (feature core-power) is supported\n");
0995     else
0996         fprintf(outf, "Intel(R) SST-CP (feature core-power) is not supported\n");
0997 }
0998 
0999 static void isst_print_platform_information(void)
1000 {
1001     struct isst_if_platform_info platform_info;
1002     const char *pathname = "/dev/isst_interface";
1003     int fd;
1004 
1005     if (is_clx_n_platform()) {
1006         fprintf(stderr, "\nThis option in not supported on this platform\n");
1007         exit(0);
1008     }
1009 
1010     fd = open(pathname, O_RDWR);
1011     if (fd < 0)
1012         err(-1, "%s open failed", pathname);
1013 
1014     if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &platform_info) == -1) {
1015         perror("ISST_IF_GET_PLATFORM_INFO");
1016     } else {
1017         fprintf(outf, "Platform: API version : %d\n",
1018             platform_info.api_version);
1019         fprintf(outf, "Platform: Driver version : %d\n",
1020             platform_info.driver_version);
1021         fprintf(outf, "Platform: mbox supported : %d\n",
1022             platform_info.mbox_supported);
1023         fprintf(outf, "Platform: mmio supported : %d\n",
1024             platform_info.mmio_supported);
1025         isst_print_extended_platform_info();
1026     }
1027 
1028     close(fd);
1029 
1030     exit(0);
1031 }
1032 
1033 static char *local_str0, *local_str1;
1034 static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1035                  void *arg4)
1036 {
1037     int (*fn_ptr)(int cpu, void *arg);
1038     int ret;
1039 
1040     fn_ptr = arg1;
1041     ret = fn_ptr(cpu, arg2);
1042     if (ret)
1043         isst_display_error_info_message(1, "get_tdp_* failed", 0, 0);
1044     else
1045         isst_ctdp_display_core_info(cpu, outf, arg3,
1046                         *(unsigned int *)arg4,
1047                         local_str0, local_str1);
1048 }
1049 
1050 #define _get_tdp_level(desc, suffix, object, help, str0, str1)          \
1051     static void get_tdp_##object(int arg)                                    \
1052     {                                                                         \
1053         struct isst_pkg_ctdp ctdp;                                        \
1054 \
1055         if (cmd_help) {                                                   \
1056             fprintf(stderr,                                           \
1057                 "Print %s [No command arguments are required]\n", \
1058                 help);                                            \
1059             exit(0);                                                  \
1060         }                                                                 \
1061         local_str0 = str0;                        \
1062         local_str1 = str1;                        \
1063         isst_ctdp_display_information_start(outf);                        \
1064         if (max_target_cpus)                                              \
1065             for_each_online_target_cpu_in_set(                        \
1066                 exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix,     \
1067                 &ctdp, desc, &ctdp.object);                       \
1068         else                                                              \
1069             for_each_online_package_in_set(exec_on_get_ctdp_cpu,      \
1070                                isst_get_ctdp_##suffix,    \
1071                                &ctdp, desc,               \
1072                                &ctdp.object);             \
1073         isst_ctdp_display_information_end(outf);                          \
1074     }
1075 
1076 _get_tdp_level("get-config-levels", levels, levels, "Max TDP level", NULL, NULL);
1077 _get_tdp_level("get-config-version", levels, version, "TDP version", NULL, NULL);
1078 _get_tdp_level("get-config-enabled", levels, enabled, "perf-profile enable status", "disabled", "enabled");
1079 _get_tdp_level("get-config-current_level", levels, current_level,
1080            "Current TDP Level", NULL, NULL);
1081 _get_tdp_level("get-lock-status", levels, locked, "TDP lock status", "unlocked", "locked");
1082 
1083 struct isst_pkg_ctdp clx_n_pkg_dev;
1084 
1085 static int clx_n_get_base_ratio(void)
1086 {
1087     FILE *fp;
1088     char *begin, *end, *line = NULL;
1089     char number[5];
1090     float value = 0;
1091     size_t n = 0;
1092 
1093     fp = fopen("/proc/cpuinfo", "r");
1094     if (!fp)
1095         err(-1, "cannot open /proc/cpuinfo\n");
1096 
1097     while (getline(&line, &n, fp) > 0) {
1098         if (strstr(line, "model name")) {
1099             /* this is true for CascadeLake-N */
1100             begin = strstr(line, "@ ") + 2;
1101             end = strstr(line, "GHz");
1102             strncpy(number, begin, end - begin);
1103             value = atof(number) * 10;
1104             break;
1105         }
1106     }
1107     free(line);
1108     fclose(fp);
1109 
1110     return (int)(value);
1111 }
1112 
1113 static int clx_n_config(int cpu)
1114 {
1115     int i, ret, pkg_id, die_id;
1116     unsigned long cpu_bf;
1117     struct isst_pkg_ctdp_level_info *ctdp_level;
1118     struct isst_pbf_info *pbf_info;
1119 
1120     ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1121     pbf_info = &ctdp_level->pbf_info;
1122     ctdp_level->core_cpumask_size =
1123             alloc_cpu_set(&ctdp_level->core_cpumask);
1124 
1125     /* find the frequency base ratio */
1126     ctdp_level->tdp_ratio = clx_n_get_base_ratio();
1127     if (ctdp_level->tdp_ratio == 0) {
1128         debug_printf("CLX: cn base ratio is zero\n");
1129         ret = -1;
1130         goto error_ret;
1131     }
1132 
1133     /* find the high and low priority frequencies */
1134     pbf_info->p1_high = 0;
1135     pbf_info->p1_low = ~0;
1136 
1137     pkg_id = get_physical_package_id(cpu);
1138     die_id = get_physical_die_id(cpu);
1139 
1140     for (i = 0; i < topo_max_cpus; i++) {
1141         if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1142             continue;
1143 
1144         if (pkg_id != get_physical_package_id(i) ||
1145             die_id != get_physical_die_id(i))
1146             continue;
1147 
1148         CPU_SET_S(i, ctdp_level->core_cpumask_size,
1149               ctdp_level->core_cpumask);
1150 
1151         cpu_bf = parse_int_file(1,
1152             "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1153                     i);
1154         if (cpu_bf > pbf_info->p1_high)
1155             pbf_info->p1_high = cpu_bf;
1156         if (cpu_bf < pbf_info->p1_low)
1157             pbf_info->p1_low = cpu_bf;
1158     }
1159 
1160     if (pbf_info->p1_high == ~0UL) {
1161         debug_printf("CLX: maximum base frequency not set\n");
1162         ret = -1;
1163         goto error_ret;
1164     }
1165 
1166     if (pbf_info->p1_low == 0) {
1167         debug_printf("CLX: minimum base frequency not set\n");
1168         ret = -1;
1169         goto error_ret;
1170     }
1171 
1172     /* convert frequencies back to ratios */
1173     pbf_info->p1_high = pbf_info->p1_high / 100000;
1174     pbf_info->p1_low = pbf_info->p1_low / 100000;
1175 
1176     /* create high priority cpu mask */
1177     pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
1178     for (i = 0; i < topo_max_cpus; i++) {
1179         if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1180             continue;
1181 
1182         if (pkg_id != get_physical_package_id(i) ||
1183             die_id != get_physical_die_id(i))
1184             continue;
1185 
1186         cpu_bf = parse_int_file(1,
1187             "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1188                     i);
1189         cpu_bf = cpu_bf / 100000;
1190         if (cpu_bf == pbf_info->p1_high)
1191             CPU_SET_S(i, pbf_info->core_cpumask_size,
1192                   pbf_info->core_cpumask);
1193     }
1194 
1195     /* extra ctdp & pbf struct parameters */
1196     ctdp_level->processed = 1;
1197     ctdp_level->pbf_support = 1; /* PBF is always supported and enabled */
1198     ctdp_level->pbf_enabled = 1;
1199     ctdp_level->fact_support = 0; /* FACT is never supported */
1200     ctdp_level->fact_enabled = 0;
1201 
1202     return 0;
1203 
1204 error_ret:
1205     free_cpu_set(ctdp_level->core_cpumask);
1206     return ret;
1207 }
1208 
1209 static void dump_clx_n_config_for_cpu(int cpu, void *arg1, void *arg2,
1210                    void *arg3, void *arg4)
1211 {
1212     int ret;
1213 
1214     if (tdp_level != 0xff && tdp_level != 0) {
1215         isst_display_error_info_message(1, "Invalid level", 1, tdp_level);
1216         exit(0);
1217     }
1218 
1219     ret = clx_n_config(cpu);
1220     if (ret) {
1221         debug_printf("clx_n_config failed");
1222     } else {
1223         struct isst_pkg_ctdp_level_info *ctdp_level;
1224         struct isst_pbf_info *pbf_info;
1225 
1226         ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1227         pbf_info = &ctdp_level->pbf_info;
1228         clx_n_pkg_dev.processed = 1;
1229         isst_ctdp_display_information(cpu, outf, tdp_level, &clx_n_pkg_dev);
1230         free_cpu_set(ctdp_level->core_cpumask);
1231         free_cpu_set(pbf_info->core_cpumask);
1232     }
1233 }
1234 
1235 static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2,
1236                      void *arg3, void *arg4)
1237 {
1238     struct isst_pkg_ctdp pkg_dev;
1239     int ret;
1240 
1241     memset(&pkg_dev, 0, sizeof(pkg_dev));
1242     ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev);
1243     if (ret) {
1244         isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, cpu);
1245         isst_ctdp_display_information_end(outf);
1246         exit(1);
1247     } else {
1248         isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev);
1249         isst_get_process_ctdp_complete(cpu, &pkg_dev);
1250     }
1251 }
1252 
1253 static void dump_isst_config(int arg)
1254 {
1255     void *fn;
1256 
1257     if (cmd_help) {
1258         fprintf(stderr,
1259             "Print Intel(R) Speed Select Technology Performance profile configuration\n");
1260         fprintf(stderr,
1261             "including base frequency and turbo frequency configurations\n");
1262         fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
1263         fprintf(stderr,
1264             "\tIf no arguments, dump information for all TDP levels\n");
1265         exit(0);
1266     }
1267 
1268     if (!is_clx_n_platform())
1269         fn = dump_isst_config_for_cpu;
1270     else
1271         fn = dump_clx_n_config_for_cpu;
1272 
1273     isst_ctdp_display_information_start(outf);
1274 
1275     if (max_target_cpus)
1276         for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1277     else
1278         for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL);
1279 
1280     isst_ctdp_display_information_end(outf);
1281 }
1282 
1283 static void adjust_scaling_max_from_base_freq(int cpu);
1284 
1285 static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1286                   void *arg4)
1287 {
1288     int ret;
1289 
1290     ret = isst_set_tdp_level(cpu, tdp_level);
1291     if (ret) {
1292         isst_display_error_info_message(1, "Set TDP level failed", 0, 0);
1293         isst_ctdp_display_information_end(outf);
1294         exit(1);
1295     } else {
1296         isst_display_result(cpu, outf, "perf-profile", "set_tdp_level",
1297                     ret);
1298         if (force_online_offline) {
1299             struct isst_pkg_ctdp_level_info ctdp_level;
1300             int pkg_id = get_physical_package_id(cpu);
1301             int die_id = get_physical_die_id(cpu);
1302 
1303             /* Wait for updated base frequencies */
1304             usleep(2000);
1305 
1306             fprintf(stderr, "Option is set to online/offline\n");
1307             ctdp_level.core_cpumask_size =
1308                 alloc_cpu_set(&ctdp_level.core_cpumask);
1309             ret = isst_get_coremask_info(cpu, tdp_level, &ctdp_level);
1310             if (ret) {
1311                 isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
1312                 return;
1313             }
1314             if (ctdp_level.cpu_count) {
1315                 int i, max_cpus = get_topo_max_cpus();
1316                 for (i = 0; i < max_cpus; ++i) {
1317                     if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
1318                         continue;
1319                     if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
1320                         fprintf(stderr, "online cpu %d\n", i);
1321                         set_cpu_online_offline(i, 1);
1322                         adjust_scaling_max_from_base_freq(i);
1323                     } else {
1324                         fprintf(stderr, "offline cpu %d\n", i);
1325                         set_cpu_online_offline(i, 0);
1326                     }
1327                 }
1328             }
1329         }
1330     }
1331 }
1332 
1333 static void set_tdp_level(int arg)
1334 {
1335     if (cmd_help) {
1336         fprintf(stderr, "Set Config TDP level\n");
1337         fprintf(stderr,
1338             "\t Arguments: -l|--level : Specify tdp level\n");
1339         fprintf(stderr,
1340             "\t Optional Arguments: -o | online : online/offline for the tdp level\n");
1341         fprintf(stderr,
1342             "\t  online/offline operation has limitations, refer to Linux hotplug documentation\n");
1343         exit(0);
1344     }
1345 
1346     if (tdp_level == 0xff) {
1347         isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1348         exit(1);
1349     }
1350     isst_ctdp_display_information_start(outf);
1351     if (max_target_cpus)
1352         for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
1353                           NULL, NULL, NULL);
1354     else
1355         for_each_online_package_in_set(set_tdp_level_for_cpu, NULL,
1356                            NULL, NULL, NULL);
1357     isst_ctdp_display_information_end(outf);
1358 }
1359 
1360 static void clx_n_dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2,
1361                        void *arg3, void *arg4)
1362 {
1363     int ret;
1364 
1365     ret = clx_n_config(cpu);
1366     if (ret) {
1367         isst_display_error_info_message(1, "clx_n_config failed", 0, 0);
1368     } else {
1369         struct isst_pkg_ctdp_level_info *ctdp_level;
1370         struct isst_pbf_info *pbf_info;
1371 
1372         ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1373         pbf_info = &ctdp_level->pbf_info;
1374         isst_pbf_display_information(cpu, outf, tdp_level, pbf_info);
1375         free_cpu_set(ctdp_level->core_cpumask);
1376         free_cpu_set(pbf_info->core_cpumask);
1377     }
1378 }
1379 
1380 static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1381                     void *arg4)
1382 {
1383     struct isst_pbf_info pbf_info;
1384     int ret;
1385 
1386     ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info);
1387     if (ret) {
1388         isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level);
1389         isst_ctdp_display_information_end(outf);
1390         exit(1);
1391     } else {
1392         isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info);
1393         isst_get_pbf_info_complete(&pbf_info);
1394     }
1395 }
1396 
1397 static void dump_pbf_config(int arg)
1398 {
1399     void *fn;
1400 
1401     if (cmd_help) {
1402         fprintf(stderr,
1403             "Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
1404         fprintf(stderr,
1405             "\tArguments: -l|--level : Specify tdp level\n");
1406         exit(0);
1407     }
1408 
1409     if (tdp_level == 0xff) {
1410         isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1411         exit(1);
1412     }
1413 
1414     if (!is_clx_n_platform())
1415         fn = dump_pbf_config_for_cpu;
1416     else
1417         fn = clx_n_dump_pbf_config_for_cpu;
1418 
1419     isst_ctdp_display_information_start(outf);
1420 
1421     if (max_target_cpus)
1422         for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1423     else
1424         for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL);
1425 
1426     isst_ctdp_display_information_end(outf);
1427 }
1428 
1429 static int set_clos_param(int cpu, int clos, int epp, int wt, int min, int max)
1430 {
1431     struct isst_clos_config clos_config;
1432     int ret;
1433 
1434     ret = isst_pm_get_clos(cpu, clos, &clos_config);
1435     if (ret) {
1436         isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
1437         return ret;
1438     }
1439     clos_config.clos_min = min;
1440     clos_config.clos_max = max;
1441     clos_config.epp = epp;
1442     clos_config.clos_prop_prio = wt;
1443     ret = isst_set_clos(cpu, clos, &clos_config);
1444     if (ret) {
1445         isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
1446         return ret;
1447     }
1448 
1449     return 0;
1450 }
1451 
1452 static int set_cpufreq_scaling_min_max(int cpu, int max, int freq)
1453 {
1454     char buffer[128], freq_str[16];
1455     int fd, ret, len;
1456 
1457     if (max)
1458         snprintf(buffer, sizeof(buffer),
1459              "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1460     else
1461         snprintf(buffer, sizeof(buffer),
1462              "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1463 
1464     fd = open(buffer, O_WRONLY);
1465     if (fd < 0)
1466         return fd;
1467 
1468     snprintf(freq_str, sizeof(freq_str), "%d", freq);
1469     len = strlen(freq_str);
1470     ret = write(fd, freq_str, len);
1471     if (ret == -1) {
1472         close(fd);
1473         return ret;
1474     }
1475     close(fd);
1476 
1477     return 0;
1478 }
1479 
1480 static int no_turbo(void)
1481 {
1482     return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo");
1483 }
1484 
1485 static void adjust_scaling_max_from_base_freq(int cpu)
1486 {
1487     int base_freq, scaling_max_freq;
1488 
1489     scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1490     base_freq = get_cpufreq_base_freq(cpu);
1491     if (scaling_max_freq < base_freq || no_turbo())
1492         set_cpufreq_scaling_min_max(cpu, 1, base_freq);
1493 }
1494 
1495 static void adjust_scaling_min_from_base_freq(int cpu)
1496 {
1497     int base_freq, scaling_min_freq;
1498 
1499     scaling_min_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1500     base_freq = get_cpufreq_base_freq(cpu);
1501     if (scaling_min_freq < base_freq)
1502         set_cpufreq_scaling_min_max(cpu, 0, base_freq);
1503 }
1504 
1505 static int set_clx_pbf_cpufreq_scaling_min_max(int cpu)
1506 {
1507     struct isst_pkg_ctdp_level_info *ctdp_level;
1508     struct isst_pbf_info *pbf_info;
1509     int i, pkg_id, die_id, freq, freq_high, freq_low;
1510     int ret;
1511 
1512     ret = clx_n_config(cpu);
1513     if (ret) {
1514         debug_printf("cpufreq_scaling_min_max failed for CLX");
1515         return ret;
1516     }
1517 
1518     ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1519     pbf_info = &ctdp_level->pbf_info;
1520     freq_high = pbf_info->p1_high * 100000;
1521     freq_low = pbf_info->p1_low * 100000;
1522 
1523     pkg_id = get_physical_package_id(cpu);
1524     die_id = get_physical_die_id(cpu);
1525     for (i = 0; i < get_topo_max_cpus(); ++i) {
1526         if (pkg_id != get_physical_package_id(i) ||
1527             die_id != get_physical_die_id(i))
1528             continue;
1529 
1530         if (CPU_ISSET_S(i, pbf_info->core_cpumask_size,
1531                   pbf_info->core_cpumask))
1532             freq = freq_high;
1533         else
1534             freq = freq_low;
1535 
1536         set_cpufreq_scaling_min_max(i, 1, freq);
1537         set_cpufreq_scaling_min_max(i, 0, freq);
1538     }
1539 
1540     return 0;
1541 }
1542 
1543 static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, int scaling_max)
1544 {
1545     char buffer[128], min_freq[16];
1546     int fd, ret, len;
1547 
1548     if (!CPU_ISSET_S(cpu, present_cpumask_size, present_cpumask))
1549         return -1;
1550 
1551     if (cpuinfo_max)
1552         snprintf(buffer, sizeof(buffer),
1553              "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu);
1554     else
1555         snprintf(buffer, sizeof(buffer),
1556              "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpu);
1557 
1558     fd = open(buffer, O_RDONLY);
1559     if (fd < 0)
1560         return fd;
1561 
1562     len = read(fd, min_freq, sizeof(min_freq));
1563     close(fd);
1564 
1565     if (len < 0)
1566         return len;
1567 
1568     if (scaling_max)
1569         snprintf(buffer, sizeof(buffer),
1570              "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1571     else
1572         snprintf(buffer, sizeof(buffer),
1573              "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1574 
1575     fd = open(buffer, O_WRONLY);
1576     if (fd < 0)
1577         return fd;
1578 
1579     len = strlen(min_freq);
1580     ret = write(fd, min_freq, len);
1581     if (ret == -1) {
1582         close(fd);
1583         return ret;
1584     }
1585     close(fd);
1586 
1587     return 0;
1588 }
1589 
1590 static void set_scaling_min_to_cpuinfo_max(int cpu)
1591 {
1592     int i, pkg_id, die_id;
1593 
1594     pkg_id = get_physical_package_id(cpu);
1595     die_id = get_physical_die_id(cpu);
1596     for (i = 0; i < get_topo_max_cpus(); ++i) {
1597         if (pkg_id != get_physical_package_id(i) ||
1598             die_id != get_physical_die_id(i))
1599             continue;
1600 
1601         adjust_scaling_max_from_base_freq(i);
1602         set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0);
1603         adjust_scaling_min_from_base_freq(i);
1604     }
1605 }
1606 
1607 static void set_scaling_min_to_cpuinfo_min(int cpu)
1608 {
1609     int i, pkg_id, die_id;
1610 
1611     pkg_id = get_physical_package_id(cpu);
1612     die_id = get_physical_die_id(cpu);
1613     for (i = 0; i < get_topo_max_cpus(); ++i) {
1614         if (pkg_id != get_physical_package_id(i) ||
1615             die_id != get_physical_die_id(i))
1616             continue;
1617 
1618         adjust_scaling_max_from_base_freq(i);
1619         set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0);
1620     }
1621 }
1622 
1623 static void set_scaling_max_to_cpuinfo_max(int cpu)
1624 {
1625     int i, pkg_id, die_id;
1626 
1627     pkg_id = get_physical_package_id(cpu);
1628     die_id = get_physical_die_id(cpu);
1629     for (i = 0; i < get_topo_max_cpus(); ++i) {
1630         if (pkg_id != get_physical_package_id(i) ||
1631             die_id != get_physical_die_id(i))
1632             continue;
1633 
1634         set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1);
1635     }
1636 }
1637 
1638 static int set_core_priority_and_min(int cpu, int mask_size,
1639                      cpu_set_t *cpu_mask, int min_high,
1640                      int min_low)
1641 {
1642     int pkg_id, die_id, ret, i;
1643 
1644     if (!CPU_COUNT_S(mask_size, cpu_mask))
1645         return -1;
1646 
1647     ret = set_clos_param(cpu, 0, 0, 0, min_high, 0xff);
1648     if (ret)
1649         return ret;
1650 
1651     ret = set_clos_param(cpu, 1, 15, 15, min_low, 0xff);
1652     if (ret)
1653         return ret;
1654 
1655     ret = set_clos_param(cpu, 2, 15, 15, min_low, 0xff);
1656     if (ret)
1657         return ret;
1658 
1659     ret = set_clos_param(cpu, 3, 15, 15, min_low, 0xff);
1660     if (ret)
1661         return ret;
1662 
1663     pkg_id = get_physical_package_id(cpu);
1664     die_id = get_physical_die_id(cpu);
1665     for (i = 0; i < get_topo_max_cpus(); ++i) {
1666         int clos;
1667 
1668         if (pkg_id != get_physical_package_id(i) ||
1669             die_id != get_physical_die_id(i))
1670             continue;
1671 
1672         if (CPU_ISSET_S(i, mask_size, cpu_mask))
1673             clos = 0;
1674         else
1675             clos = 3;
1676 
1677         debug_printf("Associate cpu: %d clos: %d\n", i, clos);
1678         ret = isst_clos_associate(i, clos);
1679         if (ret) {
1680             isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0);
1681             return ret;
1682         }
1683     }
1684 
1685     return 0;
1686 }
1687 
1688 static int set_pbf_core_power(int cpu)
1689 {
1690     struct isst_pbf_info pbf_info;
1691     struct isst_pkg_ctdp pkg_dev;
1692     int ret;
1693 
1694     ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1695     if (ret) {
1696         debug_printf("isst_get_ctdp_levels failed");
1697         return ret;
1698     }
1699     debug_printf("Current_level: %d\n", pkg_dev.current_level);
1700 
1701     ret = isst_get_pbf_info(cpu, pkg_dev.current_level, &pbf_info);
1702     if (ret) {
1703         debug_printf("isst_get_pbf_info failed");
1704         return ret;
1705     }
1706     debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high,
1707              pbf_info.p1_low);
1708 
1709     ret = set_core_priority_and_min(cpu, pbf_info.core_cpumask_size,
1710                     pbf_info.core_cpumask,
1711                     pbf_info.p1_high, pbf_info.p1_low);
1712     if (ret) {
1713         debug_printf("set_core_priority_and_min failed");
1714         return ret;
1715     }
1716 
1717     ret = isst_pm_qos_config(cpu, 1, 1);
1718     if (ret) {
1719         debug_printf("isst_pm_qos_config failed");
1720         return ret;
1721     }
1722 
1723     return 0;
1724 }
1725 
1726 static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1727                 void *arg4)
1728 {
1729     struct isst_pkg_ctdp_level_info ctdp_level;
1730     struct isst_pkg_ctdp pkg_dev;
1731     int ret;
1732     int status = *(int *)arg4;
1733 
1734     if (is_clx_n_platform()) {
1735         ret = 0;
1736         if (status) {
1737             set_clx_pbf_cpufreq_scaling_min_max(cpu);
1738 
1739         } else {
1740             set_scaling_max_to_cpuinfo_max(cpu);
1741             set_scaling_min_to_cpuinfo_min(cpu);
1742         }
1743         goto disp_result;
1744     }
1745 
1746     ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1747     if (ret) {
1748         isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
1749         goto disp_result;
1750     }
1751 
1752     ret = isst_get_ctdp_control(cpu, pkg_dev.current_level, &ctdp_level);
1753     if (ret) {
1754         isst_display_error_info_message(1, "Failed to get current level", 0, 0);
1755         goto disp_result;
1756     }
1757 
1758     if (!ctdp_level.pbf_support) {
1759         isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, pkg_dev.current_level);
1760         ret = -1;
1761         goto disp_result;
1762     }
1763 
1764     if (auto_mode && status) {
1765         ret = set_pbf_core_power(cpu);
1766         if (ret)
1767             goto disp_result;
1768     }
1769 
1770     ret = isst_set_pbf_fact_status(cpu, 1, status);
1771     if (ret) {
1772         debug_printf("isst_set_pbf_fact_status failed");
1773         if (auto_mode)
1774             isst_pm_qos_config(cpu, 0, 0);
1775     } else {
1776         if (auto_mode) {
1777             if (status)
1778                 set_scaling_min_to_cpuinfo_max(cpu);
1779             else
1780                 set_scaling_min_to_cpuinfo_min(cpu);
1781         }
1782     }
1783 
1784     if (auto_mode && !status)
1785         isst_pm_qos_config(cpu, 0, 1);
1786 
1787 disp_result:
1788     if (status)
1789         isst_display_result(cpu, outf, "base-freq", "enable",
1790                     ret);
1791     else
1792         isst_display_result(cpu, outf, "base-freq", "disable",
1793                     ret);
1794 }
1795 
1796 static void set_pbf_enable(int arg)
1797 {
1798     int enable = arg;
1799 
1800     if (cmd_help) {
1801         if (enable) {
1802             fprintf(stderr,
1803                 "Enable Intel Speed Select Technology base frequency feature\n");
1804             if (is_clx_n_platform()) {
1805                 fprintf(stderr,
1806                     "\tOn this platform this command doesn't enable feature in the hardware.\n");
1807                 fprintf(stderr,
1808                     "\tIt updates the cpufreq scaling_min_freq to match cpufreq base_frequency.\n");
1809                 exit(0);
1810 
1811             }
1812             fprintf(stderr,
1813                 "\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n");
1814         } else {
1815 
1816             if (is_clx_n_platform()) {
1817                 fprintf(stderr,
1818                     "\tOn this platform this command doesn't disable feature in the hardware.\n");
1819                 fprintf(stderr,
1820                     "\tIt updates the cpufreq scaling_min_freq to match cpuinfo_min_freq\n");
1821                 exit(0);
1822             }
1823             fprintf(stderr,
1824                 "Disable Intel Speed Select Technology base frequency feature\n");
1825             fprintf(stderr,
1826                 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
1827         }
1828         exit(0);
1829     }
1830 
1831     isst_ctdp_display_information_start(outf);
1832     if (max_target_cpus)
1833         for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
1834                           NULL, &enable);
1835     else
1836         for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
1837                            NULL, &enable);
1838     isst_ctdp_display_information_end(outf);
1839 }
1840 
1841 static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2,
1842                      void *arg3, void *arg4)
1843 {
1844     struct isst_fact_info fact_info;
1845     int ret;
1846 
1847     ret = isst_get_fact_info(cpu, tdp_level, fact_bucket, &fact_info);
1848     if (ret) {
1849         isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level);
1850         isst_ctdp_display_information_end(outf);
1851         exit(1);
1852     } else {
1853         isst_fact_display_information(cpu, outf, tdp_level, fact_bucket,
1854                           fact_avx, &fact_info);
1855     }
1856 }
1857 
1858 static void dump_fact_config(int arg)
1859 {
1860     if (cmd_help) {
1861         fprintf(stderr,
1862             "Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
1863         fprintf(stderr,
1864             "\tArguments: -l|--level : Specify tdp level\n");
1865         fprintf(stderr,
1866             "\tArguments: -b|--bucket : Bucket index to dump\n");
1867         fprintf(stderr,
1868             "\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
1869         exit(0);
1870     }
1871 
1872     if (tdp_level == 0xff) {
1873         isst_display_error_info_message(1, "Invalid command: specify tdp_level\n", 0, 0);
1874         exit(1);
1875     }
1876 
1877     isst_ctdp_display_information_start(outf);
1878     if (max_target_cpus)
1879         for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
1880                           NULL, NULL, NULL, NULL);
1881     else
1882         for_each_online_package_in_set(dump_fact_config_for_cpu, NULL,
1883                            NULL, NULL, NULL);
1884     isst_ctdp_display_information_end(outf);
1885 }
1886 
1887 static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1888                  void *arg4)
1889 {
1890     struct isst_pkg_ctdp_level_info ctdp_level;
1891     struct isst_pkg_ctdp pkg_dev;
1892     int ret;
1893     int status = *(int *)arg4;
1894 
1895     if (status && no_turbo()) {
1896         isst_display_error_info_message(1, "Turbo mode is disabled", 0, 0);
1897         ret = -1;
1898         goto disp_results;
1899     }
1900 
1901     ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1902     if (ret) {
1903         isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
1904         goto disp_results;
1905     }
1906 
1907     ret = isst_get_ctdp_control(cpu, pkg_dev.current_level, &ctdp_level);
1908     if (ret) {
1909         isst_display_error_info_message(1, "Failed to get current level", 0, 0);
1910         goto disp_results;
1911     }
1912 
1913     if (!ctdp_level.fact_support) {
1914         isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, pkg_dev.current_level);
1915         ret = -1;
1916         goto disp_results;
1917     }
1918 
1919     if (status) {
1920         ret = isst_pm_qos_config(cpu, 1, 1);
1921         if (ret)
1922             goto disp_results;
1923     }
1924 
1925     ret = isst_set_pbf_fact_status(cpu, 0, status);
1926     if (ret) {
1927         debug_printf("isst_set_pbf_fact_status failed");
1928         if (auto_mode)
1929             isst_pm_qos_config(cpu, 0, 0);
1930 
1931         goto disp_results;
1932     }
1933 
1934     /* Set TRL */
1935     if (status) {
1936         struct isst_pkg_ctdp pkg_dev;
1937 
1938         ret = isst_get_ctdp_levels(cpu, &pkg_dev);
1939         if (!ret)
1940             ret = isst_set_trl(cpu, fact_trl);
1941         if (ret && auto_mode)
1942             isst_pm_qos_config(cpu, 0, 0);
1943     } else {
1944         if (auto_mode)
1945             isst_pm_qos_config(cpu, 0, 0);
1946     }
1947 
1948 disp_results:
1949     if (status) {
1950         isst_display_result(cpu, outf, "turbo-freq", "enable", ret);
1951         if (ret)
1952             fact_enable_fail = ret;
1953     } else {
1954         /* Since we modified TRL during Fact enable, restore it */
1955         isst_set_trl_from_current_tdp(cpu, fact_trl);
1956         isst_display_result(cpu, outf, "turbo-freq", "disable", ret);
1957     }
1958 }
1959 
1960 static void set_fact_enable(int arg)
1961 {
1962     int i, ret, enable = arg;
1963 
1964     if (cmd_help) {
1965         if (enable) {
1966             fprintf(stderr,
1967                 "Enable Intel Speed Select Technology Turbo frequency feature\n");
1968             fprintf(stderr,
1969                 "Optional: -t|--trl : Specify turbo ratio limit\n");
1970             fprintf(stderr,
1971                 "\tOptional Arguments: -a|--auto : Designate specified target CPUs with");
1972             fprintf(stderr,
1973                 "-C|--cpu option as as high priority using core-power feature\n");
1974         } else {
1975             fprintf(stderr,
1976                 "Disable Intel Speed Select Technology turbo frequency feature\n");
1977             fprintf(stderr,
1978                 "Optional: -t|--trl : Specify turbo ratio limit\n");
1979             fprintf(stderr,
1980                 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
1981         }
1982         exit(0);
1983     }
1984 
1985     isst_ctdp_display_information_start(outf);
1986     if (max_target_cpus)
1987         for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
1988                           NULL, &enable);
1989     else
1990         for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
1991                            NULL, &enable);
1992     isst_ctdp_display_information_end(outf);
1993 
1994     if (!fact_enable_fail && enable && auto_mode) {
1995         /*
1996          * When we adjust CLOS param, we have to set for siblings also.
1997          * So for the each user specified CPU, also add the sibling
1998          * in the present_cpu_mask.
1999          */
2000         for (i = 0; i < get_topo_max_cpus(); ++i) {
2001             char buffer[128], sibling_list[128], *cpu_str;
2002             int fd, len;
2003 
2004             if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
2005                 continue;
2006 
2007             snprintf(buffer, sizeof(buffer),
2008                  "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i);
2009 
2010             fd = open(buffer, O_RDONLY);
2011             if (fd < 0)
2012                 continue;
2013 
2014             len = read(fd, sibling_list, sizeof(sibling_list));
2015             close(fd);
2016 
2017             if (len < 0)
2018                 continue;
2019 
2020             cpu_str = strtok(sibling_list, ",");
2021             while (cpu_str != NULL) {
2022                 int cpu;
2023 
2024                 sscanf(cpu_str, "%d", &cpu);
2025                 CPU_SET_S(cpu, target_cpumask_size, target_cpumask);
2026                 cpu_str = strtok(NULL, ",");
2027             }
2028         }
2029 
2030         for (i = 0; i < get_topo_max_cpus(); ++i) {
2031             int clos;
2032 
2033             if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
2034                 continue;
2035 
2036             ret = set_clos_param(i, 0, 0, 0, 0, 0xff);
2037             if (ret)
2038                 goto error_disp;
2039 
2040             ret = set_clos_param(i, 1, 15, 15, 0, 0xff);
2041             if (ret)
2042                 goto error_disp;
2043 
2044             ret = set_clos_param(i, 2, 15, 15, 0, 0xff);
2045             if (ret)
2046                 goto error_disp;
2047 
2048             ret = set_clos_param(i, 3, 15, 15, 0, 0xff);
2049             if (ret)
2050                 goto error_disp;
2051 
2052             if (CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
2053                 clos = 0;
2054             else
2055                 clos = 3;
2056 
2057             debug_printf("Associate cpu: %d clos: %d\n", i, clos);
2058             ret = isst_clos_associate(i, clos);
2059             if (ret)
2060                 goto error_disp;
2061         }
2062         isst_display_result(-1, outf, "turbo-freq --auto", "enable", 0);
2063     }
2064 
2065     return;
2066 
2067 error_disp:
2068     isst_display_result(i, outf, "turbo-freq --auto", "enable", ret);
2069 
2070 }
2071 
2072 static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
2073                    void *arg4)
2074 {
2075     int ret;
2076     int status = *(int *)arg4;
2077 
2078     if (is_skx_based_platform())
2079         clos_priority_type = 1;
2080 
2081     ret = isst_pm_qos_config(cpu, status, clos_priority_type);
2082     if (ret)
2083         isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0);
2084 
2085     if (status)
2086         isst_display_result(cpu, outf, "core-power", "enable",
2087                     ret);
2088     else
2089         isst_display_result(cpu, outf, "core-power", "disable",
2090                     ret);
2091 }
2092 
2093 static void set_clos_enable(int arg)
2094 {
2095     int enable = arg;
2096 
2097     if (cmd_help) {
2098         if (enable) {
2099             fprintf(stderr,
2100                 "Enable core-power for a package/die\n");
2101             if (!is_skx_based_platform()) {
2102                 fprintf(stderr,
2103                     "\tClos Enable: Specify priority type with [--priority|-p]\n");
2104                 fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
2105             }
2106         } else {
2107             fprintf(stderr,
2108                 "Disable core-power: [No command arguments are required]\n");
2109         }
2110         exit(0);
2111     }
2112 
2113     if (enable && cpufreq_sysfs_present()) {
2114         fprintf(stderr,
2115             "cpufreq subsystem and core-power enable will interfere with each other!\n");
2116     }
2117 
2118     isst_ctdp_display_information_start(outf);
2119     if (max_target_cpus)
2120         for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
2121                           NULL, NULL, &enable);
2122     else
2123         for_each_online_package_in_set(enable_clos_qos_config, NULL,
2124                            NULL, NULL, &enable);
2125     isst_ctdp_display_information_end(outf);
2126 }
2127 
2128 static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2,
2129                      void *arg3, void *arg4)
2130 {
2131     struct isst_clos_config clos_config;
2132     int ret;
2133 
2134     ret = isst_pm_get_clos(cpu, current_clos, &clos_config);
2135     if (ret)
2136         isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
2137     else
2138         isst_clos_display_information(cpu, outf, current_clos,
2139                           &clos_config);
2140 }
2141 
2142 static void dump_clos_config(int arg)
2143 {
2144     if (cmd_help) {
2145         fprintf(stderr,
2146             "Print Intel Speed Select Technology core power configuration\n");
2147         fprintf(stderr,
2148             "\tArguments: [-c | --clos]: Specify clos id\n");
2149         exit(0);
2150     }
2151     if (current_clos < 0 || current_clos > 3) {
2152         isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2153         isst_ctdp_display_information_end(outf);
2154         exit(0);
2155     }
2156 
2157     isst_ctdp_display_information_start(outf);
2158     if (max_target_cpus)
2159         for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
2160                           NULL, NULL, NULL, NULL);
2161     else
2162         for_each_online_package_in_set(dump_clos_config_for_cpu, NULL,
2163                            NULL, NULL, NULL);
2164     isst_ctdp_display_information_end(outf);
2165 }
2166 
2167 static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2168                   void *arg4)
2169 {
2170     int enable, ret, prio_type;
2171 
2172     ret = isst_clos_get_clos_information(cpu, &enable, &prio_type);
2173     if (ret)
2174         isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0);
2175     else {
2176         int cp_state, cp_cap;
2177 
2178         isst_read_pm_config(cpu, &cp_state, &cp_cap);
2179         isst_clos_display_clos_information(cpu, outf, enable, prio_type,
2180                            cp_state, cp_cap);
2181     }
2182 }
2183 
2184 static void dump_clos_info(int arg)
2185 {
2186     if (cmd_help) {
2187         fprintf(stderr,
2188             "Print Intel Speed Select Technology core power information\n");
2189         fprintf(stderr, "\t Optionally specify targeted cpu id with [--cpu|-c]\n");
2190         exit(0);
2191     }
2192 
2193     isst_ctdp_display_information_start(outf);
2194     if (max_target_cpus)
2195         for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL,
2196                           NULL, NULL, NULL);
2197     else
2198         for_each_online_package_in_set(get_clos_info_for_cpu, NULL,
2199                            NULL, NULL, NULL);
2200     isst_ctdp_display_information_end(outf);
2201 
2202 }
2203 
2204 static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2205                     void *arg4)
2206 {
2207     struct isst_clos_config clos_config;
2208     int ret;
2209 
2210     clos_config.pkg_id = get_physical_package_id(cpu);
2211     clos_config.die_id = get_physical_die_id(cpu);
2212 
2213     clos_config.epp = clos_epp;
2214     clos_config.clos_prop_prio = clos_prop_prio;
2215     clos_config.clos_min = clos_min;
2216     clos_config.clos_max = clos_max;
2217     clos_config.clos_desired = clos_desired;
2218     ret = isst_set_clos(cpu, current_clos, &clos_config);
2219     if (ret)
2220         isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
2221     else
2222         isst_display_result(cpu, outf, "core-power", "config", ret);
2223 }
2224 
2225 static void set_clos_config(int arg)
2226 {
2227     if (cmd_help) {
2228         fprintf(stderr,
2229             "Set core-power configuration for one of the four clos ids\n");
2230         fprintf(stderr,
2231             "\tSpecify targeted clos id with [--clos|-c]\n");
2232         if (!is_skx_based_platform()) {
2233             fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
2234             fprintf(stderr,
2235                 "\tSpecify clos Proportional Priority [--weight|-w]\n");
2236         }
2237         fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n");
2238         fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n");
2239         exit(0);
2240     }
2241 
2242     if (current_clos < 0 || current_clos > 3) {
2243         isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2244         exit(0);
2245     }
2246     if (!is_skx_based_platform() && (clos_epp < 0 || clos_epp > 0x0F)) {
2247         fprintf(stderr, "clos epp is not specified or invalid, default: 0\n");
2248         clos_epp = 0;
2249     }
2250     if (!is_skx_based_platform() && (clos_prop_prio < 0 || clos_prop_prio > 0x0F)) {
2251         fprintf(stderr,
2252             "clos frequency weight is not specified or invalid, default: 0\n");
2253         clos_prop_prio = 0;
2254     }
2255     if (clos_min < 0) {
2256         fprintf(stderr, "clos min is not specified, default: 0\n");
2257         clos_min = 0;
2258     }
2259     if (clos_max < 0) {
2260         fprintf(stderr, "clos max is not specified, default: Max frequency (ratio 0xff)\n");
2261         clos_max = 0xff;
2262     }
2263     if (clos_desired) {
2264         fprintf(stderr, "clos desired is not supported on this platform\n");
2265         clos_desired = 0x00;
2266     }
2267 
2268     isst_ctdp_display_information_start(outf);
2269     if (max_target_cpus)
2270         for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
2271                           NULL, NULL, NULL);
2272     else
2273         for_each_online_package_in_set(set_clos_config_for_cpu, NULL,
2274                            NULL, NULL, NULL);
2275     isst_ctdp_display_information_end(outf);
2276 }
2277 
2278 static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2279                    void *arg4)
2280 {
2281     int ret;
2282 
2283     ret = isst_clos_associate(cpu, current_clos);
2284     if (ret)
2285         debug_printf("isst_clos_associate failed");
2286     else
2287         isst_display_result(cpu, outf, "core-power", "assoc", ret);
2288 }
2289 
2290 static void set_clos_assoc(int arg)
2291 {
2292     if (cmd_help) {
2293         fprintf(stderr, "Associate a clos id to a CPU\n");
2294         fprintf(stderr,
2295             "\tSpecify targeted clos id with [--clos|-c]\n");
2296         fprintf(stderr,
2297             "\tFor example to associate clos 1 to CPU 0: issue\n");
2298         fprintf(stderr,
2299             "\tintel-speed-select --cpu 0 core-power assoc --clos 1\n");
2300         exit(0);
2301     }
2302 
2303     if (current_clos < 0 || current_clos > 3) {
2304         isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2305         exit(0);
2306     }
2307     if (max_target_cpus)
2308         for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
2309                           NULL, NULL, NULL);
2310     else {
2311         isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2312     }
2313 }
2314 
2315 static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
2316                    void *arg4)
2317 {
2318     int clos, ret;
2319 
2320     ret = isst_clos_get_assoc_status(cpu, &clos);
2321     if (ret)
2322         isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0);
2323     else
2324         isst_clos_display_assoc_information(cpu, outf, clos);
2325 }
2326 
2327 static void get_clos_assoc(int arg)
2328 {
2329     if (cmd_help) {
2330         fprintf(stderr, "Get associate clos id to a CPU\n");
2331         fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
2332         exit(0);
2333     }
2334 
2335     if (!max_target_cpus) {
2336         isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2337         exit(0);
2338     }
2339 
2340     isst_ctdp_display_information_start(outf);
2341     for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
2342                       NULL, NULL, NULL);
2343     isst_ctdp_display_information_end(outf);
2344 }
2345 
2346 static void set_turbo_mode_for_cpu(int cpu, int status)
2347 {
2348     int base_freq;
2349 
2350     if (status) {
2351         base_freq = get_cpufreq_base_freq(cpu);
2352         set_cpufreq_scaling_min_max(cpu, 1, base_freq);
2353     } else {
2354         set_scaling_max_to_cpuinfo_max(cpu);
2355     }
2356 
2357     if (status) {
2358         isst_display_result(cpu, outf, "turbo-mode", "enable", 0);
2359     } else {
2360         isst_display_result(cpu, outf, "turbo-mode", "disable", 0);
2361     }
2362 }
2363 
2364 static void set_turbo_mode(int arg)
2365 {
2366     int i, enable = arg;
2367 
2368     if (cmd_help) {
2369         if (enable)
2370             fprintf(stderr, "Set turbo mode enable\n");
2371         else
2372             fprintf(stderr, "Set turbo mode disable\n");
2373         exit(0);
2374     }
2375 
2376     isst_ctdp_display_information_start(outf);
2377 
2378     for (i = 0; i < topo_max_cpus; ++i) {
2379         int online;
2380 
2381         if (i)
2382             online = parse_int_file(
2383                 1, "/sys/devices/system/cpu/cpu%d/online", i);
2384         else
2385             online =
2386                 1; /* online entry for CPU 0 needs some special configs */
2387 
2388         if (online)
2389             set_turbo_mode_for_cpu(i, enable);
2390 
2391     }
2392     isst_ctdp_display_information_end(outf);
2393 }
2394 
2395 static void get_set_trl(int cpu, void *arg1, void *arg2, void *arg3,
2396             void *arg4)
2397 {
2398     unsigned long long trl;
2399     int set = *(int *)arg4;
2400     int ret;
2401 
2402     if (set && !fact_trl) {
2403         isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0);
2404         exit(0);
2405     }
2406 
2407     if (set) {
2408         ret = isst_set_trl(cpu, fact_trl);
2409         isst_display_result(cpu, outf, "turbo-mode", "set-trl", ret);
2410         return;
2411     }
2412 
2413     ret = isst_get_trl(cpu, &trl);
2414     if (ret)
2415         isst_display_result(cpu, outf, "turbo-mode", "get-trl", ret);
2416     else
2417         isst_trl_display_information(cpu, outf, trl);
2418 }
2419 
2420 static void process_trl(int arg)
2421 {
2422     if (cmd_help) {
2423         if (arg) {
2424             fprintf(stderr, "Set TRL (turbo ratio limits)\n");
2425             fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL\n");
2426         } else {
2427             fprintf(stderr, "Get TRL (turbo ratio limits)\n");
2428         }
2429         exit(0);
2430     }
2431 
2432     isst_ctdp_display_information_start(outf);
2433     if (max_target_cpus)
2434         for_each_online_target_cpu_in_set(get_set_trl, NULL,
2435                           NULL, NULL, &arg);
2436     else
2437         for_each_online_package_in_set(get_set_trl, NULL,
2438                            NULL, NULL, &arg);
2439     isst_ctdp_display_information_end(outf);
2440 }
2441 
2442 static struct process_cmd_struct clx_n_cmds[] = {
2443     { "perf-profile", "info", dump_isst_config, 0 },
2444     { "base-freq", "info", dump_pbf_config, 0 },
2445     { "base-freq", "enable", set_pbf_enable, 1 },
2446     { "base-freq", "disable", set_pbf_enable, 0 },
2447     { NULL, NULL, NULL, 0 }
2448 };
2449 
2450 static struct process_cmd_struct isst_cmds[] = {
2451     { "perf-profile", "get-lock-status", get_tdp_locked, 0 },
2452     { "perf-profile", "get-config-levels", get_tdp_levels, 0 },
2453     { "perf-profile", "get-config-version", get_tdp_version, 0 },
2454     { "perf-profile", "get-config-enabled", get_tdp_enabled, 0 },
2455     { "perf-profile", "get-config-current-level", get_tdp_current_level,
2456      0 },
2457     { "perf-profile", "set-config-level", set_tdp_level, 0 },
2458     { "perf-profile", "info", dump_isst_config, 0 },
2459     { "base-freq", "info", dump_pbf_config, 0 },
2460     { "base-freq", "enable", set_pbf_enable, 1 },
2461     { "base-freq", "disable", set_pbf_enable, 0 },
2462     { "turbo-freq", "info", dump_fact_config, 0 },
2463     { "turbo-freq", "enable", set_fact_enable, 1 },
2464     { "turbo-freq", "disable", set_fact_enable, 0 },
2465     { "core-power", "info", dump_clos_info, 0 },
2466     { "core-power", "enable", set_clos_enable, 1 },
2467     { "core-power", "disable", set_clos_enable, 0 },
2468     { "core-power", "config", set_clos_config, 0 },
2469     { "core-power", "get-config", dump_clos_config, 0 },
2470     { "core-power", "assoc", set_clos_assoc, 0 },
2471     { "core-power", "get-assoc", get_clos_assoc, 0 },
2472     { "turbo-mode", "enable", set_turbo_mode, 0 },
2473     { "turbo-mode", "disable", set_turbo_mode, 1 },
2474     { "turbo-mode", "get-trl", process_trl, 0 },
2475     { "turbo-mode", "set-trl", process_trl, 1 },
2476     { NULL, NULL, NULL }
2477 };
2478 
2479 /*
2480  * parse cpuset with following syntax
2481  * 1,2,4..6,8-10 and set bits in cpu_subset
2482  */
2483 void parse_cpu_command(char *optarg)
2484 {
2485     unsigned int start, end;
2486     char *next;
2487 
2488     next = optarg;
2489 
2490     while (next && *next) {
2491         if (*next == '-') /* no negative cpu numbers */
2492             goto error;
2493 
2494         start = strtoul(next, &next, 10);
2495 
2496         if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2497             target_cpus[max_target_cpus++] = start;
2498 
2499         if (*next == '\0')
2500             break;
2501 
2502         if (*next == ',') {
2503             next += 1;
2504             continue;
2505         }
2506 
2507         if (*next == '-') {
2508             next += 1; /* start range */
2509         } else if (*next == '.') {
2510             next += 1;
2511             if (*next == '.')
2512                 next += 1; /* start range */
2513             else
2514                 goto error;
2515         }
2516 
2517         end = strtoul(next, &next, 10);
2518         if (end <= start)
2519             goto error;
2520 
2521         while (++start <= end) {
2522             if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2523                 target_cpus[max_target_cpus++] = start;
2524         }
2525 
2526         if (*next == ',')
2527             next += 1;
2528         else if (*next != '\0')
2529             goto error;
2530     }
2531 
2532 #ifdef DEBUG
2533     {
2534         int i;
2535 
2536         for (i = 0; i < max_target_cpus; ++i)
2537             printf("cpu [%d] in arg\n", target_cpus[i]);
2538     }
2539 #endif
2540     return;
2541 
2542 error:
2543     fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
2544     exit(-1);
2545 }
2546 
2547 static void parse_cmd_args(int argc, int start, char **argv)
2548 {
2549     int opt;
2550     int option_index;
2551 
2552     static struct option long_options[] = {
2553         { "bucket", required_argument, 0, 'b' },
2554         { "level", required_argument, 0, 'l' },
2555         { "online", required_argument, 0, 'o' },
2556         { "trl-type", required_argument, 0, 'r' },
2557         { "trl", required_argument, 0, 't' },
2558         { "help", no_argument, 0, 'h' },
2559         { "clos", required_argument, 0, 'c' },
2560         { "desired", required_argument, 0, 'd' },
2561         { "epp", required_argument, 0, 'e' },
2562         { "min", required_argument, 0, 'n' },
2563         { "max", required_argument, 0, 'm' },
2564         { "priority", required_argument, 0, 'p' },
2565         { "weight", required_argument, 0, 'w' },
2566         { "auto", no_argument, 0, 'a' },
2567         { 0, 0, 0, 0 }
2568     };
2569 
2570     option_index = start;
2571 
2572     optind = start + 1;
2573     while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:r:hoa",
2574                   long_options, &option_index)) != -1) {
2575         switch (opt) {
2576         case 'a':
2577             auto_mode = 1;
2578             break;
2579         case 'b':
2580             fact_bucket = atoi(optarg);
2581             break;
2582         case 'h':
2583             cmd_help = 1;
2584             break;
2585         case 'l':
2586             tdp_level = atoi(optarg);
2587             break;
2588         case 'o':
2589             force_online_offline = 1;
2590             break;
2591         case 't':
2592             sscanf(optarg, "0x%llx", &fact_trl);
2593             break;
2594         case 'r':
2595             if (!strncmp(optarg, "sse", 3)) {
2596                 fact_avx = 0x01;
2597             } else if (!strncmp(optarg, "avx2", 4)) {
2598                 fact_avx = 0x02;
2599             } else if (!strncmp(optarg, "avx512", 6)) {
2600                 fact_avx = 0x04;
2601             } else {
2602                 fprintf(outf, "Invalid sse,avx options\n");
2603                 exit(1);
2604             }
2605             break;
2606         /* CLOS related */
2607         case 'c':
2608             current_clos = atoi(optarg);
2609             break;
2610         case 'd':
2611             clos_desired = atoi(optarg);
2612             clos_desired /= DISP_FREQ_MULTIPLIER;
2613             break;
2614         case 'e':
2615             clos_epp = atoi(optarg);
2616             if (is_skx_based_platform()) {
2617                 isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0);
2618                 exit(0);
2619             }
2620             break;
2621         case 'n':
2622             clos_min = atoi(optarg);
2623             clos_min /= DISP_FREQ_MULTIPLIER;
2624             break;
2625         case 'm':
2626             clos_max = atoi(optarg);
2627             clos_max /= DISP_FREQ_MULTIPLIER;
2628             break;
2629         case 'p':
2630             clos_priority_type = atoi(optarg);
2631             if (is_skx_based_platform() && !clos_priority_type) {
2632                 isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0);
2633                 exit(0);
2634             }
2635             break;
2636         case 'w':
2637             clos_prop_prio = atoi(optarg);
2638             if (is_skx_based_platform()) {
2639                 isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0);
2640                 exit(0);
2641             }
2642             break;
2643         default:
2644             printf("Unknown option: ignore\n");
2645         }
2646     }
2647 
2648     if (argv[optind])
2649         printf("Garbage at the end of command: ignore\n");
2650 }
2651 
2652 static void isst_help(void)
2653 {
2654     printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
2655         performance profiles per system via static and/or dynamic\n\
2656         adjustment of core count, workload, Tjmax, and\n\
2657         TDP, etc.\n");
2658     printf("\nCommands : For feature=perf-profile\n");
2659     printf("\tinfo\n");
2660 
2661     if (!is_clx_n_platform()) {
2662         printf("\tget-lock-status\n");
2663         printf("\tget-config-levels\n");
2664         printf("\tget-config-version\n");
2665         printf("\tget-config-enabled\n");
2666         printf("\tget-config-current-level\n");
2667         printf("\tset-config-level\n");
2668     }
2669 }
2670 
2671 static void pbf_help(void)
2672 {
2673     printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
2674         on certain cores (high priority cores) in exchange for lower\n\
2675         base frequency on remaining cores (low priority cores).\n");
2676     printf("\tcommand : info\n");
2677     printf("\tcommand : enable\n");
2678     printf("\tcommand : disable\n");
2679 }
2680 
2681 static void fact_help(void)
2682 {
2683     printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
2684         limits to cores based on priority.\n");
2685     printf("\nCommand: For feature=turbo-freq\n");
2686     printf("\tcommand : info\n");
2687     printf("\tcommand : enable\n");
2688     printf("\tcommand : disable\n");
2689 }
2690 
2691 static void turbo_mode_help(void)
2692 {
2693     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");
2694     printf("\tcommand : enable\n");
2695     printf("\tcommand : disable\n");
2696     printf("\tcommand : get-trl\n");
2697     printf("\tcommand : set-trl\n");
2698 }
2699 
2700 
2701 static void core_power_help(void)
2702 {
2703     printf("core-power:\tInterface that allows user to define per core/tile\n\
2704         priority.\n");
2705     printf("\nCommands : For feature=core-power\n");
2706     printf("\tinfo\n");
2707     printf("\tenable\n");
2708     printf("\tdisable\n");
2709     printf("\tconfig\n");
2710     printf("\tget-config\n");
2711     printf("\tassoc\n");
2712     printf("\tget-assoc\n");
2713 }
2714 
2715 struct process_cmd_help_struct {
2716     char *feature;
2717     void (*process_fn)(void);
2718 };
2719 
2720 static struct process_cmd_help_struct isst_help_cmds[] = {
2721     { "perf-profile", isst_help },
2722     { "base-freq", pbf_help },
2723     { "turbo-freq", fact_help },
2724     { "core-power", core_power_help },
2725     { "turbo-mode", turbo_mode_help },
2726     { NULL, NULL }
2727 };
2728 
2729 static struct process_cmd_help_struct clx_n_help_cmds[] = {
2730     { "perf-profile", isst_help },
2731     { "base-freq", pbf_help },
2732     { NULL, NULL }
2733 };
2734 
2735 void process_command(int argc, char **argv,
2736              struct process_cmd_help_struct *help_cmds,
2737              struct process_cmd_struct *cmds)
2738 {
2739     int i = 0, matched = 0;
2740     char *feature = argv[optind];
2741     char *cmd = argv[optind + 1];
2742 
2743     if (!feature || !cmd)
2744         return;
2745 
2746     debug_printf("feature name [%s] command [%s]\n", feature, cmd);
2747     if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
2748         while (help_cmds[i].feature) {
2749             if (!strcmp(help_cmds[i].feature, feature)) {
2750                 help_cmds[i].process_fn();
2751                 exit(0);
2752             }
2753             ++i;
2754         }
2755     }
2756 
2757     if (!is_clx_n_platform())
2758         create_cpu_map();
2759 
2760     i = 0;
2761     while (cmds[i].feature) {
2762         if (!strcmp(cmds[i].feature, feature) &&
2763             !strcmp(cmds[i].command, cmd)) {
2764             parse_cmd_args(argc, optind + 1, argv);
2765             cmds[i].process_fn(cmds[i].arg);
2766             matched = 1;
2767             break;
2768         }
2769         ++i;
2770     }
2771 
2772     if (!matched)
2773         fprintf(stderr, "Invalid command\n");
2774 }
2775 
2776 static void usage(void)
2777 {
2778     if (is_clx_n_platform()) {
2779         fprintf(stderr, "\nThere is limited support of Intel Speed Select features on this platform.\n");
2780         fprintf(stderr, "Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware.\n\n");
2781     }
2782 
2783     printf("\nUsage:\n");
2784     printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
2785     printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features:\n");
2786     if (is_clx_n_platform())
2787         printf("\nFEATURE : [perf-profile|base-freq]\n");
2788     else
2789         printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power|turbo-mode]\n");
2790     printf("\nFor help on each feature, use -h|--help\n");
2791     printf("\tFor example:  intel-speed-select perf-profile -h\n");
2792 
2793     printf("\nFor additional help on each command for a feature, use --h|--help\n");
2794     printf("\tFor example:  intel-speed-select perf-profile get-lock-status -h\n");
2795     printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
2796 
2797     printf("\nOPTIONS\n");
2798     printf("\t[-c|--cpu] : logical cpu number\n");
2799     printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
2800     printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
2801     printf("\t[-d|--debug] : Debug mode\n");
2802     printf("\t[-f|--format] : output format [json|text]. Default: text\n");
2803     printf("\t[-h|--help] : Print help\n");
2804     printf("\t[-i|--info] : Print platform information\n");
2805     printf("\t[-a|--all-cpus-online] : Force online every CPU in the system\n");
2806     printf("\t[-o|--out] : Output file\n");
2807     printf("\t\t\tDefault : stderr\n");
2808     printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n");
2809     printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n");
2810     printf("\t[-v|--version] : Print version\n");
2811     printf("\t[-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent.\n");
2812     printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n");
2813     printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n");
2814     printf("\nResult format\n");
2815     printf("\tResult display uses a common format for each command:\n");
2816     printf("\tResults are formatted in text/JSON with\n");
2817     printf("\t\tPackage, Die, CPU, and command specific results.\n");
2818 
2819     printf("\nExamples\n");
2820     printf("\tTo get platform information:\n");
2821     printf("\t\tintel-speed-select --info\n");
2822     printf("\tTo get full perf-profile information dump:\n");
2823     printf("\t\tintel-speed-select perf-profile info\n");
2824     printf("\tTo get full base-freq information dump:\n");
2825     printf("\t\tintel-speed-select base-freq info -l 0\n");
2826     if (!is_clx_n_platform()) {
2827         printf("\tTo get full turbo-freq information dump:\n");
2828         printf("\t\tintel-speed-select turbo-freq info -l 0\n");
2829     }
2830     exit(1);
2831 }
2832 
2833 static void print_version(void)
2834 {
2835     fprintf(outf, "Version %s\n", version_str);
2836     exit(0);
2837 }
2838 
2839 static void cmdline(int argc, char **argv)
2840 {
2841     const char *pathname = "/dev/isst_interface";
2842     char *ptr;
2843     FILE *fp;
2844     int opt, force_cpus_online = 0;
2845     int option_index = 0;
2846     int ret;
2847     int oob_mode = 0;
2848     int poll_interval = -1;
2849     int no_daemon = 0;
2850 
2851     static struct option long_options[] = {
2852         { "all-cpus-online", no_argument, 0, 'a' },
2853         { "cpu", required_argument, 0, 'c' },
2854         { "debug", no_argument, 0, 'd' },
2855         { "format", required_argument, 0, 'f' },
2856         { "help", no_argument, 0, 'h' },
2857         { "info", no_argument, 0, 'i' },
2858         { "pause", required_argument, 0, 'p' },
2859         { "out", required_argument, 0, 'o' },
2860         { "retry", required_argument, 0, 'r' },
2861         { "version", no_argument, 0, 'v' },
2862         { "oob", no_argument, 0, 'b' },
2863         { "no-daemon", no_argument, 0, 'n' },
2864         { "poll-interval", required_argument, 0, 'w' },
2865         { 0, 0, 0, 0 }
2866     };
2867 
2868     if (geteuid() != 0) {
2869         fprintf(stderr, "Must run as root\n");
2870         exit(0);
2871     }
2872 
2873     ret = update_cpu_model();
2874     if (ret)
2875         err(-1, "Invalid CPU model (%d)\n", cpu_model);
2876     printf("Intel(R) Speed Select Technology\n");
2877     printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
2878 
2879     if (!is_clx_n_platform()) {
2880         fp = fopen(pathname, "rb");
2881         if (!fp) {
2882             fprintf(stderr, "Intel speed select drivers are not loaded on this system.\n");
2883             fprintf(stderr, "Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE.\n");
2884             fprintf(stderr, "If the config is included then this is not a supported platform.\n");
2885             exit(0);
2886         }
2887         fclose(fp);
2888     }
2889 
2890     progname = argv[0];
2891     while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:n", long_options,
2892                        &option_index)) != -1) {
2893         switch (opt) {
2894         case 'a':
2895             force_cpus_online = 1;
2896             break;
2897         case 'c':
2898             parse_cpu_command(optarg);
2899             break;
2900         case 'd':
2901             debug_flag = 1;
2902             printf("Debug Mode ON\n");
2903             break;
2904         case 'f':
2905             if (!strncmp(optarg, "json", 4))
2906                 out_format_json = 1;
2907             break;
2908         case 'h':
2909             usage();
2910             break;
2911         case 'i':
2912             isst_print_platform_information();
2913             break;
2914         case 'o':
2915             if (outf)
2916                 fclose(outf);
2917             outf = fopen_or_exit(optarg, "w");
2918             break;
2919         case 'p':
2920             ret = strtol(optarg, &ptr, 10);
2921             if (!ret)
2922                 fprintf(stderr, "Invalid pause interval, ignore\n");
2923             else
2924                 mbox_delay = ret;
2925             break;
2926         case 'r':
2927             ret = strtol(optarg, &ptr, 10);
2928             if (!ret)
2929                 fprintf(stderr, "Invalid retry count, ignore\n");
2930             else
2931                 mbox_retries = ret;
2932             break;
2933         case 'v':
2934             print_version();
2935             break;
2936         case 'b':
2937             oob_mode = 1;
2938             break;
2939         case 'n':
2940             no_daemon = 1;
2941             break;
2942         case 'w':
2943             ret = strtol(optarg, &ptr, 10);
2944             if (!ret) {
2945                 fprintf(stderr, "Invalid poll interval count\n");
2946                 exit(0);
2947             }
2948             poll_interval = ret;
2949             break;
2950         default:
2951             usage();
2952         }
2953     }
2954 
2955     if (optind > (argc - 2) && !oob_mode) {
2956         usage();
2957         exit(0);
2958     }
2959     set_max_cpu_num();
2960     if (force_cpus_online)
2961         force_all_cpus_online();
2962     store_cpu_topology();
2963     set_cpu_present_cpu_mask();
2964     set_cpu_target_cpu_mask();
2965 
2966     if (oob_mode) {
2967         create_cpu_map();
2968         if (debug_flag)
2969             fprintf(stderr, "OOB mode is enabled in debug mode\n");
2970 
2971         ret = isst_daemon(debug_flag, poll_interval, no_daemon);
2972         if (ret)
2973             fprintf(stderr, "OOB mode enable failed\n");
2974         goto out;
2975     }
2976 
2977     if (!is_clx_n_platform()) {
2978         ret = isst_fill_platform_info();
2979         if (ret)
2980             goto out;
2981         process_command(argc, argv, isst_help_cmds, isst_cmds);
2982     } else {
2983         process_command(argc, argv, clx_n_help_cmds, clx_n_cmds);
2984     }
2985 out:
2986     free_cpu_set(present_cpumask);
2987     free_cpu_set(target_cpumask);
2988 }
2989 
2990 int main(int argc, char **argv)
2991 {
2992     outf = stderr;
2993     cmdline(argc, argv);
2994     return 0;
2995 }