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
printcpulist(int str_len,char * str,int mask_size,cpu_set_t * cpu_mask)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
printcpumask(int str_len,char * str,int mask_size,cpu_set_t * cpu_mask)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
format_and_print_txt(FILE * outf,int level,char * header,char * value)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;
format_and_print(FILE * outf,int level,char * header,char * value)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
print_package_info(int cpu,FILE * outf)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
_isst_pbf_display_information(int cpu,FILE * outf,int level,struct isst_pbf_info * pbf_info,int disp_level)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
_isst_fact_display_information(int cpu,FILE * outf,int level,int fact_bucket,int fact_avx,struct isst_fact_info * fact_info,int base_level)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
isst_ctdp_display_core_info(int cpu,FILE * outf,char * prefix,unsigned int val)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
isst_ctdp_display_information(int cpu,FILE * outf,int tdp_level,struct isst_pkg_ctdp * pkg_dev)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 if (pkg_dev->processed)
318 print_package_info(cpu, outf);
319
320 for (i = 0; i <= pkg_dev->levels; ++i) {
321 struct isst_pkg_ctdp_level_info *ctdp_level;
322 int j;
323
324 ctdp_level = &pkg_dev->ctdp_level[i];
325 if (!ctdp_level->processed)
326 continue;
327
328 snprintf(header, sizeof(header), "perf-profile-level-%d",
329 ctdp_level->level);
330 format_and_print(outf, base_level + 3, header, NULL);
331
332 snprintf(header, sizeof(header), "cpu-count");
333 j = get_cpu_count(get_physical_die_id(cpu),
334 get_physical_die_id(cpu));
335 snprintf(value, sizeof(value), "%d", j);
336 format_and_print(outf, base_level + 4, header, value);
337
338 snprintf(header, sizeof(header), "enable-cpu-mask");
339 printcpumask(sizeof(value), value,
340 ctdp_level->core_cpumask_size,
341 ctdp_level->core_cpumask);
342 format_and_print(outf, base_level + 4, header, value);
343
344 snprintf(header, sizeof(header), "enable-cpu-list");
345 printcpulist(sizeof(value), value,
346 ctdp_level->core_cpumask_size,
347 ctdp_level->core_cpumask);
348 format_and_print(outf, base_level + 4, header, value);
349
350 snprintf(header, sizeof(header), "thermal-design-power-ratio");
351 snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio);
352 format_and_print(outf, base_level + 4, header, value);
353
354 snprintf(header, sizeof(header), "base-frequency(MHz)");
355 snprintf(value, sizeof(value), "%d",
356 ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER);
357 format_and_print(outf, base_level + 4, header, value);
358
359 snprintf(header, sizeof(header),
360 "speed-select-turbo-freq");
361 if (ctdp_level->fact_support) {
362 if (ctdp_level->fact_enabled)
363 snprintf(value, sizeof(value), "enabled");
364 else
365 snprintf(value, sizeof(value), "disabled");
366 } else
367 snprintf(value, sizeof(value), "unsupported");
368 format_and_print(outf, base_level + 4, header, value);
369
370 snprintf(header, sizeof(header),
371 "speed-select-base-freq");
372 if (ctdp_level->pbf_support) {
373 if (ctdp_level->pbf_enabled)
374 snprintf(value, sizeof(value), "enabled");
375 else
376 snprintf(value, sizeof(value), "disabled");
377 } else
378 snprintf(value, sizeof(value), "unsupported");
379 format_and_print(outf, base_level + 4, header, value);
380
381 snprintf(header, sizeof(header), "thermal-design-power(W)");
382 snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp);
383 format_and_print(outf, base_level + 4, header, value);
384
385 snprintf(header, sizeof(header), "tjunction-max(C)");
386 snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot);
387 format_and_print(outf, base_level + 4, header, value);
388
389 snprintf(header, sizeof(header), "turbo-ratio-limits-sse");
390 format_and_print(outf, base_level + 4, header, NULL);
391 for (j = 0; j < 8; ++j) {
392 snprintf(header, sizeof(header), "bucket-%d", j);
393 format_and_print(outf, base_level + 5, header, NULL);
394
395 snprintf(header, sizeof(header), "core-count");
396 snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
397 format_and_print(outf, base_level + 6, header, value);
398
399 snprintf(header, sizeof(header),
400 "max-turbo-frequency(MHz)");
401 snprintf(value, sizeof(value), "%d",
402 ctdp_level->trl_sse_active_cores[j] *
403 DISP_FREQ_MULTIPLIER);
404 format_and_print(outf, base_level + 6, header, value);
405 }
406 snprintf(header, sizeof(header), "turbo-ratio-limits-avx");
407 format_and_print(outf, base_level + 4, header, NULL);
408 for (j = 0; j < 8; ++j) {
409 snprintf(header, sizeof(header), "bucket-%d", j);
410 format_and_print(outf, base_level + 5, header, NULL);
411
412 snprintf(header, sizeof(header), "core-count");
413 snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
414 format_and_print(outf, base_level + 6, header, value);
415
416 snprintf(header, sizeof(header),
417 "max-turbo-frequency(MHz)");
418 snprintf(value, sizeof(value), "%d",
419 ctdp_level->trl_avx_active_cores[j] *
420 DISP_FREQ_MULTIPLIER);
421 format_and_print(outf, base_level + 6, header, value);
422 }
423
424 snprintf(header, sizeof(header), "turbo-ratio-limits-avx512");
425 format_and_print(outf, base_level + 4, header, NULL);
426 for (j = 0; j < 8; ++j) {
427 snprintf(header, sizeof(header), "bucket-%d", j);
428 format_and_print(outf, base_level + 5, header, NULL);
429
430 snprintf(header, sizeof(header), "core-count");
431 snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
432 format_and_print(outf, base_level + 6, header, value);
433
434 snprintf(header, sizeof(header),
435 "max-turbo-frequency(MHz)");
436 snprintf(value, sizeof(value), "%d",
437 ctdp_level->trl_avx_512_active_cores[j] *
438 DISP_FREQ_MULTIPLIER);
439 format_and_print(outf, base_level + 6, header, value);
440 }
441 if (ctdp_level->pbf_support)
442 _isst_pbf_display_information(cpu, outf, i,
443 &ctdp_level->pbf_info,
444 base_level + 4);
445 if (ctdp_level->fact_support)
446 _isst_fact_display_information(cpu, outf, i, 0xff, 0xff,
447 &ctdp_level->fact_info,
448 base_level + 4);
449 }
450
451 format_and_print(outf, 1, NULL, NULL);
452 }
453
isst_ctdp_display_information_start(FILE * outf)454 void isst_ctdp_display_information_start(FILE *outf)
455 {
456 last_level = 0;
457 format_and_print(outf, 0, "start", NULL);
458 }
459
isst_ctdp_display_information_end(FILE * outf)460 void isst_ctdp_display_information_end(FILE *outf)
461 {
462 format_and_print(outf, 0, NULL, NULL);
463 }
464
isst_pbf_display_information(int cpu,FILE * outf,int level,struct isst_pbf_info * pbf_info)465 void isst_pbf_display_information(int cpu, FILE *outf, int level,
466 struct isst_pbf_info *pbf_info)
467 {
468 print_package_info(cpu, outf);
469 _isst_pbf_display_information(cpu, outf, level, pbf_info, 4);
470 format_and_print(outf, 1, NULL, NULL);
471 }
472
isst_fact_display_information(int cpu,FILE * outf,int level,int fact_bucket,int fact_avx,struct isst_fact_info * fact_info)473 void isst_fact_display_information(int cpu, FILE *outf, int level,
474 int fact_bucket, int fact_avx,
475 struct isst_fact_info *fact_info)
476 {
477 print_package_info(cpu, outf);
478 _isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx,
479 fact_info, 4);
480 format_and_print(outf, 1, NULL, NULL);
481 }
482
isst_clos_display_information(int cpu,FILE * outf,int clos,struct isst_clos_config * clos_config)483 void isst_clos_display_information(int cpu, FILE *outf, int clos,
484 struct isst_clos_config *clos_config)
485 {
486 char header[256];
487 char value[256];
488
489 snprintf(header, sizeof(header), "package-%d",
490 get_physical_package_id(cpu));
491 format_and_print(outf, 1, header, NULL);
492 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
493 format_and_print(outf, 2, header, NULL);
494 snprintf(header, sizeof(header), "cpu-%d", cpu);
495 format_and_print(outf, 3, header, NULL);
496
497 snprintf(header, sizeof(header), "core-power");
498 format_and_print(outf, 4, header, NULL);
499
500 snprintf(header, sizeof(header), "clos");
501 snprintf(value, sizeof(value), "%d", clos);
502 format_and_print(outf, 5, header, value);
503
504 snprintf(header, sizeof(header), "epp");
505 snprintf(value, sizeof(value), "%d", clos_config->epp);
506 format_and_print(outf, 5, header, value);
507
508 snprintf(header, sizeof(header), "clos-proportional-priority");
509 snprintf(value, sizeof(value), "%d", clos_config->clos_prop_prio);
510 format_and_print(outf, 5, header, value);
511
512 snprintf(header, sizeof(header), "clos-min");
513 snprintf(value, sizeof(value), "%d", clos_config->clos_min);
514 format_and_print(outf, 5, header, value);
515
516 snprintf(header, sizeof(header), "clos-max");
517 snprintf(value, sizeof(value), "%d", clos_config->clos_max);
518 format_and_print(outf, 5, header, value);
519
520 snprintf(header, sizeof(header), "clos-desired");
521 snprintf(value, sizeof(value), "%d", clos_config->clos_desired);
522 format_and_print(outf, 5, header, value);
523
524 format_and_print(outf, 1, NULL, NULL);
525 }
526
isst_clos_display_clos_information(int cpu,FILE * outf,int clos_enable,int type)527 void isst_clos_display_clos_information(int cpu, FILE *outf,
528 int clos_enable, int type)
529 {
530 char header[256];
531 char value[256];
532
533 snprintf(header, sizeof(header), "package-%d",
534 get_physical_package_id(cpu));
535 format_and_print(outf, 1, header, NULL);
536 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
537 format_and_print(outf, 2, header, NULL);
538 snprintf(header, sizeof(header), "cpu-%d", cpu);
539 format_and_print(outf, 3, header, NULL);
540
541 snprintf(header, sizeof(header), "core-power");
542 format_and_print(outf, 4, header, NULL);
543
544 snprintf(header, sizeof(header), "enable-status");
545 snprintf(value, sizeof(value), "%d", clos_enable);
546 format_and_print(outf, 5, header, value);
547
548 snprintf(header, sizeof(header), "priority-type");
549 snprintf(value, sizeof(value), "%d", type);
550 format_and_print(outf, 5, header, value);
551
552 format_and_print(outf, 1, NULL, NULL);
553 }
554
isst_clos_display_assoc_information(int cpu,FILE * outf,int clos)555 void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos)
556 {
557 char header[256];
558 char value[256];
559
560 snprintf(header, sizeof(header), "package-%d",
561 get_physical_package_id(cpu));
562 format_and_print(outf, 1, header, NULL);
563 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
564 format_and_print(outf, 2, header, NULL);
565 snprintf(header, sizeof(header), "cpu-%d", cpu);
566 format_and_print(outf, 3, header, NULL);
567
568 snprintf(header, sizeof(header), "get-assoc");
569 format_and_print(outf, 4, header, NULL);
570
571 snprintf(header, sizeof(header), "clos");
572 snprintf(value, sizeof(value), "%d", clos);
573 format_and_print(outf, 5, header, value);
574
575 format_and_print(outf, 1, NULL, NULL);
576 }
577
isst_display_result(int cpu,FILE * outf,char * feature,char * cmd,int result)578 void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
579 int result)
580 {
581 char header[256];
582 char value[256];
583
584 snprintf(header, sizeof(header), "package-%d",
585 get_physical_package_id(cpu));
586 format_and_print(outf, 1, header, NULL);
587 snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
588 format_and_print(outf, 2, header, NULL);
589 snprintf(header, sizeof(header), "cpu-%d", cpu);
590 format_and_print(outf, 3, header, NULL);
591 snprintf(header, sizeof(header), "%s", feature);
592 format_and_print(outf, 4, header, NULL);
593 snprintf(header, sizeof(header), "%s", cmd);
594 if (!result)
595 snprintf(value, sizeof(value), "success");
596 else
597 snprintf(value, sizeof(value), "failed(error %d)", result);
598 format_and_print(outf, 5, header, value);
599
600 format_and_print(outf, 1, NULL, NULL);
601 }
602