xref: /linux/tools/power/x86/intel-speed-select/isst-core.c (revision f73a058be5d70dd81a43f16b2bbff4b1576a7af8)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel Speed Select -- Enumerate and control features
4  * Copyright (c) 2019 Intel Corporation.
5  */
6 
7 #include "isst.h"
8 
9 static struct isst_platform_ops		*isst_ops;
10 
11 #define CHECK_CB(_name)	\
12 	do {	\
13 		if (!isst_ops || !isst_ops->_name) {	\
14 			fprintf(stderr, "Invalid ops\n");	\
15 			exit(0);	\
16 		}	\
17 	} while (0)
18 
19 int isst_set_platform_ops(int api_version)
20 {
21 	switch (api_version) {
22 	case 1:
23 		isst_ops = mbox_get_platform_ops();
24 		break;
25 	case 2:
26 	case 3:
27 		isst_ops = tpmi_get_platform_ops();
28 		break;
29 	default:
30 		isst_ops = NULL;
31 		break;
32 	}
33 
34 	if (!isst_ops)
35 		return -1;
36 	return 0;
37 }
38 
39 void isst_update_platform_param(enum isst_platform_param param, int value)
40 {
41 	CHECK_CB(update_platform_param);
42 
43 	isst_ops->update_platform_param(param, value);
44 }
45 
46 int isst_get_disp_freq_multiplier(void)
47 {
48 	CHECK_CB(get_disp_freq_multiplier);
49 	return isst_ops->get_disp_freq_multiplier();
50 }
51 
52 int isst_get_trl_max_levels(void)
53 {
54 	CHECK_CB(get_trl_max_levels);
55 	return isst_ops->get_trl_max_levels();
56 }
57 
58 char *isst_get_trl_level_name(int level)
59 {
60 	CHECK_CB(get_trl_level_name);
61 	return isst_ops->get_trl_level_name(level);
62 }
63 
64 int isst_is_punit_valid(struct isst_id *id)
65 {
66 	CHECK_CB(is_punit_valid);
67 	return isst_ops->is_punit_valid(id);
68 }
69 
70 int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
71 			  unsigned long long *req_resp)
72 {
73 	struct isst_if_msr_cmds msr_cmds;
74 	const char *pathname = "/dev/isst_interface";
75 	FILE *outf = get_output_file();
76 	int fd;
77 
78 	fd = open(pathname, O_RDWR);
79 	if (fd < 0)
80 		err(-1, "%s open failed", pathname);
81 
82 	msr_cmds.cmd_count = 1;
83 	msr_cmds.msr_cmd[0].logical_cpu = cpu;
84 	msr_cmds.msr_cmd[0].msr = msr;
85 	msr_cmds.msr_cmd[0].read_write = write;
86 	if (write)
87 		msr_cmds.msr_cmd[0].data = *req_resp;
88 
89 	if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
90 		perror("ISST_IF_MSR_COMMAND");
91 		fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
92 			cpu, msr, write);
93 	} else {
94 		if (!write)
95 			*req_resp = msr_cmds.msr_cmd[0].data;
96 
97 		debug_printf(
98 			"msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
99 			cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
100 	}
101 
102 	close(fd);
103 
104 	return 0;
105 }
106 
107 int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
108 {
109 	CHECK_CB(read_pm_config);
110 	return isst_ops->read_pm_config(id, cp_state, cp_cap);
111 }
112 
113 int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
114 {
115 	CHECK_CB(get_config_levels);
116 	return isst_ops->get_config_levels(id, pkg_dev);
117 }
118 
119 int isst_get_ctdp_control(struct isst_id *id, int config_index,
120 			  struct isst_pkg_ctdp_level_info *ctdp_level)
121 {
122 	CHECK_CB(get_ctdp_control);
123 	return isst_ops->get_ctdp_control(id, config_index, ctdp_level);
124 }
125 
126 int isst_get_tdp_info(struct isst_id *id, int config_index,
127 		      struct isst_pkg_ctdp_level_info *ctdp_level)
128 {
129 	CHECK_CB(get_tdp_info);
130 	return isst_ops->get_tdp_info(id, config_index, ctdp_level);
131 }
132 
133 int isst_get_pwr_info(struct isst_id *id, int config_index,
134 		      struct isst_pkg_ctdp_level_info *ctdp_level)
135 {
136 	CHECK_CB(get_pwr_info);
137 	return isst_ops->get_pwr_info(id, config_index, ctdp_level);
138 }
139 
140 int isst_get_coremask_info(struct isst_id *id, int config_index,
141 			   struct isst_pkg_ctdp_level_info *ctdp_level)
142 {
143 	CHECK_CB(get_coremask_info);
144 	return isst_ops->get_coremask_info(id, config_index, ctdp_level);
145 }
146 
147 int isst_get_get_trl_from_msr(struct isst_id *id, int *trl)
148 {
149 	unsigned long long msr_trl;
150 	int ret;
151 
152 	ret = isst_send_msr_command(id->cpu, 0x1AD, 0, &msr_trl);
153 	if (ret)
154 		return ret;
155 
156 	trl[0] = msr_trl & GENMASK(7, 0);
157 	trl[1] = (msr_trl & GENMASK(15, 8)) >> 8;
158 	trl[2] = (msr_trl & GENMASK(23, 16)) >> 16;
159 	trl[3] = (msr_trl & GENMASK(31, 24)) >> 24;
160 	trl[4] = (msr_trl & GENMASK(39, 32)) >> 32;
161 	trl[5] = (msr_trl & GENMASK(47, 40)) >> 40;
162 	trl[6] = (msr_trl & GENMASK(55, 48)) >> 48;
163 	trl[7] = (msr_trl & GENMASK(63, 56)) >> 56;
164 
165 	return 0;
166 }
167 
168 int isst_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl)
169 {
170 	CHECK_CB(get_get_trl);
171 	return isst_ops->get_get_trl(id, level, avx_level, trl);
172 }
173 
174 int isst_get_get_trls(struct isst_id *id, int level, struct isst_pkg_ctdp_level_info *ctdp_level)
175 {
176 	CHECK_CB(get_get_trls);
177 	return isst_ops->get_get_trls(id, level, ctdp_level);
178 }
179 
180 int isst_get_trl_bucket_info(struct isst_id *id, int level, unsigned long long *buckets_info)
181 {
182 	CHECK_CB(get_trl_bucket_info);
183 	return isst_ops->get_trl_bucket_info(id, level, buckets_info);
184 }
185 
186 int isst_set_tdp_level(struct isst_id *id, int tdp_level)
187 {
188 	CHECK_CB(set_tdp_level);
189 	return isst_ops->set_tdp_level(id, tdp_level);
190 }
191 
192 int isst_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info)
193 {
194 	struct isst_pkg_ctdp_level_info ctdp_level;
195 	struct isst_pkg_ctdp pkg_dev;
196 	int ret;
197 
198 	ret = isst_get_ctdp_levels(id, &pkg_dev);
199 	if (ret) {
200 		isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
201 		return ret;
202 	}
203 
204 	if (level > pkg_dev.levels) {
205 		isst_display_error_info_message(1, "Invalid level", 1, level);
206 		return -1;
207 	}
208 
209 	ret = isst_get_ctdp_control(id, level, &ctdp_level);
210 	if (ret)
211 		return ret;
212 
213 	if (!ctdp_level.pbf_support) {
214 		isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, level);
215 		return -1;
216 	}
217 
218 	pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
219 
220 	CHECK_CB(get_pbf_info);
221 	return isst_ops->get_pbf_info(id, level, pbf_info);
222 }
223 
224 int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
225 {
226 	CHECK_CB(set_pbf_fact_status);
227 	return isst_ops->set_pbf_fact_status(id, pbf, enable);
228 }
229 
230 
231 
232 int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info)
233 {
234 	struct isst_pkg_ctdp_level_info ctdp_level;
235 	struct isst_pkg_ctdp pkg_dev;
236 	int ret;
237 
238 	ret = isst_get_ctdp_levels(id, &pkg_dev);
239 	if (ret) {
240 		isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
241 		return ret;
242 	}
243 
244 	if (level > pkg_dev.levels) {
245 		isst_display_error_info_message(1, "Invalid level", 1, level);
246 		return -1;
247 	}
248 
249 	ret = isst_get_ctdp_control(id, level, &ctdp_level);
250 	if (ret)
251 		return ret;
252 
253 	if (!ctdp_level.fact_support) {
254 		isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, level);
255 		return -1;
256 	}
257 	CHECK_CB(get_fact_info);
258 	return isst_ops->get_fact_info(id, level, fact_bucket, fact_info);
259 }
260 
261 int isst_get_trl(struct isst_id *id, unsigned long long *trl)
262 {
263 	int ret;
264 
265 	ret = isst_send_msr_command(id->cpu, 0x1AD, 0, trl);
266 	if (ret)
267 		return ret;
268 
269 	return 0;
270 }
271 
272 int isst_set_trl(struct isst_id *id, unsigned long long trl)
273 {
274 	int ret;
275 
276 	if (!trl)
277 		trl = 0xFFFFFFFFFFFFFFFFULL;
278 
279 	ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &trl);
280 	if (ret)
281 		return ret;
282 
283 	return 0;
284 }
285 
286 int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl)
287 {
288 	unsigned long long msr_trl;
289 	int ret;
290 
291 	if (id->cpu < 0)
292 		return 0;
293 
294 	if (trl) {
295 		msr_trl = trl;
296 	} else {
297 		struct isst_pkg_ctdp pkg_dev;
298 		int trl[8];
299 		int i;
300 
301 		ret = isst_get_ctdp_levels(id, &pkg_dev);
302 		if (ret)
303 			return ret;
304 
305 		ret = isst_get_get_trl(id, pkg_dev.current_level, 0, trl);
306 		if (ret)
307 			return ret;
308 
309 		msr_trl = 0;
310 		for (i = 0; i < 8; ++i) {
311 			unsigned long long _trl = trl[i];
312 
313 			msr_trl |= (_trl << (i * 8));
314 		}
315 	}
316 	ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &msr_trl);
317 	if (ret)
318 		return ret;
319 
320 	return 0;
321 }
322 
323 /* Return 1 if locked */
324 int isst_get_config_tdp_lock_status(struct isst_id *id)
325 {
326 	unsigned long long tdp_control = 0;
327 	int ret;
328 
329 	ret = isst_send_msr_command(id->cpu, 0x64b, 0, &tdp_control);
330 	if (ret)
331 		return ret;
332 
333 	ret = !!(tdp_control & BIT(31));
334 
335 	return ret;
336 }
337 
338 void isst_get_process_ctdp_complete(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
339 {
340 	int i;
341 
342 	if (!pkg_dev->processed)
343 		return;
344 
345 	for (i = 0; i < pkg_dev->levels; ++i) {
346 		struct isst_pkg_ctdp_level_info *ctdp_level;
347 
348 		ctdp_level = &pkg_dev->ctdp_level[i];
349 		if (ctdp_level->pbf_support)
350 			free_cpu_set(ctdp_level->pbf_info.core_cpumask);
351 		free_cpu_set(ctdp_level->core_cpumask);
352 	}
353 }
354 
355 void isst_adjust_uncore_freq(struct isst_id *id, int config_index,
356 				struct isst_pkg_ctdp_level_info *ctdp_level)
357 {
358 	CHECK_CB(adjust_uncore_freq);
359 	return isst_ops->adjust_uncore_freq(id, config_index, ctdp_level);
360 }
361 
362 int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
363 {
364 	int i, ret, valid = 0;
365 
366 	if (pkg_dev->processed)
367 		return 0;
368 
369 	ret = isst_get_ctdp_levels(id, pkg_dev);
370 	if (ret)
371 		return ret;
372 
373 	debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n",
374 		     id->cpu, pkg_dev->enabled, pkg_dev->current_level,
375 		     pkg_dev->levels);
376 
377 	if (tdp_level != 0xff && tdp_level > pkg_dev->levels) {
378 		isst_display_error_info_message(1, "Invalid level", 0, 0);
379 		return -1;
380 	}
381 
382 	if (!pkg_dev->enabled)
383 		isst_display_error_info_message(0, "perf-profile feature is not supported, just base-config level 0 is valid", 0, 0);
384 
385 	for (i = 0; i <= pkg_dev->levels; ++i) {
386 		struct isst_pkg_ctdp_level_info *ctdp_level;
387 
388 		if (tdp_level != 0xff && i != tdp_level)
389 			continue;
390 
391 		debug_printf("cpu:%d Get Information for TDP level:%d\n", id->cpu,
392 			     i);
393 		ctdp_level = &pkg_dev->ctdp_level[i];
394 
395 		ctdp_level->level = i;
396 		ctdp_level->control_cpu = id->cpu;
397 		ctdp_level->pkg_id = id->pkg;
398 		ctdp_level->die_id = id->die;
399 
400 		ret = isst_get_ctdp_control(id, i, ctdp_level);
401 		if (ret)
402 			continue;
403 
404 		valid = 1;
405 		pkg_dev->processed = 1;
406 		ctdp_level->processed = 1;
407 
408 		if (ctdp_level->pbf_support) {
409 			ret = isst_get_pbf_info(id, i, &ctdp_level->pbf_info);
410 			if (!ret)
411 				ctdp_level->pbf_found = 1;
412 		}
413 
414 		if (ctdp_level->fact_support) {
415 			ret = isst_get_fact_info(id, i, 0xff,
416 						 &ctdp_level->fact_info);
417 			if (ret)
418 				return ret;
419 		}
420 
421 		if (!pkg_dev->enabled && is_skx_based_platform()) {
422 			int freq;
423 
424 			freq = get_cpufreq_base_freq(id->cpu);
425 			if (freq > 0) {
426 				ctdp_level->sse_p1 = freq / 100000;
427 				ctdp_level->tdp_ratio = ctdp_level->sse_p1;
428 			}
429 
430 			isst_get_get_trl_from_msr(id, ctdp_level->trl_ratios[0]);
431 			isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
432 			continue;
433 		}
434 
435 		ret = isst_get_tdp_info(id, i, ctdp_level);
436 		if (ret)
437 			return ret;
438 
439 		ret = isst_get_pwr_info(id, i, ctdp_level);
440 		if (ret)
441 			return ret;
442 
443 		ctdp_level->core_cpumask_size =
444 			alloc_cpu_set(&ctdp_level->core_cpumask);
445 		ret = isst_get_coremask_info(id, i, ctdp_level);
446 		if (ret)
447 			return ret;
448 
449 		ret = isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
450 		if (ret)
451 			return ret;
452 
453 		ret = isst_get_get_trls(id, i, ctdp_level);
454 		if (ret)
455 			return ret;
456 	}
457 
458 	if (!valid)
459 		isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, id->cpu);
460 
461 	return 0;
462 }
463 
464 int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type)
465 {
466 	CHECK_CB(get_clos_information);
467 	return isst_ops->get_clos_information(id, enable, type);
468 }
469 
470 int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type)
471 {
472 	CHECK_CB(pm_qos_config);
473 	return isst_ops->pm_qos_config(id, enable_clos, priority_type);
474 }
475 
476 int isst_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
477 {
478 	CHECK_CB(pm_get_clos);
479 	return isst_ops->pm_get_clos(id, clos, clos_config);
480 }
481 
482 int isst_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
483 {
484 	CHECK_CB(set_clos);
485 	return isst_ops->set_clos(id, clos, clos_config);
486 }
487 
488 int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id)
489 {
490 	CHECK_CB(clos_get_assoc_status);
491 	return isst_ops->clos_get_assoc_status(id, clos_id);
492 }
493 
494 int isst_clos_associate(struct isst_id *id, int clos_id)
495 {
496 	CHECK_CB(clos_associate);
497 	return isst_ops->clos_associate(id, clos_id);
498 
499 }
500