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