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