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