brintos

brintos / linux-shallow public Read only

0
0
Text · 14.9 KiB · bc8899e Raw
468 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * AMD Platform Management Framework Driver4 *5 * Copyright (c) 2022, Advanced Micro Devices, Inc.6 * All Rights Reserved.7 *8 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>9 */10 11#include <linux/string_choices.h>12#include <linux/workqueue.h>13#include "pmf.h"14 15static struct cnqf_config config_store;16 17#ifdef CONFIG_AMD_PMF_DEBUG18static const char *state_as_str_cnqf(unsigned int state)19{20	switch (state) {21	case APMF_CNQF_TURBO:22		return "turbo";23	case APMF_CNQF_PERFORMANCE:24		return "performance";25	case APMF_CNQF_BALANCE:26		return "balance";27	case APMF_CNQF_QUIET:28		return "quiet";29	default:30		return "Unknown CnQF State";31	}32}33 34static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx)35{36	int i;37 38	pr_debug("Dynamic Slider %s Defaults - BEGIN\n", idx ? "DC" : "AC");39	pr_debug("size: %u\n", data->size);40	pr_debug("flags: 0x%x\n", data->flags);41 42	/* Time constants */43	pr_debug("t_perf_to_turbo: %u ms\n", data->t_perf_to_turbo);44	pr_debug("t_balanced_to_perf: %u ms\n", data->t_balanced_to_perf);45	pr_debug("t_quiet_to_balanced: %u ms\n", data->t_quiet_to_balanced);46	pr_debug("t_balanced_to_quiet: %u ms\n", data->t_balanced_to_quiet);47	pr_debug("t_perf_to_balanced: %u ms\n", data->t_perf_to_balanced);48	pr_debug("t_turbo_to_perf: %u ms\n", data->t_turbo_to_perf);49 50	for (i = 0 ; i < CNQF_MODE_MAX ; i++) {51		pr_debug("pfloor_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].pfloor);52		pr_debug("fppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].fppt);53		pr_debug("sppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].sppt);54		pr_debug("sppt_apuonly_%s: %u mW\n",55			 state_as_str_cnqf(i), data->ps[i].sppt_apu_only);56		pr_debug("spl_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].spl);57		pr_debug("stt_minlimit_%s: %u mW\n",58			 state_as_str_cnqf(i), data->ps[i].stt_min_limit);59		pr_debug("stt_skintemp_apu_%s: %u C\n", state_as_str_cnqf(i),60			 data->ps[i].stt_skintemp[STT_TEMP_APU]);61		pr_debug("stt_skintemp_hs2_%s: %u C\n", state_as_str_cnqf(i),62			 data->ps[i].stt_skintemp[STT_TEMP_HS2]);63		pr_debug("fan_id_%s: %u\n", state_as_str_cnqf(i), data->ps[i].fan_id);64	}65 66	pr_debug("Dynamic Slider %s Defaults - END\n", idx ? "DC" : "AC");67}68#else69static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) {}70#endif71 72static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx,73			    struct cnqf_config *table)74{75	struct power_table_control *pc;76 77	pc = &config_store.mode_set[src][idx].power_control;78 79	amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL);80	amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL);81	amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL);82	amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL);83	amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL);84	amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU],85			 NULL);86	amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2],87			 NULL);88 89	if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))90		apmf_update_fan_idx(dev,91				    config_store.mode_set[src][idx].fan_control.manual,92				    config_store.mode_set[src][idx].fan_control.fan_id);93 94	return 0;95}96 97static void amd_pmf_update_power_threshold(int src)98{99	struct cnqf_mode_settings *ts;100	struct cnqf_tran_params *tp;101 102	tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET];103	ts = &config_store.mode_set[src][CNQF_MODE_BALANCE];104	tp->power_threshold = ts->power_floor;105 106	tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO];107	ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE];108	tp->power_threshold = ts->power_floor;109 110	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE];111	ts = &config_store.mode_set[src][CNQF_MODE_BALANCE];112	tp->power_threshold = ts->power_floor;113 114	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE];115	ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE];116	tp->power_threshold = ts->power_floor;117 118	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE];119	ts = &config_store.mode_set[src][CNQF_MODE_QUIET];120	tp->power_threshold = ts->power_floor;121 122	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE];123	ts = &config_store.mode_set[src][CNQF_MODE_TURBO];124	tp->power_threshold = ts->power_floor;125}126 127static const char *state_as_str(unsigned int state)128{129	switch (state) {130	case CNQF_MODE_QUIET:131		return "QUIET";132	case CNQF_MODE_BALANCE:133		return "BALANCED";134	case CNQF_MODE_TURBO:135		return "TURBO";136	case CNQF_MODE_PERFORMANCE:137		return "PERFORMANCE";138	default:139		return "Unknown CnQF mode";140	}141}142 143static int amd_pmf_cnqf_get_power_source(struct amd_pmf_dev *dev)144{145	if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) &&146	    is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))147		return amd_pmf_get_power_source();148	else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))149		return POWER_SOURCE_DC;150	else151		return POWER_SOURCE_AC;152}153 154int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms)155{156	struct cnqf_tran_params *tp;157	int src, i, j;158	u32 avg_power = 0;159 160	src = amd_pmf_cnqf_get_power_source(dev);161 162	if (is_pprof_balanced(dev)) {163		amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);164	} else {165		/*166		 * Return from here if the platform_profile is not balanced167		 * so that preference is given to user mode selection, rather168		 * than enforcing CnQF to run all the time (if enabled)169		 */170		return -EINVAL;171	}172 173	for (i = 0; i < CNQF_TRANSITION_MAX; i++) {174		config_store.trans_param[src][i].timer += time_lapsed_ms;175		config_store.trans_param[src][i].total_power += socket_power;176		config_store.trans_param[src][i].count++;177 178		tp = &config_store.trans_param[src][i];179 180#ifdef CONFIG_AMD_PMF_DEBUG181		dev_dbg(dev->dev, "avg_power: %u mW total_power: %u mW count: %u timer: %u ms\n",182			avg_power, config_store.trans_param[src][i].total_power,183			config_store.trans_param[src][i].count,184			config_store.trans_param[src][i].timer);185#endif186		if (tp->timer >= tp->time_constant && tp->count) {187			avg_power = tp->total_power / tp->count;188 189			/* Reset the indices */190			tp->timer = 0;191			tp->total_power = 0;192			tp->count = 0;193 194			if ((tp->shifting_up && avg_power >= tp->power_threshold) ||195			    (!tp->shifting_up && avg_power <= tp->power_threshold)) {196				tp->priority = true;197			} else {198				tp->priority = false;199			}200		}201	}202 203	dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n",204		avg_power, socket_power, state_as_str(config_store.current_mode));205 206#ifdef CONFIG_AMD_PMF_DEBUG207	dev_dbg(dev->dev, "[CNQF] priority1: %u priority2: %u priority3: %u\n",208		config_store.trans_param[src][0].priority,209		config_store.trans_param[src][1].priority,210		config_store.trans_param[src][2].priority);211 212	dev_dbg(dev->dev, "[CNQF] priority4: %u priority5: %u priority6: %u\n",213		config_store.trans_param[src][3].priority,214		config_store.trans_param[src][4].priority,215		config_store.trans_param[src][5].priority);216#endif217 218	for (j = 0; j < CNQF_TRANSITION_MAX; j++) {219		/* apply the highest priority */220		if (config_store.trans_param[src][j].priority) {221			if (config_store.current_mode !=222			    config_store.trans_param[src][j].target_mode) {223				config_store.current_mode =224						config_store.trans_param[src][j].target_mode;225				dev_dbg(dev->dev, "Moving to Mode :%s\n",226					state_as_str(config_store.current_mode));227				amd_pmf_set_cnqf(dev, src,228						 config_store.current_mode, NULL);229			}230			break;231		}232	}233	return 0;234}235 236static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out)237{238	struct cnqf_tran_params *tp;239 240	tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET];241	tp->time_constant = out->t_balanced_to_quiet;242	tp->target_mode = CNQF_MODE_QUIET;243	tp->shifting_up = false;244 245	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE];246	tp->time_constant = out->t_balanced_to_perf;247	tp->target_mode = CNQF_MODE_PERFORMANCE;248	tp->shifting_up = true;249 250	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE];251	tp->time_constant = out->t_quiet_to_balanced;252	tp->target_mode = CNQF_MODE_BALANCE;253	tp->shifting_up = true;254 255	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE];256	tp->time_constant = out->t_perf_to_balanced;257	tp->target_mode = CNQF_MODE_BALANCE;258	tp->shifting_up = false;259 260	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE];261	tp->time_constant = out->t_turbo_to_perf;262	tp->target_mode = CNQF_MODE_PERFORMANCE;263	tp->shifting_up = false;264 265	tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO];266	tp->time_constant = out->t_perf_to_turbo;267	tp->target_mode = CNQF_MODE_TURBO;268	tp->shifting_up = true;269}270 271static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out)272{273	struct cnqf_mode_settings *ms;274 275	/* Quiet Mode */276	ms = &config_store.mode_set[idx][CNQF_MODE_QUIET];277	ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor;278	ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt;279	ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt;280	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only;281	ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl;282	ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit;283	ms->power_control.stt_skin_temp[STT_TEMP_APU] =284		out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU];285	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =286		out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2];287	ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id;288 289	/* Balance Mode */290	ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE];291	ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor;292	ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt;293	ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt;294	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only;295	ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl;296	ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit;297	ms->power_control.stt_skin_temp[STT_TEMP_APU] =298		out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU];299	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =300		out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2];301	ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id;302 303	/* Performance Mode */304	ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE];305	ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor;306	ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt;307	ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt;308	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only;309	ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl;310	ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit;311	ms->power_control.stt_skin_temp[STT_TEMP_APU] =312		out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU];313	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =314		out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2];315	ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id;316 317	/* Turbo Mode */318	ms = &config_store.mode_set[idx][CNQF_MODE_TURBO];319	ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor;320	ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt;321	ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt;322	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only;323	ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl;324	ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit;325	ms->power_control.stt_skin_temp[STT_TEMP_APU] =326		out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU];327	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =328		out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2];329	ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id;330}331 332static int amd_pmf_check_flags(struct amd_pmf_dev *dev)333{334	struct apmf_dyn_slider_output out = {};335 336	if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC))337		apmf_get_dyn_slider_def_ac(dev, &out);338	else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))339		apmf_get_dyn_slider_def_dc(dev, &out);340 341	return out.flags;342}343 344static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev)345{346	struct apmf_dyn_slider_output out;347	int i, j, ret;348 349	for (i = 0; i < POWER_SOURCE_MAX; i++) {350		if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i))351			continue;352 353		if (i == POWER_SOURCE_AC)354			ret = apmf_get_dyn_slider_def_ac(dev, &out);355		else356			ret = apmf_get_dyn_slider_def_dc(dev, &out);357		if (ret) {358			dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret);359			return ret;360		}361 362		amd_pmf_cnqf_dump_defaults(&out, i);363		amd_pmf_update_mode_set(i, &out);364		amd_pmf_update_trans_data(i, &out);365		amd_pmf_update_power_threshold(i);366 367		for (j = 0; j < CNQF_MODE_MAX; j++) {368			if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO)369				config_store.mode_set[i][j].fan_control.manual = false;370			else371				config_store.mode_set[i][j].fan_control.manual = true;372		}373	}374 375	/* set to initial default values */376	config_store.current_mode = CNQF_MODE_BALANCE;377 378	return 0;379}380 381static ssize_t cnqf_enable_store(struct device *dev,382				 struct device_attribute *attr,383				 const char *buf, size_t count)384{385	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);386	int result, src;387	bool input;388 389	result = kstrtobool(buf, &input);390	if (result)391		return result;392 393	src = amd_pmf_cnqf_get_power_source(pdev);394	pdev->cnqf_enabled = input;395 396	if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) {397		amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL);398	} else {399		if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))400			amd_pmf_set_sps_power_limits(pdev);401	}402 403	dev_dbg(pdev->dev, "Received CnQF %s\n", str_on_off(input));404	return count;405}406 407static ssize_t cnqf_enable_show(struct device *dev,408				struct device_attribute *attr,409				char *buf)410{411	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);412 413	return sysfs_emit(buf, "%s\n", str_on_off(pdev->cnqf_enabled));414}415 416static DEVICE_ATTR_RW(cnqf_enable);417 418static umode_t cnqf_feature_is_visible(struct kobject *kobj,419				       struct attribute *attr, int n)420{421	struct device *dev = kobj_to_dev(kobj);422	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);423 424	return pdev->cnqf_supported ? attr->mode : 0;425}426 427static struct attribute *cnqf_feature_attrs[] = {428	&dev_attr_cnqf_enable.attr,429	NULL430};431 432const struct attribute_group cnqf_feature_attribute_group = {433	.is_visible = cnqf_feature_is_visible,434	.attrs = cnqf_feature_attrs,435};436 437void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev)438{439	cancel_delayed_work_sync(&dev->work_buffer);440}441 442int amd_pmf_init_cnqf(struct amd_pmf_dev *dev)443{444	int ret, src;445 446	/*447	 * Note the caller of this function has already checked that both448	 * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported.449	 */450 451	ret = amd_pmf_load_defaults_cnqf(dev);452	if (ret < 0)453		return ret;454 455	amd_pmf_init_metrics_table(dev);456 457	dev->cnqf_supported = true;458	dev->cnqf_enabled = amd_pmf_check_flags(dev);459 460	/* update the thermal for CnQF */461	if (dev->cnqf_enabled && is_pprof_balanced(dev)) {462		src = amd_pmf_cnqf_get_power_source(dev);463		amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);464	}465 466	return 0;467}468