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 12 struct process_cmd_struct { 13 char *feature; 14 char *command; 15 void (*process_fn)(int arg); 16 int arg; 17 }; 18 19 static const char *version_str = "v1.23"; 20 21 static const int supported_api_ver = 3; 22 static struct isst_if_platform_info isst_platform_info; 23 static char *progname; 24 static int debug_flag; 25 static FILE *outf; 26 27 static int cpu_model; 28 static int cpu_stepping; 29 static int extended_family; 30 31 #define MAX_CPUS_IN_ONE_REQ 512 32 static short max_target_cpus; 33 static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ]; 34 35 static int topo_max_cpus; 36 static size_t present_cpumask_size; 37 static cpu_set_t *present_cpumask; 38 static size_t target_cpumask_size; 39 static cpu_set_t *target_cpumask; 40 static int tdp_level = 0xFF; 41 static int fact_bucket = 0xFF; 42 static int fact_avx = 0xFF; 43 static unsigned long long fact_trl; 44 static int out_format_json; 45 static int cmd_help; 46 static int force_online_offline; 47 static int auto_mode; 48 static int fact_enable_fail; 49 static int cgroupv2; 50 static int max_pkg_id; 51 static int max_die_id; 52 static int max_die_id_package_0; 53 54 /* clos related */ 55 static int current_clos = -1; 56 static int clos_epp = -1; 57 static int clos_prop_prio = -1; 58 static int clos_min = -1; 59 static int clos_max = -1; 60 static int clos_desired = -1; 61 static int clos_priority_type; 62 static int cpu_0_cgroupv2; 63 static int cpu_0_workaround(int isolate); 64 65 struct _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 }; 74 struct _cpu_map *cpu_map; 75 76 struct cpu_topology { 77 short cpu; 78 short core_id; 79 short pkg_id; 80 short die_id; 81 }; 82 83 FILE *get_output_file(void) 84 { 85 return outf; 86 } 87 88 int is_debug_enabled(void) 89 { 90 return debug_flag; 91 } 92 93 void 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 106 int 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 114 int is_skx_based_platform(void) 115 { 116 if (cpu_model == 0x55) 117 return 1; 118 119 return 0; 120 } 121 122 int is_spr_platform(void) 123 { 124 if (cpu_model == 0x8F) 125 return 1; 126 127 return 0; 128 } 129 130 int is_emr_platform(void) 131 { 132 if (cpu_model == 0xCF) 133 return 1; 134 135 return 0; 136 } 137 138 139 int is_icx_platform(void) 140 { 141 if (cpu_model == 0x6A || cpu_model == 0x6C) 142 return 1; 143 144 return 0; 145 } 146 147 static int is_dmr_plus_platform(void) 148 { 149 if (extended_family == 0x04) 150 return 1; 151 152 return 0; 153 } 154 155 static 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 195 int api_version(void) 196 { 197 return isst_platform_info.api_version; 198 } 199 200 /* Open a file, and exit on failure */ 201 static 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 */ 212 static 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 236 int 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 249 int out_format_is_json(void) 250 { 251 return out_format_json; 252 } 253 254 static 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 280 err_ret: 281 fclose(fp); 282 283 return ret; 284 } 285 286 static 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 336 static 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 360 static 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 384 static 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 415 static 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 426 void 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 443 int 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 455 int 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 460 int get_topo_max_cpus(void) 461 { 462 return topo_max_cpus; 463 } 464 465 static 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 492 void 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 528 static 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 540 void 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 614 static 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 645 static 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 674 size_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 689 void free_cpu_set(cpu_set_t *cpu_set) 690 { 691 CPU_FREE(cpu_set); 692 } 693 694 static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE]; 695 696 int 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 714 int 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 722 static 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 762 static 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 856 void 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 888 int 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 896 int use_cgroupv2(void) 897 { 898 return cgroupv2; 899 } 900 901 int 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 923 int 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 return ret; 954 } 955 956 return 0; 957 } 958 959 if (!CPU_COUNT_S(mask_size, cpu_mask)) { 960 return -1; 961 } 962 963 curr_index = 0; 964 first = 1; 965 str[0] = '\0'; 966 967 if (cpu_0_only) { 968 snprintf(str, str_len, "0"); 969 goto create_partition; 970 } 971 972 for (i = 0; i < get_topo_max_cpus(); ++i) { 973 if (!is_cpu_in_power_domain(i, id)) 974 continue; 975 976 if (CPU_ISSET_S(i, mask_size, cpu_mask)) 977 continue; 978 979 if (!first) { 980 index = snprintf(&str[curr_index], 981 str_len - curr_index, ","); 982 curr_index += index; 983 if (curr_index >= str_len) 984 break; 985 } 986 index = snprintf(&str[curr_index], str_len - curr_index, "%d", 987 i); 988 curr_index += index; 989 if (curr_index >= str_len) 990 break; 991 first = 0; 992 } 993 994 create_partition: 995 debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str); 996 997 snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name); 998 999 fd = open(cpuset_cpus, O_RDWR, 0); 1000 if (fd < 0) { 1001 return fd; 1002 } 1003 1004 ret = write(fd, str, strlen(str)); 1005 close(fd); 1006 1007 if (ret == -1) { 1008 debug_printf("Can't activate cpuset controller: Write failed\n"); 1009 return ret; 1010 } 1011 1012 snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus.partition", dir_name); 1013 1014 fd = open(cpuset_cpus, O_RDWR, 0); 1015 if (fd < 0) { 1016 return fd; 1017 } 1018 1019 ret = write(fd, "isolated", strlen("isolated")); 1020 if (ret == -1) { 1021 debug_printf("Can't update to isolated\n"); 1022 ret = write(fd, "root", strlen("root")); 1023 if (ret == -1) 1024 debug_printf("Can't update to root\n"); 1025 } 1026 1027 close(fd); 1028 1029 if (ret < 0) 1030 return ret; 1031 1032 return 0; 1033 } 1034 1035 static int cpu_0_workaround(int isolate) 1036 { 1037 int fd, fd1, len, ret; 1038 cpu_set_t cpu_mask; 1039 struct isst_id id; 1040 char str[2]; 1041 1042 debug_printf("isolate CPU 0 state: %d\n", isolate); 1043 1044 if (isolate) 1045 goto isolate; 1046 1047 /* First check if CPU 0 was isolated to remove isolation. */ 1048 1049 /* If the cpuset.cpus doesn't exist, that means that none of the CPUs are isolated*/ 1050 fd = open("/sys/fs/cgroup/0-0-0/cpuset.cpus", O_RDONLY, 0); 1051 if (fd < 0) 1052 return 0; 1053 1054 len = read(fd, str, sizeof(str)); 1055 /* Error check, but unlikely to fail. If fails that means that not isolated */ 1056 if (len == -1) 1057 return 0; 1058 1059 1060 /* Is CPU 0 is in isolate list, the display is sorted so first element will be CPU 0*/ 1061 if (str[0] != '0') { 1062 close(fd); 1063 return 0; 1064 } 1065 1066 fd1 = open("/sys/fs/cgroup/0-0-0/cpuset.cpus.partition", O_RDONLY, 0); 1067 /* Unlikely that, this attribute is not present, but handle error */ 1068 if (fd1 < 0) { 1069 close(fd); 1070 return 0; 1071 } 1072 1073 /* Is CPU 0 already changed partition to "member" */ 1074 len = read(fd1, str, sizeof(str)); 1075 if (len != -1 && str[0] == 'm') { 1076 close(fd1); 1077 close(fd); 1078 return 0; 1079 } 1080 1081 close(fd1); 1082 close(fd); 1083 1084 debug_printf("CPU 0 was isolated before, so remove isolation\n"); 1085 1086 isolate: 1087 ret = enable_cpuset_controller(); 1088 if (ret) 1089 goto isolate_fail; 1090 1091 CPU_ZERO(&cpu_mask); 1092 memset(&id, 0, sizeof(struct isst_id)); 1093 CPU_SET(0, &cpu_mask); 1094 1095 ret = isolate_cpus(&id, sizeof(cpu_mask), &cpu_mask, isolate, 1); 1096 isolate_fail: 1097 if (ret) 1098 fprintf(stderr, "Can't isolate CPU 0\n"); 1099 1100 return ret; 1101 } 1102 1103 static int isst_fill_platform_info(void) 1104 { 1105 const char *pathname = "/dev/isst_interface"; 1106 int fd; 1107 1108 if (is_clx_n_platform()) { 1109 isst_platform_info.api_version = 1; 1110 goto set_platform_ops; 1111 } 1112 1113 fd = open(pathname, O_RDWR); 1114 if (fd < 0) 1115 err(-1, "%s open failed", pathname); 1116 1117 if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) { 1118 perror("ISST_IF_GET_PLATFORM_INFO"); 1119 close(fd); 1120 return -1; 1121 } 1122 1123 close(fd); 1124 1125 if (isst_platform_info.api_version > supported_api_ver) { 1126 printf("Incompatible API versions; Upgrade of tool is required\n"); 1127 return -1; 1128 } 1129 1130 set_platform_ops: 1131 if (isst_set_platform_ops(isst_platform_info.api_version)) { 1132 fprintf(stderr, "Failed to set platform callbacks\n"); 1133 exit(0); 1134 } 1135 return 0; 1136 } 1137 1138 void get_isst_status(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) 1139 { 1140 struct isst_pkg_ctdp pkg_dev; 1141 struct isst_id *tid = (struct isst_id *)arg2; 1142 int *mask = (int *)arg3; 1143 int *max_level = (int *)arg4; 1144 int j, ret; 1145 1146 /* Only check the first cpu power domain */ 1147 if (id->cpu < 0 || tid->cpu >= 0) 1148 return; 1149 1150 ret = isst_get_ctdp_levels(id, &pkg_dev); 1151 if (ret) 1152 return; 1153 1154 if (pkg_dev.enabled) 1155 *mask |= BIT(0); 1156 1157 if (pkg_dev.locked) 1158 *mask |= BIT(1); 1159 1160 if (*max_level < pkg_dev.levels) 1161 *max_level = pkg_dev.levels; 1162 1163 for (j = 0; j <= pkg_dev.levels; ++j) { 1164 struct isst_pkg_ctdp_level_info ctdp_level; 1165 1166 ret = isst_get_ctdp_control(id, j, &ctdp_level); 1167 if (ret) 1168 continue; 1169 1170 if (ctdp_level.fact_support) 1171 *mask |= BIT(2); 1172 1173 if (ctdp_level.pbf_support) 1174 *mask |= BIT(3); 1175 } 1176 1177 tid->cpu = id->cpu; 1178 tid->pkg = id->pkg; 1179 tid->die = id->die; 1180 tid->punit = id->punit; 1181 } 1182 1183 static void isst_print_extended_platform_info(void) 1184 { 1185 int cp_state, cp_cap; 1186 struct isst_id id; 1187 int mask = 0, max_level = 0; 1188 1189 id.cpu = -1; 1190 for_each_online_power_domain_in_set(get_isst_status, NULL, &id, &mask, &max_level); 1191 1192 if (mask & BIT(0)) { 1193 fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is supported\n"); 1194 } else { 1195 fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is not supported\n"); 1196 fprintf(outf, "Only performance level 0 (base level) is present\n"); 1197 } 1198 1199 if (mask & BIT(1)) 1200 fprintf(outf, "TDP level change control is locked\n"); 1201 else 1202 fprintf(outf, "TDP level change control is unlocked, max level: %d\n", max_level); 1203 1204 if (mask & BIT(2)) 1205 fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is supported\n"); 1206 else 1207 fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is not supported\n"); 1208 1209 if (mask & BIT(3)) 1210 fprintf(outf, "Intel(R) SST-BF (feature base-freq) is supported\n"); 1211 else 1212 fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n"); 1213 1214 if (isst_read_pm_config(&id, &cp_state, &cp_cap)) { 1215 fprintf(outf, "Intel(R) SST-CP (feature core-power) status is unknown\n"); 1216 return; 1217 } 1218 1219 if (cp_cap) 1220 fprintf(outf, "Intel(R) SST-CP (feature core-power) is supported\n"); 1221 else 1222 fprintf(outf, "Intel(R) SST-CP (feature core-power) is not supported\n"); 1223 } 1224 1225 static void isst_print_platform_information(void) 1226 { 1227 if (is_clx_n_platform()) { 1228 fprintf(stderr, "\nThis option in not supported on this platform\n"); 1229 exit(0); 1230 } 1231 1232 /* Early initialization to create working cpu_map */ 1233 set_max_cpu_num(); 1234 create_cpu_map(); 1235 1236 fprintf(outf, "Platform: API version : %d\n", 1237 isst_platform_info.api_version); 1238 fprintf(outf, "Platform: Driver version : %d\n", 1239 isst_platform_info.driver_version); 1240 fprintf(outf, "Platform: mbox supported : %d\n", 1241 isst_platform_info.mbox_supported); 1242 fprintf(outf, "Platform: mmio supported : %d\n", 1243 isst_platform_info.mmio_supported); 1244 isst_print_extended_platform_info(); 1245 1246 exit(0); 1247 } 1248 1249 static char *local_str0, *local_str1; 1250 static void exec_on_get_ctdp_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 1251 void *arg4) 1252 { 1253 int (*fn_ptr)(struct isst_id *id, void *arg); 1254 int ret; 1255 1256 fn_ptr = arg1; 1257 ret = fn_ptr(id, arg2); 1258 if (ret) 1259 isst_display_error_info_message(1, "get_tdp_* failed", 0, 0); 1260 else 1261 isst_ctdp_display_core_info(id, outf, arg3, 1262 *(unsigned int *)arg4, 1263 local_str0, local_str1); 1264 } 1265 1266 #define _get_tdp_level(desc, suffix, object, help, str0, str1) \ 1267 static void get_tdp_##object(int arg) \ 1268 { \ 1269 struct isst_pkg_ctdp ctdp; \ 1270 \ 1271 if (cmd_help) { \ 1272 fprintf(stderr, \ 1273 "Print %s [No command arguments are required]\n", \ 1274 help); \ 1275 exit(0); \ 1276 } \ 1277 local_str0 = str0; \ 1278 local_str1 = str1; \ 1279 isst_ctdp_display_information_start(outf); \ 1280 if (max_target_cpus) \ 1281 for_each_online_target_cpu_in_set( \ 1282 exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix, \ 1283 &ctdp, desc, &ctdp.object); \ 1284 else \ 1285 for_each_online_power_domain_in_set(exec_on_get_ctdp_cpu, \ 1286 isst_get_ctdp_##suffix, \ 1287 &ctdp, desc, \ 1288 &ctdp.object); \ 1289 isst_ctdp_display_information_end(outf); \ 1290 } 1291 1292 _get_tdp_level("get-config-levels", levels, levels, "Max TDP level", NULL, NULL); 1293 _get_tdp_level("get-config-version", levels, version, "TDP version", NULL, NULL); 1294 _get_tdp_level("get-config-enabled", levels, enabled, "perf-profile enable status", "disabled", "enabled"); 1295 _get_tdp_level("get-config-current_level", levels, current_level, 1296 "Current TDP Level", NULL, NULL); 1297 _get_tdp_level("get-lock-status", levels, locked, "TDP lock status", "unlocked", "locked"); 1298 1299 struct isst_pkg_ctdp clx_n_pkg_dev; 1300 1301 static int clx_n_get_base_ratio(void) 1302 { 1303 FILE *fp; 1304 char *begin, *end, *line = NULL; 1305 char number[5]; 1306 float value = 0; 1307 size_t n = 0; 1308 1309 fp = fopen("/proc/cpuinfo", "r"); 1310 if (!fp) 1311 err(-1, "cannot open /proc/cpuinfo\n"); 1312 1313 while (getline(&line, &n, fp) > 0) { 1314 if (strstr(line, "model name")) { 1315 /* this is true for CascadeLake-N */ 1316 begin = strstr(line, "@ ") + 2; 1317 end = strstr(line, "GHz"); 1318 strncpy(number, begin, end - begin); 1319 value = atof(number) * 10; 1320 break; 1321 } 1322 } 1323 free(line); 1324 fclose(fp); 1325 1326 return (int)(value); 1327 } 1328 1329 static int clx_n_config(struct isst_id *id) 1330 { 1331 int i, ret; 1332 unsigned long cpu_bf; 1333 struct isst_pkg_ctdp_level_info *ctdp_level; 1334 struct isst_pbf_info *pbf_info; 1335 1336 ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 1337 pbf_info = &ctdp_level->pbf_info; 1338 ctdp_level->core_cpumask_size = 1339 alloc_cpu_set(&ctdp_level->core_cpumask); 1340 1341 /* find the frequency base ratio */ 1342 ctdp_level->tdp_ratio = clx_n_get_base_ratio(); 1343 if (ctdp_level->tdp_ratio == 0) { 1344 debug_printf("CLX: cn base ratio is zero\n"); 1345 ret = -1; 1346 goto error_ret; 1347 } 1348 1349 /* find the high and low priority frequencies */ 1350 pbf_info->p1_high = 0; 1351 pbf_info->p1_low = ~0; 1352 1353 for (i = 0; i < topo_max_cpus; i++) { 1354 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) 1355 continue; 1356 1357 if (!is_cpu_in_power_domain(i, id)) 1358 continue; 1359 1360 CPU_SET_S(i, ctdp_level->core_cpumask_size, 1361 ctdp_level->core_cpumask); 1362 1363 cpu_bf = parse_int_file(1, 1364 "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", 1365 i); 1366 if (cpu_bf > pbf_info->p1_high) 1367 pbf_info->p1_high = cpu_bf; 1368 if (cpu_bf < pbf_info->p1_low) 1369 pbf_info->p1_low = cpu_bf; 1370 } 1371 1372 if (pbf_info->p1_high == ~0UL) { 1373 debug_printf("CLX: maximum base frequency not set\n"); 1374 ret = -1; 1375 goto error_ret; 1376 } 1377 1378 if (pbf_info->p1_low == 0) { 1379 debug_printf("CLX: minimum base frequency not set\n"); 1380 ret = -1; 1381 goto error_ret; 1382 } 1383 1384 /* convert frequencies back to ratios */ 1385 pbf_info->p1_high = pbf_info->p1_high / 100000; 1386 pbf_info->p1_low = pbf_info->p1_low / 100000; 1387 1388 /* create high priority cpu mask */ 1389 pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask); 1390 for (i = 0; i < topo_max_cpus; i++) { 1391 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) 1392 continue; 1393 1394 if (!is_cpu_in_power_domain(i, id)) 1395 continue; 1396 1397 cpu_bf = parse_int_file(1, 1398 "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", 1399 i); 1400 cpu_bf = cpu_bf / 100000; 1401 if (cpu_bf == pbf_info->p1_high) 1402 CPU_SET_S(i, pbf_info->core_cpumask_size, 1403 pbf_info->core_cpumask); 1404 } 1405 1406 /* extra ctdp & pbf struct parameters */ 1407 ctdp_level->processed = 1; 1408 ctdp_level->pbf_support = 1; /* PBF is always supported and enabled */ 1409 ctdp_level->pbf_enabled = 1; 1410 ctdp_level->fact_support = 0; /* FACT is never supported */ 1411 ctdp_level->fact_enabled = 0; 1412 1413 return 0; 1414 1415 error_ret: 1416 free_cpu_set(ctdp_level->core_cpumask); 1417 return ret; 1418 } 1419 1420 static void dump_clx_n_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, 1421 void *arg3, void *arg4) 1422 { 1423 int ret; 1424 1425 if (tdp_level != 0xff && tdp_level != 0) { 1426 isst_display_error_info_message(1, "Invalid level", 1, tdp_level); 1427 exit(0); 1428 } 1429 1430 ret = clx_n_config(id); 1431 if (ret) { 1432 debug_printf("clx_n_config failed"); 1433 } else { 1434 struct isst_pkg_ctdp_level_info *ctdp_level; 1435 struct isst_pbf_info *pbf_info; 1436 1437 ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 1438 pbf_info = &ctdp_level->pbf_info; 1439 clx_n_pkg_dev.processed = 1; 1440 isst_ctdp_display_information(id, outf, tdp_level, &clx_n_pkg_dev); 1441 free_cpu_set(ctdp_level->core_cpumask); 1442 free_cpu_set(pbf_info->core_cpumask); 1443 } 1444 } 1445 1446 static void dump_isst_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, 1447 void *arg3, void *arg4) 1448 { 1449 struct isst_pkg_ctdp pkg_dev; 1450 int ret; 1451 1452 memset(&pkg_dev, 0, sizeof(pkg_dev)); 1453 ret = isst_get_process_ctdp(id, tdp_level, &pkg_dev); 1454 if (ret) { 1455 isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, id->cpu); 1456 isst_ctdp_display_information_end(outf); 1457 exit(1); 1458 } else { 1459 isst_ctdp_display_information(id, outf, tdp_level, &pkg_dev); 1460 isst_get_process_ctdp_complete(id, &pkg_dev); 1461 } 1462 } 1463 1464 static void dump_isst_config(int arg) 1465 { 1466 void *fn; 1467 1468 if (cmd_help) { 1469 fprintf(stderr, 1470 "Print Intel(R) Speed Select Technology Performance profile configuration\n"); 1471 fprintf(stderr, 1472 "including base frequency and turbo frequency configurations\n"); 1473 fprintf(stderr, "Optional: -l|--level : Specify tdp level\n"); 1474 fprintf(stderr, 1475 "\tIf no arguments, dump information for all TDP levels\n"); 1476 exit(0); 1477 } 1478 1479 if (!is_clx_n_platform()) 1480 fn = dump_isst_config_for_cpu; 1481 else 1482 fn = dump_clx_n_config_for_cpu; 1483 1484 isst_ctdp_display_information_start(outf); 1485 1486 if (max_target_cpus) 1487 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL); 1488 else 1489 for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL); 1490 1491 isst_ctdp_display_information_end(outf); 1492 } 1493 1494 static void adjust_scaling_max_from_base_freq(int cpu); 1495 1496 static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 1497 void *arg4) 1498 { 1499 struct isst_pkg_ctdp pkg_dev; 1500 int ret; 1501 1502 ret = isst_get_ctdp_levels(id, &pkg_dev); 1503 if (ret) { 1504 isst_display_error_info_message(1, "Get TDP level failed", 0, 0); 1505 isst_ctdp_display_information_end(outf); 1506 exit(1); 1507 } 1508 1509 if (pkg_dev.current_level == tdp_level) { 1510 debug_printf("TDP level already set. Skipped\n"); 1511 goto display_result; 1512 } 1513 1514 ret = isst_set_tdp_level(id, tdp_level); 1515 if (ret) { 1516 isst_display_error_info_message(1, "Set TDP level failed", 0, 0); 1517 isst_ctdp_display_information_end(outf); 1518 exit(1); 1519 } 1520 1521 display_result: 1522 isst_display_result(id, outf, "perf-profile", "set_tdp_level", ret); 1523 if (force_online_offline && id->cpu >= 0) { 1524 struct isst_pkg_ctdp_level_info ctdp_level; 1525 1526 /* Wait for updated base frequencies */ 1527 usleep(2000); 1528 1529 /* Adjusting uncore freq */ 1530 if (!is_dmr_plus_platform()) 1531 isst_adjust_uncore_freq(id, tdp_level, &ctdp_level); 1532 1533 fprintf(stderr, "Option is set to online/offline\n"); 1534 ctdp_level.core_cpumask_size = 1535 alloc_cpu_set(&ctdp_level.core_cpumask); 1536 ret = isst_get_coremask_info(id, tdp_level, &ctdp_level); 1537 if (ret) { 1538 isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0); 1539 goto free_mask; 1540 } 1541 1542 if (use_cgroupv2()) { 1543 int ret; 1544 1545 fprintf(stderr, "Using cgroup v2 in lieu of online/offline\n"); 1546 ret = enable_cpuset_controller(); 1547 if (ret) 1548 goto use_offline; 1549 1550 ret = isolate_cpus(id, ctdp_level.core_cpumask_size, 1551 ctdp_level.core_cpumask, tdp_level, 0); 1552 if (ret) 1553 goto use_offline; 1554 1555 goto free_mask; 1556 } 1557 1558 use_offline: 1559 if (ctdp_level.cpu_count) { 1560 int i, max_cpus = get_topo_max_cpus(); 1561 for (i = 0; i < max_cpus; ++i) { 1562 if (!is_cpu_in_power_domain(i, id)) 1563 continue; 1564 if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) { 1565 fprintf(stderr, "online cpu %d\n", i); 1566 set_cpu_online_offline(i, 1); 1567 adjust_scaling_max_from_base_freq(i); 1568 } else { 1569 fprintf(stderr, "offline cpu %d\n", i); 1570 set_cpu_online_offline(i, 0); 1571 } 1572 } 1573 } 1574 free_mask: 1575 free_cpu_set(ctdp_level.core_cpumask); 1576 } 1577 } 1578 1579 static void set_tdp_level(int arg) 1580 { 1581 if (cmd_help) { 1582 fprintf(stderr, "Set Config TDP level\n"); 1583 fprintf(stderr, 1584 "\t Arguments: -l|--level : Specify tdp level\n"); 1585 fprintf(stderr, 1586 "\t Optional Arguments: -o | online : online/offline for the tdp level\n"); 1587 fprintf(stderr, 1588 "\t online/offline operation has limitations, refer to Linux hotplug documentation\n"); 1589 exit(0); 1590 } 1591 1592 if (tdp_level == 0xff) { 1593 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0); 1594 exit(1); 1595 } 1596 isst_ctdp_display_information_start(outf); 1597 if (max_target_cpus) 1598 for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL, 1599 NULL, NULL, NULL); 1600 else 1601 for_each_online_power_domain_in_set(set_tdp_level_for_cpu, NULL, 1602 NULL, NULL, NULL); 1603 isst_ctdp_display_information_end(outf); 1604 } 1605 1606 static void clx_n_dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, 1607 void *arg3, void *arg4) 1608 { 1609 int ret; 1610 1611 ret = clx_n_config(id); 1612 if (ret) { 1613 isst_display_error_info_message(1, "clx_n_config failed", 0, 0); 1614 } else { 1615 struct isst_pkg_ctdp_level_info *ctdp_level; 1616 struct isst_pbf_info *pbf_info; 1617 1618 ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 1619 pbf_info = &ctdp_level->pbf_info; 1620 isst_pbf_display_information(id, outf, tdp_level, pbf_info); 1621 free_cpu_set(ctdp_level->core_cpumask); 1622 free_cpu_set(pbf_info->core_cpumask); 1623 } 1624 } 1625 1626 static void dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 1627 void *arg4) 1628 { 1629 struct isst_pbf_info pbf_info; 1630 int ret; 1631 1632 ret = isst_get_pbf_info(id, tdp_level, &pbf_info); 1633 if (ret) { 1634 isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level); 1635 isst_ctdp_display_information_end(outf); 1636 exit(1); 1637 } else { 1638 isst_pbf_display_information(id, outf, tdp_level, &pbf_info); 1639 free_cpu_set(pbf_info.core_cpumask); 1640 } 1641 } 1642 1643 static void dump_pbf_config(int arg) 1644 { 1645 void *fn; 1646 1647 if (cmd_help) { 1648 fprintf(stderr, 1649 "Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n"); 1650 fprintf(stderr, 1651 "\tArguments: -l|--level : Specify tdp level\n"); 1652 exit(0); 1653 } 1654 1655 if (tdp_level == 0xff) { 1656 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0); 1657 exit(1); 1658 } 1659 1660 if (!is_clx_n_platform()) 1661 fn = dump_pbf_config_for_cpu; 1662 else 1663 fn = clx_n_dump_pbf_config_for_cpu; 1664 1665 isst_ctdp_display_information_start(outf); 1666 1667 if (max_target_cpus) 1668 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL); 1669 else 1670 for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL); 1671 1672 isst_ctdp_display_information_end(outf); 1673 } 1674 1675 static int set_clos_param(struct isst_id *id, int clos, int epp, int wt, int min, int max) 1676 { 1677 struct isst_clos_config clos_config; 1678 int ret; 1679 1680 ret = isst_pm_get_clos(id, clos, &clos_config); 1681 if (ret) { 1682 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0); 1683 return ret; 1684 } 1685 clos_config.clos_min = min; 1686 clos_config.clos_max = max; 1687 clos_config.epp = epp; 1688 clos_config.clos_prop_prio = wt; 1689 ret = isst_set_clos(id, clos, &clos_config); 1690 if (ret) { 1691 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0); 1692 return ret; 1693 } 1694 1695 return 0; 1696 } 1697 1698 static int set_cpufreq_scaling_min_max(int cpu, int max, int freq) 1699 { 1700 char buffer[128], freq_str[16]; 1701 int fd, ret, len; 1702 1703 if (max) 1704 snprintf(buffer, sizeof(buffer), 1705 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); 1706 else 1707 snprintf(buffer, sizeof(buffer), 1708 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); 1709 1710 fd = open(buffer, O_WRONLY); 1711 if (fd < 0) 1712 return fd; 1713 1714 snprintf(freq_str, sizeof(freq_str), "%d", freq); 1715 len = strlen(freq_str); 1716 ret = write(fd, freq_str, len); 1717 if (ret == -1) { 1718 close(fd); 1719 return ret; 1720 } 1721 close(fd); 1722 1723 return 0; 1724 } 1725 1726 static int no_turbo(void) 1727 { 1728 return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); 1729 } 1730 1731 static void adjust_scaling_max_from_base_freq(int cpu) 1732 { 1733 int base_freq, scaling_max_freq; 1734 1735 scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); 1736 base_freq = get_cpufreq_base_freq(cpu); 1737 if (scaling_max_freq < base_freq || no_turbo()) 1738 set_cpufreq_scaling_min_max(cpu, 1, base_freq); 1739 } 1740 1741 static void adjust_scaling_min_from_base_freq(int cpu) 1742 { 1743 int base_freq, scaling_min_freq; 1744 1745 scaling_min_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); 1746 base_freq = get_cpufreq_base_freq(cpu); 1747 if (scaling_min_freq < base_freq) 1748 set_cpufreq_scaling_min_max(cpu, 0, base_freq); 1749 } 1750 1751 static int set_clx_pbf_cpufreq_scaling_min_max(struct isst_id *id) 1752 { 1753 struct isst_pkg_ctdp_level_info *ctdp_level; 1754 struct isst_pbf_info *pbf_info; 1755 int i, freq, freq_high, freq_low; 1756 int ret; 1757 1758 ret = clx_n_config(id); 1759 if (ret) { 1760 debug_printf("cpufreq_scaling_min_max failed for CLX"); 1761 return ret; 1762 } 1763 1764 ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 1765 pbf_info = &ctdp_level->pbf_info; 1766 freq_high = pbf_info->p1_high * 100000; 1767 freq_low = pbf_info->p1_low * 100000; 1768 1769 for (i = 0; i < get_topo_max_cpus(); ++i) { 1770 if (!is_cpu_in_power_domain(i, id)) 1771 continue; 1772 1773 if (CPU_ISSET_S(i, pbf_info->core_cpumask_size, 1774 pbf_info->core_cpumask)) 1775 freq = freq_high; 1776 else 1777 freq = freq_low; 1778 1779 set_cpufreq_scaling_min_max(i, 1, freq); 1780 set_cpufreq_scaling_min_max(i, 0, freq); 1781 } 1782 1783 return 0; 1784 } 1785 1786 static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, int scaling_max) 1787 { 1788 char buffer[128], min_freq[16]; 1789 int fd, ret, len; 1790 1791 if (!CPU_ISSET_S(cpu, present_cpumask_size, present_cpumask)) 1792 return -1; 1793 1794 if (cpuinfo_max) 1795 snprintf(buffer, sizeof(buffer), 1796 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu); 1797 else 1798 snprintf(buffer, sizeof(buffer), 1799 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpu); 1800 1801 fd = open(buffer, O_RDONLY); 1802 if (fd < 0) 1803 return fd; 1804 1805 len = read(fd, min_freq, sizeof(min_freq)); 1806 close(fd); 1807 1808 if (len < 0) 1809 return len; 1810 1811 if (scaling_max) 1812 snprintf(buffer, sizeof(buffer), 1813 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); 1814 else 1815 snprintf(buffer, sizeof(buffer), 1816 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); 1817 1818 fd = open(buffer, O_WRONLY); 1819 if (fd < 0) 1820 return fd; 1821 1822 min_freq[15] = '\0'; 1823 len = strlen(min_freq); 1824 ret = write(fd, min_freq, len); 1825 if (ret == -1) { 1826 close(fd); 1827 return ret; 1828 } 1829 close(fd); 1830 1831 return 0; 1832 } 1833 1834 static void set_scaling_min_to_cpuinfo_max(struct isst_id *id) 1835 { 1836 int i; 1837 1838 if (id->cpu < 0) 1839 return; 1840 1841 for (i = 0; i < get_topo_max_cpus(); ++i) { 1842 if (!is_cpu_in_power_domain(i, id)) 1843 continue; 1844 1845 if (is_cpu_online(i) != 1) 1846 continue; 1847 1848 adjust_scaling_max_from_base_freq(i); 1849 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0); 1850 adjust_scaling_min_from_base_freq(i); 1851 } 1852 } 1853 1854 static void set_scaling_min_to_cpuinfo_min(struct isst_id *id) 1855 { 1856 int i; 1857 1858 if (id->cpu < 0) 1859 return; 1860 1861 for (i = 0; i < get_topo_max_cpus(); ++i) { 1862 if (!is_cpu_in_power_domain(i, id)) 1863 continue; 1864 1865 if (is_cpu_online(i) != 1) 1866 continue; 1867 1868 adjust_scaling_max_from_base_freq(i); 1869 set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0); 1870 } 1871 } 1872 1873 static void set_scaling_max_to_cpuinfo_max(struct isst_id *id) 1874 { 1875 int i; 1876 1877 for (i = 0; i < get_topo_max_cpus(); ++i) { 1878 if (!is_cpu_in_power_domain(i, id)) 1879 continue; 1880 1881 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1); 1882 } 1883 } 1884 1885 static int set_core_priority_and_min(struct isst_id *id, int mask_size, 1886 cpu_set_t *cpu_mask, int min_high, 1887 int min_low) 1888 { 1889 int ret, i; 1890 1891 if (!CPU_COUNT_S(mask_size, cpu_mask)) 1892 return -1; 1893 1894 ret = set_clos_param(id, 0, 0, 0, min_high, 0xff); 1895 if (ret) 1896 return ret; 1897 1898 ret = set_clos_param(id, 1, 15, 15, min_low, 0xff); 1899 if (ret) 1900 return ret; 1901 1902 ret = set_clos_param(id, 2, 15, 15, min_low, 0xff); 1903 if (ret) 1904 return ret; 1905 1906 ret = set_clos_param(id, 3, 15, 15, min_low, 0xff); 1907 if (ret) 1908 return ret; 1909 1910 for (i = 0; i < get_topo_max_cpus(); ++i) { 1911 int clos; 1912 struct isst_id tid; 1913 1914 if (!is_cpu_in_power_domain(i, id)) 1915 continue; 1916 1917 if (CPU_ISSET_S(i, mask_size, cpu_mask)) 1918 clos = 0; 1919 else 1920 clos = 3; 1921 1922 debug_printf("Associate cpu: %d clos: %d\n", i, clos); 1923 set_isst_id(&tid, i); 1924 ret = isst_clos_associate(&tid, clos); 1925 if (ret) { 1926 isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0); 1927 return ret; 1928 } 1929 } 1930 1931 return 0; 1932 } 1933 1934 static int set_pbf_core_power(struct isst_id *id) 1935 { 1936 struct isst_pbf_info pbf_info; 1937 struct isst_pkg_ctdp pkg_dev; 1938 int ret; 1939 1940 if (id->cpu < 0) 1941 return 0; 1942 1943 ret = isst_get_ctdp_levels(id, &pkg_dev); 1944 if (ret) { 1945 debug_printf("isst_get_ctdp_levels failed"); 1946 return ret; 1947 } 1948 debug_printf("Current_level: %d\n", pkg_dev.current_level); 1949 1950 ret = isst_get_pbf_info(id, pkg_dev.current_level, &pbf_info); 1951 if (ret) { 1952 debug_printf("isst_get_pbf_info failed"); 1953 return ret; 1954 } 1955 debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high, 1956 pbf_info.p1_low); 1957 1958 ret = set_core_priority_and_min(id, pbf_info.core_cpumask_size, 1959 pbf_info.core_cpumask, 1960 pbf_info.p1_high, pbf_info.p1_low); 1961 if (ret) { 1962 debug_printf("set_core_priority_and_min failed"); 1963 return ret; 1964 } 1965 1966 ret = isst_pm_qos_config(id, 1, 1); 1967 if (ret) { 1968 debug_printf("isst_pm_qos_config failed"); 1969 return ret; 1970 } 1971 1972 return 0; 1973 } 1974 1975 static void set_pbf_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 1976 void *arg4) 1977 { 1978 struct isst_pkg_ctdp_level_info ctdp_level; 1979 struct isst_pkg_ctdp pkg_dev; 1980 int ret; 1981 int status = *(int *)arg4; 1982 1983 if (is_clx_n_platform()) { 1984 ret = 0; 1985 if (status) { 1986 set_clx_pbf_cpufreq_scaling_min_max(id); 1987 1988 } else { 1989 set_scaling_max_to_cpuinfo_max(id); 1990 set_scaling_min_to_cpuinfo_min(id); 1991 } 1992 goto disp_result; 1993 } 1994 1995 ret = isst_get_ctdp_levels(id, &pkg_dev); 1996 if (ret) { 1997 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0); 1998 goto disp_result; 1999 } 2000 2001 ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level); 2002 if (ret) { 2003 isst_display_error_info_message(1, "Failed to get current level", 0, 0); 2004 goto disp_result; 2005 } 2006 2007 if (!ctdp_level.pbf_support) { 2008 isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, pkg_dev.current_level); 2009 ret = -1; 2010 goto disp_result; 2011 } 2012 2013 if (auto_mode && status) { 2014 ret = set_pbf_core_power(id); 2015 if (ret) 2016 goto disp_result; 2017 } 2018 2019 ret = isst_set_pbf_fact_status(id, 1, status); 2020 if (ret) { 2021 debug_printf("isst_set_pbf_fact_status failed"); 2022 if (auto_mode) 2023 isst_pm_qos_config(id, 0, 0); 2024 } else { 2025 if (auto_mode) { 2026 if (status) 2027 set_scaling_min_to_cpuinfo_max(id); 2028 else 2029 set_scaling_min_to_cpuinfo_min(id); 2030 } 2031 } 2032 2033 if (auto_mode && !status) 2034 isst_pm_qos_config(id, 0, 1); 2035 2036 disp_result: 2037 if (status) 2038 isst_display_result(id, outf, "base-freq", "enable", 2039 ret); 2040 else 2041 isst_display_result(id, outf, "base-freq", "disable", 2042 ret); 2043 } 2044 2045 static void set_pbf_enable(int arg) 2046 { 2047 int enable = arg; 2048 2049 if (cmd_help) { 2050 if (enable) { 2051 fprintf(stderr, 2052 "Enable Intel Speed Select Technology base frequency feature\n"); 2053 if (is_clx_n_platform()) { 2054 fprintf(stderr, 2055 "\tOn this platform this command doesn't enable feature in the hardware.\n"); 2056 fprintf(stderr, 2057 "\tIt updates the cpufreq scaling_min_freq to match cpufreq base_frequency.\n"); 2058 exit(0); 2059 2060 } 2061 fprintf(stderr, 2062 "\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n"); 2063 } else { 2064 2065 if (is_clx_n_platform()) { 2066 fprintf(stderr, 2067 "\tOn this platform this command doesn't disable feature in the hardware.\n"); 2068 fprintf(stderr, 2069 "\tIt updates the cpufreq scaling_min_freq to match cpuinfo_min_freq\n"); 2070 exit(0); 2071 } 2072 fprintf(stderr, 2073 "Disable Intel Speed Select Technology base frequency feature\n"); 2074 fprintf(stderr, 2075 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); 2076 } 2077 exit(0); 2078 } 2079 2080 isst_ctdp_display_information_start(outf); 2081 if (max_target_cpus) 2082 for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL, 2083 NULL, &enable); 2084 else 2085 for_each_online_power_domain_in_set(set_pbf_for_cpu, NULL, NULL, 2086 NULL, &enable); 2087 isst_ctdp_display_information_end(outf); 2088 } 2089 2090 static void dump_fact_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, 2091 void *arg3, void *arg4) 2092 { 2093 struct isst_fact_info fact_info; 2094 int ret; 2095 2096 memset(&fact_info, 0, sizeof(fact_info)); 2097 ret = isst_get_fact_info(id, tdp_level, fact_bucket, &fact_info); 2098 if (ret) { 2099 isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level); 2100 isst_ctdp_display_information_end(outf); 2101 exit(1); 2102 } else { 2103 isst_fact_display_information(id, outf, tdp_level, fact_bucket, 2104 fact_avx, &fact_info); 2105 } 2106 } 2107 2108 static void dump_fact_config(int arg) 2109 { 2110 if (cmd_help) { 2111 fprintf(stderr, 2112 "Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n"); 2113 fprintf(stderr, 2114 "\tArguments: -l|--level : Specify tdp level\n"); 2115 fprintf(stderr, 2116 "\tArguments: -b|--bucket : Bucket index to dump\n"); 2117 fprintf(stderr, 2118 "\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n"); 2119 exit(0); 2120 } 2121 2122 if (tdp_level == 0xff) { 2123 isst_display_error_info_message(1, "Invalid command: specify tdp_level\n", 0, 0); 2124 exit(1); 2125 } 2126 2127 isst_ctdp_display_information_start(outf); 2128 if (max_target_cpus) 2129 for_each_online_target_cpu_in_set(dump_fact_config_for_cpu, 2130 NULL, NULL, NULL, NULL); 2131 else 2132 for_each_online_power_domain_in_set(dump_fact_config_for_cpu, NULL, 2133 NULL, NULL, NULL); 2134 isst_ctdp_display_information_end(outf); 2135 } 2136 2137 static void set_fact_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 2138 void *arg4) 2139 { 2140 struct isst_pkg_ctdp_level_info ctdp_level; 2141 struct isst_pkg_ctdp pkg_dev; 2142 int ret; 2143 int status = *(int *)arg4; 2144 2145 if (status && no_turbo()) { 2146 isst_display_error_info_message(1, "Turbo mode is disabled", 0, 0); 2147 ret = -1; 2148 goto disp_results; 2149 } 2150 2151 ret = isst_get_ctdp_levels(id, &pkg_dev); 2152 if (ret) { 2153 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0); 2154 goto disp_results; 2155 } 2156 2157 ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level); 2158 if (ret) { 2159 isst_display_error_info_message(1, "Failed to get current level", 0, 0); 2160 goto disp_results; 2161 } 2162 2163 if (!ctdp_level.fact_support) { 2164 isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, pkg_dev.current_level); 2165 ret = -1; 2166 goto disp_results; 2167 } 2168 2169 if (status) { 2170 ret = isst_pm_qos_config(id, 1, 1); 2171 if (ret) 2172 goto disp_results; 2173 } 2174 2175 ret = isst_set_pbf_fact_status(id, 0, status); 2176 if (ret) { 2177 debug_printf("isst_set_pbf_fact_status failed"); 2178 if (auto_mode) 2179 isst_pm_qos_config(id, 0, 0); 2180 2181 goto disp_results; 2182 } 2183 2184 /* Set TRL */ 2185 if (status) { 2186 struct isst_pkg_ctdp pkg_dev; 2187 2188 ret = isst_get_ctdp_levels(id, &pkg_dev); 2189 if (!ret && id->cpu >= 0) 2190 ret = isst_set_trl(id, fact_trl); 2191 if (ret && auto_mode) 2192 isst_pm_qos_config(id, 0, 0); 2193 } else { 2194 if (auto_mode) 2195 isst_pm_qos_config(id, 0, 0); 2196 } 2197 2198 disp_results: 2199 if (status) { 2200 isst_display_result(id, outf, "turbo-freq", "enable", ret); 2201 if (ret) 2202 fact_enable_fail = ret; 2203 } else { 2204 /* Since we modified TRL during Fact enable, restore it */ 2205 isst_set_trl_from_current_tdp(id, fact_trl); 2206 isst_display_result(id, outf, "turbo-freq", "disable", ret); 2207 } 2208 } 2209 2210 static void set_fact_enable(int arg) 2211 { 2212 int i, ret, enable = arg; 2213 struct isst_id id; 2214 2215 if (cmd_help) { 2216 if (enable) { 2217 fprintf(stderr, 2218 "Enable Intel Speed Select Technology Turbo frequency feature\n"); 2219 fprintf(stderr, 2220 "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n"); 2221 fprintf(stderr, 2222 "\tOptional Arguments: -a|--auto : Designate specified target CPUs with"); 2223 fprintf(stderr, 2224 "-C|--cpu option as as high priority using core-power feature\n"); 2225 } else { 2226 fprintf(stderr, 2227 "Disable Intel Speed Select Technology turbo frequency feature\n"); 2228 fprintf(stderr, 2229 "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n"); 2230 fprintf(stderr, 2231 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); 2232 } 2233 exit(0); 2234 } 2235 2236 isst_ctdp_display_information_start(outf); 2237 if (max_target_cpus) 2238 for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL, 2239 NULL, &enable); 2240 else 2241 for_each_online_power_domain_in_set(set_fact_for_cpu, NULL, NULL, 2242 NULL, &enable); 2243 2244 if (!fact_enable_fail && enable && auto_mode) { 2245 /* 2246 * When we adjust CLOS param, we have to set for siblings also. 2247 * So for the each user specified CPU, also add the sibling 2248 * in the present_cpu_mask. 2249 */ 2250 for (i = 0; i < get_topo_max_cpus(); ++i) { 2251 char buffer[128], sibling_list[128], *cpu_str; 2252 int fd, len; 2253 2254 if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask)) 2255 continue; 2256 2257 snprintf(buffer, sizeof(buffer), 2258 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i); 2259 2260 fd = open(buffer, O_RDONLY); 2261 if (fd < 0) 2262 continue; 2263 2264 len = read(fd, sibling_list, sizeof(sibling_list)); 2265 close(fd); 2266 2267 if (len < 0) 2268 continue; 2269 2270 sibling_list[127] = '\0'; 2271 cpu_str = strtok(sibling_list, ","); 2272 while (cpu_str != NULL) { 2273 int cpu; 2274 2275 sscanf(cpu_str, "%d", &cpu); 2276 CPU_SET_S(cpu, target_cpumask_size, target_cpumask); 2277 cpu_str = strtok(NULL, ","); 2278 } 2279 } 2280 2281 for (i = 0; i < get_topo_max_cpus(); ++i) { 2282 int clos; 2283 2284 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) 2285 continue; 2286 2287 if (is_cpu_online(i) != 1) 2288 continue; 2289 2290 set_isst_id(&id, i); 2291 ret = set_clos_param(&id, 0, 0, 0, 0, 0xff); 2292 if (ret) 2293 goto error_disp; 2294 2295 ret = set_clos_param(&id, 1, 15, 15, 0, 0xff); 2296 if (ret) 2297 goto error_disp; 2298 2299 ret = set_clos_param(&id, 2, 15, 15, 0, 0xff); 2300 if (ret) 2301 goto error_disp; 2302 2303 ret = set_clos_param(&id, 3, 15, 15, 0, 0xff); 2304 if (ret) 2305 goto error_disp; 2306 2307 if (CPU_ISSET_S(i, target_cpumask_size, target_cpumask)) 2308 clos = 0; 2309 else 2310 clos = 3; 2311 2312 debug_printf("Associate cpu: %d clos: %d\n", i, clos); 2313 ret = isst_clos_associate(&id, clos); 2314 if (ret) 2315 goto error_disp; 2316 } 2317 set_isst_id(&id, -1); 2318 isst_display_result(&id, outf, "turbo-freq --auto", "enable", 0); 2319 } 2320 2321 isst_ctdp_display_information_end(outf); 2322 2323 return; 2324 2325 error_disp: 2326 isst_display_result(&id, outf, "turbo-freq --auto", "enable", ret); 2327 isst_ctdp_display_information_end(outf); 2328 2329 } 2330 2331 static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, void *arg3, 2332 void *arg4) 2333 { 2334 int ret; 2335 int status = *(int *)arg4; 2336 int cp_state, cp_cap; 2337 2338 if (!isst_read_pm_config(id, &cp_state, &cp_cap)) { 2339 if (!cp_cap) { 2340 isst_display_error_info_message(1, "core-power not supported", 0, 0); 2341 return; 2342 } 2343 } 2344 2345 if (is_skx_based_platform()) 2346 clos_priority_type = 1; 2347 2348 ret = isst_pm_qos_config(id, status, clos_priority_type); 2349 if (ret) 2350 isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0); 2351 2352 if (status) 2353 isst_display_result(id, outf, "core-power", "enable", 2354 ret); 2355 else 2356 isst_display_result(id, outf, "core-power", "disable", 2357 ret); 2358 } 2359 2360 static void set_clos_enable(int arg) 2361 { 2362 int enable = arg; 2363 2364 if (cmd_help) { 2365 if (enable) { 2366 fprintf(stderr, 2367 "Enable core-power for a package/die\n"); 2368 if (!is_skx_based_platform()) { 2369 fprintf(stderr, 2370 "\tClos Enable: Specify priority type with [--priority|-p]\n"); 2371 fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n"); 2372 } 2373 } else { 2374 fprintf(stderr, 2375 "Disable core-power: [No command arguments are required]\n"); 2376 } 2377 exit(0); 2378 } 2379 2380 if (enable && cpufreq_sysfs_present()) { 2381 fprintf(stderr, 2382 "cpufreq subsystem and core-power enable will interfere with each other!\n"); 2383 } 2384 2385 isst_ctdp_display_information_start(outf); 2386 if (max_target_cpus) 2387 for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL, 2388 NULL, NULL, &enable); 2389 else 2390 for_each_online_power_domain_in_set(enable_clos_qos_config, NULL, 2391 NULL, NULL, &enable); 2392 isst_ctdp_display_information_end(outf); 2393 } 2394 2395 static void dump_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, 2396 void *arg3, void *arg4) 2397 { 2398 struct isst_clos_config clos_config; 2399 int ret; 2400 2401 ret = isst_pm_get_clos(id, current_clos, &clos_config); 2402 if (ret) 2403 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0); 2404 else 2405 isst_clos_display_information(id, outf, current_clos, 2406 &clos_config); 2407 } 2408 2409 static void dump_clos_config(int arg) 2410 { 2411 if (cmd_help) { 2412 fprintf(stderr, 2413 "Print Intel Speed Select Technology core power configuration\n"); 2414 fprintf(stderr, 2415 "\tArguments: [-c | --clos]: Specify clos id\n"); 2416 exit(0); 2417 } 2418 if (current_clos < 0 || current_clos > 3) { 2419 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); 2420 isst_ctdp_display_information_end(outf); 2421 exit(0); 2422 } 2423 2424 isst_ctdp_display_information_start(outf); 2425 if (max_target_cpus) 2426 for_each_online_target_cpu_in_set(dump_clos_config_for_cpu, 2427 NULL, NULL, NULL, NULL); 2428 else 2429 for_each_online_power_domain_in_set(dump_clos_config_for_cpu, NULL, 2430 NULL, NULL, NULL); 2431 isst_ctdp_display_information_end(outf); 2432 } 2433 2434 static void get_clos_info_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 2435 void *arg4) 2436 { 2437 int enable, ret, prio_type; 2438 2439 ret = isst_clos_get_clos_information(id, &enable, &prio_type); 2440 if (ret) 2441 isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0); 2442 else { 2443 int cp_state, cp_cap; 2444 2445 isst_read_pm_config(id, &cp_state, &cp_cap); 2446 isst_clos_display_clos_information(id, outf, enable, prio_type, 2447 cp_state, cp_cap); 2448 } 2449 } 2450 2451 static void dump_clos_info(int arg) 2452 { 2453 if (cmd_help) { 2454 fprintf(stderr, 2455 "Print Intel Speed Select Technology core power information\n"); 2456 fprintf(stderr, "\t Optionally specify targeted cpu id with [--cpu|-c]\n"); 2457 exit(0); 2458 } 2459 2460 isst_ctdp_display_information_start(outf); 2461 if (max_target_cpus) 2462 for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL, 2463 NULL, NULL, NULL); 2464 else 2465 for_each_online_power_domain_in_set(get_clos_info_for_cpu, NULL, 2466 NULL, NULL, NULL); 2467 isst_ctdp_display_information_end(outf); 2468 2469 } 2470 2471 static void set_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 2472 void *arg4) 2473 { 2474 struct isst_clos_config clos_config; 2475 int ret; 2476 2477 if (id->cpu < 0) 2478 return; 2479 2480 clos_config.epp = clos_epp; 2481 clos_config.clos_prop_prio = clos_prop_prio; 2482 clos_config.clos_min = clos_min; 2483 clos_config.clos_max = clos_max; 2484 clos_config.clos_desired = clos_desired; 2485 ret = isst_set_clos(id, current_clos, &clos_config); 2486 if (ret) 2487 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0); 2488 else 2489 isst_display_result(id, outf, "core-power", "config", ret); 2490 } 2491 2492 static void set_clos_config(int arg) 2493 { 2494 if (cmd_help) { 2495 fprintf(stderr, 2496 "Set core-power configuration for one of the four clos ids\n"); 2497 fprintf(stderr, 2498 "\tSpecify targeted clos id with [--clos|-c]\n"); 2499 if (!is_skx_based_platform()) { 2500 fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n"); 2501 fprintf(stderr, 2502 "\tSpecify clos Proportional Priority [--weight|-w]\n"); 2503 } 2504 fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n"); 2505 fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n"); 2506 exit(0); 2507 } 2508 2509 if (current_clos < 0 || current_clos > 3) { 2510 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); 2511 exit(0); 2512 } 2513 if (!is_skx_based_platform() && (clos_epp < 0 || clos_epp > 0x0F)) { 2514 fprintf(stderr, "clos epp is not specified or invalid, default: 0\n"); 2515 clos_epp = 0; 2516 } 2517 if (!is_skx_based_platform() && (clos_prop_prio < 0 || clos_prop_prio > 0x0F)) { 2518 fprintf(stderr, 2519 "clos frequency weight is not specified or invalid, default: 0\n"); 2520 clos_prop_prio = 0; 2521 } 2522 if (clos_min < 0) { 2523 fprintf(stderr, "clos min is not specified, default: 0\n"); 2524 clos_min = 0; 2525 } 2526 if (clos_max < 0) { 2527 fprintf(stderr, "clos max is not specified, default: Max frequency (ratio 0xff)\n"); 2528 clos_max = 0xff; 2529 } 2530 if (clos_desired) { 2531 fprintf(stderr, "clos desired is not supported on this platform\n"); 2532 clos_desired = 0x00; 2533 } 2534 2535 isst_ctdp_display_information_start(outf); 2536 if (max_target_cpus) 2537 for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL, 2538 NULL, NULL, NULL); 2539 else 2540 for_each_online_power_domain_in_set(set_clos_config_for_cpu, NULL, 2541 NULL, NULL, NULL); 2542 isst_ctdp_display_information_end(outf); 2543 } 2544 2545 static void set_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 2546 void *arg4) 2547 { 2548 int ret; 2549 2550 ret = isst_clos_associate(id, current_clos); 2551 if (ret) 2552 debug_printf("isst_clos_associate failed"); 2553 else 2554 isst_display_result(id, outf, "core-power", "assoc", ret); 2555 } 2556 2557 static void set_clos_assoc(int arg) 2558 { 2559 if (cmd_help) { 2560 fprintf(stderr, "Associate a clos id to a CPU\n"); 2561 fprintf(stderr, 2562 "\tSpecify targeted clos id with [--clos|-c]\n"); 2563 fprintf(stderr, 2564 "\tFor example to associate clos 1 to CPU 0: issue\n"); 2565 fprintf(stderr, 2566 "\tintel-speed-select --cpu 0 core-power assoc --clos 1\n"); 2567 exit(0); 2568 } 2569 2570 if (current_clos < 0 || current_clos > 3) { 2571 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); 2572 exit(0); 2573 } 2574 2575 isst_ctdp_display_information_start(outf); 2576 2577 if (max_target_cpus) 2578 for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL, 2579 NULL, NULL, NULL); 2580 else { 2581 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0); 2582 } 2583 isst_ctdp_display_information_end(outf); 2584 } 2585 2586 static void get_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, 2587 void *arg4) 2588 { 2589 int clos, ret; 2590 2591 ret = isst_clos_get_assoc_status(id, &clos); 2592 if (ret) 2593 isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0); 2594 else 2595 isst_clos_display_assoc_information(id, outf, clos); 2596 } 2597 2598 static void get_clos_assoc(int arg) 2599 { 2600 if (cmd_help) { 2601 fprintf(stderr, "Get associate clos id to a CPU\n"); 2602 fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n"); 2603 exit(0); 2604 } 2605 2606 if (!max_target_cpus) { 2607 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0); 2608 exit(0); 2609 } 2610 2611 isst_ctdp_display_information_start(outf); 2612 for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL, 2613 NULL, NULL, NULL); 2614 isst_ctdp_display_information_end(outf); 2615 } 2616 2617 static void set_turbo_mode_for_cpu(struct isst_id *id, int status) 2618 { 2619 int base_freq; 2620 2621 if (status) { 2622 base_freq = get_cpufreq_base_freq(id->cpu); 2623 set_cpufreq_scaling_min_max(id->cpu, 1, base_freq); 2624 } else { 2625 set_scaling_max_to_cpuinfo_max(id); 2626 } 2627 2628 if (status) { 2629 isst_display_result(id, outf, "turbo-mode", "disable", 0); 2630 } else { 2631 isst_display_result(id, outf, "turbo-mode", "enable", 0); 2632 } 2633 } 2634 2635 static void set_turbo_mode(int arg) 2636 { 2637 int i, disable = arg; 2638 struct isst_id id; 2639 2640 if (cmd_help) { 2641 if (disable) 2642 fprintf(stderr, "Set turbo mode disable\n"); 2643 else 2644 fprintf(stderr, "Set turbo mode enable\n"); 2645 exit(0); 2646 } 2647 2648 isst_ctdp_display_information_start(outf); 2649 2650 for (i = 0; i < topo_max_cpus; ++i) { 2651 int online; 2652 2653 if (i) 2654 online = parse_int_file( 2655 1, "/sys/devices/system/cpu/cpu%d/online", i); 2656 else 2657 online = 2658 1; /* online entry for CPU 0 needs some special configs */ 2659 2660 if (online) { 2661 set_isst_id(&id, i); 2662 set_turbo_mode_for_cpu(&id, disable); 2663 } 2664 2665 } 2666 isst_ctdp_display_information_end(outf); 2667 } 2668 2669 static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3, 2670 void *arg4) 2671 { 2672 unsigned long long trl; 2673 int set = *(int *)arg4; 2674 int ret; 2675 2676 if (id->cpu < 0) 2677 return; 2678 2679 if (set && !fact_trl) { 2680 isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0); 2681 exit(0); 2682 } 2683 2684 if (set) { 2685 ret = isst_set_trl(id, fact_trl); 2686 isst_display_result(id, outf, "turbo-mode", "set-trl", ret); 2687 return; 2688 } 2689 2690 ret = isst_get_trl(id, &trl); 2691 if (ret) 2692 isst_display_result(id, outf, "turbo-mode", "get-trl", ret); 2693 else 2694 isst_trl_display_information(id, outf, trl); 2695 } 2696 2697 static void process_trl(int arg) 2698 { 2699 if (cmd_help) { 2700 if (arg) { 2701 fprintf(stderr, "Set TRL (turbo ratio limits)\n"); 2702 fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL in hex starting with 0x\n"); 2703 } else { 2704 fprintf(stderr, "Get TRL (turbo ratio limits)\n"); 2705 } 2706 exit(0); 2707 } 2708 2709 isst_ctdp_display_information_start(outf); 2710 if (max_target_cpus) 2711 for_each_online_target_cpu_in_set(get_set_trl, NULL, 2712 NULL, NULL, &arg); 2713 else 2714 for_each_online_power_domain_in_set(get_set_trl, NULL, 2715 NULL, NULL, &arg); 2716 isst_ctdp_display_information_end(outf); 2717 } 2718 2719 static struct process_cmd_struct clx_n_cmds[] = { 2720 { "perf-profile", "info", dump_isst_config, 0 }, 2721 { "base-freq", "info", dump_pbf_config, 0 }, 2722 { "base-freq", "enable", set_pbf_enable, 1 }, 2723 { "base-freq", "disable", set_pbf_enable, 0 }, 2724 { NULL, NULL, NULL, 0 } 2725 }; 2726 2727 static struct process_cmd_struct isst_cmds[] = { 2728 { "perf-profile", "get-lock-status", get_tdp_locked, 0 }, 2729 { "perf-profile", "get-config-levels", get_tdp_levels, 0 }, 2730 { "perf-profile", "get-config-version", get_tdp_version, 0 }, 2731 { "perf-profile", "get-config-enabled", get_tdp_enabled, 0 }, 2732 { "perf-profile", "get-config-current-level", get_tdp_current_level, 2733 0 }, 2734 { "perf-profile", "set-config-level", set_tdp_level, 0 }, 2735 { "perf-profile", "info", dump_isst_config, 0 }, 2736 { "base-freq", "info", dump_pbf_config, 0 }, 2737 { "base-freq", "enable", set_pbf_enable, 1 }, 2738 { "base-freq", "disable", set_pbf_enable, 0 }, 2739 { "turbo-freq", "info", dump_fact_config, 0 }, 2740 { "turbo-freq", "enable", set_fact_enable, 1 }, 2741 { "turbo-freq", "disable", set_fact_enable, 0 }, 2742 { "core-power", "info", dump_clos_info, 0 }, 2743 { "core-power", "enable", set_clos_enable, 1 }, 2744 { "core-power", "disable", set_clos_enable, 0 }, 2745 { "core-power", "config", set_clos_config, 0 }, 2746 { "core-power", "get-config", dump_clos_config, 0 }, 2747 { "core-power", "assoc", set_clos_assoc, 0 }, 2748 { "core-power", "get-assoc", get_clos_assoc, 0 }, 2749 { "turbo-mode", "enable", set_turbo_mode, 0 }, 2750 { "turbo-mode", "disable", set_turbo_mode, 1 }, 2751 { "turbo-mode", "get-trl", process_trl, 0 }, 2752 { "turbo-mode", "set-trl", process_trl, 1 }, 2753 { NULL, NULL, NULL } 2754 }; 2755 2756 /* 2757 * parse cpuset with following syntax 2758 * 1,2,4..6,8-10 and set bits in cpu_subset 2759 */ 2760 void parse_cpu_command(char *optarg) 2761 { 2762 unsigned int start, end, invalid_count; 2763 char *next; 2764 2765 next = optarg; 2766 invalid_count = 0; 2767 2768 while (next && *next) { 2769 if (*next == '-') /* no negative cpu numbers */ 2770 goto error; 2771 2772 start = strtoul(next, &next, 10); 2773 2774 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ) 2775 target_cpus[max_target_cpus++] = start; 2776 else 2777 invalid_count = 1; 2778 2779 if (*next == '\0') 2780 break; 2781 2782 if (*next == ',') { 2783 next += 1; 2784 continue; 2785 } 2786 2787 if (*next == '-') { 2788 next += 1; /* start range */ 2789 } else if (*next == '.') { 2790 next += 1; 2791 if (*next == '.') 2792 next += 1; /* start range */ 2793 else 2794 goto error; 2795 } 2796 2797 end = strtoul(next, &next, 10); 2798 if (end <= start) 2799 goto error; 2800 2801 while (++start <= end) { 2802 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ) 2803 target_cpus[max_target_cpus++] = start; 2804 else 2805 invalid_count = 1; 2806 } 2807 2808 if (*next == ',') 2809 next += 1; 2810 else if (*next != '\0') 2811 goto error; 2812 } 2813 2814 if (invalid_count) { 2815 isst_ctdp_display_information_start(outf); 2816 isst_display_error_info_message(1, "Too many CPUs in one request: max is", 1, MAX_CPUS_IN_ONE_REQ - 1); 2817 isst_ctdp_display_information_end(outf); 2818 exit(-1); 2819 } 2820 2821 #ifdef DEBUG 2822 { 2823 int i; 2824 2825 for (i = 0; i < max_target_cpus; ++i) 2826 printf("cpu [%d] in arg\n", target_cpus[i]); 2827 } 2828 #endif 2829 return; 2830 2831 error: 2832 fprintf(stderr, "\"--cpu %s\" malformed\n", optarg); 2833 exit(-1); 2834 } 2835 2836 static void check_optarg(char *option, int hex) 2837 { 2838 if (optarg) { 2839 char *start = optarg; 2840 int i; 2841 2842 if (hex && strlen(optarg) < 3) { 2843 /* At least 0x plus one character must be present */ 2844 fprintf(stderr, "malformed arguments for:%s [%s]\n", option, optarg); 2845 exit(0); 2846 } 2847 2848 if (hex) { 2849 if (optarg[0] != '0' || tolower(optarg[1]) != 'x') { 2850 fprintf(stderr, "malformed arguments for:%s [%s]\n", 2851 option, optarg); 2852 exit(0); 2853 } 2854 start = &optarg[2]; 2855 } 2856 2857 for (i = 0; i < strlen(start); ++i) { 2858 if (hex) { 2859 if (!isxdigit(start[i])) { 2860 fprintf(stderr, "malformed arguments for:%s [%s]\n", 2861 option, optarg); 2862 exit(0); 2863 } 2864 } else if (!isdigit(start[i])) { 2865 fprintf(stderr, "malformed arguments for:%s [%s]\n", 2866 option, optarg); 2867 exit(0); 2868 } 2869 } 2870 } 2871 } 2872 2873 static void parse_cmd_args(int argc, int start, char **argv) 2874 { 2875 int opt; 2876 int option_index; 2877 2878 static struct option long_options[] = { 2879 { "bucket", required_argument, 0, 'b' }, 2880 { "level", required_argument, 0, 'l' }, 2881 { "online", required_argument, 0, 'o' }, 2882 { "trl-type", required_argument, 0, 'r' }, 2883 { "trl", required_argument, 0, 't' }, 2884 { "help", no_argument, 0, 'h' }, 2885 { "clos", required_argument, 0, 'c' }, 2886 { "desired", required_argument, 0, 'd' }, 2887 { "epp", required_argument, 0, 'e' }, 2888 { "min", required_argument, 0, 'n' }, 2889 { "max", required_argument, 0, 'm' }, 2890 { "priority", required_argument, 0, 'p' }, 2891 { "weight", required_argument, 0, 'w' }, 2892 { "auto", no_argument, 0, 'a' }, 2893 { 0, 0, 0, 0 } 2894 }; 2895 2896 option_index = start; 2897 2898 optind = start + 1; 2899 while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:r:hoa", 2900 long_options, &option_index)) != -1) { 2901 switch (opt) { 2902 case 'a': 2903 auto_mode = 1; 2904 break; 2905 case 'b': 2906 check_optarg("bucket", 0); 2907 fact_bucket = atoi(optarg); 2908 break; 2909 case 'h': 2910 cmd_help = 1; 2911 break; 2912 case 'l': 2913 check_optarg("level", 0); 2914 tdp_level = atoi(optarg); 2915 break; 2916 case 'o': 2917 force_online_offline = 1; 2918 break; 2919 case 't': 2920 check_optarg("trl", 1); 2921 sscanf(optarg, "0x%llx", &fact_trl); 2922 break; 2923 case 'r': 2924 if (!strncmp(optarg, "sse", 3)) { 2925 fact_avx = 0x01; 2926 } else if (!strncmp(optarg, "avx2", 4)) { 2927 fact_avx = 0x02; 2928 } else if (!strncmp(optarg, "avx512", 6)) { 2929 fact_avx = 0x04; 2930 } else { 2931 fprintf(outf, "Invalid sse,avx options\n"); 2932 exit(1); 2933 } 2934 break; 2935 /* CLOS related */ 2936 case 'c': 2937 check_optarg("clos", 0); 2938 current_clos = atoi(optarg); 2939 break; 2940 case 'd': 2941 check_optarg("desired", 0); 2942 clos_desired = atoi(optarg); 2943 clos_desired /= isst_get_disp_freq_multiplier(); 2944 break; 2945 case 'e': 2946 check_optarg("epp", 0); 2947 clos_epp = atoi(optarg); 2948 if (is_skx_based_platform()) { 2949 isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0); 2950 exit(0); 2951 } 2952 break; 2953 case 'n': 2954 check_optarg("min", 0); 2955 clos_min = atoi(optarg); 2956 clos_min /= isst_get_disp_freq_multiplier(); 2957 break; 2958 case 'm': 2959 check_optarg("max", 0); 2960 clos_max = atoi(optarg); 2961 clos_max /= isst_get_disp_freq_multiplier(); 2962 break; 2963 case 'p': 2964 check_optarg("priority", 0); 2965 clos_priority_type = atoi(optarg); 2966 if (is_skx_based_platform() && !clos_priority_type) { 2967 isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0); 2968 exit(0); 2969 } 2970 break; 2971 case 'w': 2972 check_optarg("weight", 0); 2973 clos_prop_prio = atoi(optarg); 2974 if (is_skx_based_platform()) { 2975 isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0); 2976 exit(0); 2977 } 2978 break; 2979 default: 2980 printf("Unknown option: ignore\n"); 2981 } 2982 } 2983 2984 if (argv[optind]) 2985 printf("Garbage at the end of command: ignore\n"); 2986 } 2987 2988 static void isst_help(void) 2989 { 2990 printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\ 2991 performance profiles per system via static and/or dynamic\n\ 2992 adjustment of core count, workload, Tjmax, and\n\ 2993 TDP, etc.\n"); 2994 printf("\nCommands : For feature=perf-profile\n"); 2995 printf("\tinfo\n"); 2996 2997 if (!is_clx_n_platform()) { 2998 printf("\tget-lock-status\n"); 2999 printf("\tget-config-levels\n"); 3000 printf("\tget-config-version\n"); 3001 printf("\tget-config-enabled\n"); 3002 printf("\tget-config-current-level\n"); 3003 printf("\tset-config-level\n"); 3004 } 3005 } 3006 3007 static void pbf_help(void) 3008 { 3009 printf("base-freq:\tEnables users to increase guaranteed base frequency\n\ 3010 on certain cores (high priority cores) in exchange for lower\n\ 3011 base frequency on remaining cores (low priority cores).\n"); 3012 printf("\tcommand : info\n"); 3013 printf("\tcommand : enable\n"); 3014 printf("\tcommand : disable\n"); 3015 } 3016 3017 static void fact_help(void) 3018 { 3019 printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\ 3020 limits to cores based on priority.\n"); 3021 printf("\nCommand: For feature=turbo-freq\n"); 3022 printf("\tcommand : info\n"); 3023 printf("\tcommand : enable\n"); 3024 printf("\tcommand : disable\n"); 3025 } 3026 3027 static void turbo_mode_help(void) 3028 { 3029 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"); 3030 printf("\tcommand : enable\n"); 3031 printf("\tcommand : disable\n"); 3032 printf("\tcommand : get-trl\n"); 3033 printf("\tcommand : set-trl\n"); 3034 } 3035 3036 3037 static void core_power_help(void) 3038 { 3039 printf("core-power:\tInterface that allows user to define per core/tile\n\ 3040 priority.\n"); 3041 printf("\nCommands : For feature=core-power\n"); 3042 printf("\tinfo\n"); 3043 printf("\tenable\n"); 3044 printf("\tdisable\n"); 3045 printf("\tconfig\n"); 3046 printf("\tget-config\n"); 3047 printf("\tassoc\n"); 3048 printf("\tget-assoc\n"); 3049 } 3050 3051 struct process_cmd_help_struct { 3052 char *feature; 3053 void (*process_fn)(void); 3054 }; 3055 3056 static struct process_cmd_help_struct isst_help_cmds[] = { 3057 { "perf-profile", isst_help }, 3058 { "base-freq", pbf_help }, 3059 { "turbo-freq", fact_help }, 3060 { "core-power", core_power_help }, 3061 { "turbo-mode", turbo_mode_help }, 3062 { NULL, NULL } 3063 }; 3064 3065 static struct process_cmd_help_struct clx_n_help_cmds[] = { 3066 { "perf-profile", isst_help }, 3067 { "base-freq", pbf_help }, 3068 { NULL, NULL } 3069 }; 3070 3071 void process_command(int argc, char **argv, 3072 struct process_cmd_help_struct *help_cmds, 3073 struct process_cmd_struct *cmds) 3074 { 3075 int i = 0, matched = 0; 3076 char *feature = argv[optind]; 3077 char *cmd = argv[optind + 1]; 3078 3079 if (!feature || !cmd) 3080 return; 3081 3082 debug_printf("feature name [%s] command [%s]\n", feature, cmd); 3083 if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) { 3084 while (help_cmds[i].feature) { 3085 if (!strcmp(help_cmds[i].feature, feature)) { 3086 help_cmds[i].process_fn(); 3087 exit(0); 3088 } 3089 ++i; 3090 } 3091 } 3092 3093 i = 0; 3094 while (cmds[i].feature) { 3095 if (!strcmp(cmds[i].feature, feature) && 3096 !strcmp(cmds[i].command, cmd)) { 3097 parse_cmd_args(argc, optind + 1, argv); 3098 cmds[i].process_fn(cmds[i].arg); 3099 matched = 1; 3100 break; 3101 } 3102 ++i; 3103 } 3104 3105 if (!matched) 3106 fprintf(stderr, "Invalid command\n"); 3107 } 3108 3109 static void usage(void) 3110 { 3111 if (is_clx_n_platform()) { 3112 fprintf(stderr, "\nThere is limited support of Intel Speed Select features on this platform.\n"); 3113 fprintf(stderr, "Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware.\n\n"); 3114 } 3115 3116 printf("\nUsage:\n"); 3117 printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n"); 3118 printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features:\n"); 3119 if (is_clx_n_platform()) 3120 printf("\nFEATURE : [perf-profile|base-freq]\n"); 3121 else 3122 printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power|turbo-mode]\n"); 3123 printf("\nFor help on each feature, use -h|--help\n"); 3124 printf("\tFor example: intel-speed-select perf-profile -h\n"); 3125 3126 printf("\nFor additional help on each command for a feature, use --h|--help\n"); 3127 printf("\tFor example: intel-speed-select perf-profile get-lock-status -h\n"); 3128 printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n"); 3129 3130 printf("\nOPTIONS\n"); 3131 printf("\t[-c|--cpu] : logical cpu number\n"); 3132 printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n"); 3133 printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n"); 3134 printf("\t[-d|--debug] : Debug mode\n"); 3135 printf("\t[-f|--format] : output format [json|text]. Default: text\n"); 3136 printf("\t[-h|--help] : Print help\n"); 3137 printf("\t[-i|--info] : Print platform information\n"); 3138 printf("\t[-a|--all-cpus-online] : Force online every CPU in the system\n"); 3139 printf("\t[-o|--out] : Output file\n"); 3140 printf("\t\t\tDefault : stderr\n"); 3141 printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n"); 3142 printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n"); 3143 printf("\t[-v|--version] : Print version\n"); 3144 printf("\t[-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent.\n"); 3145 printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n"); 3146 printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n"); 3147 printf("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n"); 3148 printf("\t[-u|--cpu0-workaround : Don't try to online/offline CPU0 instead use cgroup v2.\n"); 3149 printf("\nResult format\n"); 3150 printf("\tResult display uses a common format for each command:\n"); 3151 printf("\tResults are formatted in text/JSON with\n"); 3152 printf("\t\tPackage, Die, CPU, and command specific results.\n"); 3153 3154 printf("\nExamples\n"); 3155 printf("\tTo get platform information:\n"); 3156 printf("\t\tintel-speed-select --info\n"); 3157 printf("\tTo get full perf-profile information dump:\n"); 3158 printf("\t\tintel-speed-select perf-profile info\n"); 3159 printf("\tTo get full base-freq information dump:\n"); 3160 printf("\t\tintel-speed-select base-freq info -l 0\n"); 3161 if (!is_clx_n_platform()) { 3162 printf("\tTo get full turbo-freq information dump:\n"); 3163 printf("\t\tintel-speed-select turbo-freq info -l 0\n"); 3164 } 3165 exit(1); 3166 } 3167 3168 static void print_version(void) 3169 { 3170 fprintf(outf, "Version %s\n", version_str); 3171 exit(0); 3172 } 3173 3174 static void cmdline(int argc, char **argv) 3175 { 3176 const char *pathname = "/dev/isst_interface"; 3177 char *ptr; 3178 FILE *fp; 3179 int opt, force_cpus_online = 0; 3180 int option_index = 0; 3181 int ret; 3182 int oob_mode = 0; 3183 int poll_interval = -1; 3184 int no_daemon = 0; 3185 int mbox_delay = 0, mbox_retries = 3; 3186 3187 static struct option long_options[] = { 3188 { "all-cpus-online", no_argument, 0, 'a' }, 3189 { "cpu", required_argument, 0, 'c' }, 3190 { "debug", no_argument, 0, 'd' }, 3191 { "format", required_argument, 0, 'f' }, 3192 { "help", no_argument, 0, 'h' }, 3193 { "info", no_argument, 0, 'i' }, 3194 { "pause", required_argument, 0, 'p' }, 3195 { "out", required_argument, 0, 'o' }, 3196 { "retry", required_argument, 0, 'r' }, 3197 { "version", no_argument, 0, 'v' }, 3198 { "oob", no_argument, 0, 'b' }, 3199 { "no-daemon", no_argument, 0, 'n' }, 3200 { "poll-interval", required_argument, 0, 'w' }, 3201 { "cgroupv2", required_argument, 0, 'g' }, 3202 { "cpu0-workaround", required_argument, 0, 'u' }, 3203 { 0, 0, 0, 0 } 3204 }; 3205 3206 if (geteuid() != 0) { 3207 fprintf(stderr, "Must run as root\n"); 3208 exit(0); 3209 } 3210 3211 ret = update_cpu_model(); 3212 if (ret) 3213 err(-1, "Invalid CPU model (%d)\n", cpu_model); 3214 printf("Intel(R) Speed Select Technology\n"); 3215 printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model); 3216 3217 if (!is_clx_n_platform()) { 3218 fp = fopen(pathname, "rb"); 3219 if (!fp) { 3220 fprintf(stderr, "Intel speed select drivers are not loaded on this system.\n"); 3221 fprintf(stderr, "Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE.\n"); 3222 fprintf(stderr, "If the config is included then this is not a supported platform.\n"); 3223 exit(0); 3224 } 3225 fclose(fp); 3226 } 3227 3228 ret = isst_fill_platform_info(); 3229 if (ret) 3230 goto out; 3231 3232 progname = argv[0]; 3233 while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ngu", long_options, 3234 &option_index)) != -1) { 3235 switch (opt) { 3236 case 'a': 3237 force_cpus_online = 1; 3238 break; 3239 case 'c': 3240 parse_cpu_command(optarg); 3241 break; 3242 case 'd': 3243 debug_flag = 1; 3244 printf("Debug Mode ON\n"); 3245 break; 3246 case 'f': 3247 if (!strncmp(optarg, "json", 4)) 3248 out_format_json = 1; 3249 break; 3250 case 'h': 3251 usage(); 3252 break; 3253 case 'i': 3254 isst_print_platform_information(); 3255 break; 3256 case 'o': 3257 if (outf) 3258 fclose(outf); 3259 outf = fopen_or_exit(optarg, "w"); 3260 break; 3261 case 'p': 3262 ret = strtol(optarg, &ptr, 10); 3263 if (!ret) 3264 fprintf(stderr, "Invalid pause interval, ignore\n"); 3265 else 3266 mbox_delay = ret; 3267 break; 3268 case 'r': 3269 ret = strtol(optarg, &ptr, 10); 3270 if (!ret) 3271 fprintf(stderr, "Invalid retry count, ignore\n"); 3272 else 3273 mbox_retries = ret; 3274 break; 3275 case 'v': 3276 print_version(); 3277 break; 3278 case 'b': 3279 oob_mode = 1; 3280 break; 3281 case 'n': 3282 no_daemon = 1; 3283 break; 3284 case 'w': 3285 ret = strtol(optarg, &ptr, 10); 3286 if (!ret) { 3287 fprintf(stderr, "Invalid poll interval count\n"); 3288 exit(0); 3289 } 3290 poll_interval = ret; 3291 break; 3292 case 'g': 3293 cgroupv2 = 1; 3294 break; 3295 case 'u': 3296 cpu_0_cgroupv2 = 1; 3297 break; 3298 default: 3299 usage(); 3300 } 3301 } 3302 3303 if (optind > (argc - 2) && !oob_mode) { 3304 usage(); 3305 exit(0); 3306 } 3307 3308 isst_update_platform_param(ISST_PARAM_MBOX_DELAY, mbox_delay); 3309 isst_update_platform_param(ISST_PARAM_MBOX_RETRIES, mbox_retries); 3310 3311 set_max_cpu_num(); 3312 if (force_cpus_online) 3313 force_all_cpus_online(); 3314 store_cpu_topology(); 3315 create_cpu_map(); 3316 3317 if (oob_mode) { 3318 if (debug_flag) 3319 fprintf(stderr, "OOB mode is enabled in debug mode\n"); 3320 3321 ret = isst_daemon(debug_flag, poll_interval, no_daemon); 3322 if (ret) 3323 fprintf(stderr, "OOB mode enable failed\n"); 3324 goto out; 3325 } 3326 3327 if (!is_clx_n_platform()) { 3328 process_command(argc, argv, isst_help_cmds, isst_cmds); 3329 } else { 3330 process_command(argc, argv, clx_n_help_cmds, clx_n_cmds); 3331 } 3332 out: 3333 free_cpu_set(present_cpumask); 3334 free_cpu_set(target_cpumask); 3335 } 3336 3337 int main(int argc, char **argv) 3338 { 3339 outf = stderr; 3340 cmdline(argc, argv); 3341 return 0; 3342 } 3343