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