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