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