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