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