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