| // 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; |
| } |