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