brintos

brintos / linux-shallow public Read only

0
0
Text · 11.6 KiB · e05561d Raw
506 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intel Speed Select -- Enumerate and control features4 * 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		100287 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}506