File Index
Files and directories
Sign in
FILE

isst-core.c

File preview with syntax highlighting.

linux-6.19.14/tools/power/x86/intel-speed-select/isst-core.c C
  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
  9static 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
 19int 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
 39void 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
 46int isst_get_disp_freq_multiplier(void)
 47{
 48	CHECK_CB(get_disp_freq_multiplier);
 49	return isst_ops->get_disp_freq_multiplier();
 50}
 51
 52int isst_get_trl_max_levels(void)
 53{
 54	CHECK_CB(get_trl_max_levels);
 55	return isst_ops->get_trl_max_levels();
 56}
 57
 58char *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
 64int 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
 70int 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
107int 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
113int 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
119int 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
126int 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
133int 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
140int 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
147int 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
168int 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
174int 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
180int 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
186int 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
192int 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
224int 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
232int 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
261int 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
272int 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#define MSR_TRL_FREQ_MULTIPLIER		100
287
288int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl)
289{
290	unsigned long long msr_trl;
291	int ret;
292
293	if (id->cpu < 0)
294		return 0;
295
296	if (trl) {
297		msr_trl = trl;
298	} else {
299		struct isst_pkg_ctdp pkg_dev;
300		int trl[8];
301		int i;
302
303		ret = isst_get_ctdp_levels(id, &pkg_dev);
304		if (ret)
305			return ret;
306
307		ret = isst_get_get_trl(id, pkg_dev.current_level, 0, trl);
308		if (ret)
309			return ret;
310
311		msr_trl = 0;
312		for (i = 0; i < 8; ++i) {
313			unsigned long long _trl = trl[i];
314
315			/* MSR is always in 100 MHz unit */
316			if (isst_get_disp_freq_multiplier() == 1)
317				_trl /= MSR_TRL_FREQ_MULTIPLIER;
318
319			msr_trl |= (_trl << (i * 8));
320		}
321	}
322	ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &msr_trl);
323	if (ret)
324		return ret;
325
326	return 0;
327}
328
329/* Return 1 if locked */
330int isst_get_config_tdp_lock_status(struct isst_id *id)
331{
332	unsigned long long tdp_control = 0;
333	int ret;
334
335	ret = isst_send_msr_command(id->cpu, 0x64b, 0, &tdp_control);
336	if (ret)
337		return ret;
338
339	ret = !!(tdp_control & BIT(31));
340
341	return ret;
342}
343
344void isst_get_process_ctdp_complete(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
345{
346	int i;
347
348	if (!pkg_dev->processed)
349		return;
350
351	for (i = 0; i < pkg_dev->levels; ++i) {
352		struct isst_pkg_ctdp_level_info *ctdp_level;
353
354		ctdp_level = &pkg_dev->ctdp_level[i];
355		if (ctdp_level->pbf_support)
356			free_cpu_set(ctdp_level->pbf_info.core_cpumask);
357		free_cpu_set(ctdp_level->core_cpumask);
358	}
359}
360
361void isst_adjust_uncore_freq(struct isst_id *id, int config_index,
362				struct isst_pkg_ctdp_level_info *ctdp_level)
363{
364	CHECK_CB(adjust_uncore_freq);
365	return isst_ops->adjust_uncore_freq(id, config_index, ctdp_level);
366}
367
368int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
369{
370	int i, ret, valid = 0;
371
372	if (pkg_dev->processed)
373		return 0;
374
375	ret = isst_get_ctdp_levels(id, pkg_dev);
376	if (ret)
377		return ret;
378
379	debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n",
380		     id->cpu, pkg_dev->enabled, pkg_dev->current_level,
381		     pkg_dev->levels);
382
383	if (tdp_level != 0xff && tdp_level > pkg_dev->levels) {
384		isst_display_error_info_message(1, "Invalid level", 0, 0);
385		return -1;
386	}
387
388	if (!pkg_dev->enabled)
389		isst_display_error_info_message(0, "perf-profile feature is not supported, just base-config level 0 is valid", 0, 0);
390
391	for (i = 0; i <= pkg_dev->levels; ++i) {
392		struct isst_pkg_ctdp_level_info *ctdp_level;
393
394		if (tdp_level != 0xff && i != tdp_level)
395			continue;
396
397		debug_printf("cpu:%d Get Information for TDP level:%d\n", id->cpu,
398			     i);
399		ctdp_level = &pkg_dev->ctdp_level[i];
400
401		ctdp_level->level = i;
402		ctdp_level->control_cpu = id->cpu;
403		ctdp_level->pkg_id = id->pkg;
404		ctdp_level->die_id = id->die;
405
406		ret = isst_get_ctdp_control(id, i, ctdp_level);
407		if (ret)
408			continue;
409
410		valid = 1;
411		pkg_dev->processed = 1;
412		ctdp_level->processed = 1;
413
414		if (ctdp_level->pbf_support) {
415			ret = isst_get_pbf_info(id, i, &ctdp_level->pbf_info);
416			if (!ret)
417				ctdp_level->pbf_found = 1;
418		}
419
420		if (ctdp_level->fact_support) {
421			ret = isst_get_fact_info(id, i, 0xff,
422						 &ctdp_level->fact_info);
423			if (ret)
424				return ret;
425		}
426
427		if (!pkg_dev->enabled && is_skx_based_platform()) {
428			int freq;
429
430			freq = get_cpufreq_base_freq(id->cpu);
431			if (freq > 0) {
432				ctdp_level->sse_p1 = freq / 100000;
433				ctdp_level->tdp_ratio = ctdp_level->sse_p1;
434			}
435
436			isst_get_get_trl_from_msr(id, ctdp_level->trl_ratios[0]);
437			isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
438			continue;
439		}
440
441		ret = isst_get_tdp_info(id, i, ctdp_level);
442		if (ret)
443			return ret;
444
445		ret = isst_get_pwr_info(id, i, ctdp_level);
446		if (ret)
447			return ret;
448
449		ctdp_level->core_cpumask_size =
450			alloc_cpu_set(&ctdp_level->core_cpumask);
451		ret = isst_get_coremask_info(id, i, ctdp_level);
452		if (ret)
453			return ret;
454
455		ret = isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
456		if (ret)
457			return ret;
458
459		ret = isst_get_get_trls(id, i, ctdp_level);
460		if (ret)
461			return ret;
462	}
463
464	if (!valid)
465		isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, id->cpu);
466
467	return 0;
468}
469
470int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type)
471{
472	CHECK_CB(get_clos_information);
473	return isst_ops->get_clos_information(id, enable, type);
474}
475
476int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type)
477{
478	CHECK_CB(pm_qos_config);
479	return isst_ops->pm_qos_config(id, enable_clos, priority_type);
480}
481
482int isst_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
483{
484	CHECK_CB(pm_get_clos);
485	return isst_ops->pm_get_clos(id, clos, clos_config);
486}
487
488int isst_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
489{
490	CHECK_CB(set_clos);
491	return isst_ops->set_clos(id, clos, clos_config);
492}
493
494int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id)
495{
496	CHECK_CB(clos_get_assoc_status);
497	return isst_ops->clos_get_assoc_status(id, clos_id);
498}
499
500int isst_clos_associate(struct isst_id *id, int clos_id)
501{
502	CHECK_CB(clos_associate);
503	return isst_ops->clos_associate(id, clos_id);
504
505}
~/ Read-only file preview.