821 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			821 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * Intel Speed Select -- Enumerate and control features for TPMI Interface
 | 
						|
 * Copyright (c) 2022 Intel Corporation.
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/isst_if.h>
 | 
						|
#include "isst.h"
 | 
						|
 | 
						|
int tpmi_process_ioctl(int ioctl_no, void *info)
 | 
						|
{
 | 
						|
	const char *pathname = "/dev/isst_interface";
 | 
						|
	int fd;
 | 
						|
 | 
						|
	if (is_debug_enabled()) {
 | 
						|
		debug_printf("Issue IOCTL: ");
 | 
						|
		switch (ioctl_no) {
 | 
						|
		case ISST_IF_CORE_POWER_STATE:
 | 
						|
			debug_printf("ISST_IF_CORE_POWER_STATE\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_CLOS_PARAM:
 | 
						|
			debug_printf("ISST_IF_CLOS_PARAM\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_CLOS_ASSOC:
 | 
						|
			debug_printf("ISST_IF_CLOS_ASSOC\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_PERF_LEVELS:
 | 
						|
			debug_printf("ISST_IF_PERF_LEVELS\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_PERF_SET_LEVEL:
 | 
						|
			debug_printf("ISST_IF_PERF_SET_LEVEL\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_PERF_SET_FEATURE:
 | 
						|
			debug_printf("ISST_IF_PERF_SET_FEATURE\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_GET_PERF_LEVEL_INFO:
 | 
						|
			debug_printf("ISST_IF_GET_PERF_LEVEL_INFO\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_GET_PERF_LEVEL_CPU_MASK:
 | 
						|
			debug_printf("ISST_IF_GET_PERF_LEVEL_CPU_MASK\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_GET_BASE_FREQ_INFO:
 | 
						|
			debug_printf("ISST_IF_GET_BASE_FREQ_INFO\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_GET_BASE_FREQ_CPU_MASK:
 | 
						|
			debug_printf("ISST_IF_GET_BASE_FREQ_CPU_MASK\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_GET_TURBO_FREQ_INFO:
 | 
						|
			debug_printf("ISST_IF_GET_TURBO_FREQ_INFO\n");
 | 
						|
			break;
 | 
						|
		case ISST_IF_COUNT_TPMI_INSTANCES:
 | 
						|
			debug_printf("ISST_IF_COUNT_TPMI_INSTANCES\n");
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			debug_printf("%d\n", ioctl_no);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	fd = open(pathname, O_RDWR);
 | 
						|
	if (fd < 0)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	if (ioctl(fd, ioctl_no, info) == -1) {
 | 
						|
		debug_printf("IOCTL %d Failed\n", ioctl_no);
 | 
						|
		close(fd);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	close(fd);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_disp_freq_multiplier(void)
 | 
						|
{
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_trl_max_levels(void)
 | 
						|
{
 | 
						|
	return TRL_MAX_LEVELS;
 | 
						|
}
 | 
						|
 | 
						|
static char *tpmi_get_trl_level_name(int level)
 | 
						|
{
 | 
						|
	switch (level) {
 | 
						|
	case 0:
 | 
						|
		return "level-0";
 | 
						|
	case 1:
 | 
						|
		return "level-1";
 | 
						|
	case 2:
 | 
						|
		return "level-2";
 | 
						|
	case 3:
 | 
						|
		return "level-3";
 | 
						|
	case 4:
 | 
						|
		return "level-4";
 | 
						|
	case 5:
 | 
						|
		return "level-5";
 | 
						|
	case 6:
 | 
						|
		return "level-6";
 | 
						|
	case 7:
 | 
						|
		return "level-7";
 | 
						|
	default:
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void tpmi_update_platform_param(enum isst_platform_param param, int value)
 | 
						|
{
 | 
						|
	/* No params need to be updated for now */
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_is_punit_valid(struct isst_id *id)
 | 
						|
{
 | 
						|
	struct isst_tpmi_instance_count info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	if (id->punit < 0)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_COUNT_TPMI_INSTANCES, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (info.valid_mask & BIT(id->punit))
 | 
						|
		return 1;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
 | 
						|
{
 | 
						|
	struct isst_core_power info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.get_set = 0;
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	*cp_state = info.enable;
 | 
						|
	*cp_cap = info.supported;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int tpmi_get_config_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
 | 
						|
{
 | 
						|
	struct isst_perf_level_info info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_PERF_LEVELS, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	pkg_dev->version = info.feature_rev;
 | 
						|
	pkg_dev->levels = info.max_level;
 | 
						|
	pkg_dev->locked = info.locked;
 | 
						|
	pkg_dev->current_level = info.current_level;
 | 
						|
	pkg_dev->locked = info.locked;
 | 
						|
	pkg_dev->enabled = info.enabled;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_ctdp_control(struct isst_id *id, int config_index,
 | 
						|
				 struct isst_pkg_ctdp_level_info *ctdp_level)
 | 
						|
{
 | 
						|
	struct isst_core_power core_power_info;
 | 
						|
	struct isst_perf_level_info info;
 | 
						|
	int level_mask;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_PERF_LEVELS, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	if (config_index != 0xff)
 | 
						|
		level_mask = 1 << config_index;
 | 
						|
	else
 | 
						|
		level_mask = config_index;
 | 
						|
 | 
						|
	if (!(info.level_mask & level_mask))
 | 
						|
		return -1;
 | 
						|
 | 
						|
	if (api_version() > 2) {
 | 
						|
		ctdp_level->fact_support = info.sst_tf_support & BIT(config_index);
 | 
						|
		ctdp_level->pbf_support = info.sst_bf_support & BIT(config_index);
 | 
						|
	} else {
 | 
						|
		ctdp_level->fact_support = info.sst_tf_support;
 | 
						|
		ctdp_level->pbf_support = info.sst_bf_support;
 | 
						|
	}
 | 
						|
 | 
						|
	ctdp_level->fact_enabled = !!(info.feature_state & BIT(1));
 | 
						|
	ctdp_level->pbf_enabled = !!(info.feature_state & BIT(0));
 | 
						|
 | 
						|
	core_power_info.get_set = 0;
 | 
						|
	core_power_info.socket_id = id->pkg;
 | 
						|
	core_power_info.power_domain_id = id->punit;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &core_power_info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	ctdp_level->sst_cp_support = core_power_info.supported;
 | 
						|
	ctdp_level->sst_cp_enabled = core_power_info.enable;
 | 
						|
 | 
						|
	debug_printf
 | 
						|
	    ("cpu:%d CONFIG_TDP_GET_TDP_CONTROL fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
 | 
						|
	     id->cpu, ctdp_level->fact_support, ctdp_level->pbf_support,
 | 
						|
	     ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_tdp_info(struct isst_id *id, int config_index,
 | 
						|
			     struct isst_pkg_ctdp_level_info *ctdp_level)
 | 
						|
{
 | 
						|
	struct isst_perf_level_data_info info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = config_index;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	ctdp_level->pkg_tdp = info.thermal_design_power_w;
 | 
						|
	ctdp_level->tdp_ratio = info.tdp_ratio;
 | 
						|
	ctdp_level->sse_p1 = info.base_freq_mhz;
 | 
						|
	ctdp_level->avx2_p1 = info.base_freq_avx2_mhz;
 | 
						|
	ctdp_level->avx512_p1 = info.base_freq_avx512_mhz;
 | 
						|
	ctdp_level->amx_p1 = info.base_freq_amx_mhz;
 | 
						|
 | 
						|
	ctdp_level->t_proc_hot = info.tjunction_max_c;
 | 
						|
	ctdp_level->mem_freq = info.max_memory_freq_mhz;
 | 
						|
	ctdp_level->cooling_type = info.cooling_type;
 | 
						|
 | 
						|
	ctdp_level->uncore_p0 = info.p0_fabric_freq_mhz;
 | 
						|
	ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz;
 | 
						|
	ctdp_level->uncore_pm = info.pm_fabric_freq_mhz;
 | 
						|
 | 
						|
	debug_printf
 | 
						|
	    ("cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO tdp_ratio:%d pkg_tdp:%d ctdp_level->t_proc_hot:%d\n",
 | 
						|
	     id->cpu, config_index, ctdp_level->tdp_ratio, ctdp_level->pkg_tdp,
 | 
						|
	     ctdp_level->t_proc_hot);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_pwr_info(struct isst_id *id, int config_index,
 | 
						|
			     struct isst_pkg_ctdp_level_info *ctdp_level)
 | 
						|
{
 | 
						|
	/* TBD */
 | 
						|
	ctdp_level->pkg_max_power = 0;
 | 
						|
	ctdp_level->pkg_min_power = 0;
 | 
						|
 | 
						|
	debug_printf
 | 
						|
	    ("cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO pkg_max_power:%d pkg_min_power:%d\n",
 | 
						|
	     id->cpu, config_index, ctdp_level->pkg_max_power,
 | 
						|
	     ctdp_level->pkg_min_power);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int tpmi_get_coremask_info(struct isst_id *id, int config_index,
 | 
						|
			   struct isst_pkg_ctdp_level_info *ctdp_level)
 | 
						|
{
 | 
						|
	struct isst_perf_level_cpu_mask info;
 | 
						|
	int ret, cpu_count;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = config_index;
 | 
						|
	info.punit_cpu_map = 1;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_CPU_MASK, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	set_cpu_mask_from_punit_coremask(id, info.mask,
 | 
						|
					 ctdp_level->core_cpumask_size,
 | 
						|
					 ctdp_level->core_cpumask, &cpu_count);
 | 
						|
	ctdp_level->cpu_count = cpu_count;
 | 
						|
 | 
						|
	debug_printf("cpu:%d ctdp:%d core_mask ino cpu count:%d\n",
 | 
						|
		     id->cpu, config_index, ctdp_level->cpu_count);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_get_trls(struct isst_id *id, int config_index,
 | 
						|
			     struct isst_pkg_ctdp_level_info *ctdp_level)
 | 
						|
{
 | 
						|
	struct isst_perf_level_data_info info;
 | 
						|
	int ret, i, j;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = config_index;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	if (info.max_buckets > TRL_MAX_BUCKETS)
 | 
						|
		info.max_buckets = TRL_MAX_BUCKETS;
 | 
						|
 | 
						|
	if (info.max_trl_levels > TRL_MAX_LEVELS)
 | 
						|
		info.max_trl_levels = TRL_MAX_LEVELS;
 | 
						|
 | 
						|
	for (i = 0; i < info.max_trl_levels; ++i)
 | 
						|
		for (j = 0; j < info.max_buckets; ++j)
 | 
						|
			ctdp_level->trl_ratios[i][j] = info.trl_freq_mhz[i][j];
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_get_trl(struct isst_id *id, int level, int config_index,
 | 
						|
			    int *trl)
 | 
						|
{
 | 
						|
	struct isst_pkg_ctdp_level_info ctdp_level;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	ret = tpmi_get_get_trls(id, config_index, &ctdp_level);
 | 
						|
	if (ret)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	/* FIX ME: Just return for level 0 */
 | 
						|
	for (i = 0; i < 8; ++i)
 | 
						|
		trl[i] = ctdp_level.trl_ratios[0][i];
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_trl_bucket_info(struct isst_id *id, int config_index,
 | 
						|
				    unsigned long long *buckets_info)
 | 
						|
{
 | 
						|
	struct isst_perf_level_data_info info;
 | 
						|
	unsigned char *mask = (unsigned char *)buckets_info;
 | 
						|
	int ret, i;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = config_index;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	if (info.max_buckets > TRL_MAX_BUCKETS)
 | 
						|
		info.max_buckets = TRL_MAX_BUCKETS;
 | 
						|
 | 
						|
	for (i = 0; i < info.max_buckets; ++i)
 | 
						|
		mask[i] = info.bucket_core_counts[i];
 | 
						|
 | 
						|
	debug_printf("cpu:%d TRL bucket info: 0x%llx\n", id->cpu,
 | 
						|
		     *buckets_info);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_set_tdp_level(struct isst_id *id, int tdp_level)
 | 
						|
{
 | 
						|
	struct isst_perf_level_control info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = tdp_level;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_PERF_SET_LEVEL, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int _pbf_get_coremask_info(struct isst_id *id, int config_index,
 | 
						|
				  struct isst_pbf_info *pbf_info)
 | 
						|
{
 | 
						|
	struct isst_perf_level_cpu_mask info;
 | 
						|
	int ret, cpu_count;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = config_index;
 | 
						|
	info.punit_cpu_map = 1;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_BASE_FREQ_CPU_MASK, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	set_cpu_mask_from_punit_coremask(id, info.mask,
 | 
						|
					 pbf_info->core_cpumask_size,
 | 
						|
					 pbf_info->core_cpumask, &cpu_count);
 | 
						|
 | 
						|
	debug_printf("cpu:%d ctdp:%d pbf core_mask info cpu count:%d\n",
 | 
						|
		     id->cpu, config_index, cpu_count);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_pbf_info(struct isst_id *id, int level,
 | 
						|
			     struct isst_pbf_info *pbf_info)
 | 
						|
{
 | 
						|
	struct isst_base_freq_info info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = level;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_BASE_FREQ_INFO, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	pbf_info->p1_low = info.low_base_freq_mhz;
 | 
						|
	pbf_info->p1_high = info.high_base_freq_mhz;
 | 
						|
	pbf_info->tdp = info.thermal_design_power_w;
 | 
						|
	pbf_info->t_prochot = info.tjunction_max_c;
 | 
						|
 | 
						|
	debug_printf("cpu:%d ctdp:%d pbf info:%d:%d:%d:%d\n",
 | 
						|
		     id->cpu, level, pbf_info->p1_low, pbf_info->p1_high,
 | 
						|
		     pbf_info->tdp, pbf_info->t_prochot);
 | 
						|
 | 
						|
	return _pbf_get_coremask_info(id, level, pbf_info);
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
 | 
						|
{
 | 
						|
	struct isst_pkg_ctdp pkg_dev;
 | 
						|
	struct isst_pkg_ctdp_level_info ctdp_level;
 | 
						|
	int current_level;
 | 
						|
	struct isst_perf_feature_control info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = isst_get_ctdp_levels(id, &pkg_dev);
 | 
						|
	if (ret)
 | 
						|
		debug_printf("cpu:%d No support for dynamic ISST\n", id->cpu);
 | 
						|
 | 
						|
	current_level = pkg_dev.current_level;
 | 
						|
 | 
						|
	ret = isst_get_ctdp_control(id, current_level, &ctdp_level);
 | 
						|
	if (ret)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
 | 
						|
	info.feature = 0;
 | 
						|
 | 
						|
	if (pbf) {
 | 
						|
		if (ctdp_level.fact_enabled)
 | 
						|
			info.feature |= BIT(1);
 | 
						|
 | 
						|
		if (enable)
 | 
						|
			info.feature |= BIT(0);
 | 
						|
		else
 | 
						|
			info.feature &= ~BIT(0);
 | 
						|
	} else {
 | 
						|
 | 
						|
		if (enable && !ctdp_level.sst_cp_enabled)
 | 
						|
			isst_display_error_info_message(0,
 | 
						|
							"Make sure to execute before: core-power enable",
 | 
						|
							0, 0);
 | 
						|
 | 
						|
		if (ctdp_level.pbf_enabled)
 | 
						|
			info.feature |= BIT(0);
 | 
						|
 | 
						|
		if (enable)
 | 
						|
			info.feature |= BIT(1);
 | 
						|
		else
 | 
						|
			info.feature &= ~BIT(1);
 | 
						|
	}
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_PERF_SET_FEATURE, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_fact_info(struct isst_id *id, int level, int fact_bucket,
 | 
						|
			      struct isst_fact_info *fact_info)
 | 
						|
{
 | 
						|
	struct isst_turbo_freq_info info;
 | 
						|
	int i, j;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = level;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_TURBO_FREQ_INFO, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	for (i = 0; i < info.max_clip_freqs; ++i)
 | 
						|
		fact_info->lp_ratios[i] = info.lp_clip_freq_mhz[i];
 | 
						|
 | 
						|
	if (info.max_buckets > TRL_MAX_BUCKETS)
 | 
						|
		info.max_buckets = TRL_MAX_BUCKETS;
 | 
						|
 | 
						|
	if (info.max_trl_levels > TRL_MAX_LEVELS)
 | 
						|
		info.max_trl_levels = TRL_MAX_LEVELS;
 | 
						|
 | 
						|
	for (i = 0; i < info.max_trl_levels; ++i) {
 | 
						|
		for (j = 0; j < info.max_buckets; ++j)
 | 
						|
			fact_info->bucket_info[j].hp_ratios[i] =
 | 
						|
			    info.trl_freq_mhz[i][j];
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < info.max_buckets; ++i)
 | 
						|
		fact_info->bucket_info[i].hp_cores = info.bucket_core_counts[i];
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void _set_uncore_min_max(struct isst_id *id, int max, int freq)
 | 
						|
{
 | 
						|
	DIR *dir;
 | 
						|
	FILE *filep;
 | 
						|
	struct dirent *entry;
 | 
						|
	char buffer[512];
 | 
						|
	unsigned int tmp_id;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	dir = opendir("/sys/devices/system/cpu/intel_uncore_frequency/");
 | 
						|
	if (!dir)
 | 
						|
		return;
 | 
						|
 | 
						|
	while ((entry = readdir(dir)) != NULL ) {
 | 
						|
		/* Check domain_id */
 | 
						|
		snprintf(buffer, sizeof(buffer),
 | 
						|
			 "/sys/devices/system/cpu/intel_uncore_frequency/%s/domain_id", entry->d_name);
 | 
						|
 | 
						|
		filep = fopen(buffer, "r");
 | 
						|
		if (!filep)
 | 
						|
			goto end;
 | 
						|
 | 
						|
		ret = fscanf(filep, "%u", &tmp_id);
 | 
						|
		fclose(filep);
 | 
						|
		if (ret != 1)
 | 
						|
			goto end;
 | 
						|
 | 
						|
		if (tmp_id != id->punit)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Check package_id */
 | 
						|
		snprintf(buffer, sizeof(buffer),
 | 
						|
			 "/sys/devices/system/cpu/intel_uncore_frequency/%s/package_id", entry->d_name);
 | 
						|
 | 
						|
		filep = fopen(buffer, "r");
 | 
						|
		if (!filep)
 | 
						|
			goto end;
 | 
						|
 | 
						|
		ret = fscanf(filep, "%u", &tmp_id);
 | 
						|
		fclose(filep);
 | 
						|
 | 
						|
		if (ret != 1)
 | 
						|
			goto end;
 | 
						|
 | 
						|
		if (tmp_id != id->pkg)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Found the right sysfs path, adjust and quit */
 | 
						|
		if (max)
 | 
						|
			snprintf(buffer, sizeof(buffer),
 | 
						|
				 "/sys/devices/system/cpu/intel_uncore_frequency/%s/max_freq_khz", entry->d_name);
 | 
						|
		 else
 | 
						|
			snprintf(buffer, sizeof(buffer),
 | 
						|
				 "/sys/devices/system/cpu/intel_uncore_frequency/%s/min_freq_khz", entry->d_name);
 | 
						|
 | 
						|
		filep = fopen(buffer, "w");
 | 
						|
		if (!filep)
 | 
						|
			goto end;
 | 
						|
 | 
						|
		fprintf(filep, "%d\n", freq);
 | 
						|
		fclose(filep);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
end:
 | 
						|
	closedir(dir);
 | 
						|
}
 | 
						|
 | 
						|
static void tpmi_adjust_uncore_freq(struct isst_id *id, int config_index,
 | 
						|
				struct isst_pkg_ctdp_level_info *ctdp_level)
 | 
						|
{
 | 
						|
	struct isst_perf_level_data_info info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.level = config_index;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return;
 | 
						|
 | 
						|
	ctdp_level->uncore_p0 = info.p0_fabric_freq_mhz;
 | 
						|
	ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz;
 | 
						|
	ctdp_level->uncore_pm = info.pm_fabric_freq_mhz;
 | 
						|
 | 
						|
	if (ctdp_level->uncore_pm)
 | 
						|
		_set_uncore_min_max(id, 0, ctdp_level->uncore_pm * 100000);
 | 
						|
 | 
						|
	if (ctdp_level->uncore_p0)
 | 
						|
		_set_uncore_min_max(id, 1, ctdp_level->uncore_p0 * 100000);
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_get_clos_information(struct isst_id *id, int *enable, int *type)
 | 
						|
{
 | 
						|
	struct isst_core_power info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.get_set = 0;
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	*enable = info.enable;
 | 
						|
	*type = info.priority_type;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos,
 | 
						|
			      int priority_type)
 | 
						|
{
 | 
						|
	struct isst_core_power info;
 | 
						|
	int i, ret, saved_punit;
 | 
						|
 | 
						|
	info.get_set = 1;
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.enable = enable_clos;
 | 
						|
	info.priority_type = priority_type;
 | 
						|
 | 
						|
	saved_punit = id->punit;
 | 
						|
 | 
						|
	/* Set for all other dies also. This is per package setting */
 | 
						|
	for (i = 0; i < MAX_PUNIT_PER_DIE; i++) {
 | 
						|
		id->punit = i;
 | 
						|
		if (isst_is_punit_valid(id)) {
 | 
						|
			info.power_domain_id = i;
 | 
						|
			ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
 | 
						|
			if (ret == -1) {
 | 
						|
				id->punit = saved_punit;
 | 
						|
				return ret;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	id->punit = saved_punit;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int tpmi_pm_get_clos(struct isst_id *id, int clos,
 | 
						|
		     struct isst_clos_config *clos_config)
 | 
						|
{
 | 
						|
	struct isst_clos_param info;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	info.get_set = 0;
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.clos = clos;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_CLOS_PARAM, &info);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	clos_config->epp = 0;
 | 
						|
	clos_config->clos_prop_prio = info.prop_prio;
 | 
						|
	clos_config->clos_min = info.min_freq_mhz;
 | 
						|
	clos_config->clos_max = info.max_freq_mhz;
 | 
						|
	clos_config->clos_desired = 0;
 | 
						|
 | 
						|
	debug_printf("cpu:%d clos:%d min:%d max:%d\n", id->cpu, clos,
 | 
						|
		     clos_config->clos_min, clos_config->clos_max);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int tpmi_set_clos(struct isst_id *id, int clos,
 | 
						|
		  struct isst_clos_config *clos_config)
 | 
						|
{
 | 
						|
	struct isst_clos_param info;
 | 
						|
	int i, ret, saved_punit;
 | 
						|
 | 
						|
	info.get_set = 1;
 | 
						|
	info.socket_id = id->pkg;
 | 
						|
	info.power_domain_id = id->punit;
 | 
						|
	info.clos = clos;
 | 
						|
	info.prop_prio = clos_config->clos_prop_prio;
 | 
						|
 | 
						|
	info.min_freq_mhz = clos_config->clos_min;
 | 
						|
	info.max_freq_mhz = clos_config->clos_max;
 | 
						|
 | 
						|
	if (info.min_freq_mhz <= 0xff)
 | 
						|
		info.min_freq_mhz *= 100;
 | 
						|
	if (info.max_freq_mhz <= 0xff)
 | 
						|
		info.max_freq_mhz *= 100;
 | 
						|
 | 
						|
	saved_punit = id->punit;
 | 
						|
 | 
						|
	/* Set for all other dies also. This is per package setting */
 | 
						|
	for (i = 0; i < MAX_PUNIT_PER_DIE; i++) {
 | 
						|
		id->punit = i;
 | 
						|
		if (isst_is_punit_valid(id)) {
 | 
						|
			info.power_domain_id = i;
 | 
						|
			ret = tpmi_process_ioctl(ISST_IF_CLOS_PARAM, &info);
 | 
						|
			if (ret == -1) {
 | 
						|
				id->punit = saved_punit;
 | 
						|
				return ret;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	id->punit = saved_punit;
 | 
						|
 | 
						|
	debug_printf("set cpu:%d clos:%d min:%d max:%d\n", id->cpu, clos,
 | 
						|
		     clos_config->clos_min, clos_config->clos_max);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_clos_get_assoc_status(struct isst_id *id, int *clos_id)
 | 
						|
{
 | 
						|
	struct isst_if_clos_assoc_cmds assoc_cmds;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	assoc_cmds.cmd_count = 1;
 | 
						|
	assoc_cmds.get_set = 0;
 | 
						|
	assoc_cmds.punit_cpu_map = 1;
 | 
						|
	assoc_cmds.assoc_info[0].logical_cpu = find_phy_core_num(id->cpu);
 | 
						|
	assoc_cmds.assoc_info[0].socket_id = id->pkg;
 | 
						|
	assoc_cmds.assoc_info[0].power_domain_id = id->punit;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_CLOS_ASSOC, &assoc_cmds);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	*clos_id = assoc_cmds.assoc_info[0].clos;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tpmi_clos_associate(struct isst_id *id, int clos_id)
 | 
						|
{
 | 
						|
	struct isst_if_clos_assoc_cmds assoc_cmds;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	assoc_cmds.cmd_count = 1;
 | 
						|
	assoc_cmds.get_set = 1;
 | 
						|
	assoc_cmds.punit_cpu_map = 1;
 | 
						|
	assoc_cmds.assoc_info[0].logical_cpu = find_phy_core_num(id->cpu);
 | 
						|
	assoc_cmds.assoc_info[0].clos = clos_id;
 | 
						|
	assoc_cmds.assoc_info[0].socket_id = id->pkg;
 | 
						|
	assoc_cmds.assoc_info[0].power_domain_id = id->punit;
 | 
						|
 | 
						|
	ret = tpmi_process_ioctl(ISST_IF_CLOS_ASSOC, &assoc_cmds);
 | 
						|
	if (ret == -1)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static struct isst_platform_ops tpmi_ops = {
 | 
						|
	.get_disp_freq_multiplier = tpmi_get_disp_freq_multiplier,
 | 
						|
	.get_trl_max_levels = tpmi_get_trl_max_levels,
 | 
						|
	.get_trl_level_name = tpmi_get_trl_level_name,
 | 
						|
	.update_platform_param = tpmi_update_platform_param,
 | 
						|
	.is_punit_valid = tpmi_is_punit_valid,
 | 
						|
	.read_pm_config = tpmi_read_pm_config,
 | 
						|
	.get_config_levels = tpmi_get_config_levels,
 | 
						|
	.get_ctdp_control = tpmi_get_ctdp_control,
 | 
						|
	.get_tdp_info = tpmi_get_tdp_info,
 | 
						|
	.get_pwr_info = tpmi_get_pwr_info,
 | 
						|
	.get_coremask_info = tpmi_get_coremask_info,
 | 
						|
	.get_get_trl = tpmi_get_get_trl,
 | 
						|
	.get_get_trls = tpmi_get_get_trls,
 | 
						|
	.get_trl_bucket_info = tpmi_get_trl_bucket_info,
 | 
						|
	.set_tdp_level = tpmi_set_tdp_level,
 | 
						|
	.get_pbf_info = tpmi_get_pbf_info,
 | 
						|
	.set_pbf_fact_status = tpmi_set_pbf_fact_status,
 | 
						|
	.get_fact_info = tpmi_get_fact_info,
 | 
						|
	.adjust_uncore_freq = tpmi_adjust_uncore_freq,
 | 
						|
	.get_clos_information = tpmi_get_clos_information,
 | 
						|
	.pm_qos_config = tpmi_pm_qos_config,
 | 
						|
	.pm_get_clos = tpmi_pm_get_clos,
 | 
						|
	.set_clos = tpmi_set_clos,
 | 
						|
	.clos_get_assoc_status = tpmi_clos_get_assoc_status,
 | 
						|
	.clos_associate = tpmi_clos_associate,
 | 
						|
};
 | 
						|
 | 
						|
struct isst_platform_ops *tpmi_get_platform_ops(void)
 | 
						|
{
 | 
						|
	return &tpmi_ops;
 | 
						|
}
 |