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.3"; 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 64 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(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 isst_ctdp_display_information(cpu, outf, tdp_level, &clx_n_pkg_dev); 1173 free_cpu_set(ctdp_level->core_cpumask); 1174 free_cpu_set(pbf_info->core_cpumask); 1175 } 1176 } 1177 1178 static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2, 1179 void *arg3, void *arg4) 1180 { 1181 struct isst_pkg_ctdp pkg_dev; 1182 int ret; 1183 1184 memset(&pkg_dev, 0, sizeof(pkg_dev)); 1185 ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev); 1186 if (ret) { 1187 isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, cpu); 1188 isst_ctdp_display_information_end(outf); 1189 exit(1); 1190 } else { 1191 isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev); 1192 isst_get_process_ctdp_complete(cpu, &pkg_dev); 1193 } 1194 } 1195 1196 static void dump_isst_config(int arg) 1197 { 1198 void *fn; 1199 1200 if (cmd_help) { 1201 fprintf(stderr, 1202 "Print Intel(R) Speed Select Technology Performance profile configuration\n"); 1203 fprintf(stderr, 1204 "including base frequency and turbo frequency configurations\n"); 1205 fprintf(stderr, "Optional: -l|--level : Specify tdp level\n"); 1206 fprintf(stderr, 1207 "\tIf no arguments, dump information for all TDP levels\n"); 1208 exit(0); 1209 } 1210 1211 if (!is_clx_n_platform()) 1212 fn = dump_isst_config_for_cpu; 1213 else 1214 fn = dump_clx_n_config_for_cpu; 1215 1216 isst_ctdp_display_information_start(outf); 1217 1218 if (max_target_cpus) 1219 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL); 1220 else 1221 for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL); 1222 1223 isst_ctdp_display_information_end(outf); 1224 } 1225 1226 static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 1227 void *arg4) 1228 { 1229 int ret; 1230 1231 ret = isst_set_tdp_level(cpu, tdp_level); 1232 if (ret) { 1233 isst_display_error_info_message(1, "Set TDP level failed", 0, 0); 1234 isst_ctdp_display_information_end(outf); 1235 exit(1); 1236 } else { 1237 isst_display_result(cpu, outf, "perf-profile", "set_tdp_level", 1238 ret); 1239 if (force_online_offline) { 1240 struct isst_pkg_ctdp_level_info ctdp_level; 1241 int pkg_id = get_physical_package_id(cpu); 1242 int die_id = get_physical_die_id(cpu); 1243 1244 fprintf(stderr, "Option is set to online/offline\n"); 1245 ctdp_level.core_cpumask_size = 1246 alloc_cpu_set(&ctdp_level.core_cpumask); 1247 isst_get_coremask_info(cpu, tdp_level, &ctdp_level); 1248 if (ctdp_level.cpu_count) { 1249 int i, max_cpus = get_topo_max_cpus(); 1250 for (i = 0; i < max_cpus; ++i) { 1251 if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i)) 1252 continue; 1253 if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) { 1254 fprintf(stderr, "online cpu %d\n", i); 1255 set_cpu_online_offline(i, 1); 1256 } else { 1257 fprintf(stderr, "offline cpu %d\n", i); 1258 set_cpu_online_offline(i, 0); 1259 } 1260 } 1261 } 1262 } 1263 } 1264 } 1265 1266 static void set_tdp_level(int arg) 1267 { 1268 if (cmd_help) { 1269 fprintf(stderr, "Set Config TDP level\n"); 1270 fprintf(stderr, 1271 "\t Arguments: -l|--level : Specify tdp level\n"); 1272 fprintf(stderr, 1273 "\t Optional Arguments: -o | online : online/offline for the tdp level\n"); 1274 fprintf(stderr, 1275 "\t online/offline operation has limitations, refer to Linux hotplug documentation\n"); 1276 exit(0); 1277 } 1278 1279 if (tdp_level == 0xff) { 1280 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0); 1281 exit(1); 1282 } 1283 isst_ctdp_display_information_start(outf); 1284 if (max_target_cpus) 1285 for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL, 1286 NULL, NULL, NULL); 1287 else 1288 for_each_online_package_in_set(set_tdp_level_for_cpu, NULL, 1289 NULL, NULL, NULL); 1290 isst_ctdp_display_information_end(outf); 1291 } 1292 1293 static void clx_n_dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, 1294 void *arg3, void *arg4) 1295 { 1296 int ret; 1297 1298 ret = clx_n_config(cpu); 1299 if (ret) { 1300 isst_display_error_info_message(1, "clx_n_config failed", 0, 0); 1301 } else { 1302 struct isst_pkg_ctdp_level_info *ctdp_level; 1303 struct isst_pbf_info *pbf_info; 1304 1305 ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 1306 pbf_info = &ctdp_level->pbf_info; 1307 isst_pbf_display_information(cpu, outf, tdp_level, pbf_info); 1308 free_cpu_set(ctdp_level->core_cpumask); 1309 free_cpu_set(pbf_info->core_cpumask); 1310 } 1311 } 1312 1313 static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 1314 void *arg4) 1315 { 1316 struct isst_pbf_info pbf_info; 1317 int ret; 1318 1319 ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info); 1320 if (ret) { 1321 isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level); 1322 isst_ctdp_display_information_end(outf); 1323 exit(1); 1324 } else { 1325 isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info); 1326 isst_get_pbf_info_complete(&pbf_info); 1327 } 1328 } 1329 1330 static void dump_pbf_config(int arg) 1331 { 1332 void *fn; 1333 1334 if (cmd_help) { 1335 fprintf(stderr, 1336 "Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n"); 1337 fprintf(stderr, 1338 "\tArguments: -l|--level : Specify tdp level\n"); 1339 exit(0); 1340 } 1341 1342 if (tdp_level == 0xff) { 1343 isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0); 1344 exit(1); 1345 } 1346 1347 if (!is_clx_n_platform()) 1348 fn = dump_pbf_config_for_cpu; 1349 else 1350 fn = clx_n_dump_pbf_config_for_cpu; 1351 1352 isst_ctdp_display_information_start(outf); 1353 1354 if (max_target_cpus) 1355 for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL); 1356 else 1357 for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL); 1358 1359 isst_ctdp_display_information_end(outf); 1360 } 1361 1362 static int set_clos_param(int cpu, int clos, int epp, int wt, int min, int max) 1363 { 1364 struct isst_clos_config clos_config; 1365 int ret; 1366 1367 ret = isst_pm_get_clos(cpu, clos, &clos_config); 1368 if (ret) { 1369 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0); 1370 return ret; 1371 } 1372 clos_config.clos_min = min; 1373 clos_config.clos_max = max; 1374 clos_config.epp = epp; 1375 clos_config.clos_prop_prio = wt; 1376 ret = isst_set_clos(cpu, clos, &clos_config); 1377 if (ret) { 1378 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0); 1379 return ret; 1380 } 1381 1382 return 0; 1383 } 1384 1385 static int set_cpufreq_scaling_min_max(int cpu, int max, int freq) 1386 { 1387 char buffer[128], freq_str[16]; 1388 int fd, ret, len; 1389 1390 if (max) 1391 snprintf(buffer, sizeof(buffer), 1392 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); 1393 else 1394 snprintf(buffer, sizeof(buffer), 1395 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); 1396 1397 fd = open(buffer, O_WRONLY); 1398 if (fd < 0) 1399 return fd; 1400 1401 snprintf(freq_str, sizeof(freq_str), "%d", freq); 1402 len = strlen(freq_str); 1403 ret = write(fd, freq_str, len); 1404 if (ret == -1) { 1405 close(fd); 1406 return ret; 1407 } 1408 close(fd); 1409 1410 return 0; 1411 } 1412 1413 static int set_clx_pbf_cpufreq_scaling_min_max(int cpu) 1414 { 1415 struct isst_pkg_ctdp_level_info *ctdp_level; 1416 struct isst_pbf_info *pbf_info; 1417 int i, pkg_id, die_id, freq, freq_high, freq_low; 1418 int ret; 1419 1420 ret = clx_n_config(cpu); 1421 if (ret) { 1422 debug_printf("cpufreq_scaling_min_max failed for CLX"); 1423 return ret; 1424 } 1425 1426 ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; 1427 pbf_info = &ctdp_level->pbf_info; 1428 freq_high = pbf_info->p1_high * 100000; 1429 freq_low = pbf_info->p1_low * 100000; 1430 1431 pkg_id = get_physical_package_id(cpu); 1432 die_id = get_physical_die_id(cpu); 1433 for (i = 0; i < get_topo_max_cpus(); ++i) { 1434 if (pkg_id != get_physical_package_id(i) || 1435 die_id != get_physical_die_id(i)) 1436 continue; 1437 1438 if (CPU_ISSET_S(i, pbf_info->core_cpumask_size, 1439 pbf_info->core_cpumask)) 1440 freq = freq_high; 1441 else 1442 freq = freq_low; 1443 1444 set_cpufreq_scaling_min_max(i, 1, freq); 1445 set_cpufreq_scaling_min_max(i, 0, freq); 1446 } 1447 1448 return 0; 1449 } 1450 1451 static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, int scaling_max) 1452 { 1453 char buffer[128], min_freq[16]; 1454 int fd, ret, len; 1455 1456 if (!CPU_ISSET_S(cpu, present_cpumask_size, present_cpumask)) 1457 return -1; 1458 1459 if (cpuinfo_max) 1460 snprintf(buffer, sizeof(buffer), 1461 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu); 1462 else 1463 snprintf(buffer, sizeof(buffer), 1464 "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpu); 1465 1466 fd = open(buffer, O_RDONLY); 1467 if (fd < 0) 1468 return fd; 1469 1470 len = read(fd, min_freq, sizeof(min_freq)); 1471 close(fd); 1472 1473 if (len < 0) 1474 return len; 1475 1476 if (scaling_max) 1477 snprintf(buffer, sizeof(buffer), 1478 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); 1479 else 1480 snprintf(buffer, sizeof(buffer), 1481 "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); 1482 1483 fd = open(buffer, O_WRONLY); 1484 if (fd < 0) 1485 return fd; 1486 1487 len = strlen(min_freq); 1488 ret = write(fd, min_freq, len); 1489 if (ret == -1) { 1490 close(fd); 1491 return ret; 1492 } 1493 close(fd); 1494 1495 return 0; 1496 } 1497 1498 static void set_scaling_min_to_cpuinfo_max(int cpu) 1499 { 1500 int i, pkg_id, die_id; 1501 1502 pkg_id = get_physical_package_id(cpu); 1503 die_id = get_physical_die_id(cpu); 1504 for (i = 0; i < get_topo_max_cpus(); ++i) { 1505 if (pkg_id != get_physical_package_id(i) || 1506 die_id != get_physical_die_id(i)) 1507 continue; 1508 1509 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0); 1510 } 1511 } 1512 1513 static void set_scaling_min_to_cpuinfo_min(int cpu) 1514 { 1515 int i, pkg_id, die_id; 1516 1517 pkg_id = get_physical_package_id(cpu); 1518 die_id = get_physical_die_id(cpu); 1519 for (i = 0; i < get_topo_max_cpus(); ++i) { 1520 if (pkg_id != get_physical_package_id(i) || 1521 die_id != get_physical_die_id(i)) 1522 continue; 1523 1524 set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0); 1525 } 1526 } 1527 1528 static void set_scaling_max_to_cpuinfo_max(int cpu) 1529 { 1530 int i, pkg_id, die_id; 1531 1532 pkg_id = get_physical_package_id(cpu); 1533 die_id = get_physical_die_id(cpu); 1534 for (i = 0; i < get_topo_max_cpus(); ++i) { 1535 if (pkg_id != get_physical_package_id(i) || 1536 die_id != get_physical_die_id(i)) 1537 continue; 1538 1539 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1); 1540 } 1541 } 1542 1543 static int set_core_priority_and_min(int cpu, int mask_size, 1544 cpu_set_t *cpu_mask, int min_high, 1545 int min_low) 1546 { 1547 int pkg_id, die_id, ret, i; 1548 1549 if (!CPU_COUNT_S(mask_size, cpu_mask)) 1550 return -1; 1551 1552 ret = set_clos_param(cpu, 0, 0, 0, min_high, 0xff); 1553 if (ret) 1554 return ret; 1555 1556 ret = set_clos_param(cpu, 1, 15, 15, min_low, 0xff); 1557 if (ret) 1558 return ret; 1559 1560 ret = set_clos_param(cpu, 2, 15, 15, min_low, 0xff); 1561 if (ret) 1562 return ret; 1563 1564 ret = set_clos_param(cpu, 3, 15, 15, min_low, 0xff); 1565 if (ret) 1566 return ret; 1567 1568 pkg_id = get_physical_package_id(cpu); 1569 die_id = get_physical_die_id(cpu); 1570 for (i = 0; i < get_topo_max_cpus(); ++i) { 1571 int clos; 1572 1573 if (pkg_id != get_physical_package_id(i) || 1574 die_id != get_physical_die_id(i)) 1575 continue; 1576 1577 if (CPU_ISSET_S(i, mask_size, cpu_mask)) 1578 clos = 0; 1579 else 1580 clos = 3; 1581 1582 debug_printf("Associate cpu: %d clos: %d\n", i, clos); 1583 ret = isst_clos_associate(i, clos); 1584 if (ret) { 1585 isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0); 1586 return ret; 1587 } 1588 } 1589 1590 return 0; 1591 } 1592 1593 static int set_pbf_core_power(int cpu) 1594 { 1595 struct isst_pbf_info pbf_info; 1596 struct isst_pkg_ctdp pkg_dev; 1597 int ret; 1598 1599 ret = isst_get_ctdp_levels(cpu, &pkg_dev); 1600 if (ret) { 1601 debug_printf("isst_get_ctdp_levels failed"); 1602 return ret; 1603 } 1604 debug_printf("Current_level: %d\n", pkg_dev.current_level); 1605 1606 ret = isst_get_pbf_info(cpu, pkg_dev.current_level, &pbf_info); 1607 if (ret) { 1608 debug_printf("isst_get_pbf_info failed"); 1609 return ret; 1610 } 1611 debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high, 1612 pbf_info.p1_low); 1613 1614 ret = set_core_priority_and_min(cpu, pbf_info.core_cpumask_size, 1615 pbf_info.core_cpumask, 1616 pbf_info.p1_high, pbf_info.p1_low); 1617 if (ret) { 1618 debug_printf("set_core_priority_and_min failed"); 1619 return ret; 1620 } 1621 1622 ret = isst_pm_qos_config(cpu, 1, 1); 1623 if (ret) { 1624 debug_printf("isst_pm_qos_config failed"); 1625 return ret; 1626 } 1627 1628 return 0; 1629 } 1630 1631 static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 1632 void *arg4) 1633 { 1634 int ret; 1635 int status = *(int *)arg4; 1636 1637 if (is_clx_n_platform()) { 1638 ret = 0; 1639 if (status) { 1640 set_clx_pbf_cpufreq_scaling_min_max(cpu); 1641 1642 } else { 1643 set_scaling_max_to_cpuinfo_max(cpu); 1644 set_scaling_min_to_cpuinfo_min(cpu); 1645 } 1646 goto disp_result; 1647 } 1648 1649 if (auto_mode && status) { 1650 ret = set_pbf_core_power(cpu); 1651 if (ret) 1652 goto disp_result; 1653 } 1654 1655 ret = isst_set_pbf_fact_status(cpu, 1, status); 1656 if (ret) { 1657 debug_printf("isst_set_pbf_fact_status failed"); 1658 if (auto_mode) 1659 isst_pm_qos_config(cpu, 0, 0); 1660 } else { 1661 if (auto_mode) { 1662 if (status) 1663 set_scaling_min_to_cpuinfo_max(cpu); 1664 else 1665 set_scaling_min_to_cpuinfo_min(cpu); 1666 } 1667 } 1668 1669 if (auto_mode && !status) 1670 isst_pm_qos_config(cpu, 0, 1); 1671 1672 disp_result: 1673 if (status) 1674 isst_display_result(cpu, outf, "base-freq", "enable", 1675 ret); 1676 else 1677 isst_display_result(cpu, outf, "base-freq", "disable", 1678 ret); 1679 } 1680 1681 static void set_pbf_enable(int arg) 1682 { 1683 int enable = arg; 1684 1685 if (cmd_help) { 1686 if (enable) { 1687 fprintf(stderr, 1688 "Enable Intel Speed Select Technology base frequency feature\n"); 1689 if (is_clx_n_platform()) { 1690 fprintf(stderr, 1691 "\tOn this platform this command doesn't enable feature in the hardware.\n"); 1692 fprintf(stderr, 1693 "\tIt updates the cpufreq scaling_min_freq to match cpufreq base_frequency.\n"); 1694 exit(0); 1695 1696 } 1697 fprintf(stderr, 1698 "\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n"); 1699 } else { 1700 1701 if (is_clx_n_platform()) { 1702 fprintf(stderr, 1703 "\tOn this platform this command doesn't disable feature in the hardware.\n"); 1704 fprintf(stderr, 1705 "\tIt updates the cpufreq scaling_min_freq to match cpuinfo_min_freq\n"); 1706 exit(0); 1707 } 1708 fprintf(stderr, 1709 "Disable Intel Speed Select Technology base frequency feature\n"); 1710 fprintf(stderr, 1711 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); 1712 } 1713 exit(0); 1714 } 1715 1716 isst_ctdp_display_information_start(outf); 1717 if (max_target_cpus) 1718 for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL, 1719 NULL, &enable); 1720 else 1721 for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL, 1722 NULL, &enable); 1723 isst_ctdp_display_information_end(outf); 1724 } 1725 1726 static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2, 1727 void *arg3, void *arg4) 1728 { 1729 struct isst_fact_info fact_info; 1730 int ret; 1731 1732 ret = isst_get_fact_info(cpu, tdp_level, fact_bucket, &fact_info); 1733 if (ret) { 1734 isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level); 1735 isst_ctdp_display_information_end(outf); 1736 exit(1); 1737 } else { 1738 isst_fact_display_information(cpu, outf, tdp_level, fact_bucket, 1739 fact_avx, &fact_info); 1740 } 1741 } 1742 1743 static void dump_fact_config(int arg) 1744 { 1745 if (cmd_help) { 1746 fprintf(stderr, 1747 "Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n"); 1748 fprintf(stderr, 1749 "\tArguments: -l|--level : Specify tdp level\n"); 1750 fprintf(stderr, 1751 "\tArguments: -b|--bucket : Bucket index to dump\n"); 1752 fprintf(stderr, 1753 "\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n"); 1754 exit(0); 1755 } 1756 1757 if (tdp_level == 0xff) { 1758 isst_display_error_info_message(1, "Invalid command: specify tdp_level\n", 0, 0); 1759 exit(1); 1760 } 1761 1762 isst_ctdp_display_information_start(outf); 1763 if (max_target_cpus) 1764 for_each_online_target_cpu_in_set(dump_fact_config_for_cpu, 1765 NULL, NULL, NULL, NULL); 1766 else 1767 for_each_online_package_in_set(dump_fact_config_for_cpu, NULL, 1768 NULL, NULL, NULL); 1769 isst_ctdp_display_information_end(outf); 1770 } 1771 1772 static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 1773 void *arg4) 1774 { 1775 int ret; 1776 int status = *(int *)arg4; 1777 1778 if (auto_mode && status) { 1779 ret = isst_pm_qos_config(cpu, 1, 1); 1780 if (ret) 1781 goto disp_results; 1782 } 1783 1784 ret = isst_set_pbf_fact_status(cpu, 0, status); 1785 if (ret) { 1786 debug_printf("isst_set_pbf_fact_status failed"); 1787 if (auto_mode) 1788 isst_pm_qos_config(cpu, 0, 0); 1789 1790 goto disp_results; 1791 } 1792 1793 /* Set TRL */ 1794 if (status) { 1795 struct isst_pkg_ctdp pkg_dev; 1796 1797 ret = isst_get_ctdp_levels(cpu, &pkg_dev); 1798 if (!ret) 1799 ret = isst_set_trl(cpu, fact_trl); 1800 if (ret && auto_mode) 1801 isst_pm_qos_config(cpu, 0, 0); 1802 } else { 1803 if (auto_mode) 1804 isst_pm_qos_config(cpu, 0, 0); 1805 } 1806 1807 disp_results: 1808 if (status) { 1809 isst_display_result(cpu, outf, "turbo-freq", "enable", ret); 1810 if (ret) 1811 fact_enable_fail = ret; 1812 } else { 1813 /* Since we modified TRL during Fact enable, restore it */ 1814 isst_set_trl_from_current_tdp(cpu, fact_trl); 1815 isst_display_result(cpu, outf, "turbo-freq", "disable", ret); 1816 } 1817 } 1818 1819 static void set_fact_enable(int arg) 1820 { 1821 int i, ret, enable = arg; 1822 1823 if (cmd_help) { 1824 if (enable) { 1825 fprintf(stderr, 1826 "Enable Intel Speed Select Technology Turbo frequency feature\n"); 1827 fprintf(stderr, 1828 "Optional: -t|--trl : Specify turbo ratio limit\n"); 1829 fprintf(stderr, 1830 "\tOptional Arguments: -a|--auto : Designate specified target CPUs with"); 1831 fprintf(stderr, 1832 "-C|--cpu option as as high priority using core-power feature\n"); 1833 } else { 1834 fprintf(stderr, 1835 "Disable Intel Speed Select Technology turbo frequency feature\n"); 1836 fprintf(stderr, 1837 "Optional: -t|--trl : Specify turbo ratio limit\n"); 1838 fprintf(stderr, 1839 "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); 1840 } 1841 exit(0); 1842 } 1843 1844 isst_ctdp_display_information_start(outf); 1845 if (max_target_cpus) 1846 for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL, 1847 NULL, &enable); 1848 else 1849 for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL, 1850 NULL, &enable); 1851 isst_ctdp_display_information_end(outf); 1852 1853 if (!fact_enable_fail && enable && auto_mode) { 1854 /* 1855 * When we adjust CLOS param, we have to set for siblings also. 1856 * So for the each user specified CPU, also add the sibling 1857 * in the present_cpu_mask. 1858 */ 1859 for (i = 0; i < get_topo_max_cpus(); ++i) { 1860 char buffer[128], sibling_list[128], *cpu_str; 1861 int fd, len; 1862 1863 if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask)) 1864 continue; 1865 1866 snprintf(buffer, sizeof(buffer), 1867 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i); 1868 1869 fd = open(buffer, O_RDONLY); 1870 if (fd < 0) 1871 continue; 1872 1873 len = read(fd, sibling_list, sizeof(sibling_list)); 1874 close(fd); 1875 1876 if (len < 0) 1877 continue; 1878 1879 cpu_str = strtok(sibling_list, ","); 1880 while (cpu_str != NULL) { 1881 int cpu; 1882 1883 sscanf(cpu_str, "%d", &cpu); 1884 CPU_SET_S(cpu, target_cpumask_size, target_cpumask); 1885 cpu_str = strtok(NULL, ","); 1886 } 1887 } 1888 1889 for (i = 0; i < get_topo_max_cpus(); ++i) { 1890 int clos; 1891 1892 if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) 1893 continue; 1894 1895 ret = set_clos_param(i, 0, 0, 0, 0, 0xff); 1896 if (ret) 1897 goto error_disp; 1898 1899 ret = set_clos_param(i, 1, 15, 15, 0, 0xff); 1900 if (ret) 1901 goto error_disp; 1902 1903 ret = set_clos_param(i, 2, 15, 15, 0, 0xff); 1904 if (ret) 1905 goto error_disp; 1906 1907 ret = set_clos_param(i, 3, 15, 15, 0, 0xff); 1908 if (ret) 1909 goto error_disp; 1910 1911 if (CPU_ISSET_S(i, target_cpumask_size, target_cpumask)) 1912 clos = 0; 1913 else 1914 clos = 3; 1915 1916 debug_printf("Associate cpu: %d clos: %d\n", i, clos); 1917 ret = isst_clos_associate(i, clos); 1918 if (ret) 1919 goto error_disp; 1920 } 1921 isst_display_result(-1, outf, "turbo-freq --auto", "enable", 0); 1922 } 1923 1924 return; 1925 1926 error_disp: 1927 isst_display_result(i, outf, "turbo-freq --auto", "enable", ret); 1928 1929 } 1930 1931 static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3, 1932 void *arg4) 1933 { 1934 int ret; 1935 int status = *(int *)arg4; 1936 1937 if (is_skx_based_platform()) 1938 clos_priority_type = 1; 1939 1940 ret = isst_pm_qos_config(cpu, status, clos_priority_type); 1941 if (ret) 1942 isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0); 1943 1944 if (status) 1945 isst_display_result(cpu, outf, "core-power", "enable", 1946 ret); 1947 else 1948 isst_display_result(cpu, outf, "core-power", "disable", 1949 ret); 1950 } 1951 1952 static void set_clos_enable(int arg) 1953 { 1954 int enable = arg; 1955 1956 if (cmd_help) { 1957 if (enable) { 1958 fprintf(stderr, 1959 "Enable core-power for a package/die\n"); 1960 if (!is_skx_based_platform()) { 1961 fprintf(stderr, 1962 "\tClos Enable: Specify priority type with [--priority|-p]\n"); 1963 fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n"); 1964 } 1965 } else { 1966 fprintf(stderr, 1967 "Disable core-power: [No command arguments are required]\n"); 1968 } 1969 exit(0); 1970 } 1971 1972 if (enable && cpufreq_sysfs_present()) { 1973 fprintf(stderr, 1974 "cpufreq subsystem and core-power enable will interfere with each other!\n"); 1975 } 1976 1977 isst_ctdp_display_information_start(outf); 1978 if (max_target_cpus) 1979 for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL, 1980 NULL, NULL, &enable); 1981 else 1982 for_each_online_package_in_set(enable_clos_qos_config, NULL, 1983 NULL, NULL, &enable); 1984 isst_ctdp_display_information_end(outf); 1985 } 1986 1987 static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2, 1988 void *arg3, void *arg4) 1989 { 1990 struct isst_clos_config clos_config; 1991 int ret; 1992 1993 ret = isst_pm_get_clos(cpu, current_clos, &clos_config); 1994 if (ret) 1995 isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0); 1996 else 1997 isst_clos_display_information(cpu, outf, current_clos, 1998 &clos_config); 1999 } 2000 2001 static void dump_clos_config(int arg) 2002 { 2003 if (cmd_help) { 2004 fprintf(stderr, 2005 "Print Intel Speed Select Technology core power configuration\n"); 2006 fprintf(stderr, 2007 "\tArguments: [-c | --clos]: Specify clos id\n"); 2008 exit(0); 2009 } 2010 if (current_clos < 0 || current_clos > 3) { 2011 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); 2012 isst_ctdp_display_information_end(outf); 2013 exit(0); 2014 } 2015 2016 isst_ctdp_display_information_start(outf); 2017 if (max_target_cpus) 2018 for_each_online_target_cpu_in_set(dump_clos_config_for_cpu, 2019 NULL, NULL, NULL, NULL); 2020 else 2021 for_each_online_package_in_set(dump_clos_config_for_cpu, NULL, 2022 NULL, NULL, NULL); 2023 isst_ctdp_display_information_end(outf); 2024 } 2025 2026 static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 2027 void *arg4) 2028 { 2029 int enable, ret, prio_type; 2030 2031 ret = isst_clos_get_clos_information(cpu, &enable, &prio_type); 2032 if (ret) 2033 isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0); 2034 else { 2035 int cp_state, cp_cap; 2036 2037 isst_read_pm_config(cpu, &cp_state, &cp_cap); 2038 isst_clos_display_clos_information(cpu, outf, enable, prio_type, 2039 cp_state, cp_cap); 2040 } 2041 } 2042 2043 static void dump_clos_info(int arg) 2044 { 2045 if (cmd_help) { 2046 fprintf(stderr, 2047 "Print Intel Speed Select Technology core power information\n"); 2048 fprintf(stderr, "\t Optionally specify targeted cpu id with [--cpu|-c]\n"); 2049 exit(0); 2050 } 2051 2052 isst_ctdp_display_information_start(outf); 2053 if (max_target_cpus) 2054 for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL, 2055 NULL, NULL, NULL); 2056 else 2057 for_each_online_package_in_set(get_clos_info_for_cpu, NULL, 2058 NULL, NULL, NULL); 2059 isst_ctdp_display_information_end(outf); 2060 2061 } 2062 2063 static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 2064 void *arg4) 2065 { 2066 struct isst_clos_config clos_config; 2067 int ret; 2068 2069 clos_config.pkg_id = get_physical_package_id(cpu); 2070 clos_config.die_id = get_physical_die_id(cpu); 2071 2072 clos_config.epp = clos_epp; 2073 clos_config.clos_prop_prio = clos_prop_prio; 2074 clos_config.clos_min = clos_min; 2075 clos_config.clos_max = clos_max; 2076 clos_config.clos_desired = clos_desired; 2077 ret = isst_set_clos(cpu, current_clos, &clos_config); 2078 if (ret) 2079 isst_display_error_info_message(1, "isst_set_clos failed", 0, 0); 2080 else 2081 isst_display_result(cpu, outf, "core-power", "config", ret); 2082 } 2083 2084 static void set_clos_config(int arg) 2085 { 2086 if (cmd_help) { 2087 fprintf(stderr, 2088 "Set core-power configuration for one of the four clos ids\n"); 2089 fprintf(stderr, 2090 "\tSpecify targeted clos id with [--clos|-c]\n"); 2091 if (!is_skx_based_platform()) { 2092 fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n"); 2093 fprintf(stderr, 2094 "\tSpecify clos Proportional Priority [--weight|-w]\n"); 2095 } 2096 fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n"); 2097 fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n"); 2098 exit(0); 2099 } 2100 2101 if (current_clos < 0 || current_clos > 3) { 2102 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); 2103 exit(0); 2104 } 2105 if (!is_skx_based_platform() && (clos_epp < 0 || clos_epp > 0x0F)) { 2106 fprintf(stderr, "clos epp is not specified or invalid, default: 0\n"); 2107 clos_epp = 0; 2108 } 2109 if (!is_skx_based_platform() && (clos_prop_prio < 0 || clos_prop_prio > 0x0F)) { 2110 fprintf(stderr, 2111 "clos frequency weight is not specified or invalid, default: 0\n"); 2112 clos_prop_prio = 0; 2113 } 2114 if (clos_min < 0) { 2115 fprintf(stderr, "clos min is not specified, default: 0\n"); 2116 clos_min = 0; 2117 } 2118 if (clos_max < 0) { 2119 fprintf(stderr, "clos max is not specified, default: Max frequency (ratio 0xff)\n"); 2120 clos_max = 0xff; 2121 } 2122 if (clos_desired) { 2123 fprintf(stderr, "clos desired is not supported on this platform\n"); 2124 clos_desired = 0x00; 2125 } 2126 2127 isst_ctdp_display_information_start(outf); 2128 if (max_target_cpus) 2129 for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL, 2130 NULL, NULL, NULL); 2131 else 2132 for_each_online_package_in_set(set_clos_config_for_cpu, NULL, 2133 NULL, NULL, NULL); 2134 isst_ctdp_display_information_end(outf); 2135 } 2136 2137 static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 2138 void *arg4) 2139 { 2140 int ret; 2141 2142 ret = isst_clos_associate(cpu, current_clos); 2143 if (ret) 2144 debug_printf("isst_clos_associate failed"); 2145 else 2146 isst_display_result(cpu, outf, "core-power", "assoc", ret); 2147 } 2148 2149 static void set_clos_assoc(int arg) 2150 { 2151 if (cmd_help) { 2152 fprintf(stderr, "Associate a clos id to a CPU\n"); 2153 fprintf(stderr, 2154 "\tSpecify targeted clos id with [--clos|-c]\n"); 2155 fprintf(stderr, 2156 "\tFor example to associate clos 1 to CPU 0: issue\n"); 2157 fprintf(stderr, 2158 "\tintel-speed-select --cpu 0 core-power assoc --clos 1\n"); 2159 exit(0); 2160 } 2161 2162 if (current_clos < 0 || current_clos > 3) { 2163 isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); 2164 exit(0); 2165 } 2166 if (max_target_cpus) 2167 for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL, 2168 NULL, NULL, NULL); 2169 else { 2170 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0); 2171 } 2172 } 2173 2174 static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, 2175 void *arg4) 2176 { 2177 int clos, ret; 2178 2179 ret = isst_clos_get_assoc_status(cpu, &clos); 2180 if (ret) 2181 isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0); 2182 else 2183 isst_clos_display_assoc_information(cpu, outf, clos); 2184 } 2185 2186 static void get_clos_assoc(int arg) 2187 { 2188 if (cmd_help) { 2189 fprintf(stderr, "Get associate clos id to a CPU\n"); 2190 fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n"); 2191 exit(0); 2192 } 2193 2194 if (!max_target_cpus) { 2195 isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0); 2196 exit(0); 2197 } 2198 2199 isst_ctdp_display_information_start(outf); 2200 for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL, 2201 NULL, NULL, NULL); 2202 isst_ctdp_display_information_end(outf); 2203 } 2204 2205 static struct process_cmd_struct clx_n_cmds[] = { 2206 { "perf-profile", "info", dump_isst_config, 0 }, 2207 { "base-freq", "info", dump_pbf_config, 0 }, 2208 { "base-freq", "enable", set_pbf_enable, 1 }, 2209 { "base-freq", "disable", set_pbf_enable, 0 }, 2210 { NULL, NULL, NULL, 0 } 2211 }; 2212 2213 static struct process_cmd_struct isst_cmds[] = { 2214 { "perf-profile", "get-lock-status", get_tdp_locked, 0 }, 2215 { "perf-profile", "get-config-levels", get_tdp_levels, 0 }, 2216 { "perf-profile", "get-config-version", get_tdp_version, 0 }, 2217 { "perf-profile", "get-config-enabled", get_tdp_enabled, 0 }, 2218 { "perf-profile", "get-config-current-level", get_tdp_current_level, 2219 0 }, 2220 { "perf-profile", "set-config-level", set_tdp_level, 0 }, 2221 { "perf-profile", "info", dump_isst_config, 0 }, 2222 { "base-freq", "info", dump_pbf_config, 0 }, 2223 { "base-freq", "enable", set_pbf_enable, 1 }, 2224 { "base-freq", "disable", set_pbf_enable, 0 }, 2225 { "turbo-freq", "info", dump_fact_config, 0 }, 2226 { "turbo-freq", "enable", set_fact_enable, 1 }, 2227 { "turbo-freq", "disable", set_fact_enable, 0 }, 2228 { "core-power", "info", dump_clos_info, 0 }, 2229 { "core-power", "enable", set_clos_enable, 1 }, 2230 { "core-power", "disable", set_clos_enable, 0 }, 2231 { "core-power", "config", set_clos_config, 0 }, 2232 { "core-power", "get-config", dump_clos_config, 0 }, 2233 { "core-power", "assoc", set_clos_assoc, 0 }, 2234 { "core-power", "get-assoc", get_clos_assoc, 0 }, 2235 { NULL, NULL, NULL } 2236 }; 2237 2238 /* 2239 * parse cpuset with following syntax 2240 * 1,2,4..6,8-10 and set bits in cpu_subset 2241 */ 2242 void parse_cpu_command(char *optarg) 2243 { 2244 unsigned int start, end; 2245 char *next; 2246 2247 next = optarg; 2248 2249 while (next && *next) { 2250 if (*next == '-') /* no negative cpu numbers */ 2251 goto error; 2252 2253 start = strtoul(next, &next, 10); 2254 2255 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ) 2256 target_cpus[max_target_cpus++] = start; 2257 2258 if (*next == '\0') 2259 break; 2260 2261 if (*next == ',') { 2262 next += 1; 2263 continue; 2264 } 2265 2266 if (*next == '-') { 2267 next += 1; /* start range */ 2268 } else if (*next == '.') { 2269 next += 1; 2270 if (*next == '.') 2271 next += 1; /* start range */ 2272 else 2273 goto error; 2274 } 2275 2276 end = strtoul(next, &next, 10); 2277 if (end <= start) 2278 goto error; 2279 2280 while (++start <= end) { 2281 if (max_target_cpus < MAX_CPUS_IN_ONE_REQ) 2282 target_cpus[max_target_cpus++] = start; 2283 } 2284 2285 if (*next == ',') 2286 next += 1; 2287 else if (*next != '\0') 2288 goto error; 2289 } 2290 2291 #ifdef DEBUG 2292 { 2293 int i; 2294 2295 for (i = 0; i < max_target_cpus; ++i) 2296 printf("cpu [%d] in arg\n", target_cpus[i]); 2297 } 2298 #endif 2299 return; 2300 2301 error: 2302 fprintf(stderr, "\"--cpu %s\" malformed\n", optarg); 2303 exit(-1); 2304 } 2305 2306 static void parse_cmd_args(int argc, int start, char **argv) 2307 { 2308 int opt; 2309 int option_index; 2310 2311 static struct option long_options[] = { 2312 { "bucket", required_argument, 0, 'b' }, 2313 { "level", required_argument, 0, 'l' }, 2314 { "online", required_argument, 0, 'o' }, 2315 { "trl-type", required_argument, 0, 'r' }, 2316 { "trl", required_argument, 0, 't' }, 2317 { "help", no_argument, 0, 'h' }, 2318 { "clos", required_argument, 0, 'c' }, 2319 { "desired", required_argument, 0, 'd' }, 2320 { "epp", required_argument, 0, 'e' }, 2321 { "min", required_argument, 0, 'n' }, 2322 { "max", required_argument, 0, 'm' }, 2323 { "priority", required_argument, 0, 'p' }, 2324 { "weight", required_argument, 0, 'w' }, 2325 { "auto", no_argument, 0, 'a' }, 2326 { 0, 0, 0, 0 } 2327 }; 2328 2329 option_index = start; 2330 2331 optind = start + 1; 2332 while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:r:hoa", 2333 long_options, &option_index)) != -1) { 2334 switch (opt) { 2335 case 'a': 2336 auto_mode = 1; 2337 break; 2338 case 'b': 2339 fact_bucket = atoi(optarg); 2340 break; 2341 case 'h': 2342 cmd_help = 1; 2343 break; 2344 case 'l': 2345 tdp_level = atoi(optarg); 2346 break; 2347 case 'o': 2348 force_online_offline = 1; 2349 break; 2350 case 't': 2351 sscanf(optarg, "0x%llx", &fact_trl); 2352 break; 2353 case 'r': 2354 if (!strncmp(optarg, "sse", 3)) { 2355 fact_avx = 0x01; 2356 } else if (!strncmp(optarg, "avx2", 4)) { 2357 fact_avx = 0x02; 2358 } else if (!strncmp(optarg, "avx512", 6)) { 2359 fact_avx = 0x04; 2360 } else { 2361 fprintf(outf, "Invalid sse,avx options\n"); 2362 exit(1); 2363 } 2364 break; 2365 /* CLOS related */ 2366 case 'c': 2367 current_clos = atoi(optarg); 2368 break; 2369 case 'd': 2370 clos_desired = atoi(optarg); 2371 clos_desired /= DISP_FREQ_MULTIPLIER; 2372 break; 2373 case 'e': 2374 clos_epp = atoi(optarg); 2375 if (is_skx_based_platform()) { 2376 isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0); 2377 exit(0); 2378 } 2379 break; 2380 case 'n': 2381 clos_min = atoi(optarg); 2382 clos_min /= DISP_FREQ_MULTIPLIER; 2383 break; 2384 case 'm': 2385 clos_max = atoi(optarg); 2386 clos_max /= DISP_FREQ_MULTIPLIER; 2387 break; 2388 case 'p': 2389 clos_priority_type = atoi(optarg); 2390 if (is_skx_based_platform() && !clos_priority_type) { 2391 isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0); 2392 exit(0); 2393 } 2394 break; 2395 case 'w': 2396 clos_prop_prio = atoi(optarg); 2397 if (is_skx_based_platform()) { 2398 isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0); 2399 exit(0); 2400 } 2401 break; 2402 default: 2403 printf("Unknown option: ignore\n"); 2404 } 2405 } 2406 2407 if (argv[optind]) 2408 printf("Garbage at the end of command: ignore\n"); 2409 } 2410 2411 static void isst_help(void) 2412 { 2413 printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\ 2414 performance profiles per system via static and/or dynamic\n\ 2415 adjustment of core count, workload, Tjmax, and\n\ 2416 TDP, etc.\n"); 2417 printf("\nCommands : For feature=perf-profile\n"); 2418 printf("\tinfo\n"); 2419 2420 if (!is_clx_n_platform()) { 2421 printf("\tget-lock-status\n"); 2422 printf("\tget-config-levels\n"); 2423 printf("\tget-config-version\n"); 2424 printf("\tget-config-enabled\n"); 2425 printf("\tget-config-current-level\n"); 2426 printf("\tset-config-level\n"); 2427 } 2428 } 2429 2430 static void pbf_help(void) 2431 { 2432 printf("base-freq:\tEnables users to increase guaranteed base frequency\n\ 2433 on certain cores (high priority cores) in exchange for lower\n\ 2434 base frequency on remaining cores (low priority cores).\n"); 2435 printf("\tcommand : info\n"); 2436 printf("\tcommand : enable\n"); 2437 printf("\tcommand : disable\n"); 2438 } 2439 2440 static void fact_help(void) 2441 { 2442 printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\ 2443 limits to cores based on priority.\n"); 2444 printf("\nCommand: For feature=turbo-freq\n"); 2445 printf("\tcommand : info\n"); 2446 printf("\tcommand : enable\n"); 2447 printf("\tcommand : disable\n"); 2448 } 2449 2450 static void core_power_help(void) 2451 { 2452 printf("core-power:\tInterface that allows user to define per core/tile\n\ 2453 priority.\n"); 2454 printf("\nCommands : For feature=core-power\n"); 2455 printf("\tinfo\n"); 2456 printf("\tenable\n"); 2457 printf("\tdisable\n"); 2458 printf("\tconfig\n"); 2459 printf("\tget-config\n"); 2460 printf("\tassoc\n"); 2461 printf("\tget-assoc\n"); 2462 } 2463 2464 struct process_cmd_help_struct { 2465 char *feature; 2466 void (*process_fn)(void); 2467 }; 2468 2469 static struct process_cmd_help_struct isst_help_cmds[] = { 2470 { "perf-profile", isst_help }, 2471 { "base-freq", pbf_help }, 2472 { "turbo-freq", fact_help }, 2473 { "core-power", core_power_help }, 2474 { NULL, NULL } 2475 }; 2476 2477 static struct process_cmd_help_struct clx_n_help_cmds[] = { 2478 { "perf-profile", isst_help }, 2479 { "base-freq", pbf_help }, 2480 { NULL, NULL } 2481 }; 2482 2483 void process_command(int argc, char **argv, 2484 struct process_cmd_help_struct *help_cmds, 2485 struct process_cmd_struct *cmds) 2486 { 2487 int i = 0, matched = 0; 2488 char *feature = argv[optind]; 2489 char *cmd = argv[optind + 1]; 2490 2491 if (!feature || !cmd) 2492 return; 2493 2494 debug_printf("feature name [%s] command [%s]\n", feature, cmd); 2495 if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) { 2496 while (help_cmds[i].feature) { 2497 if (!strcmp(help_cmds[i].feature, feature)) { 2498 help_cmds[i].process_fn(); 2499 exit(0); 2500 } 2501 ++i; 2502 } 2503 } 2504 2505 if (!is_clx_n_platform()) 2506 create_cpu_map(); 2507 2508 i = 0; 2509 while (cmds[i].feature) { 2510 if (!strcmp(cmds[i].feature, feature) && 2511 !strcmp(cmds[i].command, cmd)) { 2512 parse_cmd_args(argc, optind + 1, argv); 2513 cmds[i].process_fn(cmds[i].arg); 2514 matched = 1; 2515 break; 2516 } 2517 ++i; 2518 } 2519 2520 if (!matched) 2521 fprintf(stderr, "Invalid command\n"); 2522 } 2523 2524 static void usage(void) 2525 { 2526 if (is_clx_n_platform()) { 2527 fprintf(stderr, "\nThere is limited support of Intel Speed Select features on this platform.\n"); 2528 fprintf(stderr, "Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware.\n\n"); 2529 } 2530 2531 printf("\nUsage:\n"); 2532 printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n"); 2533 printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features:\n"); 2534 if (is_clx_n_platform()) 2535 printf("\nFEATURE : [perf-profile|base-freq]\n"); 2536 else 2537 printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power]\n"); 2538 printf("\nFor help on each feature, use -h|--help\n"); 2539 printf("\tFor example: intel-speed-select perf-profile -h\n"); 2540 2541 printf("\nFor additional help on each command for a feature, use --h|--help\n"); 2542 printf("\tFor example: intel-speed-select perf-profile get-lock-status -h\n"); 2543 printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n"); 2544 2545 printf("\nOPTIONS\n"); 2546 printf("\t[-c|--cpu] : logical cpu number\n"); 2547 printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n"); 2548 printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n"); 2549 printf("\t[-d|--debug] : Debug mode\n"); 2550 printf("\t[-f|--format] : output format [json|text]. Default: text\n"); 2551 printf("\t[-h|--help] : Print help\n"); 2552 printf("\t[-i|--info] : Print platform information\n"); 2553 printf("\t[-o|--out] : Output file\n"); 2554 printf("\t\t\tDefault : stderr\n"); 2555 printf("\t[-v|--version] : Print version\n"); 2556 2557 printf("\nResult format\n"); 2558 printf("\tResult display uses a common format for each command:\n"); 2559 printf("\tResults are formatted in text/JSON with\n"); 2560 printf("\t\tPackage, Die, CPU, and command specific results.\n"); 2561 2562 printf("\nExamples\n"); 2563 printf("\tTo get platform information:\n"); 2564 printf("\t\tintel-speed-select --info\n"); 2565 printf("\tTo get full perf-profile information dump:\n"); 2566 printf("\t\tintel-speed-select perf-profile info\n"); 2567 printf("\tTo get full base-freq information dump:\n"); 2568 printf("\t\tintel-speed-select base-freq info -l 0\n"); 2569 if (!is_clx_n_platform()) { 2570 printf("\tTo get full turbo-freq information dump:\n"); 2571 printf("\t\tintel-speed-select turbo-freq info -l 0\n"); 2572 } 2573 exit(1); 2574 } 2575 2576 static void print_version(void) 2577 { 2578 fprintf(outf, "Version %s\n", version_str); 2579 fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__); 2580 exit(0); 2581 } 2582 2583 static void cmdline(int argc, char **argv) 2584 { 2585 const char *pathname = "/dev/isst_interface"; 2586 FILE *fp; 2587 int opt; 2588 int option_index = 0; 2589 int ret; 2590 2591 static struct option long_options[] = { 2592 { "cpu", required_argument, 0, 'c' }, 2593 { "debug", no_argument, 0, 'd' }, 2594 { "format", required_argument, 0, 'f' }, 2595 { "help", no_argument, 0, 'h' }, 2596 { "info", no_argument, 0, 'i' }, 2597 { "out", required_argument, 0, 'o' }, 2598 { "version", no_argument, 0, 'v' }, 2599 { 0, 0, 0, 0 } 2600 }; 2601 2602 if (geteuid() != 0) { 2603 fprintf(stderr, "Must run as root\n"); 2604 exit(0); 2605 } 2606 2607 ret = update_cpu_model(); 2608 if (ret) 2609 err(-1, "Invalid CPU model (%d)\n", cpu_model); 2610 printf("Intel(R) Speed Select Technology\n"); 2611 printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model); 2612 2613 if (!is_clx_n_platform()) { 2614 fp = fopen(pathname, "rb"); 2615 if (!fp) { 2616 fprintf(stderr, "Intel speed select drivers are not loaded on this system.\n"); 2617 fprintf(stderr, "Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE.\n"); 2618 fprintf(stderr, "If the config is included then this is not a supported platform.\n"); 2619 exit(0); 2620 } 2621 fclose(fp); 2622 } 2623 2624 progname = argv[0]; 2625 while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options, 2626 &option_index)) != -1) { 2627 switch (opt) { 2628 case 'c': 2629 parse_cpu_command(optarg); 2630 break; 2631 case 'd': 2632 debug_flag = 1; 2633 printf("Debug Mode ON\n"); 2634 break; 2635 case 'f': 2636 if (!strncmp(optarg, "json", 4)) 2637 out_format_json = 1; 2638 break; 2639 case 'h': 2640 usage(); 2641 break; 2642 case 'i': 2643 isst_print_platform_information(); 2644 break; 2645 case 'o': 2646 if (outf) 2647 fclose(outf); 2648 outf = fopen_or_exit(optarg, "w"); 2649 break; 2650 case 'v': 2651 print_version(); 2652 break; 2653 default: 2654 usage(); 2655 } 2656 } 2657 2658 if (optind > (argc - 2)) { 2659 usage(); 2660 exit(0); 2661 } 2662 set_max_cpu_num(); 2663 store_cpu_topology(); 2664 set_cpu_present_cpu_mask(); 2665 set_cpu_target_cpu_mask(); 2666 2667 if (!is_clx_n_platform()) { 2668 ret = isst_fill_platform_info(); 2669 if (ret) 2670 goto out; 2671 process_command(argc, argv, isst_help_cmds, isst_cmds); 2672 } else { 2673 process_command(argc, argv, clx_n_help_cmds, clx_n_cmds); 2674 } 2675 out: 2676 free_cpu_set(present_cpumask); 2677 free_cpu_set(target_cpumask); 2678 } 2679 2680 int main(int argc, char **argv) 2681 { 2682 outf = stderr; 2683 cmdline(argc, argv); 2684 return 0; 2685 } 2686