1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel dynamic_speed_select -- Enumerate and control features 4 * Copyright (c) 2019 Intel Corporation. 5 */ 6 7 #include "isst.h" 8 9 #define DISP_FREQ_MULTIPLIER 100 10 11 static void printcpulist(int str_len, char *str, int mask_size, 12 cpu_set_t *cpu_mask) 13 { 14 int i, first, curr_index, index; 15 16 if (!CPU_COUNT_S(mask_size, cpu_mask)) { 17 snprintf(str, str_len, "none"); 18 return; 19 } 20 21 curr_index = 0; 22 first = 1; 23 for (i = 0; i < get_topo_max_cpus(); ++i) { 24 if (!CPU_ISSET_S(i, mask_size, cpu_mask)) 25 continue; 26 if (!first) { 27 index = snprintf(&str[curr_index], 28 str_len - curr_index, ","); 29 curr_index += index; 30 } 31 index = snprintf(&str[curr_index], str_len - curr_index, "%d", 32 i); 33 curr_index += index; 34 first = 0; 35 } 36 } 37 38 static void printcpumask(int str_len, char *str, int mask_size, 39 cpu_set_t *cpu_mask) 40 { 41 int i, max_cpus = get_topo_max_cpus(); 42 unsigned int *mask; 43 int size, index, curr_index; 44 45 size = max_cpus / (sizeof(unsigned int) * 8); 46 if (max_cpus % (sizeof(unsigned int) * 8)) 47 size++; 48 49 mask = calloc(size, sizeof(unsigned int)); 50 if (!mask) 51 return; 52 53 for (i = 0; i < max_cpus; ++i) { 54 int mask_index, bit_index; 55 56 if (!CPU_ISSET_S(i, mask_size, cpu_mask)) 57 continue; 58 59 mask_index = i / (sizeof(unsigned int) * 8); 60 bit_index = i % (sizeof(unsigned int) * 8); 61 mask[mask_index] |= BIT(bit_index); 62 } 63 64 curr_index = 0; 65 for (i = size - 1; i >= 0; --i) { 66 index = snprintf(&str[curr_index], str_len - curr_index, "%08x", 67 mask[i]); 68 curr_index += index; 69 if (i) { 70 strncat(&str[curr_index], ",", str_len - curr_index); 71 curr_index++; 72 } 73 } 74 75 free(mask); 76 } 77 78 static void format_and_print_txt(FILE *outf, int level, char *header, 79 char *value) 80 { 81 char *spaces = " "; 82 static char delimiters[256]; 83 int i, j = 0; 84 85 if (!level) 86 return; 87 88 if (level == 1) { 89 strcpy(delimiters, " "); 90 } else { 91 for (i = 0; i < level - 1; ++i) 92 j += snprintf(&delimiters[j], sizeof(delimiters) - j, 93 "%s", spaces); 94 } 95 96 if (header && value) { 97 fprintf(outf, "%s", delimiters); 98 fprintf(outf, "%s:%s\n", header, value); 99 } else if (header) { 100 fprintf(outf, "%s", delimiters); 101 fprintf(outf, "%s\n", header); 102 } 103 } 104 105 static int last_level; 106 static void format_and_print(FILE *outf, int level, char *header, char *value) 107 { 108 char *spaces = " "; 109 static char delimiters[256]; 110 int i; 111 112 if (!out_format_is_json()) { 113 format_and_print_txt(outf, level, header, value); 114 return; 115 } 116 117 if (level == 0) { 118 if (header) 119 fprintf(outf, "{"); 120 else 121 fprintf(outf, "\n}\n"); 122 123 } else { 124 int j = 0; 125 126 for (i = 0; i < level; ++i) 127 j += snprintf(&delimiters[j], sizeof(delimiters) - j, 128 "%s", spaces); 129 130 if (last_level == level) 131 fprintf(outf, ",\n"); 132 133 if (value) { 134 if (last_level != level) 135 fprintf(outf, "\n"); 136 137 fprintf(outf, "%s\"%s\": ", delimiters, header); 138 fprintf(outf, "\"%s\"", value); 139 } else { 140 for (i = last_level - 1; i >= level; --i) { 141 int k = 0; 142 143 for (j = i; j > 0; --j) 144 k += snprintf(&delimiters[k], 145 sizeof(delimiters) - k, 146 "%s", spaces); 147 if (i == level && header) 148 fprintf(outf, "\n%s},", delimiters); 149 else 150 fprintf(outf, "\n%s}", delimiters); 151 } 152 if (abs(last_level - level) < 3) 153 fprintf(outf, "\n"); 154 if (header) 155 fprintf(outf, "%s\"%s\": {", delimiters, 156 header); 157 } 158 } 159 160 last_level = level; 161 } 162 163 static void print_package_info(int cpu, FILE *outf) 164 { 165 char header[256]; 166 167 snprintf(header, sizeof(header), "package-%d", 168 get_physical_package_id(cpu)); 169 format_and_print(outf, 1, header, NULL); 170 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 171 format_and_print(outf, 2, header, NULL); 172 snprintf(header, sizeof(header), "cpu-%d", cpu); 173 format_and_print(outf, 3, header, NULL); 174 } 175 176 static void _isst_pbf_display_information(int cpu, FILE *outf, int level, 177 struct isst_pbf_info *pbf_info, 178 int disp_level) 179 { 180 char header[256]; 181 char value[256]; 182 183 snprintf(header, sizeof(header), "speed-select-base-freq"); 184 format_and_print(outf, disp_level, header, NULL); 185 186 snprintf(header, sizeof(header), "high-priority-base-frequency(MHz)"); 187 snprintf(value, sizeof(value), "%d", 188 pbf_info->p1_high * DISP_FREQ_MULTIPLIER); 189 format_and_print(outf, disp_level + 1, header, value); 190 191 snprintf(header, sizeof(header), "high-priority-cpu-mask"); 192 printcpumask(sizeof(value), value, pbf_info->core_cpumask_size, 193 pbf_info->core_cpumask); 194 format_and_print(outf, disp_level + 1, header, value); 195 196 snprintf(header, sizeof(header), "high-priority-cpu-list"); 197 printcpulist(sizeof(value), value, 198 pbf_info->core_cpumask_size, 199 pbf_info->core_cpumask); 200 format_and_print(outf, disp_level + 1, header, value); 201 202 snprintf(header, sizeof(header), "low-priority-base-frequency(MHz)"); 203 snprintf(value, sizeof(value), "%d", 204 pbf_info->p1_low * DISP_FREQ_MULTIPLIER); 205 format_and_print(outf, disp_level + 1, header, value); 206 207 snprintf(header, sizeof(header), "tjunction-temperature(C)"); 208 snprintf(value, sizeof(value), "%d", pbf_info->t_prochot); 209 format_and_print(outf, disp_level + 1, header, value); 210 211 snprintf(header, sizeof(header), "thermal-design-power(W)"); 212 snprintf(value, sizeof(value), "%d", pbf_info->tdp); 213 format_and_print(outf, disp_level + 1, header, value); 214 } 215 216 static void _isst_fact_display_information(int cpu, FILE *outf, int level, 217 int fact_bucket, int fact_avx, 218 struct isst_fact_info *fact_info, 219 int base_level) 220 { 221 struct isst_fact_bucket_info *bucket_info = fact_info->bucket_info; 222 char header[256]; 223 char value[256]; 224 int j; 225 226 snprintf(header, sizeof(header), "speed-select-turbo-freq"); 227 format_and_print(outf, base_level, header, NULL); 228 for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) { 229 if (fact_bucket != 0xff && fact_bucket != j) 230 continue; 231 232 if (!bucket_info[j].high_priority_cores_count) 233 break; 234 235 snprintf(header, sizeof(header), "bucket-%d", j); 236 format_and_print(outf, base_level + 1, header, NULL); 237 238 snprintf(header, sizeof(header), "high-priority-cores-count"); 239 snprintf(value, sizeof(value), "%d", 240 bucket_info[j].high_priority_cores_count); 241 format_and_print(outf, base_level + 2, header, value); 242 243 if (fact_avx & 0x01) { 244 snprintf(header, sizeof(header), 245 "high-priority-max-frequency(MHz)"); 246 snprintf(value, sizeof(value), "%d", 247 bucket_info[j].sse_trl * DISP_FREQ_MULTIPLIER); 248 format_and_print(outf, base_level + 2, header, value); 249 } 250 251 if (fact_avx & 0x02) { 252 snprintf(header, sizeof(header), 253 "high-priority-max-avx2-frequency(MHz)"); 254 snprintf(value, sizeof(value), "%d", 255 bucket_info[j].avx_trl * DISP_FREQ_MULTIPLIER); 256 format_and_print(outf, base_level + 2, header, value); 257 } 258 259 if (fact_avx & 0x04) { 260 snprintf(header, sizeof(header), 261 "high-priority-max-avx512-frequency(MHz)"); 262 snprintf(value, sizeof(value), "%d", 263 bucket_info[j].avx512_trl * 264 DISP_FREQ_MULTIPLIER); 265 format_and_print(outf, base_level + 2, header, value); 266 } 267 } 268 snprintf(header, sizeof(header), 269 "speed-select-turbo-freq-clip-frequencies"); 270 format_and_print(outf, base_level + 1, header, NULL); 271 snprintf(header, sizeof(header), "low-priority-max-frequency(MHz)"); 272 snprintf(value, sizeof(value), "%d", 273 fact_info->lp_clipping_ratio_license_sse * 274 DISP_FREQ_MULTIPLIER); 275 format_and_print(outf, base_level + 2, header, value); 276 snprintf(header, sizeof(header), 277 "low-priority-max-avx2-frequency(MHz)"); 278 snprintf(value, sizeof(value), "%d", 279 fact_info->lp_clipping_ratio_license_avx2 * 280 DISP_FREQ_MULTIPLIER); 281 format_and_print(outf, base_level + 2, header, value); 282 snprintf(header, sizeof(header), 283 "low-priority-max-avx512-frequency(MHz)"); 284 snprintf(value, sizeof(value), "%d", 285 fact_info->lp_clipping_ratio_license_avx512 * 286 DISP_FREQ_MULTIPLIER); 287 format_and_print(outf, base_level + 2, header, value); 288 } 289 290 void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix, 291 unsigned int val) 292 { 293 char header[256]; 294 char value[256]; 295 296 snprintf(header, sizeof(header), "package-%d", 297 get_physical_package_id(cpu)); 298 format_and_print(outf, 1, header, NULL); 299 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 300 format_and_print(outf, 2, header, NULL); 301 snprintf(header, sizeof(header), "cpu-%d", cpu); 302 format_and_print(outf, 3, header, NULL); 303 304 snprintf(value, sizeof(value), "%u", val); 305 format_and_print(outf, 4, prefix, value); 306 307 format_and_print(outf, 1, NULL, NULL); 308 } 309 310 void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level, 311 struct isst_pkg_ctdp *pkg_dev) 312 { 313 char header[256]; 314 char value[256]; 315 int i, base_level = 1; 316 317 print_package_info(cpu, outf); 318 319 for (i = 0; i <= pkg_dev->levels; ++i) { 320 struct isst_pkg_ctdp_level_info *ctdp_level; 321 int j; 322 323 ctdp_level = &pkg_dev->ctdp_level[i]; 324 if (!ctdp_level->processed) 325 continue; 326 327 snprintf(header, sizeof(header), "perf-profile-level-%d", 328 ctdp_level->level); 329 format_and_print(outf, base_level + 3, header, NULL); 330 331 snprintf(header, sizeof(header), "cpu-count"); 332 j = get_cpu_count(get_physical_die_id(cpu), 333 get_physical_die_id(cpu)); 334 snprintf(value, sizeof(value), "%d", j); 335 format_and_print(outf, base_level + 4, header, value); 336 337 snprintf(header, sizeof(header), "enable-cpu-mask"); 338 printcpumask(sizeof(value), value, 339 ctdp_level->core_cpumask_size, 340 ctdp_level->core_cpumask); 341 format_and_print(outf, base_level + 4, header, value); 342 343 snprintf(header, sizeof(header), "enable-cpu-list"); 344 printcpulist(sizeof(value), value, 345 ctdp_level->core_cpumask_size, 346 ctdp_level->core_cpumask); 347 format_and_print(outf, base_level + 4, header, value); 348 349 snprintf(header, sizeof(header), "thermal-design-power-ratio"); 350 snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio); 351 format_and_print(outf, base_level + 4, header, value); 352 353 snprintf(header, sizeof(header), "base-frequency(MHz)"); 354 snprintf(value, sizeof(value), "%d", 355 ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER); 356 format_and_print(outf, base_level + 4, header, value); 357 358 snprintf(header, sizeof(header), 359 "speed-select-turbo-freq"); 360 if (ctdp_level->fact_support) { 361 if (ctdp_level->fact_enabled) 362 snprintf(value, sizeof(value), "enabled"); 363 else 364 snprintf(value, sizeof(value), "disabled"); 365 } else 366 snprintf(value, sizeof(value), "unsupported"); 367 format_and_print(outf, base_level + 4, header, value); 368 369 snprintf(header, sizeof(header), 370 "speed-select-base-freq"); 371 if (ctdp_level->pbf_support) { 372 if (ctdp_level->pbf_enabled) 373 snprintf(value, sizeof(value), "enabled"); 374 else 375 snprintf(value, sizeof(value), "disabled"); 376 } else 377 snprintf(value, sizeof(value), "unsupported"); 378 format_and_print(outf, base_level + 4, header, value); 379 380 snprintf(header, sizeof(header), "thermal-design-power(W)"); 381 snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp); 382 format_and_print(outf, base_level + 4, header, value); 383 384 snprintf(header, sizeof(header), "tjunction-max(C)"); 385 snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot); 386 format_and_print(outf, base_level + 4, header, value); 387 388 snprintf(header, sizeof(header), "turbo-ratio-limits-sse"); 389 format_and_print(outf, base_level + 4, header, NULL); 390 for (j = 0; j < 8; ++j) { 391 snprintf(header, sizeof(header), "bucket-%d", j); 392 format_and_print(outf, base_level + 5, header, NULL); 393 394 snprintf(header, sizeof(header), "core-count"); 395 snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff); 396 format_and_print(outf, base_level + 6, header, value); 397 398 snprintf(header, sizeof(header), 399 "max-turbo-frequency(MHz)"); 400 snprintf(value, sizeof(value), "%d", 401 ctdp_level->trl_sse_active_cores[j] * 402 DISP_FREQ_MULTIPLIER); 403 format_and_print(outf, base_level + 6, header, value); 404 } 405 snprintf(header, sizeof(header), "turbo-ratio-limits-avx"); 406 format_and_print(outf, base_level + 4, header, NULL); 407 for (j = 0; j < 8; ++j) { 408 snprintf(header, sizeof(header), "bucket-%d", j); 409 format_and_print(outf, base_level + 5, header, NULL); 410 411 snprintf(header, sizeof(header), "core-count"); 412 snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff); 413 format_and_print(outf, base_level + 6, header, value); 414 415 snprintf(header, sizeof(header), 416 "max-turbo-frequency(MHz)"); 417 snprintf(value, sizeof(value), "%d", 418 ctdp_level->trl_avx_active_cores[j] * 419 DISP_FREQ_MULTIPLIER); 420 format_and_print(outf, base_level + 6, header, value); 421 } 422 423 snprintf(header, sizeof(header), "turbo-ratio-limits-avx512"); 424 format_and_print(outf, base_level + 4, header, NULL); 425 for (j = 0; j < 8; ++j) { 426 snprintf(header, sizeof(header), "bucket-%d", j); 427 format_and_print(outf, base_level + 5, header, NULL); 428 429 snprintf(header, sizeof(header), "core-count"); 430 snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff); 431 format_and_print(outf, base_level + 6, header, value); 432 433 snprintf(header, sizeof(header), 434 "max-turbo-frequency(MHz)"); 435 snprintf(value, sizeof(value), "%d", 436 ctdp_level->trl_avx_512_active_cores[j] * 437 DISP_FREQ_MULTIPLIER); 438 format_and_print(outf, base_level + 6, header, value); 439 } 440 if (ctdp_level->pbf_support) 441 _isst_pbf_display_information(cpu, outf, i, 442 &ctdp_level->pbf_info, 443 base_level + 4); 444 if (ctdp_level->fact_support) 445 _isst_fact_display_information(cpu, outf, i, 0xff, 0xff, 446 &ctdp_level->fact_info, 447 base_level + 4); 448 } 449 450 format_and_print(outf, 1, NULL, NULL); 451 } 452 453 void isst_ctdp_display_information_start(FILE *outf) 454 { 455 last_level = 0; 456 format_and_print(outf, 0, "start", NULL); 457 } 458 459 void isst_ctdp_display_information_end(FILE *outf) 460 { 461 format_and_print(outf, 0, NULL, NULL); 462 } 463 464 void isst_pbf_display_information(int cpu, FILE *outf, int level, 465 struct isst_pbf_info *pbf_info) 466 { 467 print_package_info(cpu, outf); 468 _isst_pbf_display_information(cpu, outf, level, pbf_info, 4); 469 format_and_print(outf, 1, NULL, NULL); 470 } 471 472 void isst_fact_display_information(int cpu, FILE *outf, int level, 473 int fact_bucket, int fact_avx, 474 struct isst_fact_info *fact_info) 475 { 476 print_package_info(cpu, outf); 477 _isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx, 478 fact_info, 4); 479 format_and_print(outf, 1, NULL, NULL); 480 } 481 482 void isst_clos_display_information(int cpu, FILE *outf, int clos, 483 struct isst_clos_config *clos_config) 484 { 485 char header[256]; 486 char value[256]; 487 488 snprintf(header, sizeof(header), "package-%d", 489 get_physical_package_id(cpu)); 490 format_and_print(outf, 1, header, NULL); 491 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 492 format_and_print(outf, 2, header, NULL); 493 snprintf(header, sizeof(header), "cpu-%d", cpu); 494 format_and_print(outf, 3, header, NULL); 495 496 snprintf(header, sizeof(header), "core-power"); 497 format_and_print(outf, 4, header, NULL); 498 499 snprintf(header, sizeof(header), "clos"); 500 snprintf(value, sizeof(value), "%d", clos); 501 format_and_print(outf, 5, header, value); 502 503 snprintf(header, sizeof(header), "epp"); 504 snprintf(value, sizeof(value), "%d", clos_config->epp); 505 format_and_print(outf, 5, header, value); 506 507 snprintf(header, sizeof(header), "clos-proportional-priority"); 508 snprintf(value, sizeof(value), "%d", clos_config->clos_prop_prio); 509 format_and_print(outf, 5, header, value); 510 511 snprintf(header, sizeof(header), "clos-min"); 512 snprintf(value, sizeof(value), "%d", clos_config->clos_min); 513 format_and_print(outf, 5, header, value); 514 515 snprintf(header, sizeof(header), "clos-max"); 516 snprintf(value, sizeof(value), "%d", clos_config->clos_max); 517 format_and_print(outf, 5, header, value); 518 519 snprintf(header, sizeof(header), "clos-desired"); 520 snprintf(value, sizeof(value), "%d", clos_config->clos_desired); 521 format_and_print(outf, 5, header, value); 522 523 format_and_print(outf, 1, NULL, NULL); 524 } 525 526 void isst_clos_display_clos_information(int cpu, FILE *outf, 527 int clos_enable, int type) 528 { 529 char header[256]; 530 char value[256]; 531 532 snprintf(header, sizeof(header), "package-%d", 533 get_physical_package_id(cpu)); 534 format_and_print(outf, 1, header, NULL); 535 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 536 format_and_print(outf, 2, header, NULL); 537 snprintf(header, sizeof(header), "cpu-%d", cpu); 538 format_and_print(outf, 3, header, NULL); 539 540 snprintf(header, sizeof(header), "core-power"); 541 format_and_print(outf, 4, header, NULL); 542 543 snprintf(header, sizeof(header), "enable-status"); 544 snprintf(value, sizeof(value), "%d", clos_enable); 545 format_and_print(outf, 5, header, value); 546 547 snprintf(header, sizeof(header), "priority-type"); 548 snprintf(value, sizeof(value), "%d", type); 549 format_and_print(outf, 5, header, value); 550 551 format_and_print(outf, 1, NULL, NULL); 552 } 553 554 void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos) 555 { 556 char header[256]; 557 char value[256]; 558 559 snprintf(header, sizeof(header), "package-%d", 560 get_physical_package_id(cpu)); 561 format_and_print(outf, 1, header, NULL); 562 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 563 format_and_print(outf, 2, header, NULL); 564 snprintf(header, sizeof(header), "cpu-%d", cpu); 565 format_and_print(outf, 3, header, NULL); 566 567 snprintf(header, sizeof(header), "get-assoc"); 568 format_and_print(outf, 4, header, NULL); 569 570 snprintf(header, sizeof(header), "clos"); 571 snprintf(value, sizeof(value), "%d", clos); 572 format_and_print(outf, 5, header, value); 573 574 format_and_print(outf, 1, NULL, NULL); 575 } 576 577 void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd, 578 int result) 579 { 580 char header[256]; 581 char value[256]; 582 583 snprintf(header, sizeof(header), "package-%d", 584 get_physical_package_id(cpu)); 585 format_and_print(outf, 1, header, NULL); 586 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 587 format_and_print(outf, 2, header, NULL); 588 snprintf(header, sizeof(header), "cpu-%d", cpu); 589 format_and_print(outf, 3, header, NULL); 590 snprintf(header, sizeof(header), "%s", feature); 591 format_and_print(outf, 4, header, NULL); 592 snprintf(header, sizeof(header), "%s", cmd); 593 if (!result) 594 snprintf(value, sizeof(value), "success"); 595 else 596 snprintf(value, sizeof(value), "failed(error %d)", result); 597 format_and_print(outf, 5, header, value); 598 599 format_and_print(outf, 1, NULL, NULL); 600 } 601