brintos

brintos / linux-shallow public Read only

0
0
Text · 19.7 KiB · 706fffc Raw
815 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2021 Intel Corporation4 */5 6#include <drm/drm_cache.h>7#include <linux/string_helpers.h>8 9#include "i915_drv.h"10#include "i915_reg.h"11#include "intel_guc_slpc.h"12#include "intel_guc_print.h"13#include "intel_mchbar_regs.h"14#include "gt/intel_gt.h"15#include "gt/intel_gt_regs.h"16#include "gt/intel_rps.h"17 18static inline struct intel_guc *slpc_to_guc(struct intel_guc_slpc *slpc)19{20	return container_of(slpc, struct intel_guc, slpc);21}22 23static inline struct intel_gt *slpc_to_gt(struct intel_guc_slpc *slpc)24{25	return guc_to_gt(slpc_to_guc(slpc));26}27 28static inline struct drm_i915_private *slpc_to_i915(struct intel_guc_slpc *slpc)29{30	return slpc_to_gt(slpc)->i915;31}32 33static bool __detect_slpc_supported(struct intel_guc *guc)34{35	/* GuC SLPC is unavailable for pre-Gen12 */36	return guc->submission_supported &&37		GRAPHICS_VER(guc_to_i915(guc)) >= 12;38}39 40static bool __guc_slpc_selected(struct intel_guc *guc)41{42	if (!intel_guc_slpc_is_supported(guc))43		return false;44 45	return guc->submission_selected;46}47 48void intel_guc_slpc_init_early(struct intel_guc_slpc *slpc)49{50	struct intel_guc *guc = slpc_to_guc(slpc);51 52	slpc->supported = __detect_slpc_supported(guc);53	slpc->selected = __guc_slpc_selected(guc);54}55 56static void slpc_mem_set_param(struct slpc_shared_data *data,57			       u32 id, u32 value)58{59	GEM_BUG_ON(id >= SLPC_MAX_OVERRIDE_PARAMETERS);60	/*61	 * When the flag bit is set, corresponding value will be read62	 * and applied by SLPC.63	 */64	data->override_params.bits[id >> 5] |= (1 << (id % 32));65	data->override_params.values[id] = value;66}67 68static void slpc_mem_set_enabled(struct slpc_shared_data *data,69				 u8 enable_id, u8 disable_id)70{71	/*72	 * Enabling a param involves setting the enable_id73	 * to 1 and disable_id to 0.74	 */75	slpc_mem_set_param(data, enable_id, 1);76	slpc_mem_set_param(data, disable_id, 0);77}78 79static void slpc_mem_set_disabled(struct slpc_shared_data *data,80				  u8 enable_id, u8 disable_id)81{82	/*83	 * Disabling a param involves setting the enable_id84	 * to 0 and disable_id to 1.85	 */86	slpc_mem_set_param(data, disable_id, 1);87	slpc_mem_set_param(data, enable_id, 0);88}89 90static u32 slpc_get_state(struct intel_guc_slpc *slpc)91{92	struct slpc_shared_data *data;93 94	GEM_BUG_ON(!slpc->vma);95 96	drm_clflush_virt_range(slpc->vaddr, sizeof(u32));97	data = slpc->vaddr;98 99	return data->header.global_state;100}101 102static int guc_action_slpc_set_param_nb(struct intel_guc *guc, u8 id, u32 value)103{104	u32 request[] = {105		GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST,106		SLPC_EVENT(SLPC_EVENT_PARAMETER_SET, 2),107		id,108		value,109	};110	int ret;111 112	ret = intel_guc_send_nb(guc, request, ARRAY_SIZE(request), 0);113 114	return ret > 0 ? -EPROTO : ret;115}116 117static int slpc_set_param_nb(struct intel_guc_slpc *slpc, u8 id, u32 value)118{119	struct intel_guc *guc = slpc_to_guc(slpc);120 121	GEM_BUG_ON(id >= SLPC_MAX_PARAM);122 123	return guc_action_slpc_set_param_nb(guc, id, value);124}125 126static int guc_action_slpc_set_param(struct intel_guc *guc, u8 id, u32 value)127{128	u32 request[] = {129		GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST,130		SLPC_EVENT(SLPC_EVENT_PARAMETER_SET, 2),131		id,132		value,133	};134	int ret;135 136	ret = intel_guc_send(guc, request, ARRAY_SIZE(request));137 138	return ret > 0 ? -EPROTO : ret;139}140 141static bool slpc_is_running(struct intel_guc_slpc *slpc)142{143	return slpc_get_state(slpc) == SLPC_GLOBAL_STATE_RUNNING;144}145 146static int guc_action_slpc_query(struct intel_guc *guc, u32 offset)147{148	u32 request[] = {149		GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST,150		SLPC_EVENT(SLPC_EVENT_QUERY_TASK_STATE, 2),151		offset,152		0,153	};154	int ret;155 156	ret = intel_guc_send(guc, request, ARRAY_SIZE(request));157 158	return ret > 0 ? -EPROTO : ret;159}160 161static int slpc_query_task_state(struct intel_guc_slpc *slpc)162{163	struct intel_guc *guc = slpc_to_guc(slpc);164	u32 offset = intel_guc_ggtt_offset(guc, slpc->vma);165	int ret;166 167	ret = guc_action_slpc_query(guc, offset);168	if (unlikely(ret))169		guc_probe_error(guc, "Failed to query task state: %pe\n", ERR_PTR(ret));170 171	drm_clflush_virt_range(slpc->vaddr, SLPC_PAGE_SIZE_BYTES);172 173	return ret;174}175 176static int slpc_set_param(struct intel_guc_slpc *slpc, u8 id, u32 value)177{178	struct intel_guc *guc = slpc_to_guc(slpc);179	int ret;180 181	GEM_BUG_ON(id >= SLPC_MAX_PARAM);182 183	ret = guc_action_slpc_set_param(guc, id, value);184	if (ret)185		guc_probe_error(guc, "Failed to set param %d to %u: %pe\n",186				id, value, ERR_PTR(ret));187 188	return ret;189}190 191static int slpc_force_min_freq(struct intel_guc_slpc *slpc, u32 freq)192{193	struct intel_guc *guc = slpc_to_guc(slpc);194	struct drm_i915_private *i915 = slpc_to_i915(slpc);195	intel_wakeref_t wakeref;196	int ret = 0;197 198	lockdep_assert_held(&slpc->lock);199 200	if (!intel_guc_is_ready(guc))201		return -ENODEV;202 203	/*204	 * This function is a little different as compared to205	 * intel_guc_slpc_set_min_freq(). Softlimit will not be updated206	 * here since this is used to temporarily change min freq,207	 * for example, during a waitboost. Caller is responsible for208	 * checking bounds.209	 */210 211	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {212		/* Non-blocking request will avoid stalls */213		ret = slpc_set_param_nb(slpc,214					SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,215					freq);216		if (ret)217			guc_notice(guc, "Failed to send set_param for min freq(%d): %pe\n",218				   freq, ERR_PTR(ret));219	}220 221	return ret;222}223 224static void slpc_boost_work(struct work_struct *work)225{226	struct intel_guc_slpc *slpc = container_of(work, typeof(*slpc), boost_work);227	int err;228 229	/*230	 * Raise min freq to boost. It's possible that231	 * this is greater than current max. But it will232	 * certainly be limited by RP0. An error setting233	 * the min param is not fatal.234	 */235	mutex_lock(&slpc->lock);236	if (atomic_read(&slpc->num_waiters)) {237		err = slpc_force_min_freq(slpc, slpc->boost_freq);238		if (!err)239			slpc->num_boosts++;240	}241	mutex_unlock(&slpc->lock);242}243 244int intel_guc_slpc_init(struct intel_guc_slpc *slpc)245{246	struct intel_guc *guc = slpc_to_guc(slpc);247	u32 size = PAGE_ALIGN(sizeof(struct slpc_shared_data));248	int err;249 250	GEM_BUG_ON(slpc->vma);251 252	err = intel_guc_allocate_and_map_vma(guc, size, &slpc->vma, (void **)&slpc->vaddr);253	if (unlikely(err)) {254		guc_probe_error(guc, "Failed to allocate SLPC struct: %pe\n", ERR_PTR(err));255		return err;256	}257 258	slpc->max_freq_softlimit = 0;259	slpc->min_freq_softlimit = 0;260	slpc->ignore_eff_freq = false;261	slpc->min_is_rpmax = false;262 263	slpc->boost_freq = 0;264	atomic_set(&slpc->num_waiters, 0);265	slpc->num_boosts = 0;266	slpc->media_ratio_mode = SLPC_MEDIA_RATIO_MODE_DYNAMIC_CONTROL;267 268	mutex_init(&slpc->lock);269	INIT_WORK(&slpc->boost_work, slpc_boost_work);270 271	return err;272}273 274static const char *slpc_global_state_to_string(enum slpc_global_state state)275{276	switch (state) {277	case SLPC_GLOBAL_STATE_NOT_RUNNING:278		return "not running";279	case SLPC_GLOBAL_STATE_INITIALIZING:280		return "initializing";281	case SLPC_GLOBAL_STATE_RESETTING:282		return "resetting";283	case SLPC_GLOBAL_STATE_RUNNING:284		return "running";285	case SLPC_GLOBAL_STATE_SHUTTING_DOWN:286		return "shutting down";287	case SLPC_GLOBAL_STATE_ERROR:288		return "error";289	default:290		return "unknown";291	}292}293 294static const char *slpc_get_state_string(struct intel_guc_slpc *slpc)295{296	return slpc_global_state_to_string(slpc_get_state(slpc));297}298 299static int guc_action_slpc_reset(struct intel_guc *guc, u32 offset)300{301	u32 request[] = {302		GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST,303		SLPC_EVENT(SLPC_EVENT_RESET, 2),304		offset,305		0,306	};307	int ret;308 309	ret = intel_guc_send(guc, request, ARRAY_SIZE(request));310 311	return ret > 0 ? -EPROTO : ret;312}313 314static int slpc_reset(struct intel_guc_slpc *slpc)315{316	struct intel_guc *guc = slpc_to_guc(slpc);317	u32 offset = intel_guc_ggtt_offset(guc, slpc->vma);318	int ret;319 320	ret = guc_action_slpc_reset(guc, offset);321 322	if (unlikely(ret < 0)) {323		guc_probe_error(guc, "SLPC reset action failed: %pe\n", ERR_PTR(ret));324		return ret;325	}326 327	if (!ret) {328		if (wait_for(slpc_is_running(slpc), SLPC_RESET_TIMEOUT_MS)) {329			guc_probe_error(guc, "SLPC not enabled! State = %s\n",330					slpc_get_state_string(slpc));331			return -EIO;332		}333	}334 335	return 0;336}337 338static u32 slpc_decode_min_freq(struct intel_guc_slpc *slpc)339{340	struct slpc_shared_data *data = slpc->vaddr;341 342	GEM_BUG_ON(!slpc->vma);343 344	return	DIV_ROUND_CLOSEST(REG_FIELD_GET(SLPC_MIN_UNSLICE_FREQ_MASK,345				  data->task_state_data.freq) *346				  GT_FREQUENCY_MULTIPLIER, GEN9_FREQ_SCALER);347}348 349static u32 slpc_decode_max_freq(struct intel_guc_slpc *slpc)350{351	struct slpc_shared_data *data = slpc->vaddr;352 353	GEM_BUG_ON(!slpc->vma);354 355	return	DIV_ROUND_CLOSEST(REG_FIELD_GET(SLPC_MAX_UNSLICE_FREQ_MASK,356				  data->task_state_data.freq) *357				  GT_FREQUENCY_MULTIPLIER, GEN9_FREQ_SCALER);358}359 360static void slpc_shared_data_reset(struct slpc_shared_data *data)361{362	memset(data, 0, sizeof(struct slpc_shared_data));363 364	data->header.size = sizeof(struct slpc_shared_data);365 366	/* Enable only GTPERF task, disable others */367	slpc_mem_set_enabled(data, SLPC_PARAM_TASK_ENABLE_GTPERF,368			     SLPC_PARAM_TASK_DISABLE_GTPERF);369 370	slpc_mem_set_disabled(data, SLPC_PARAM_TASK_ENABLE_BALANCER,371			      SLPC_PARAM_TASK_DISABLE_BALANCER);372 373	slpc_mem_set_disabled(data, SLPC_PARAM_TASK_ENABLE_DCC,374			      SLPC_PARAM_TASK_DISABLE_DCC);375}376 377/**378 * intel_guc_slpc_set_max_freq() - Set max frequency limit for SLPC.379 * @slpc: pointer to intel_guc_slpc.380 * @val: frequency (MHz)381 *382 * This function will invoke GuC SLPC action to update the max frequency383 * limit for unslice.384 *385 * Return: 0 on success, non-zero error code on failure.386 */387int intel_guc_slpc_set_max_freq(struct intel_guc_slpc *slpc, u32 val)388{389	struct drm_i915_private *i915 = slpc_to_i915(slpc);390	intel_wakeref_t wakeref;391	int ret;392 393	if (val < slpc->min_freq ||394	    val > slpc->rp0_freq ||395	    val < slpc->min_freq_softlimit)396		return -EINVAL;397 398	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {399		ret = slpc_set_param(slpc,400				     SLPC_PARAM_GLOBAL_MAX_GT_UNSLICE_FREQ_MHZ,401				     val);402 403		/* Return standardized err code for sysfs calls */404		if (ret)405			ret = -EIO;406	}407 408	if (!ret)409		slpc->max_freq_softlimit = val;410 411	return ret;412}413 414/**415 * intel_guc_slpc_get_max_freq() - Get max frequency limit for SLPC.416 * @slpc: pointer to intel_guc_slpc.417 * @val: pointer to val which will hold max frequency (MHz)418 *419 * This function will invoke GuC SLPC action to read the max frequency420 * limit for unslice.421 *422 * Return: 0 on success, non-zero error code on failure.423 */424int intel_guc_slpc_get_max_freq(struct intel_guc_slpc *slpc, u32 *val)425{426	struct drm_i915_private *i915 = slpc_to_i915(slpc);427	intel_wakeref_t wakeref;428	int ret = 0;429 430	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {431		/* Force GuC to update task data */432		ret = slpc_query_task_state(slpc);433 434		if (!ret)435			*val = slpc_decode_max_freq(slpc);436	}437 438	return ret;439}440 441int intel_guc_slpc_set_ignore_eff_freq(struct intel_guc_slpc *slpc, bool val)442{443	struct drm_i915_private *i915 = slpc_to_i915(slpc);444	intel_wakeref_t wakeref;445	int ret;446 447	mutex_lock(&slpc->lock);448	wakeref = intel_runtime_pm_get(&i915->runtime_pm);449 450	ret = slpc_set_param(slpc,451			     SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY,452			     val);453	if (ret) {454		guc_probe_error(slpc_to_guc(slpc), "Failed to set efficient freq(%d): %pe\n",455				val, ERR_PTR(ret));456	} else {457		slpc->ignore_eff_freq = val;458 459		/* Set min to RPn when we disable efficient freq */460		if (val)461			ret = slpc_set_param(slpc,462					     SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,463					     slpc->min_freq);464	}465 466	intel_runtime_pm_put(&i915->runtime_pm, wakeref);467	mutex_unlock(&slpc->lock);468	return ret;469}470 471/**472 * intel_guc_slpc_set_min_freq() - Set min frequency limit for SLPC.473 * @slpc: pointer to intel_guc_slpc.474 * @val: frequency (MHz)475 *476 * This function will invoke GuC SLPC action to update the min unslice477 * frequency.478 *479 * Return: 0 on success, non-zero error code on failure.480 */481int intel_guc_slpc_set_min_freq(struct intel_guc_slpc *slpc, u32 val)482{483	struct drm_i915_private *i915 = slpc_to_i915(slpc);484	intel_wakeref_t wakeref;485	int ret;486 487	if (val < slpc->min_freq ||488	    val > slpc->rp0_freq ||489	    val > slpc->max_freq_softlimit)490		return -EINVAL;491 492	/* Need a lock now since waitboost can be modifying min as well */493	mutex_lock(&slpc->lock);494	wakeref = intel_runtime_pm_get(&i915->runtime_pm);495 496	ret = slpc_set_param(slpc,497			     SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,498			     val);499 500	if (!ret)501		slpc->min_freq_softlimit = val;502 503	intel_runtime_pm_put(&i915->runtime_pm, wakeref);504	mutex_unlock(&slpc->lock);505 506	/* Return standardized err code for sysfs calls */507	if (ret)508		ret = -EIO;509 510	return ret;511}512 513/**514 * intel_guc_slpc_get_min_freq() - Get min frequency limit for SLPC.515 * @slpc: pointer to intel_guc_slpc.516 * @val: pointer to val which will hold min frequency (MHz)517 *518 * This function will invoke GuC SLPC action to read the min frequency519 * limit for unslice.520 *521 * Return: 0 on success, non-zero error code on failure.522 */523int intel_guc_slpc_get_min_freq(struct intel_guc_slpc *slpc, u32 *val)524{525	struct drm_i915_private *i915 = slpc_to_i915(slpc);526	intel_wakeref_t wakeref;527	int ret = 0;528 529	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {530		/* Force GuC to update task data */531		ret = slpc_query_task_state(slpc);532 533		if (!ret)534			*val = slpc_decode_min_freq(slpc);535	}536 537	return ret;538}539 540int intel_guc_slpc_set_strategy(struct intel_guc_slpc *slpc, u32 val)541{542	struct drm_i915_private *i915 = slpc_to_i915(slpc);543	intel_wakeref_t wakeref;544	int ret = 0;545 546	with_intel_runtime_pm(&i915->runtime_pm, wakeref)547		ret = slpc_set_param(slpc,548				     SLPC_PARAM_STRATEGIES,549				     val);550 551	return ret;552}553 554int intel_guc_slpc_set_media_ratio_mode(struct intel_guc_slpc *slpc, u32 val)555{556	struct drm_i915_private *i915 = slpc_to_i915(slpc);557	intel_wakeref_t wakeref;558	int ret = 0;559 560	if (!HAS_MEDIA_RATIO_MODE(i915))561		return -ENODEV;562 563	with_intel_runtime_pm(&i915->runtime_pm, wakeref)564		ret = slpc_set_param(slpc,565				     SLPC_PARAM_MEDIA_FF_RATIO_MODE,566				     val);567	return ret;568}569 570void intel_guc_pm_intrmsk_enable(struct intel_gt *gt)571{572	u32 pm_intrmsk_mbz = 0;573 574	/*575	 * Allow GuC to receive ARAT timer expiry event.576	 * This interrupt register is setup by RPS code577	 * when host based Turbo is enabled.578	 */579	pm_intrmsk_mbz |= ARAT_EXPIRED_INTRMSK;580 581	intel_uncore_rmw(gt->uncore,582			 GEN6_PMINTRMSK, pm_intrmsk_mbz, 0);583}584 585static int slpc_set_softlimits(struct intel_guc_slpc *slpc)586{587	int ret = 0;588 589	/*590	 * Softlimits are initially equivalent to platform limits591	 * unless they have deviated from defaults, in which case,592	 * we retain the values and set min/max accordingly.593	 */594	if (!slpc->max_freq_softlimit) {595		slpc->max_freq_softlimit = slpc->rp0_freq;596		slpc_to_gt(slpc)->defaults.max_freq = slpc->max_freq_softlimit;597	} else if (slpc->max_freq_softlimit != slpc->rp0_freq) {598		ret = intel_guc_slpc_set_max_freq(slpc,599						  slpc->max_freq_softlimit);600	}601 602	if (unlikely(ret))603		return ret;604 605	if (!slpc->min_freq_softlimit) {606		/* Min softlimit is initialized to RPn */607		slpc->min_freq_softlimit = slpc->min_freq;608		slpc_to_gt(slpc)->defaults.min_freq = slpc->min_freq_softlimit;609	} else {610		return intel_guc_slpc_set_min_freq(slpc,611						   slpc->min_freq_softlimit);612	}613 614	return 0;615}616 617static bool is_slpc_min_freq_rpmax(struct intel_guc_slpc *slpc)618{619	int slpc_min_freq;620	int ret;621 622	ret = intel_guc_slpc_get_min_freq(slpc, &slpc_min_freq);623	if (ret) {624		guc_err(slpc_to_guc(slpc), "Failed to get min freq: %pe\n", ERR_PTR(ret));625		return false;626	}627 628	if (slpc_min_freq == SLPC_MAX_FREQ_MHZ)629		return true;630	else631		return false;632}633 634static void update_server_min_softlimit(struct intel_guc_slpc *slpc)635{636	/* For server parts, SLPC min will be at RPMax.637	 * Use min softlimit to clamp it to RP0 instead.638	 */639	if (!slpc->min_freq_softlimit &&640	    is_slpc_min_freq_rpmax(slpc)) {641		slpc->min_is_rpmax = true;642		slpc->min_freq_softlimit = slpc->rp0_freq;643		(slpc_to_gt(slpc))->defaults.min_freq = slpc->min_freq_softlimit;644	}645}646 647static int slpc_use_fused_rp0(struct intel_guc_slpc *slpc)648{649	/* Force SLPC to used platform rp0 */650	return slpc_set_param(slpc,651			      SLPC_PARAM_GLOBAL_MAX_GT_UNSLICE_FREQ_MHZ,652			      slpc->rp0_freq);653}654 655static void slpc_get_rp_values(struct intel_guc_slpc *slpc)656{657	struct intel_rps *rps = &slpc_to_gt(slpc)->rps;658	struct intel_rps_freq_caps caps;659 660	gen6_rps_get_freq_caps(rps, &caps);661	slpc->rp0_freq = intel_gpu_freq(rps, caps.rp0_freq);662	slpc->rp1_freq = intel_gpu_freq(rps, caps.rp1_freq);663	slpc->min_freq = intel_gpu_freq(rps, caps.min_freq);664 665	if (!slpc->boost_freq)666		slpc->boost_freq = slpc->rp0_freq;667}668 669/*670 * intel_guc_slpc_enable() - Start SLPC671 * @slpc: pointer to intel_guc_slpc.672 *673 * SLPC is enabled by setting up the shared data structure and674 * sending reset event to GuC SLPC. Initial data is setup in675 * intel_guc_slpc_init. Here we send the reset event. We do676 * not currently need a slpc_disable since this is taken care677 * of automatically when a reset/suspend occurs and the GuC678 * CTB is destroyed.679 *680 * Return: 0 on success, non-zero error code on failure.681 */682int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)683{684	struct intel_guc *guc = slpc_to_guc(slpc);685	int ret;686 687	GEM_BUG_ON(!slpc->vma);688 689	slpc_shared_data_reset(slpc->vaddr);690 691	ret = slpc_reset(slpc);692	if (unlikely(ret < 0)) {693		guc_probe_error(guc, "SLPC Reset event returned: %pe\n", ERR_PTR(ret));694		return ret;695	}696 697	ret = slpc_query_task_state(slpc);698	if (unlikely(ret < 0))699		return ret;700 701	intel_guc_pm_intrmsk_enable(slpc_to_gt(slpc));702 703	slpc_get_rp_values(slpc);704 705	/* Handle the case where min=max=RPmax */706	update_server_min_softlimit(slpc);707 708	/* Set SLPC max limit to RP0 */709	ret = slpc_use_fused_rp0(slpc);710	if (unlikely(ret)) {711		guc_probe_error(guc, "Failed to set SLPC max to RP0: %pe\n", ERR_PTR(ret));712		return ret;713	}714 715	/* Set cached value of ignore efficient freq */716	intel_guc_slpc_set_ignore_eff_freq(slpc, slpc->ignore_eff_freq);717 718	/* Revert SLPC min/max to softlimits if necessary */719	ret = slpc_set_softlimits(slpc);720	if (unlikely(ret)) {721		guc_probe_error(guc, "Failed to set SLPC softlimits: %pe\n", ERR_PTR(ret));722		return ret;723	}724 725	/* Set cached media freq ratio mode */726	intel_guc_slpc_set_media_ratio_mode(slpc, slpc->media_ratio_mode);727 728	/* Enable SLPC Optimized Strategy for compute */729	intel_guc_slpc_set_strategy(slpc, SLPC_OPTIMIZED_STRATEGY_COMPUTE);730 731	return 0;732}733 734int intel_guc_slpc_set_boost_freq(struct intel_guc_slpc *slpc, u32 val)735{736	int ret = 0;737 738	if (val < slpc->min_freq || val > slpc->rp0_freq)739		return -EINVAL;740 741	mutex_lock(&slpc->lock);742 743	if (slpc->boost_freq != val) {744		/* Apply only if there are active waiters */745		if (atomic_read(&slpc->num_waiters)) {746			ret = slpc_force_min_freq(slpc, val);747			if (ret) {748				ret = -EIO;749				goto done;750			}751		}752 753		slpc->boost_freq = val;754	}755 756done:757	mutex_unlock(&slpc->lock);758	return ret;759}760 761void intel_guc_slpc_dec_waiters(struct intel_guc_slpc *slpc)762{763	/*764	 * Return min back to the softlimit.765	 * This is called during request retire,766	 * so we don't need to fail that if the767	 * set_param fails.768	 */769	mutex_lock(&slpc->lock);770	if (atomic_dec_and_test(&slpc->num_waiters))771		slpc_force_min_freq(slpc, slpc->min_freq_softlimit);772	mutex_unlock(&slpc->lock);773}774 775int intel_guc_slpc_print_info(struct intel_guc_slpc *slpc, struct drm_printer *p)776{777	struct drm_i915_private *i915 = slpc_to_i915(slpc);778	struct slpc_shared_data *data = slpc->vaddr;779	struct slpc_task_state_data *slpc_tasks;780	intel_wakeref_t wakeref;781	int ret = 0;782 783	GEM_BUG_ON(!slpc->vma);784 785	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {786		ret = slpc_query_task_state(slpc);787 788		if (!ret) {789			slpc_tasks = &data->task_state_data;790 791			drm_printf(p, "\tSLPC state: %s\n", slpc_get_state_string(slpc));792			drm_printf(p, "\tGTPERF task active: %s\n",793				   str_yes_no(slpc_tasks->status & SLPC_GTPERF_TASK_ENABLED));794			drm_printf(p, "\tMax freq: %u MHz\n",795				   slpc_decode_max_freq(slpc));796			drm_printf(p, "\tMin freq: %u MHz\n",797				   slpc_decode_min_freq(slpc));798			drm_printf(p, "\twaitboosts: %u\n",799				   slpc->num_boosts);800			drm_printf(p, "\tBoosts outstanding: %u\n",801				   atomic_read(&slpc->num_waiters));802		}803	}804 805	return ret;806}807 808void intel_guc_slpc_fini(struct intel_guc_slpc *slpc)809{810	if (!slpc->vma)811		return;812 813	i915_vma_unpin_and_release(&slpc->vma, I915_VMA_RELEASE_MAP);814}815