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 100000 10 11 static void printcpumask(int str_len, char *str, int mask_size, 12 cpu_set_t *cpu_mask) 13 { 14 int i, max_cpus = get_topo_max_cpus(); 15 unsigned int *mask; 16 int size, index, curr_index; 17 18 size = max_cpus / (sizeof(unsigned int) * 8); 19 if (max_cpus % (sizeof(unsigned int) * 8)) 20 size++; 21 22 mask = calloc(size, sizeof(unsigned int)); 23 if (!mask) 24 return; 25 26 for (i = 0; i < max_cpus; ++i) { 27 int mask_index, bit_index; 28 29 if (!CPU_ISSET_S(i, mask_size, cpu_mask)) 30 continue; 31 32 mask_index = i / (sizeof(unsigned int) * 8); 33 bit_index = i % (sizeof(unsigned int) * 8); 34 mask[mask_index] |= BIT(bit_index); 35 } 36 37 curr_index = 0; 38 for (i = size - 1; i >= 0; --i) { 39 index = snprintf(&str[curr_index], str_len - curr_index, "%08x", 40 mask[i]); 41 curr_index += index; 42 if (i) { 43 strncat(&str[curr_index], ",", str_len - curr_index); 44 curr_index++; 45 } 46 } 47 48 free(mask); 49 } 50 51 static void format_and_print_txt(FILE *outf, int level, char *header, 52 char *value) 53 { 54 char *spaces = " "; 55 static char delimiters[256]; 56 int i, j = 0; 57 58 if (!level) 59 return; 60 61 if (level == 1) { 62 strcpy(delimiters, " "); 63 } else { 64 for (i = 0; i < level - 1; ++i) 65 j += snprintf(&delimiters[j], sizeof(delimiters) - j, 66 "%s", spaces); 67 } 68 69 if (header && value) { 70 fprintf(outf, "%s", delimiters); 71 fprintf(outf, "%s:%s\n", header, value); 72 } else if (header) { 73 fprintf(outf, "%s", delimiters); 74 fprintf(outf, "%s\n", header); 75 } 76 } 77 78 static int last_level; 79 static void format_and_print(FILE *outf, int level, char *header, char *value) 80 { 81 char *spaces = " "; 82 static char delimiters[256]; 83 int i; 84 85 if (!out_format_is_json()) { 86 format_and_print_txt(outf, level, header, value); 87 return; 88 } 89 90 if (level == 0) { 91 if (header) 92 fprintf(outf, "{"); 93 else 94 fprintf(outf, "\n}\n"); 95 96 } else { 97 int j = 0; 98 99 for (i = 0; i < level; ++i) 100 j += snprintf(&delimiters[j], sizeof(delimiters) - j, 101 "%s", spaces); 102 103 if (last_level == level) 104 fprintf(outf, ",\n"); 105 106 if (value) { 107 if (last_level != level) 108 fprintf(outf, "\n"); 109 110 fprintf(outf, "%s\"%s\": ", delimiters, header); 111 fprintf(outf, "\"%s\"", value); 112 } else { 113 for (i = last_level - 1; i >= level; --i) { 114 int k = 0; 115 116 for (j = i; j > 0; --j) 117 k += snprintf(&delimiters[k], 118 sizeof(delimiters) - k, 119 "%s", spaces); 120 if (i == level && header) 121 fprintf(outf, "\n%s},", delimiters); 122 else 123 fprintf(outf, "\n%s}", delimiters); 124 } 125 if (abs(last_level - level) < 3) 126 fprintf(outf, "\n"); 127 if (header) 128 fprintf(outf, "%s\"%s\": {", delimiters, 129 header); 130 } 131 } 132 133 last_level = level; 134 } 135 136 static void print_packag_info(int cpu, FILE *outf) 137 { 138 char header[256]; 139 140 snprintf(header, sizeof(header), "package-%d", 141 get_physical_package_id(cpu)); 142 format_and_print(outf, 1, header, NULL); 143 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 144 format_and_print(outf, 2, header, NULL); 145 snprintf(header, sizeof(header), "cpu-%d", cpu); 146 format_and_print(outf, 3, header, NULL); 147 } 148 149 static void _isst_pbf_display_information(int cpu, FILE *outf, int level, 150 struct isst_pbf_info *pbf_info, 151 int disp_level) 152 { 153 char header[256]; 154 char value[256]; 155 156 snprintf(header, sizeof(header), "speed-select-base-freq"); 157 format_and_print(outf, disp_level, header, NULL); 158 159 snprintf(header, sizeof(header), "high-priority-base-frequency(KHz)"); 160 snprintf(value, sizeof(value), "%d", 161 pbf_info->p1_high * DISP_FREQ_MULTIPLIER); 162 format_and_print(outf, disp_level + 1, header, value); 163 164 snprintf(header, sizeof(header), "high-priority-cpu-mask"); 165 printcpumask(sizeof(value), value, pbf_info->core_cpumask_size, 166 pbf_info->core_cpumask); 167 format_and_print(outf, disp_level + 1, header, value); 168 169 snprintf(header, sizeof(header), "low-priority-base-frequency(KHz)"); 170 snprintf(value, sizeof(value), "%d", 171 pbf_info->p1_low * DISP_FREQ_MULTIPLIER); 172 format_and_print(outf, disp_level + 1, header, value); 173 174 snprintf(header, sizeof(header), "tjunction-temperature(C)"); 175 snprintf(value, sizeof(value), "%d", pbf_info->t_prochot); 176 format_and_print(outf, disp_level + 1, header, value); 177 178 snprintf(header, sizeof(header), "thermal-design-power(W)"); 179 snprintf(value, sizeof(value), "%d", pbf_info->tdp); 180 format_and_print(outf, disp_level + 1, header, value); 181 } 182 183 static void _isst_fact_display_information(int cpu, FILE *outf, int level, 184 int fact_bucket, int fact_avx, 185 struct isst_fact_info *fact_info, 186 int base_level) 187 { 188 struct isst_fact_bucket_info *bucket_info = fact_info->bucket_info; 189 char header[256]; 190 char value[256]; 191 int j; 192 193 snprintf(header, sizeof(header), "speed-select-turbo-freq"); 194 format_and_print(outf, base_level, header, NULL); 195 for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) { 196 if (fact_bucket != 0xff && fact_bucket != j) 197 continue; 198 199 if (!bucket_info[j].high_priority_cores_count) 200 break; 201 202 snprintf(header, sizeof(header), "bucket-%d", j); 203 format_and_print(outf, base_level + 1, header, NULL); 204 205 snprintf(header, sizeof(header), "high-priority-cores-count"); 206 snprintf(value, sizeof(value), "%d", 207 bucket_info[j].high_priority_cores_count); 208 format_and_print(outf, base_level + 2, header, value); 209 210 if (fact_avx & 0x01) { 211 snprintf(header, sizeof(header), 212 "high-priority-max-frequency(KHz)"); 213 snprintf(value, sizeof(value), "%d", 214 bucket_info[j].sse_trl * DISP_FREQ_MULTIPLIER); 215 format_and_print(outf, base_level + 2, header, value); 216 } 217 218 if (fact_avx & 0x02) { 219 snprintf(header, sizeof(header), 220 "high-priority-max-avx2-frequency(KHz)"); 221 snprintf(value, sizeof(value), "%d", 222 bucket_info[j].avx_trl * DISP_FREQ_MULTIPLIER); 223 format_and_print(outf, base_level + 2, header, value); 224 } 225 226 if (fact_avx & 0x04) { 227 snprintf(header, sizeof(header), 228 "high-priority-max-avx512-frequency(KHz)"); 229 snprintf(value, sizeof(value), "%d", 230 bucket_info[j].avx512_trl * 231 DISP_FREQ_MULTIPLIER); 232 format_and_print(outf, base_level + 2, header, value); 233 } 234 } 235 snprintf(header, sizeof(header), 236 "speed-select-turbo-freq-clip-frequencies"); 237 format_and_print(outf, base_level + 1, header, NULL); 238 snprintf(header, sizeof(header), "low-priority-max-frequency(KHz)"); 239 snprintf(value, sizeof(value), "%d", 240 fact_info->lp_clipping_ratio_license_sse * 241 DISP_FREQ_MULTIPLIER); 242 format_and_print(outf, base_level + 2, header, value); 243 snprintf(header, sizeof(header), 244 "low-priority-max-avx2-frequency(KHz)"); 245 snprintf(value, sizeof(value), "%d", 246 fact_info->lp_clipping_ratio_license_avx2 * 247 DISP_FREQ_MULTIPLIER); 248 format_and_print(outf, base_level + 2, header, value); 249 snprintf(header, sizeof(header), 250 "low-priority-max-avx512-frequency(KHz)"); 251 snprintf(value, sizeof(value), "%d", 252 fact_info->lp_clipping_ratio_license_avx512 * 253 DISP_FREQ_MULTIPLIER); 254 format_and_print(outf, base_level + 2, header, value); 255 } 256 257 void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level, 258 struct isst_pkg_ctdp *pkg_dev) 259 { 260 char header[256]; 261 char value[256]; 262 int i, base_level = 1; 263 264 print_packag_info(cpu, outf); 265 266 for (i = 0; i <= pkg_dev->levels; ++i) { 267 struct isst_pkg_ctdp_level_info *ctdp_level; 268 int j; 269 270 ctdp_level = &pkg_dev->ctdp_level[i]; 271 if (!ctdp_level->processed) 272 continue; 273 274 snprintf(header, sizeof(header), "perf-profile-level-%d", 275 ctdp_level->level); 276 format_and_print(outf, base_level + 3, header, NULL); 277 278 snprintf(header, sizeof(header), "cpu-count"); 279 j = get_cpu_count(get_physical_die_id(cpu), 280 get_physical_die_id(cpu)); 281 snprintf(value, sizeof(value), "%d", j); 282 format_and_print(outf, base_level + 4, header, value); 283 284 snprintf(header, sizeof(header), "enable-cpu-mask"); 285 printcpumask(sizeof(value), value, 286 ctdp_level->core_cpumask_size, 287 ctdp_level->core_cpumask); 288 format_and_print(outf, base_level + 4, header, value); 289 290 snprintf(header, sizeof(header), "thermal-design-power-ratio"); 291 snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio); 292 format_and_print(outf, base_level + 4, header, value); 293 294 snprintf(header, sizeof(header), "base-frequency(KHz)"); 295 snprintf(value, sizeof(value), "%d", 296 ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER); 297 format_and_print(outf, base_level + 4, header, value); 298 299 snprintf(header, sizeof(header), 300 "speed-select-turbo-freq-support"); 301 snprintf(value, sizeof(value), "%d", ctdp_level->fact_support); 302 format_and_print(outf, base_level + 4, header, value); 303 304 snprintf(header, sizeof(header), 305 "speed-select-base-freq-support"); 306 snprintf(value, sizeof(value), "%d", ctdp_level->pbf_support); 307 format_and_print(outf, base_level + 4, header, value); 308 309 snprintf(header, sizeof(header), 310 "speed-select-base-freq-enabled"); 311 snprintf(value, sizeof(value), "%d", ctdp_level->pbf_enabled); 312 format_and_print(outf, base_level + 4, header, value); 313 314 snprintf(header, sizeof(header), 315 "speed-select-turbo-freq-enabled"); 316 snprintf(value, sizeof(value), "%d", ctdp_level->fact_enabled); 317 format_and_print(outf, base_level + 4, header, value); 318 319 snprintf(header, sizeof(header), "thermal-design-power(W)"); 320 snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp); 321 format_and_print(outf, base_level + 4, header, value); 322 323 snprintf(header, sizeof(header), "tjunction-max(C)"); 324 snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot); 325 format_and_print(outf, base_level + 4, header, value); 326 327 snprintf(header, sizeof(header), "turbo-ratio-limits-sse"); 328 format_and_print(outf, base_level + 4, header, NULL); 329 for (j = 0; j < 8; ++j) { 330 snprintf(header, sizeof(header), "bucket-%d", j); 331 format_and_print(outf, base_level + 5, header, NULL); 332 333 snprintf(header, sizeof(header), "core-count"); 334 snprintf(value, sizeof(value), "%d", j); 335 format_and_print(outf, base_level + 6, header, value); 336 337 snprintf(header, sizeof(header), "turbo-ratio"); 338 snprintf(value, sizeof(value), "%d", 339 ctdp_level->trl_sse_active_cores[j]); 340 format_and_print(outf, base_level + 6, header, value); 341 } 342 snprintf(header, sizeof(header), "turbo-ratio-limits-avx"); 343 format_and_print(outf, base_level + 4, header, NULL); 344 for (j = 0; j < 8; ++j) { 345 snprintf(header, sizeof(header), "bucket-%d", j); 346 format_and_print(outf, base_level + 5, header, NULL); 347 348 snprintf(header, sizeof(header), "core-count"); 349 snprintf(value, sizeof(value), "%d", j); 350 format_and_print(outf, base_level + 6, header, value); 351 352 snprintf(header, sizeof(header), "turbo-ratio"); 353 snprintf(value, sizeof(value), "%d", 354 ctdp_level->trl_avx_active_cores[j]); 355 format_and_print(outf, base_level + 6, header, value); 356 } 357 358 snprintf(header, sizeof(header), "turbo-ratio-limits-avx512"); 359 format_and_print(outf, base_level + 4, header, NULL); 360 for (j = 0; j < 8; ++j) { 361 snprintf(header, sizeof(header), "bucket-%d", j); 362 format_and_print(outf, base_level + 5, header, NULL); 363 364 snprintf(header, sizeof(header), "core-count"); 365 snprintf(value, sizeof(value), "%d", j); 366 format_and_print(outf, base_level + 6, header, value); 367 368 snprintf(header, sizeof(header), "turbo-ratio"); 369 snprintf(value, sizeof(value), "%d", 370 ctdp_level->trl_avx_512_active_cores[j]); 371 format_and_print(outf, base_level + 6, header, value); 372 } 373 if (ctdp_level->pbf_support) 374 _isst_pbf_display_information(cpu, outf, i, 375 &ctdp_level->pbf_info, 376 base_level + 4); 377 if (ctdp_level->fact_support) 378 _isst_fact_display_information(cpu, outf, i, 0xff, 0xff, 379 &ctdp_level->fact_info, 380 base_level + 4); 381 } 382 383 format_and_print(outf, 1, NULL, NULL); 384 } 385 386 void isst_ctdp_display_information_start(FILE *outf) 387 { 388 last_level = 0; 389 format_and_print(outf, 0, "start", NULL); 390 } 391 392 void isst_ctdp_display_information_end(FILE *outf) 393 { 394 format_and_print(outf, 0, NULL, NULL); 395 } 396 397 void isst_pbf_display_information(int cpu, FILE *outf, int level, 398 struct isst_pbf_info *pbf_info) 399 { 400 print_packag_info(cpu, outf); 401 _isst_pbf_display_information(cpu, outf, level, pbf_info, 4); 402 format_and_print(outf, 1, NULL, NULL); 403 } 404 405 void isst_fact_display_information(int cpu, FILE *outf, int level, 406 int fact_bucket, int fact_avx, 407 struct isst_fact_info *fact_info) 408 { 409 print_packag_info(cpu, outf); 410 _isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx, 411 fact_info, 4); 412 format_and_print(outf, 1, NULL, NULL); 413 } 414 415 void isst_clos_display_information(int cpu, FILE *outf, int clos, 416 struct isst_clos_config *clos_config) 417 { 418 char header[256]; 419 char value[256]; 420 421 snprintf(header, sizeof(header), "package-%d", 422 get_physical_package_id(cpu)); 423 format_and_print(outf, 1, header, NULL); 424 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 425 format_and_print(outf, 2, header, NULL); 426 snprintf(header, sizeof(header), "cpu-%d", cpu); 427 format_and_print(outf, 3, header, NULL); 428 429 snprintf(header, sizeof(header), "core-power"); 430 format_and_print(outf, 4, header, NULL); 431 432 snprintf(header, sizeof(header), "clos"); 433 snprintf(value, sizeof(value), "%d", clos); 434 format_and_print(outf, 5, header, value); 435 436 snprintf(header, sizeof(header), "epp"); 437 snprintf(value, sizeof(value), "%d", clos_config->epp); 438 format_and_print(outf, 5, header, value); 439 440 snprintf(header, sizeof(header), "clos-proportional-priority"); 441 snprintf(value, sizeof(value), "%d", clos_config->clos_prop_prio); 442 format_and_print(outf, 5, header, value); 443 444 snprintf(header, sizeof(header), "clos-min"); 445 snprintf(value, sizeof(value), "%d", clos_config->clos_min); 446 format_and_print(outf, 5, header, value); 447 448 snprintf(header, sizeof(header), "clos-max"); 449 snprintf(value, sizeof(value), "%d", clos_config->clos_max); 450 format_and_print(outf, 5, header, value); 451 452 snprintf(header, sizeof(header), "clos-desired"); 453 snprintf(value, sizeof(value), "%d", clos_config->clos_desired); 454 format_and_print(outf, 5, header, value); 455 456 format_and_print(outf, 1, NULL, NULL); 457 } 458 459 void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd, 460 int result) 461 { 462 char header[256]; 463 char value[256]; 464 465 snprintf(header, sizeof(header), "package-%d", 466 get_physical_package_id(cpu)); 467 format_and_print(outf, 1, header, NULL); 468 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); 469 format_and_print(outf, 2, header, NULL); 470 snprintf(header, sizeof(header), "cpu-%d", cpu); 471 format_and_print(outf, 3, header, NULL); 472 snprintf(header, sizeof(header), "%s", feature); 473 format_and_print(outf, 4, header, NULL); 474 snprintf(header, sizeof(header), "%s", cmd); 475 snprintf(value, sizeof(value), "%d", result); 476 format_and_print(outf, 5, header, value); 477 478 format_and_print(outf, 1, NULL, NULL); 479 } 480