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