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_information(int cpu, FILE *outf, int tdp_level,
291 				   struct isst_pkg_ctdp *pkg_dev)
292 {
293 	char header[256];
294 	char value[256];
295 	int i, base_level = 1;
296 
297 	print_package_info(cpu, outf);
298 
299 	for (i = 0; i <= pkg_dev->levels; ++i) {
300 		struct isst_pkg_ctdp_level_info *ctdp_level;
301 		int j;
302 
303 		ctdp_level = &pkg_dev->ctdp_level[i];
304 		if (!ctdp_level->processed)
305 			continue;
306 
307 		snprintf(header, sizeof(header), "perf-profile-level-%d",
308 			 ctdp_level->level);
309 		format_and_print(outf, base_level + 3, header, NULL);
310 
311 		snprintf(header, sizeof(header), "cpu-count");
312 		j = get_cpu_count(get_physical_die_id(cpu),
313 				  get_physical_die_id(cpu));
314 		snprintf(value, sizeof(value), "%d", j);
315 		format_and_print(outf, base_level + 4, header, value);
316 
317 		snprintf(header, sizeof(header), "enable-cpu-mask");
318 		printcpumask(sizeof(value), value,
319 			     ctdp_level->core_cpumask_size,
320 			     ctdp_level->core_cpumask);
321 		format_and_print(outf, base_level + 4, header, value);
322 
323 		snprintf(header, sizeof(header), "enable-cpu-list");
324 		printcpulist(sizeof(value), value,
325 			     ctdp_level->core_cpumask_size,
326 			     ctdp_level->core_cpumask);
327 		format_and_print(outf, base_level + 4, header, value);
328 
329 		snprintf(header, sizeof(header), "thermal-design-power-ratio");
330 		snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio);
331 		format_and_print(outf, base_level + 4, header, value);
332 
333 		snprintf(header, sizeof(header), "base-frequency(MHz)");
334 		snprintf(value, sizeof(value), "%d",
335 			 ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER);
336 		format_and_print(outf, base_level + 4, header, value);
337 
338 		snprintf(header, sizeof(header),
339 			 "speed-select-turbo-freq");
340 		if (ctdp_level->fact_support) {
341 			if (ctdp_level->fact_enabled)
342 				snprintf(value, sizeof(value), "enabled");
343 			else
344 				snprintf(value, sizeof(value), "disabled");
345 		} else
346 			snprintf(value, sizeof(value), "unsupported");
347 		format_and_print(outf, base_level + 4, header, value);
348 
349 		snprintf(header, sizeof(header),
350 			 "speed-select-base-freq");
351 		if (ctdp_level->pbf_support) {
352 			if (ctdp_level->pbf_enabled)
353 				snprintf(value, sizeof(value), "enabled");
354 			else
355 				snprintf(value, sizeof(value), "disabled");
356 		} else
357 			snprintf(value, sizeof(value), "unsupported");
358 		format_and_print(outf, base_level + 4, header, value);
359 
360 		snprintf(header, sizeof(header), "thermal-design-power(W)");
361 		snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp);
362 		format_and_print(outf, base_level + 4, header, value);
363 
364 		snprintf(header, sizeof(header), "tjunction-max(C)");
365 		snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot);
366 		format_and_print(outf, base_level + 4, header, value);
367 
368 		snprintf(header, sizeof(header), "turbo-ratio-limits-sse");
369 		format_and_print(outf, base_level + 4, header, NULL);
370 		for (j = 0; j < 8; ++j) {
371 			snprintf(header, sizeof(header), "bucket-%d", j);
372 			format_and_print(outf, base_level + 5, header, NULL);
373 
374 			snprintf(header, sizeof(header), "core-count");
375 			snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
376 			format_and_print(outf, base_level + 6, header, value);
377 
378 			snprintf(header, sizeof(header),
379 				"max-turbo-frequency(MHz)");
380 			snprintf(value, sizeof(value), "%d",
381 				 ctdp_level->trl_sse_active_cores[j] *
382 				  DISP_FREQ_MULTIPLIER);
383 			format_and_print(outf, base_level + 6, header, value);
384 		}
385 		snprintf(header, sizeof(header), "turbo-ratio-limits-avx");
386 		format_and_print(outf, base_level + 4, header, NULL);
387 		for (j = 0; j < 8; ++j) {
388 			snprintf(header, sizeof(header), "bucket-%d", j);
389 			format_and_print(outf, base_level + 5, header, NULL);
390 
391 			snprintf(header, sizeof(header), "core-count");
392 			snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
393 			format_and_print(outf, base_level + 6, header, value);
394 
395 			snprintf(header, sizeof(header),
396 				"max-turbo-frequency(MHz)");
397 			snprintf(value, sizeof(value), "%d",
398 				 ctdp_level->trl_avx_active_cores[j] *
399 				  DISP_FREQ_MULTIPLIER);
400 			format_and_print(outf, base_level + 6, header, value);
401 		}
402 
403 		snprintf(header, sizeof(header), "turbo-ratio-limits-avx512");
404 		format_and_print(outf, base_level + 4, header, NULL);
405 		for (j = 0; j < 8; ++j) {
406 			snprintf(header, sizeof(header), "bucket-%d", j);
407 			format_and_print(outf, base_level + 5, header, NULL);
408 
409 			snprintf(header, sizeof(header), "core-count");
410 			snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
411 			format_and_print(outf, base_level + 6, header, value);
412 
413 			snprintf(header, sizeof(header),
414 				"max-turbo-frequency(MHz)");
415 			snprintf(value, sizeof(value), "%d",
416 				 ctdp_level->trl_avx_512_active_cores[j] *
417 				  DISP_FREQ_MULTIPLIER);
418 			format_and_print(outf, base_level + 6, header, value);
419 		}
420 		if (ctdp_level->pbf_support)
421 			_isst_pbf_display_information(cpu, outf, i,
422 						      &ctdp_level->pbf_info,
423 						      base_level + 4);
424 		if (ctdp_level->fact_support)
425 			_isst_fact_display_information(cpu, outf, i, 0xff, 0xff,
426 						       &ctdp_level->fact_info,
427 						       base_level + 4);
428 	}
429 
430 	format_and_print(outf, 1, NULL, NULL);
431 }
432 
433 void isst_ctdp_display_information_start(FILE *outf)
434 {
435 	last_level = 0;
436 	format_and_print(outf, 0, "start", NULL);
437 }
438 
439 void isst_ctdp_display_information_end(FILE *outf)
440 {
441 	format_and_print(outf, 0, NULL, NULL);
442 }
443 
444 void isst_pbf_display_information(int cpu, FILE *outf, int level,
445 				  struct isst_pbf_info *pbf_info)
446 {
447 	print_package_info(cpu, outf);
448 	_isst_pbf_display_information(cpu, outf, level, pbf_info, 4);
449 	format_and_print(outf, 1, NULL, NULL);
450 }
451 
452 void isst_fact_display_information(int cpu, FILE *outf, int level,
453 				   int fact_bucket, int fact_avx,
454 				   struct isst_fact_info *fact_info)
455 {
456 	print_package_info(cpu, outf);
457 	_isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx,
458 				       fact_info, 4);
459 	format_and_print(outf, 1, NULL, NULL);
460 }
461 
462 void isst_clos_display_information(int cpu, FILE *outf, int clos,
463 				   struct isst_clos_config *clos_config)
464 {
465 	char header[256];
466 	char value[256];
467 
468 	snprintf(header, sizeof(header), "package-%d",
469 		 get_physical_package_id(cpu));
470 	format_and_print(outf, 1, header, NULL);
471 	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
472 	format_and_print(outf, 2, header, NULL);
473 	snprintf(header, sizeof(header), "cpu-%d", cpu);
474 	format_and_print(outf, 3, header, NULL);
475 
476 	snprintf(header, sizeof(header), "core-power");
477 	format_and_print(outf, 4, header, NULL);
478 
479 	snprintf(header, sizeof(header), "clos");
480 	snprintf(value, sizeof(value), "%d", clos);
481 	format_and_print(outf, 5, header, value);
482 
483 	snprintf(header, sizeof(header), "epp");
484 	snprintf(value, sizeof(value), "%d", clos_config->epp);
485 	format_and_print(outf, 5, header, value);
486 
487 	snprintf(header, sizeof(header), "clos-proportional-priority");
488 	snprintf(value, sizeof(value), "%d", clos_config->clos_prop_prio);
489 	format_and_print(outf, 5, header, value);
490 
491 	snprintf(header, sizeof(header), "clos-min");
492 	snprintf(value, sizeof(value), "%d", clos_config->clos_min);
493 	format_and_print(outf, 5, header, value);
494 
495 	snprintf(header, sizeof(header), "clos-max");
496 	snprintf(value, sizeof(value), "%d", clos_config->clos_max);
497 	format_and_print(outf, 5, header, value);
498 
499 	snprintf(header, sizeof(header), "clos-desired");
500 	snprintf(value, sizeof(value), "%d", clos_config->clos_desired);
501 	format_and_print(outf, 5, header, value);
502 
503 	format_and_print(outf, 1, NULL, NULL);
504 }
505 
506 void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
507 			 int result)
508 {
509 	char header[256];
510 	char value[256];
511 
512 	snprintf(header, sizeof(header), "package-%d",
513 		 get_physical_package_id(cpu));
514 	format_and_print(outf, 1, header, NULL);
515 	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
516 	format_and_print(outf, 2, header, NULL);
517 	snprintf(header, sizeof(header), "cpu-%d", cpu);
518 	format_and_print(outf, 3, header, NULL);
519 	snprintf(header, sizeof(header), "%s", feature);
520 	format_and_print(outf, 4, header, NULL);
521 	snprintf(header, sizeof(header), "%s", cmd);
522 	if (!result)
523 		snprintf(value, sizeof(value), "success");
524 	else
525 		snprintf(value, sizeof(value), "failed(error %d)", result);
526 	format_and_print(outf, 5, header, value);
527 
528 	format_and_print(outf, 1, NULL, NULL);
529 }
530