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