Path: blob/master/tools/power/x86/intel-speed-select/isst-core.c
26295 views
// SPDX-License-Identifier: GPL-2.01/*2* Intel Speed Select -- Enumerate and control features3* Copyright (c) 2019 Intel Corporation.4*/56#include "isst.h"78static struct isst_platform_ops *isst_ops;910#define CHECK_CB(_name) \11do { \12if (!isst_ops || !isst_ops->_name) { \13fprintf(stderr, "Invalid ops\n"); \14exit(0); \15} \16} while (0)1718int isst_set_platform_ops(int api_version)19{20switch (api_version) {21case 1:22isst_ops = mbox_get_platform_ops();23break;24case 2:25case 3:26isst_ops = tpmi_get_platform_ops();27break;28default:29isst_ops = NULL;30break;31}3233if (!isst_ops)34return -1;35return 0;36}3738void isst_update_platform_param(enum isst_platform_param param, int value)39{40CHECK_CB(update_platform_param);4142isst_ops->update_platform_param(param, value);43}4445int isst_get_disp_freq_multiplier(void)46{47CHECK_CB(get_disp_freq_multiplier);48return isst_ops->get_disp_freq_multiplier();49}5051int isst_get_trl_max_levels(void)52{53CHECK_CB(get_trl_max_levels);54return isst_ops->get_trl_max_levels();55}5657char *isst_get_trl_level_name(int level)58{59CHECK_CB(get_trl_level_name);60return isst_ops->get_trl_level_name(level);61}6263int isst_is_punit_valid(struct isst_id *id)64{65CHECK_CB(is_punit_valid);66return isst_ops->is_punit_valid(id);67}6869int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,70unsigned long long *req_resp)71{72struct isst_if_msr_cmds msr_cmds;73const char *pathname = "/dev/isst_interface";74FILE *outf = get_output_file();75int fd;7677fd = open(pathname, O_RDWR);78if (fd < 0)79err(-1, "%s open failed", pathname);8081msr_cmds.cmd_count = 1;82msr_cmds.msr_cmd[0].logical_cpu = cpu;83msr_cmds.msr_cmd[0].msr = msr;84msr_cmds.msr_cmd[0].read_write = write;85if (write)86msr_cmds.msr_cmd[0].data = *req_resp;8788if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {89perror("ISST_IF_MSR_COMMAND");90fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",91cpu, msr, write);92} else {93if (!write)94*req_resp = msr_cmds.msr_cmd[0].data;9596debug_printf(97"msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",98cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);99}100101close(fd);102103return 0;104}105106int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)107{108CHECK_CB(read_pm_config);109return isst_ops->read_pm_config(id, cp_state, cp_cap);110}111112int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)113{114CHECK_CB(get_config_levels);115return isst_ops->get_config_levels(id, pkg_dev);116}117118int isst_get_ctdp_control(struct isst_id *id, int config_index,119struct isst_pkg_ctdp_level_info *ctdp_level)120{121CHECK_CB(get_ctdp_control);122return isst_ops->get_ctdp_control(id, config_index, ctdp_level);123}124125int isst_get_tdp_info(struct isst_id *id, int config_index,126struct isst_pkg_ctdp_level_info *ctdp_level)127{128CHECK_CB(get_tdp_info);129return isst_ops->get_tdp_info(id, config_index, ctdp_level);130}131132int isst_get_pwr_info(struct isst_id *id, int config_index,133struct isst_pkg_ctdp_level_info *ctdp_level)134{135CHECK_CB(get_pwr_info);136return isst_ops->get_pwr_info(id, config_index, ctdp_level);137}138139int isst_get_coremask_info(struct isst_id *id, int config_index,140struct isst_pkg_ctdp_level_info *ctdp_level)141{142CHECK_CB(get_coremask_info);143return isst_ops->get_coremask_info(id, config_index, ctdp_level);144}145146int isst_get_get_trl_from_msr(struct isst_id *id, int *trl)147{148unsigned long long msr_trl;149int ret;150151ret = isst_send_msr_command(id->cpu, 0x1AD, 0, &msr_trl);152if (ret)153return ret;154155trl[0] = msr_trl & GENMASK(7, 0);156trl[1] = (msr_trl & GENMASK(15, 8)) >> 8;157trl[2] = (msr_trl & GENMASK(23, 16)) >> 16;158trl[3] = (msr_trl & GENMASK(31, 24)) >> 24;159trl[4] = (msr_trl & GENMASK(39, 32)) >> 32;160trl[5] = (msr_trl & GENMASK(47, 40)) >> 40;161trl[6] = (msr_trl & GENMASK(55, 48)) >> 48;162trl[7] = (msr_trl & GENMASK(63, 56)) >> 56;163164return 0;165}166167int isst_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl)168{169CHECK_CB(get_get_trl);170return isst_ops->get_get_trl(id, level, avx_level, trl);171}172173int isst_get_get_trls(struct isst_id *id, int level, struct isst_pkg_ctdp_level_info *ctdp_level)174{175CHECK_CB(get_get_trls);176return isst_ops->get_get_trls(id, level, ctdp_level);177}178179int isst_get_trl_bucket_info(struct isst_id *id, int level, unsigned long long *buckets_info)180{181CHECK_CB(get_trl_bucket_info);182return isst_ops->get_trl_bucket_info(id, level, buckets_info);183}184185int isst_set_tdp_level(struct isst_id *id, int tdp_level)186{187CHECK_CB(set_tdp_level);188return isst_ops->set_tdp_level(id, tdp_level);189}190191int isst_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info)192{193struct isst_pkg_ctdp_level_info ctdp_level;194struct isst_pkg_ctdp pkg_dev;195int ret;196197ret = isst_get_ctdp_levels(id, &pkg_dev);198if (ret) {199isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);200return ret;201}202203if (level > pkg_dev.levels) {204isst_display_error_info_message(1, "Invalid level", 1, level);205return -1;206}207208ret = isst_get_ctdp_control(id, level, &ctdp_level);209if (ret)210return ret;211212if (!ctdp_level.pbf_support) {213isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, level);214return -1;215}216217pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);218219CHECK_CB(get_pbf_info);220return isst_ops->get_pbf_info(id, level, pbf_info);221}222223int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)224{225CHECK_CB(set_pbf_fact_status);226return isst_ops->set_pbf_fact_status(id, pbf, enable);227}228229230231int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info)232{233struct isst_pkg_ctdp_level_info ctdp_level;234struct isst_pkg_ctdp pkg_dev;235int ret;236237ret = isst_get_ctdp_levels(id, &pkg_dev);238if (ret) {239isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);240return ret;241}242243if (level > pkg_dev.levels) {244isst_display_error_info_message(1, "Invalid level", 1, level);245return -1;246}247248ret = isst_get_ctdp_control(id, level, &ctdp_level);249if (ret)250return ret;251252if (!ctdp_level.fact_support) {253isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, level);254return -1;255}256CHECK_CB(get_fact_info);257return isst_ops->get_fact_info(id, level, fact_bucket, fact_info);258}259260int isst_get_trl(struct isst_id *id, unsigned long long *trl)261{262int ret;263264ret = isst_send_msr_command(id->cpu, 0x1AD, 0, trl);265if (ret)266return ret;267268return 0;269}270271int isst_set_trl(struct isst_id *id, unsigned long long trl)272{273int ret;274275if (!trl)276trl = 0xFFFFFFFFFFFFFFFFULL;277278ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &trl);279if (ret)280return ret;281282return 0;283}284285#define MSR_TRL_FREQ_MULTIPLIER 100286287int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl)288{289unsigned long long msr_trl;290int ret;291292if (id->cpu < 0)293return 0;294295if (trl) {296msr_trl = trl;297} else {298struct isst_pkg_ctdp pkg_dev;299int trl[8];300int i;301302ret = isst_get_ctdp_levels(id, &pkg_dev);303if (ret)304return ret;305306ret = isst_get_get_trl(id, pkg_dev.current_level, 0, trl);307if (ret)308return ret;309310msr_trl = 0;311for (i = 0; i < 8; ++i) {312unsigned long long _trl = trl[i];313314/* MSR is always in 100 MHz unit */315if (isst_get_disp_freq_multiplier() == 1)316_trl /= MSR_TRL_FREQ_MULTIPLIER;317318msr_trl |= (_trl << (i * 8));319}320}321ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &msr_trl);322if (ret)323return ret;324325return 0;326}327328/* Return 1 if locked */329int isst_get_config_tdp_lock_status(struct isst_id *id)330{331unsigned long long tdp_control = 0;332int ret;333334ret = isst_send_msr_command(id->cpu, 0x64b, 0, &tdp_control);335if (ret)336return ret;337338ret = !!(tdp_control & BIT(31));339340return ret;341}342343void isst_get_process_ctdp_complete(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)344{345int i;346347if (!pkg_dev->processed)348return;349350for (i = 0; i < pkg_dev->levels; ++i) {351struct isst_pkg_ctdp_level_info *ctdp_level;352353ctdp_level = &pkg_dev->ctdp_level[i];354if (ctdp_level->pbf_support)355free_cpu_set(ctdp_level->pbf_info.core_cpumask);356free_cpu_set(ctdp_level->core_cpumask);357}358}359360void isst_adjust_uncore_freq(struct isst_id *id, int config_index,361struct isst_pkg_ctdp_level_info *ctdp_level)362{363CHECK_CB(adjust_uncore_freq);364return isst_ops->adjust_uncore_freq(id, config_index, ctdp_level);365}366367int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev)368{369int i, ret, valid = 0;370371if (pkg_dev->processed)372return 0;373374ret = isst_get_ctdp_levels(id, pkg_dev);375if (ret)376return ret;377378debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n",379id->cpu, pkg_dev->enabled, pkg_dev->current_level,380pkg_dev->levels);381382if (tdp_level != 0xff && tdp_level > pkg_dev->levels) {383isst_display_error_info_message(1, "Invalid level", 0, 0);384return -1;385}386387if (!pkg_dev->enabled)388isst_display_error_info_message(0, "perf-profile feature is not supported, just base-config level 0 is valid", 0, 0);389390for (i = 0; i <= pkg_dev->levels; ++i) {391struct isst_pkg_ctdp_level_info *ctdp_level;392393if (tdp_level != 0xff && i != tdp_level)394continue;395396debug_printf("cpu:%d Get Information for TDP level:%d\n", id->cpu,397i);398ctdp_level = &pkg_dev->ctdp_level[i];399400ctdp_level->level = i;401ctdp_level->control_cpu = id->cpu;402ctdp_level->pkg_id = id->pkg;403ctdp_level->die_id = id->die;404405ret = isst_get_ctdp_control(id, i, ctdp_level);406if (ret)407continue;408409valid = 1;410pkg_dev->processed = 1;411ctdp_level->processed = 1;412413if (ctdp_level->pbf_support) {414ret = isst_get_pbf_info(id, i, &ctdp_level->pbf_info);415if (!ret)416ctdp_level->pbf_found = 1;417}418419if (ctdp_level->fact_support) {420ret = isst_get_fact_info(id, i, 0xff,421&ctdp_level->fact_info);422if (ret)423return ret;424}425426if (!pkg_dev->enabled && is_skx_based_platform()) {427int freq;428429freq = get_cpufreq_base_freq(id->cpu);430if (freq > 0) {431ctdp_level->sse_p1 = freq / 100000;432ctdp_level->tdp_ratio = ctdp_level->sse_p1;433}434435isst_get_get_trl_from_msr(id, ctdp_level->trl_ratios[0]);436isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);437continue;438}439440ret = isst_get_tdp_info(id, i, ctdp_level);441if (ret)442return ret;443444ret = isst_get_pwr_info(id, i, ctdp_level);445if (ret)446return ret;447448ctdp_level->core_cpumask_size =449alloc_cpu_set(&ctdp_level->core_cpumask);450ret = isst_get_coremask_info(id, i, ctdp_level);451if (ret)452return ret;453454ret = isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);455if (ret)456return ret;457458ret = isst_get_get_trls(id, i, ctdp_level);459if (ret)460return ret;461}462463if (!valid)464isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, id->cpu);465466return 0;467}468469int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type)470{471CHECK_CB(get_clos_information);472return isst_ops->get_clos_information(id, enable, type);473}474475int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type)476{477CHECK_CB(pm_qos_config);478return isst_ops->pm_qos_config(id, enable_clos, priority_type);479}480481int isst_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)482{483CHECK_CB(pm_get_clos);484return isst_ops->pm_get_clos(id, clos, clos_config);485}486487int isst_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)488{489CHECK_CB(set_clos);490return isst_ops->set_clos(id, clos, clos_config);491}492493int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id)494{495CHECK_CB(clos_get_assoc_status);496return isst_ops->clos_get_assoc_status(id, clos_id);497}498499int isst_clos_associate(struct isst_id *id, int clos_id)500{501CHECK_CB(clos_associate);502return isst_ops->clos_associate(id, clos_id);503504}505506507