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