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