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)(void);
  15};
  16
  17static const char *version_str = "v1.0";
  18static const int supported_api_ver = 1;
  19static struct isst_if_platform_info isst_platform_info;
  20static char *progname;
  21static int debug_flag;
  22static FILE *outf;
  23
  24static int cpu_model;
  25
  26#define MAX_CPUS_IN_ONE_REQ 64
  27static short max_target_cpus;
  28static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ];
  29
  30static int topo_max_cpus;
  31static size_t present_cpumask_size;
  32static cpu_set_t *present_cpumask;
  33static size_t target_cpumask_size;
  34static cpu_set_t *target_cpumask;
  35static int tdp_level = 0xFF;
  36static int fact_bucket = 0xFF;
  37static int fact_avx = 0xFF;
  38static unsigned long long fact_trl;
  39static int out_format_json;
  40static int cmd_help;
  41
  42/* clos related */
  43static int current_clos = -1;
  44static int clos_epp = -1;
  45static int clos_prop_prio = -1;
  46static int clos_min = -1;
  47static int clos_max = -1;
  48static int clos_desired = -1;
  49static int clos_priority_type;
  50
  51struct _cpu_map {
  52        unsigned short core_id;
  53        unsigned short pkg_id;
  54        unsigned short die_id;
  55        unsigned short punit_cpu;
  56        unsigned short punit_cpu_core;
  57};
  58struct _cpu_map *cpu_map;
  59
  60void debug_printf(const char *format, ...)
  61{
  62        va_list args;
  63
  64        va_start(args, format);
  65
  66        if (debug_flag)
  67                vprintf(format, args);
  68
  69        va_end(args);
  70}
  71
  72static void update_cpu_model(void)
  73{
  74        unsigned int ebx, ecx, edx;
  75        unsigned int fms, family;
  76
  77        __cpuid(1, fms, ebx, ecx, edx);
  78        family = (fms >> 8) & 0xf;
  79        cpu_model = (fms >> 4) & 0xf;
  80        if (family == 6 || family == 0xf)
  81                cpu_model += ((fms >> 16) & 0xf) << 4;
  82}
  83
  84/* Open a file, and exit on failure */
  85static FILE *fopen_or_exit(const char *path, const char *mode)
  86{
  87        FILE *filep = fopen(path, mode);
  88
  89        if (!filep)
  90                err(1, "%s: open failed", path);
  91
  92        return filep;
  93}
  94
  95/* Parse a file containing a single int */
  96static int parse_int_file(int fatal, const char *fmt, ...)
  97{
  98        va_list args;
  99        char path[PATH_MAX];
 100        FILE *filep;
 101        int value;
 102
 103        va_start(args, fmt);
 104        vsnprintf(path, sizeof(path), fmt, args);
 105        va_end(args);
 106        if (fatal) {
 107                filep = fopen_or_exit(path, "r");
 108        } else {
 109                filep = fopen(path, "r");
 110                if (!filep)
 111                        return -1;
 112        }
 113        if (fscanf(filep, "%d", &value) != 1)
 114                err(1, "%s: failed to parse number from file", path);
 115        fclose(filep);
 116
 117        return value;
 118}
 119
 120int cpufreq_sysfs_present(void)
 121{
 122        DIR *dir;
 123
 124        dir = opendir("/sys/devices/system/cpu/cpu0/cpufreq");
 125        if (dir) {
 126                closedir(dir);
 127                return 1;
 128        }
 129
 130        return 0;
 131}
 132
 133int out_format_is_json(void)
 134{
 135        return out_format_json;
 136}
 137
 138int get_physical_package_id(int cpu)
 139{
 140        return parse_int_file(
 141                1, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
 142                cpu);
 143}
 144
 145int get_physical_core_id(int cpu)
 146{
 147        return parse_int_file(
 148                1, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
 149}
 150
 151int get_physical_die_id(int cpu)
 152{
 153        int ret;
 154
 155        ret = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/topology/die_id",
 156                             cpu);
 157        if (ret < 0)
 158                ret = 0;
 159
 160        return ret;
 161}
 162
 163int get_topo_max_cpus(void)
 164{
 165        return topo_max_cpus;
 166}
 167
 168#define MAX_PACKAGE_COUNT 8
 169#define MAX_DIE_PER_PACKAGE 2
 170static void for_each_online_package_in_set(void (*callback)(int, void *, void *,
 171                                                            void *, void *),
 172                                           void *arg1, void *arg2, void *arg3,
 173                                           void *arg4)
 174{
 175        int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
 176        int pkg_index = 0, i;
 177
 178        memset(max_packages, 0xff, sizeof(max_packages));
 179        for (i = 0; i < topo_max_cpus; ++i) {
 180                int j, online, pkg_id, die_id = 0, skip = 0;
 181
 182                if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
 183                        continue;
 184                if (i)
 185                        online = parse_int_file(
 186                                1, "/sys/devices/system/cpu/cpu%d/online", i);
 187                else
 188                        online =
 189                                1; /* online entry for CPU 0 needs some special configs */
 190
 191                die_id = get_physical_die_id(i);
 192                if (die_id < 0)
 193                        die_id = 0;
 194                pkg_id = get_physical_package_id(i);
 195                /* Create an unique id for package, die combination to store */
 196                pkg_id = (MAX_PACKAGE_COUNT * pkg_id + die_id);
 197
 198                for (j = 0; j < pkg_index; ++j) {
 199                        if (max_packages[j] == pkg_id) {
 200                                skip = 1;
 201                                break;
 202                        }
 203                }
 204
 205                if (!skip && online && callback) {
 206                        callback(i, arg1, arg2, arg3, arg4);
 207                        max_packages[pkg_index++] = pkg_id;
 208                }
 209        }
 210}
 211
 212static void for_each_online_target_cpu_in_set(
 213        void (*callback)(int, void *, void *, void *, void *), void *arg1,
 214        void *arg2, void *arg3, void *arg4)
 215{
 216        int i;
 217
 218        for (i = 0; i < topo_max_cpus; ++i) {
 219                int online;
 220
 221                if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
 222                        continue;
 223                if (i)
 224                        online = parse_int_file(
 225                                1, "/sys/devices/system/cpu/cpu%d/online", i);
 226                else
 227                        online =
 228                                1; /* online entry for CPU 0 needs some special configs */
 229
 230                if (online && callback)
 231                        callback(i, arg1, arg2, arg3, arg4);
 232        }
 233}
 234
 235#define BITMASK_SIZE 32
 236static void set_max_cpu_num(void)
 237{
 238        FILE *filep;
 239        unsigned long dummy;
 240
 241        topo_max_cpus = 0;
 242        filep = fopen_or_exit(
 243                "/sys/devices/system/cpu/cpu0/topology/thread_siblings", "r");
 244        while (fscanf(filep, "%lx,", &dummy) == 1)
 245                topo_max_cpus += BITMASK_SIZE;
 246        fclose(filep);
 247        topo_max_cpus--; /* 0 based */
 248
 249        debug_printf("max cpus %d\n", topo_max_cpus);
 250}
 251
 252size_t alloc_cpu_set(cpu_set_t **cpu_set)
 253{
 254        cpu_set_t *_cpu_set;
 255        size_t size;
 256
 257        _cpu_set = CPU_ALLOC((topo_max_cpus + 1));
 258        if (_cpu_set == NULL)
 259                err(3, "CPU_ALLOC");
 260        size = CPU_ALLOC_SIZE((topo_max_cpus + 1));
 261        CPU_ZERO_S(size, _cpu_set);
 262
 263        *cpu_set = _cpu_set;
 264        return size;
 265}
 266
 267void free_cpu_set(cpu_set_t *cpu_set)
 268{
 269        CPU_FREE(cpu_set);
 270}
 271
 272static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
 273static void set_cpu_present_cpu_mask(void)
 274{
 275        size_t size;
 276        DIR *dir;
 277        int i;
 278
 279        size = alloc_cpu_set(&present_cpumask);
 280        present_cpumask_size = size;
 281        for (i = 0; i < topo_max_cpus; ++i) {
 282                char buffer[256];
 283
 284                snprintf(buffer, sizeof(buffer),
 285                         "/sys/devices/system/cpu/cpu%d", i);
 286                dir = opendir(buffer);
 287                if (dir) {
 288                        int pkg_id, die_id;
 289
 290                        CPU_SET_S(i, size, present_cpumask);
 291                        die_id = get_physical_die_id(i);
 292                        if (die_id < 0)
 293                                die_id = 0;
 294
 295                        pkg_id = get_physical_package_id(i);
 296                        if (pkg_id < MAX_PACKAGE_COUNT &&
 297                            die_id < MAX_DIE_PER_PACKAGE)
 298                                cpu_cnt[pkg_id][die_id]++;
 299                }
 300                closedir(dir);
 301        }
 302}
 303
 304int get_cpu_count(int pkg_id, int die_id)
 305{
 306        if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE)
 307                return cpu_cnt[pkg_id][die_id] + 1;
 308
 309        return 0;
 310}
 311
 312static void set_cpu_target_cpu_mask(void)
 313{
 314        size_t size;
 315        int i;
 316
 317        size = alloc_cpu_set(&target_cpumask);
 318        target_cpumask_size = size;
 319        for (i = 0; i < max_target_cpus; ++i) {
 320                if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
 321                                 present_cpumask))
 322                        continue;
 323
 324                CPU_SET_S(target_cpus[i], size, target_cpumask);
 325        }
 326}
 327
 328static void create_cpu_map(void)
 329{
 330        const char *pathname = "/dev/isst_interface";
 331        int i, fd = 0;
 332        struct isst_if_cpu_maps map;
 333
 334        cpu_map = malloc(sizeof(*cpu_map) * topo_max_cpus);
 335        if (!cpu_map)
 336                err(3, "cpumap");
 337
 338        fd = open(pathname, O_RDWR);
 339        if (fd < 0)
 340                err(-1, "%s open failed", pathname);
 341
 342        for (i = 0; i < topo_max_cpus; ++i) {
 343                if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
 344                        continue;
 345
 346                map.cmd_count = 1;
 347                map.cpu_map[0].logical_cpu = i;
 348
 349                debug_printf(" map logical_cpu:%d\n",
 350                             map.cpu_map[0].logical_cpu);
 351                if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
 352                        perror("ISST_IF_GET_PHY_ID");
 353                        fprintf(outf, "Error: map logical_cpu:%d\n",
 354                                map.cpu_map[0].logical_cpu);
 355                        continue;
 356                }
 357                cpu_map[i].core_id = get_physical_core_id(i);
 358                cpu_map[i].pkg_id = get_physical_package_id(i);
 359                cpu_map[i].die_id = get_physical_die_id(i);
 360                cpu_map[i].punit_cpu = map.cpu_map[0].physical_cpu;
 361                cpu_map[i].punit_cpu_core = (map.cpu_map[0].physical_cpu >>
 362                                             1); // shift to get core id
 363
 364                debug_printf(
 365                        "map logical_cpu:%d core: %d die:%d pkg:%d punit_cpu:%d punit_core:%d\n",
 366                        i, cpu_map[i].core_id, cpu_map[i].die_id,
 367                        cpu_map[i].pkg_id, cpu_map[i].punit_cpu,
 368                        cpu_map[i].punit_cpu_core);
 369        }
 370
 371        if (fd)
 372                close(fd);
 373}
 374
 375int find_logical_cpu(int pkg_id, int die_id, int punit_core_id)
 376{
 377        int i;
 378
 379        for (i = 0; i < topo_max_cpus; ++i) {
 380                if (cpu_map[i].pkg_id == pkg_id &&
 381                    cpu_map[i].die_id == die_id &&
 382                    cpu_map[i].punit_cpu_core == punit_core_id)
 383                        return i;
 384        }
 385
 386        return -EINVAL;
 387}
 388
 389void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask,
 390                                      size_t core_cpumask_size,
 391                                      cpu_set_t *core_cpumask, int *cpu_cnt)
 392{
 393        int i, cnt = 0;
 394        int die_id, pkg_id;
 395
 396        *cpu_cnt = 0;
 397        die_id = get_physical_die_id(cpu);
 398        pkg_id = get_physical_package_id(cpu);
 399
 400        for (i = 0; i < 64; ++i) {
 401                if (core_mask & BIT(i)) {
 402                        int j;
 403
 404                        for (j = 0; j < topo_max_cpus; ++j) {
 405                                if (cpu_map[j].pkg_id == pkg_id &&
 406                                    cpu_map[j].die_id == die_id &&
 407                                    cpu_map[j].punit_cpu_core == i) {
 408                                        CPU_SET_S(j, core_cpumask_size,
 409                                                  core_cpumask);
 410                                        ++cnt;
 411                                }
 412                        }
 413                }
 414        }
 415
 416        *cpu_cnt = cnt;
 417}
 418
 419int find_phy_core_num(int logical_cpu)
 420{
 421        if (logical_cpu < topo_max_cpus)
 422                return cpu_map[logical_cpu].punit_cpu_core;
 423
 424        return -EINVAL;
 425}
 426
 427static int isst_send_mmio_command(unsigned int cpu, unsigned int reg, int write,
 428                                  unsigned int *value)
 429{
 430        struct isst_if_io_regs io_regs;
 431        const char *pathname = "/dev/isst_interface";
 432        int cmd;
 433        int fd;
 434
 435        debug_printf("mmio_cmd cpu:%d reg:%d write:%d\n", cpu, reg, write);
 436
 437        fd = open(pathname, O_RDWR);
 438        if (fd < 0)
 439                err(-1, "%s open failed", pathname);
 440
 441        io_regs.req_count = 1;
 442        io_regs.io_reg[0].logical_cpu = cpu;
 443        io_regs.io_reg[0].reg = reg;
 444        cmd = ISST_IF_IO_CMD;
 445        if (write) {
 446                io_regs.io_reg[0].read_write = 1;
 447                io_regs.io_reg[0].value = *value;
 448        } else {
 449                io_regs.io_reg[0].read_write = 0;
 450        }
 451
 452        if (ioctl(fd, cmd, &io_regs) == -1) {
 453                perror("ISST_IF_IO_CMD");
 454                fprintf(outf, "Error: mmio_cmd cpu:%d reg:%x read_write:%x\n",
 455                        cpu, reg, write);
 456        } else {
 457                if (!write)
 458                        *value = io_regs.io_reg[0].value;
 459
 460                debug_printf(
 461                        "mmio_cmd response: cpu:%d reg:%x rd_write:%x resp:%x\n",
 462                        cpu, reg, write, *value);
 463        }
 464
 465        close(fd);
 466
 467        return 0;
 468}
 469
 470int isst_send_mbox_command(unsigned int cpu, unsigned char command,
 471                           unsigned char sub_command, unsigned int parameter,
 472                           unsigned int req_data, unsigned int *resp)
 473{
 474        const char *pathname = "/dev/isst_interface";
 475        int fd;
 476        struct isst_if_mbox_cmds mbox_cmds = { 0 };
 477
 478        debug_printf(
 479                "mbox_send: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
 480                cpu, command, sub_command, parameter, req_data);
 481
 482        if (isst_platform_info.mmio_supported && command == CONFIG_CLOS) {
 483                unsigned int value;
 484                int write = 0;
 485                int clos_id, core_id, ret = 0;
 486
 487                debug_printf("CLOS %d\n", cpu);
 488
 489                if (parameter & BIT(MBOX_CMD_WRITE_BIT)) {
 490                        value = req_data;
 491                        write = 1;
 492                }
 493
 494                switch (sub_command) {
 495                case CLOS_PQR_ASSOC:
 496                        core_id = parameter & 0xff;
 497                        ret = isst_send_mmio_command(
 498                                cpu, PQR_ASSOC_OFFSET + core_id * 4, write,
 499                                &value);
 500                        if (!ret && !write)
 501                                *resp = value;
 502                        break;
 503                case CLOS_PM_CLOS:
 504                        clos_id = parameter & 0x03;
 505                        ret = isst_send_mmio_command(
 506                                cpu, PM_CLOS_OFFSET + clos_id * 4, write,
 507                                &value);
 508                        if (!ret && !write)
 509                                *resp = value;
 510                        break;
 511                case CLOS_PM_QOS_CONFIG:
 512                        ret = isst_send_mmio_command(cpu, PM_QOS_CONFIG_OFFSET,
 513                                                     write, &value);
 514                        if (!ret && !write)
 515                                *resp = value;
 516                        break;
 517                case CLOS_STATUS:
 518                        break;
 519                default:
 520                        break;
 521                }
 522                return ret;
 523        }
 524
 525        mbox_cmds.cmd_count = 1;
 526        mbox_cmds.mbox_cmd[0].logical_cpu = cpu;
 527        mbox_cmds.mbox_cmd[0].command = command;
 528        mbox_cmds.mbox_cmd[0].sub_command = sub_command;
 529        mbox_cmds.mbox_cmd[0].parameter = parameter;
 530        mbox_cmds.mbox_cmd[0].req_data = req_data;
 531
 532        fd = open(pathname, O_RDWR);
 533        if (fd < 0)
 534                err(-1, "%s open failed", pathname);
 535
 536        if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
 537                perror("ISST_IF_MBOX_COMMAND");
 538                fprintf(outf,
 539                        "Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
 540                        cpu, command, sub_command, parameter, req_data);
 541        } else {
 542                *resp = mbox_cmds.mbox_cmd[0].resp_data;
 543                debug_printf(
 544                        "mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
 545                        cpu, command, sub_command, parameter, req_data, *resp);
 546        }
 547
 548        close(fd);
 549
 550        return 0;
 551}
 552
 553int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
 554                          unsigned long long *req_resp)
 555{
 556        struct isst_if_msr_cmds msr_cmds;
 557        const char *pathname = "/dev/isst_interface";
 558        int fd;
 559
 560        fd = open(pathname, O_RDWR);
 561        if (fd < 0)
 562                err(-1, "%s open failed", pathname);
 563
 564        msr_cmds.cmd_count = 1;
 565        msr_cmds.msr_cmd[0].logical_cpu = cpu;
 566        msr_cmds.msr_cmd[0].msr = msr;
 567        msr_cmds.msr_cmd[0].read_write = write;
 568        if (write)
 569                msr_cmds.msr_cmd[0].data = *req_resp;
 570
 571        if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
 572                perror("ISST_IF_MSR_COMMAD");
 573                fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
 574                        cpu, msr, write);
 575        } else {
 576                if (!write)
 577                        *req_resp = msr_cmds.msr_cmd[0].data;
 578
 579                debug_printf(
 580                        "msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
 581                        cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
 582        }
 583
 584        close(fd);
 585
 586        return 0;
 587}
 588
 589static int isst_fill_platform_info(void)
 590{
 591        const char *pathname = "/dev/isst_interface";
 592        int fd;
 593
 594        fd = open(pathname, O_RDWR);
 595        if (fd < 0)
 596                err(-1, "%s open failed", pathname);
 597
 598        if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) {
 599                perror("ISST_IF_GET_PLATFORM_INFO");
 600                close(fd);
 601                return -1;
 602        }
 603
 604        close(fd);
 605
 606        return 0;
 607}
 608
 609static void isst_print_platform_information(void)
 610{
 611        struct isst_if_platform_info platform_info;
 612        const char *pathname = "/dev/isst_interface";
 613        int fd;
 614
 615        fd = open(pathname, O_RDWR);
 616        if (fd < 0)
 617                err(-1, "%s open failed", pathname);
 618
 619        if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &platform_info) == -1) {
 620                perror("ISST_IF_GET_PLATFORM_INFO");
 621        } else {
 622                fprintf(outf, "Platform: API version : %d\n",
 623                        platform_info.api_version);
 624                fprintf(outf, "Platform: Driver version : %d\n",
 625                        platform_info.driver_version);
 626                fprintf(outf, "Platform: mbox supported : %d\n",
 627                        platform_info.mbox_supported);
 628                fprintf(outf, "Platform: mmio supported : %d\n",
 629                        platform_info.mmio_supported);
 630        }
 631
 632        close(fd);
 633
 634        exit(0);
 635}
 636
 637static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3,
 638                                 void *arg4)
 639{
 640        int (*fn_ptr)(int cpu, void *arg);
 641        int ret;
 642
 643        fn_ptr = arg1;
 644        ret = fn_ptr(cpu, arg2);
 645        if (ret)
 646                perror("get_tdp_*");
 647        else
 648                isst_display_result(cpu, outf, "perf-profile", (char *)arg3,
 649                                    *(unsigned int *)arg4);
 650}
 651
 652#define _get_tdp_level(desc, suffix, object, help)                                \
 653        static void get_tdp_##object(void)                                        \
 654        {                                                                         \
 655                struct isst_pkg_ctdp ctdp;                                        \
 656\
 657                if (cmd_help) {                                                   \
 658                        fprintf(stderr,                                           \
 659                                "Print %s [No command arguments are required]\n", \
 660                                help);                                            \
 661                        exit(0);                                                  \
 662                }                                                                 \
 663                isst_ctdp_display_information_start(outf);                        \
 664                if (max_target_cpus)                                              \
 665                        for_each_online_target_cpu_in_set(                        \
 666                                exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix,     \
 667                                &ctdp, desc, &ctdp.object);                       \
 668                else                                                              \
 669                        for_each_online_package_in_set(exec_on_get_ctdp_cpu,      \
 670                                                       isst_get_ctdp_##suffix,    \
 671                                                       &ctdp, desc,               \
 672                                                       &ctdp.object);             \
 673                isst_ctdp_display_information_end(outf);                          \
 674        }
 675
 676_get_tdp_level("get-config-levels", levels, levels, "TDP levels");
 677_get_tdp_level("get-config-version", levels, version, "TDP version");
 678_get_tdp_level("get-config-enabled", levels, enabled, "TDP enable status");
 679_get_tdp_level("get-config-current_level", levels, current_level,
 680               "Current TDP Level");
 681_get_tdp_level("get-lock-status", levels, locked, "TDP lock status");
 682
 683static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2,
 684                                     void *arg3, void *arg4)
 685{
 686        struct isst_pkg_ctdp pkg_dev;
 687        int ret;
 688
 689        memset(&pkg_dev, 0, sizeof(pkg_dev));
 690        ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev);
 691        if (ret) {
 692                perror("isst_get_process_ctdp");
 693        } else {
 694                isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev);
 695                isst_get_process_ctdp_complete(cpu, &pkg_dev);
 696        }
 697}
 698
 699static void dump_isst_config(void)
 700{
 701        if (cmd_help) {
 702                fprintf(stderr,
 703                        "Print Intel(R) Speed Select Technology Performance profile configuration\n");
 704                fprintf(stderr,
 705                        "including base frequency and turbo frequency configurations\n");
 706                fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
 707                fprintf(stderr,
 708                        "\tIf no arguments, dump information for all TDP levels\n");
 709                exit(0);
 710        }
 711
 712        isst_ctdp_display_information_start(outf);
 713
 714        if (max_target_cpus)
 715                for_each_online_target_cpu_in_set(dump_isst_config_for_cpu,
 716                                                  NULL, NULL, NULL, NULL);
 717        else
 718                for_each_online_package_in_set(dump_isst_config_for_cpu, NULL,
 719                                               NULL, NULL, NULL);
 720
 721        isst_ctdp_display_information_end(outf);
 722}
 723
 724static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
 725                                  void *arg4)
 726{
 727        int ret;
 728
 729        ret = isst_set_tdp_level(cpu, tdp_level);
 730        if (ret)
 731                perror("set_tdp_level_for_cpu");
 732        else
 733                isst_display_result(cpu, outf, "perf-profile", "set_tdp_level",
 734                                    ret);
 735}
 736
 737static void set_tdp_level(void)
 738{
 739        if (cmd_help) {
 740                fprintf(stderr, "Set Config TDP level\n");
 741                fprintf(stderr,
 742                        "\t Arguments: -l|--level : Specify tdp level\n");
 743                exit(0);
 744        }
 745
 746        if (tdp_level == 0xff) {
 747                fprintf(outf, "Invalid command: specify tdp_level\n");
 748                exit(1);
 749        }
 750        isst_ctdp_display_information_start(outf);
 751        if (max_target_cpus)
 752                for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
 753                                                  NULL, NULL, NULL);
 754        else
 755                for_each_online_package_in_set(set_tdp_level_for_cpu, NULL,
 756                                               NULL, NULL, NULL);
 757        isst_ctdp_display_information_end(outf);
 758}
 759
 760static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
 761                                    void *arg4)
 762{
 763        struct isst_pbf_info pbf_info;
 764        int ret;
 765
 766        ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info);
 767        if (ret) {
 768                perror("isst_get_pbf_info");
 769        } else {
 770                isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info);
 771                isst_get_pbf_info_complete(&pbf_info);
 772        }
 773}
 774
 775static void dump_pbf_config(void)
 776{
 777        if (cmd_help) {
 778                fprintf(stderr,
 779                        "Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
 780                fprintf(stderr,
 781                        "\tArguments: -l|--level : Specify tdp level\n");
 782                exit(0);
 783        }
 784
 785        if (tdp_level == 0xff) {
 786                fprintf(outf, "Invalid command: specify tdp_level\n");
 787                exit(1);
 788        }
 789
 790        isst_ctdp_display_information_start(outf);
 791        if (max_target_cpus)
 792                for_each_online_target_cpu_in_set(dump_pbf_config_for_cpu, NULL,
 793                                                  NULL, NULL, NULL);
 794        else
 795                for_each_online_package_in_set(dump_pbf_config_for_cpu, NULL,
 796                                               NULL, NULL, NULL);
 797        isst_ctdp_display_information_end(outf);
 798}
 799
 800static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
 801                            void *arg4)
 802{
 803        int ret;
 804        int status = *(int *)arg4;
 805
 806        ret = isst_set_pbf_fact_status(cpu, 1, status);
 807        if (ret) {
 808                perror("isst_set_pbf");
 809        } else {
 810                if (status)
 811                        isst_display_result(cpu, outf, "base-freq", "enable",
 812                                            ret);
 813                else
 814                        isst_display_result(cpu, outf, "base-freq", "disable",
 815                                            ret);
 816        }
 817}
 818
 819static void set_pbf_enable(void)
 820{
 821        int status = 1;
 822
 823        if (cmd_help) {
 824                fprintf(stderr,
 825                        "Enable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
 826                exit(0);
 827        }
 828
 829        isst_ctdp_display_information_start(outf);
 830        if (max_target_cpus)
 831                for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
 832                                                  NULL, &status);
 833        else
 834                for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
 835                                               NULL, &status);
 836        isst_ctdp_display_information_end(outf);
 837}
 838
 839static void set_pbf_disable(void)
 840{
 841        int status = 0;
 842
 843        if (cmd_help) {
 844                fprintf(stderr,
 845                        "Disable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
 846                exit(0);
 847        }
 848
 849        isst_ctdp_display_information_start(outf);
 850        if (max_target_cpus)
 851                for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
 852                                                  NULL, &status);
 853        else
 854                for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
 855                                               NULL, &status);
 856        isst_ctdp_display_information_end(outf);
 857}
 858
 859static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2,
 860                                     void *arg3, void *arg4)
 861{
 862        struct isst_fact_info fact_info;
 863        int ret;
 864
 865        ret = isst_get_fact_info(cpu, tdp_level, &fact_info);
 866        if (ret)
 867                perror("isst_get_fact_bucket_info");
 868        else
 869                isst_fact_display_information(cpu, outf, tdp_level, fact_bucket,
 870                                              fact_avx, &fact_info);
 871}
 872
 873static void dump_fact_config(void)
 874{
 875        if (cmd_help) {
 876                fprintf(stderr,
 877                        "Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
 878                fprintf(stderr,
 879                        "\tArguments: -l|--level : Specify tdp level\n");
 880                fprintf(stderr,
 881                        "\tArguments: -b|--bucket : Bucket index to dump\n");
 882                fprintf(stderr,
 883                        "\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
 884                exit(0);
 885        }
 886
 887        if (tdp_level == 0xff) {
 888                fprintf(outf, "Invalid command: specify tdp_level\n");
 889                exit(1);
 890        }
 891
 892        isst_ctdp_display_information_start(outf);
 893        if (max_target_cpus)
 894                for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
 895                                                  NULL, NULL, NULL, NULL);
 896        else
 897                for_each_online_package_in_set(dump_fact_config_for_cpu, NULL,
 898                                               NULL, NULL, NULL);
 899        isst_ctdp_display_information_end(outf);
 900}
 901
 902static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
 903                             void *arg4)
 904{
 905        int ret;
 906        int status = *(int *)arg4;
 907
 908        ret = isst_set_pbf_fact_status(cpu, 0, status);
 909        if (ret)
 910                perror("isst_set_fact");
 911        else {
 912                if (status) {
 913                        struct isst_pkg_ctdp pkg_dev;
 914
 915                        ret = isst_get_ctdp_levels(cpu, &pkg_dev);
 916                        if (ret) {
 917                                isst_display_result(cpu, outf, "turbo-freq",
 918                                                    "enable", ret);
 919                                return;
 920                        }
 921                        ret = isst_set_trl(cpu, fact_trl);
 922                        isst_display_result(cpu, outf, "turbo-freq", "enable",
 923                                            ret);
 924                } else {
 925                        /* Since we modified TRL during Fact enable, restore it */
 926                        isst_set_trl_from_current_tdp(cpu, fact_trl);
 927                        isst_display_result(cpu, outf, "turbo-freq", "disable",
 928                                            ret);
 929                }
 930        }
 931}
 932
 933static void set_fact_enable(void)
 934{
 935        int status = 1;
 936
 937        if (cmd_help) {
 938                fprintf(stderr,
 939                        "Enable Intel Speed Select Technology Turbo frequency feature\n");
 940                fprintf(stderr,
 941                        "Optional: -t|--trl : Specify turbo ratio limit\n");
 942                exit(0);
 943        }
 944
 945        isst_ctdp_display_information_start(outf);
 946        if (max_target_cpus)
 947                for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
 948                                                  NULL, &status);
 949        else
 950                for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
 951                                               NULL, &status);
 952        isst_ctdp_display_information_end(outf);
 953}
 954
 955static void set_fact_disable(void)
 956{
 957        int status = 0;
 958
 959        if (cmd_help) {
 960                fprintf(stderr,
 961                        "Disable Intel Speed Select Technology turbo frequency feature\n");
 962                fprintf(stderr,
 963                        "Optional: -t|--trl : Specify turbo ratio limit\n");
 964                exit(0);
 965        }
 966
 967        isst_ctdp_display_information_start(outf);
 968        if (max_target_cpus)
 969                for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
 970                                                  NULL, &status);
 971        else
 972                for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
 973                                               NULL, &status);
 974        isst_ctdp_display_information_end(outf);
 975}
 976
 977static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
 978                                   void *arg4)
 979{
 980        int ret;
 981        int status = *(int *)arg4;
 982
 983        ret = isst_pm_qos_config(cpu, status, clos_priority_type);
 984        if (ret) {
 985                perror("isst_pm_qos_config");
 986        } else {
 987                if (status)
 988                        isst_display_result(cpu, outf, "core-power", "enable",
 989                                            ret);
 990                else
 991                        isst_display_result(cpu, outf, "core-power", "disable",
 992                                            ret);
 993        }
 994}
 995
 996static void set_clos_enable(void)
 997{
 998        int status = 1;
 999
1000        if (cmd_help) {
1001                fprintf(stderr, "Enable core-power for a package/die\n");
1002                fprintf(stderr,
1003                        "\tClos Enable: Specify priority type with [--priority|-p]\n");
1004                fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
1005                exit(0);
1006        }
1007
1008        if (cpufreq_sysfs_present()) {
1009                fprintf(stderr,
1010                        "cpufreq subsystem and core-power enable will interfere with each other!\n");
1011        }
1012
1013        isst_ctdp_display_information_start(outf);
1014        if (max_target_cpus)
1015                for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
1016                                                  NULL, NULL, &status);
1017        else
1018                for_each_online_package_in_set(enable_clos_qos_config, NULL,
1019                                               NULL, NULL, &status);
1020        isst_ctdp_display_information_end(outf);
1021}
1022
1023static void set_clos_disable(void)
1024{
1025        int status = 0;
1026
1027        if (cmd_help) {
1028                fprintf(stderr,
1029                        "Disable core-power: [No command arguments are required]\n");
1030                exit(0);
1031        }
1032
1033        isst_ctdp_display_information_start(outf);
1034        if (max_target_cpus)
1035                for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
1036                                                  NULL, NULL, &status);
1037        else
1038                for_each_online_package_in_set(enable_clos_qos_config, NULL,
1039                                               NULL, NULL, &status);
1040        isst_ctdp_display_information_end(outf);
1041}
1042
1043static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2,
1044                                     void *arg3, void *arg4)
1045{
1046        struct isst_clos_config clos_config;
1047        int ret;
1048
1049        ret = isst_pm_get_clos(cpu, current_clos, &clos_config);
1050        if (ret)
1051                perror("isst_pm_get_clos");
1052        else
1053                isst_clos_display_information(cpu, outf, current_clos,
1054                                              &clos_config);
1055}
1056
1057static void dump_clos_config(void)
1058{
1059        if (cmd_help) {
1060                fprintf(stderr,
1061                        "Print Intel Speed Select Technology core power configuration\n");
1062                fprintf(stderr,
1063                        "\tArguments: [-c | --clos]: Specify clos id\n");
1064                exit(0);
1065        }
1066        if (current_clos < 0 || current_clos > 3) {
1067                fprintf(stderr, "Invalid clos id\n");
1068                exit(0);
1069        }
1070
1071        isst_ctdp_display_information_start(outf);
1072        if (max_target_cpus)
1073                for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
1074                                                  NULL, NULL, NULL, NULL);
1075        else
1076                for_each_online_package_in_set(dump_clos_config_for_cpu, NULL,
1077                                               NULL, NULL, NULL);
1078        isst_ctdp_display_information_end(outf);
1079}
1080
1081static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1082                                    void *arg4)
1083{
1084        struct isst_clos_config clos_config;
1085        int ret;
1086
1087        clos_config.pkg_id = get_physical_package_id(cpu);
1088        clos_config.die_id = get_physical_die_id(cpu);
1089
1090        clos_config.epp = clos_epp;
1091        clos_config.clos_prop_prio = clos_prop_prio;
1092        clos_config.clos_min = clos_min;
1093        clos_config.clos_max = clos_max;
1094        clos_config.clos_desired = clos_desired;
1095        ret = isst_set_clos(cpu, current_clos, &clos_config);
1096        if (ret)
1097                perror("isst_set_clos");
1098        else
1099                isst_display_result(cpu, outf, "core-power", "config", ret);
1100}
1101
1102static void set_clos_config(void)
1103{
1104        if (cmd_help) {
1105                fprintf(stderr,
1106                        "Set core-power configuration for one of the four clos ids\n");
1107                fprintf(stderr,
1108                        "\tSpecify targeted clos id with [--clos|-c]\n");
1109                fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
1110                fprintf(stderr,
1111                        "\tSpecify clos Proportional Priority [--weight|-w]\n");
1112                fprintf(stderr, "\tSpecify clos min with [--min|-n]\n");
1113                fprintf(stderr, "\tSpecify clos max with [--max|-m]\n");
1114                fprintf(stderr, "\tSpecify clos desired with [--desired|-d]\n");
1115                exit(0);
1116        }
1117
1118        if (current_clos < 0 || current_clos > 3) {
1119                fprintf(stderr, "Invalid clos id\n");
1120                exit(0);
1121        }
1122        if (clos_epp < 0 || clos_epp > 0x0F) {
1123                fprintf(stderr, "clos epp is not specified, default: 0\n");
1124                clos_epp = 0;
1125        }
1126        if (clos_prop_prio < 0 || clos_prop_prio > 0x0F) {
1127                fprintf(stderr,
1128                        "clos frequency weight is not specified, default: 0\n");
1129                clos_prop_prio = 0;
1130        }
1131        if (clos_min < 0) {
1132                fprintf(stderr, "clos min is not specified, default: 0\n");
1133                clos_min = 0;
1134        }
1135        if (clos_max < 0) {
1136                fprintf(stderr, "clos max is not specified, default: 0xff\n");
1137                clos_max = 0xff;
1138        }
1139        if (clos_desired < 0) {
1140                fprintf(stderr, "clos desired is not specified, default: 0\n");
1141                clos_desired = 0x00;
1142        }
1143
1144        isst_ctdp_display_information_start(outf);
1145        if (max_target_cpus)
1146                for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
1147                                                  NULL, NULL, NULL);
1148        else
1149                for_each_online_package_in_set(set_clos_config_for_cpu, NULL,
1150                                               NULL, NULL, NULL);
1151        isst_ctdp_display_information_end(outf);
1152}
1153
1154static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1155                                   void *arg4)
1156{
1157        int ret;
1158
1159        ret = isst_clos_associate(cpu, current_clos);
1160        if (ret)
1161                perror("isst_clos_associate");
1162        else
1163                isst_display_result(cpu, outf, "core-power", "assoc", ret);
1164}
1165
1166static void set_clos_assoc(void)
1167{
1168        if (cmd_help) {
1169                fprintf(stderr, "Associate a clos id to a CPU\n");
1170                fprintf(stderr,
1171                        "\tSpecify targeted clos id with [--clos|-c]\n");
1172                exit(0);
1173        }
1174
1175        if (current_clos < 0 || current_clos > 3) {
1176                fprintf(stderr, "Invalid clos id\n");
1177                exit(0);
1178        }
1179        if (max_target_cpus)
1180                for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
1181                                                  NULL, NULL, NULL);
1182        else {
1183                fprintf(stderr,
1184                        "Invalid target cpu. Specify with [-c|--cpu]\n");
1185        }
1186}
1187
1188static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1189                                   void *arg4)
1190{
1191        int clos, ret;
1192
1193        ret = isst_clos_get_assoc_status(cpu, &clos);
1194        if (ret)
1195                perror("isst_clos_get_assoc_status");
1196        else
1197                isst_display_result(cpu, outf, "core-power", "get-assoc", clos);
1198}
1199
1200static void get_clos_assoc(void)
1201{
1202        if (cmd_help) {
1203                fprintf(stderr, "Get associate clos id to a CPU\n");
1204                fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
1205                exit(0);
1206        }
1207        if (max_target_cpus)
1208                for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
1209                                                  NULL, NULL, NULL);
1210        else {
1211                fprintf(stderr,
1212                        "Invalid target cpu. Specify with [-c|--cpu]\n");
1213        }
1214}
1215
1216static struct process_cmd_struct isst_cmds[] = {
1217        { "perf-profile", "get-lock-status", get_tdp_locked },
1218        { "perf-profile", "get-config-levels", get_tdp_levels },
1219        { "perf-profile", "get-config-version", get_tdp_version },
1220        { "perf-profile", "get-config-enabled", get_tdp_enabled },
1221        { "perf-profile", "get-config-current-level", get_tdp_current_level },
1222        { "perf-profile", "set-config-level", set_tdp_level },
1223        { "perf-profile", "info", dump_isst_config },
1224        { "base-freq", "info", dump_pbf_config },
1225        { "base-freq", "enable", set_pbf_enable },
1226        { "base-freq", "disable", set_pbf_disable },
1227        { "turbo-freq", "info", dump_fact_config },
1228        { "turbo-freq", "enable", set_fact_enable },
1229        { "turbo-freq", "disable", set_fact_disable },
1230        { "core-power", "info", dump_clos_config },
1231        { "core-power", "enable", set_clos_enable },
1232        { "core-power", "disable", set_clos_disable },
1233        { "core-power", "config", set_clos_config },
1234        { "core-power", "assoc", set_clos_assoc },
1235        { "core-power", "get-assoc", get_clos_assoc },
1236        { NULL, NULL, NULL }
1237};
1238
1239/*
1240 * parse cpuset with following syntax
1241 * 1,2,4..6,8-10 and set bits in cpu_subset
1242 */
1243void parse_cpu_command(char *optarg)
1244{
1245        unsigned int start, end;
1246        char *next;
1247
1248        next = optarg;
1249
1250        while (next && *next) {
1251                if (*next == '-') /* no negative cpu numbers */
1252                        goto error;
1253
1254                start = strtoul(next, &next, 10);
1255
1256                if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
1257                        target_cpus[max_target_cpus++] = start;
1258
1259                if (*next == '\0')
1260                        break;
1261
1262                if (*next == ',') {
1263                        next += 1;
1264                        continue;
1265                }
1266
1267                if (*next == '-') {
1268                        next += 1; /* start range */
1269                } else if (*next == '.') {
1270                        next += 1;
1271                        if (*next == '.')
1272                                next += 1; /* start range */
1273                        else
1274                                goto error;
1275                }
1276
1277                end = strtoul(next, &next, 10);
1278                if (end <= start)
1279                        goto error;
1280
1281                while (++start <= end) {
1282                        if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
1283                                target_cpus[max_target_cpus++] = start;
1284                }
1285
1286                if (*next == ',')
1287                        next += 1;
1288                else if (*next != '\0')
1289                        goto error;
1290        }
1291
1292#ifdef DEBUG
1293        {
1294                int i;
1295
1296                for (i = 0; i < max_target_cpus; ++i)
1297                        printf("cpu [%d] in arg\n", target_cpus[i]);
1298        }
1299#endif
1300        return;
1301
1302error:
1303        fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
1304        exit(-1);
1305}
1306
1307static void parse_cmd_args(int argc, int start, char **argv)
1308{
1309        int opt;
1310        int option_index;
1311
1312        static struct option long_options[] = {
1313                { "bucket", required_argument, 0, 'b' },
1314                { "level", required_argument, 0, 'l' },
1315                { "trl-type", required_argument, 0, 'r' },
1316                { "trl", required_argument, 0, 't' },
1317                { "help", no_argument, 0, 'h' },
1318                { "clos", required_argument, 0, 'c' },
1319                { "desired", required_argument, 0, 'd' },
1320                { "epp", required_argument, 0, 'e' },
1321                { "min", required_argument, 0, 'n' },
1322                { "max", required_argument, 0, 'm' },
1323                { "priority", required_argument, 0, 'p' },
1324                { "weight", required_argument, 0, 'w' },
1325                { 0, 0, 0, 0 }
1326        };
1327
1328        option_index = start;
1329
1330        optind = start + 1;
1331        while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:h",
1332                                  long_options, &option_index)) != -1) {
1333                switch (opt) {
1334                case 'b':
1335                        fact_bucket = atoi(optarg);
1336                        break;
1337                case 'h':
1338                        cmd_help = 1;
1339                        break;
1340                case 'l':
1341                        tdp_level = atoi(optarg);
1342                        break;
1343                case 't':
1344                        sscanf(optarg, "0x%llx", &fact_trl);
1345                        break;
1346                case 'r':
1347                        if (!strncmp(optarg, "sse", 3)) {
1348                                fact_avx = 0x01;
1349                        } else if (!strncmp(optarg, "avx2", 4)) {
1350                                fact_avx = 0x02;
1351                        } else if (!strncmp(optarg, "avx512", 4)) {
1352                                fact_avx = 0x04;
1353                        } else {
1354                                fprintf(outf, "Invalid sse,avx options\n");
1355                                exit(1);
1356                        }
1357                        break;
1358                /* CLOS related */
1359                case 'c':
1360                        current_clos = atoi(optarg);
1361                        printf("clos %d\n", current_clos);
1362                        break;
1363                case 'd':
1364                        clos_desired = atoi(optarg);
1365                        break;
1366                case 'e':
1367                        clos_epp = atoi(optarg);
1368                        break;
1369                case 'n':
1370                        clos_min = atoi(optarg);
1371                        break;
1372                case 'm':
1373                        clos_max = atoi(optarg);
1374                        break;
1375                case 'p':
1376                        clos_priority_type = atoi(optarg);
1377                        break;
1378                case 'w':
1379                        clos_prop_prio = atoi(optarg);
1380                        break;
1381                default:
1382                        printf("no match\n");
1383                }
1384        }
1385}
1386
1387static void isst_help(void)
1388{
1389        printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
1390                performance profiles per system via static and/or dynamic\n\
1391                adjustment of core count, workload, Tjmax, and\n\
1392                TDP, etc.\n");
1393        printf("\nCommands : For feature=perf-profile\n");
1394        printf("\tinfo\n");
1395        printf("\tget-lock-status\n");
1396        printf("\tget-config-levels\n");
1397        printf("\tget-config-version\n");
1398        printf("\tget-config-enabled\n");
1399        printf("\tget-config-current-level\n");
1400        printf("\tset-config-level\n");
1401}
1402
1403static void pbf_help(void)
1404{
1405        printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
1406                on certain cores (high priority cores) in exchange for lower\n\
1407                base frequency on remaining cores (low priority cores).\n");
1408        printf("\tcommand : info\n");
1409        printf("\tcommand : enable\n");
1410        printf("\tcommand : disable\n");
1411}
1412
1413static void fact_help(void)
1414{
1415        printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
1416                limits to cores based on priority.\n");
1417        printf("\nCommand: For feature=turbo-freq\n");
1418        printf("\tcommand : info\n");
1419        printf("\tcommand : enable\n");
1420        printf("\tcommand : disable\n");
1421}
1422
1423static void core_power_help(void)
1424{
1425        printf("core-power:\tInterface that allows user to define per core/tile\n\
1426                priority.\n");
1427        printf("\nCommands : For feature=core-power\n");
1428        printf("\tinfo\n");
1429        printf("\tenable\n");
1430        printf("\tdisable\n");
1431        printf("\tconfig\n");
1432        printf("\tassoc\n");
1433        printf("\tget-assoc\n");
1434}
1435
1436struct process_cmd_help_struct {
1437        char *feature;
1438        void (*process_fn)(void);
1439};
1440
1441static struct process_cmd_help_struct isst_help_cmds[] = {
1442        { "perf-profile", isst_help },
1443        { "base-freq", pbf_help },
1444        { "turbo-freq", fact_help },
1445        { "core-power", core_power_help },
1446        { NULL, NULL }
1447};
1448
1449void process_command(int argc, char **argv)
1450{
1451        int i = 0, matched = 0;
1452        char *feature = argv[optind];
1453        char *cmd = argv[optind + 1];
1454
1455        if (!feature || !cmd)
1456                return;
1457
1458        debug_printf("feature name [%s] command [%s]\n", feature, cmd);
1459        if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
1460                while (isst_help_cmds[i].feature) {
1461                        if (!strcmp(isst_help_cmds[i].feature, feature)) {
1462                                isst_help_cmds[i].process_fn();
1463                                exit(0);
1464                        }
1465                        ++i;
1466                }
1467        }
1468
1469        create_cpu_map();
1470
1471        i = 0;
1472        while (isst_cmds[i].feature) {
1473                if (!strcmp(isst_cmds[i].feature, feature) &&
1474                    !strcmp(isst_cmds[i].command, cmd)) {
1475                        parse_cmd_args(argc, optind + 1, argv);
1476                        isst_cmds[i].process_fn();
1477                        matched = 1;
1478                        break;
1479                }
1480                ++i;
1481        }
1482
1483        if (!matched)
1484                fprintf(stderr, "Invalid command\n");
1485}
1486
1487static void usage(void)
1488{
1489        printf("Intel(R) Speed Select Technology\n");
1490        printf("\nUsage:\n");
1491        printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
1492        printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features,\n");
1493        printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power]\n");
1494        printf("\nFor help on each feature, use --h|--help\n");
1495        printf("\tFor example:  intel-speed-select perf-profile -h\n");
1496
1497        printf("\nFor additional help on each command for a feature, use --h|--help\n");
1498        printf("\tFor example:  intel-speed-select perf-profile get-lock-status -h\n");
1499        printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
1500
1501        printf("\nOPTIONS\n");
1502        printf("\t[-c|--cpu] : logical cpu number\n");
1503        printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
1504        printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
1505        printf("\t[-d|--debug] : Debug mode\n");
1506        printf("\t[-h|--help] : Print help\n");
1507        printf("\t[-i|--info] : Print platform information\n");
1508        printf("\t[-o|--out] : Output file\n");
1509        printf("\t\t\tDefault : stderr\n");
1510        printf("\t[-f|--format] : output format [json|text]. Default: text\n");
1511        printf("\t[-v|--version] : Print version\n");
1512
1513        printf("\nResult format\n");
1514        printf("\tResult display uses a common format for each command:\n");
1515        printf("\tResults are formatted in text/JSON with\n");
1516        printf("\t\tPackage, Die, CPU, and command specific results.\n");
1517        printf("\t\t\tFor Set commands, status is 0 for success and rest for failures\n");
1518        exit(1);
1519}
1520
1521static void print_version(void)
1522{
1523        fprintf(outf, "Version %s\n", version_str);
1524        fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__);
1525        exit(0);
1526}
1527
1528static void cmdline(int argc, char **argv)
1529{
1530        int opt;
1531        int option_index = 0;
1532
1533        static struct option long_options[] = {
1534                { "cpu", required_argument, 0, 'c' },
1535                { "debug", no_argument, 0, 'd' },
1536                { "format", required_argument, 0, 'f' },
1537                { "help", no_argument, 0, 'h' },
1538                { "info", no_argument, 0, 'i' },
1539                { "out", required_argument, 0, 'o' },
1540                { "version", no_argument, 0, 'v' },
1541                { 0, 0, 0, 0 }
1542        };
1543
1544        progname = argv[0];
1545        while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options,
1546                                       &option_index)) != -1) {
1547                switch (opt) {
1548                case 'c':
1549                        parse_cpu_command(optarg);
1550                        break;
1551                case 'd':
1552                        debug_flag = 1;
1553                        printf("Debug Mode ON\n");
1554                        break;
1555                case 'f':
1556                        if (!strncmp(optarg, "json", 4))
1557                                out_format_json = 1;
1558                        break;
1559                case 'h':
1560                        usage();
1561                        break;
1562                case 'i':
1563                        isst_print_platform_information();
1564                        break;
1565                case 'o':
1566                        if (outf)
1567                                fclose(outf);
1568                        outf = fopen_or_exit(optarg, "w");
1569                        break;
1570                case 'v':
1571                        print_version();
1572                        break;
1573                default:
1574                        usage();
1575                }
1576        }
1577
1578        if (geteuid() != 0) {
1579                fprintf(stderr, "Must run as root\n");
1580                exit(0);
1581        }
1582
1583        if (optind > (argc - 2)) {
1584                fprintf(stderr, "Feature name and|or command not specified\n");
1585                exit(0);
1586        }
1587        update_cpu_model();
1588        printf("Intel(R) Speed Select Technology\n");
1589        printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
1590        set_max_cpu_num();
1591        set_cpu_present_cpu_mask();
1592        set_cpu_target_cpu_mask();
1593        isst_fill_platform_info();
1594        if (isst_platform_info.api_version > supported_api_ver) {
1595                printf("Incompatible API versions; Upgrade of tool is required\n");
1596                exit(0);
1597        }
1598
1599        process_command(argc, argv);
1600}
1601
1602int main(int argc, char **argv)
1603{
1604        outf = stderr;
1605        cmdline(argc, argv);
1606        return 0;
1607}
1608