From: Vinay Belgaumkar Date: Wed, 4 Feb 2026 01:42:32 +0000 (-0800) Subject: drm/xe: Decouple GuC RC code from xe_guc_pc X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=40a684f91d267164f9adf0d35b572b4cad0b8d3c;p=thirdparty%2Flinux.git drm/xe: Decouple GuC RC code from xe_guc_pc Move enable/disable GuC RC logic into the new file. This will allow us to independently enable/disable GuC RC and not rely on SLPC related functions. GuC already provides separate H2G interfaces to setup GuC RC and SLPC. Cc: Riana Tauro Cc: Michal Wajdeczko Reviewed-by: Michal Wajdeczko Reviewed-by: Riana Tauro Signed-off-by: Vinay Belgaumkar Link: https://patch.msgid.link/20260204014234.2867763-2-vinay.belgaumkar@intel.com --- diff --git a/Documentation/gpu/xe/xe_firmware.rst b/Documentation/gpu/xe/xe_firmware.rst index 5d23e9f273914..9c15a300bc625 100644 --- a/Documentation/gpu/xe/xe_firmware.rst +++ b/Documentation/gpu/xe/xe_firmware.rst @@ -31,6 +31,9 @@ GuC Power Conservation (PC) .. kernel-doc:: drivers/gpu/drm/xe/xe_guc_pc.c :doc: GuC Power Conservation (PC) +.. kernel-doc:: drivers/gpu/drm/xe/xe_guc_rc.c + :doc: GuC Render C-states (GuC RC) + PCIe Gen5 Limitations ===================== diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 3a6a707638b52..4a7eaeeca293c 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -74,6 +74,7 @@ xe-y += xe_bb.o \ xe_guc_log.o \ xe_guc_pagefault.o \ xe_guc_pc.o \ + xe_guc_rc.o \ xe_guc_submit.o \ xe_guc_tlb_inval.o \ xe_heci_gsc.o \ diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 22132467ff4f1..68c4771de040b 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -849,7 +849,6 @@ static void gt_reset_worker(struct work_struct *w) if (IS_SRIOV_PF(gt_to_xe(gt))) xe_gt_sriov_pf_stop_prepare(gt); - xe_uc_gucrc_disable(>->uc); xe_uc_stop_prepare(>->uc); xe_pagefault_reset(gt_to_xe(gt), gt); diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index d5910b0adbaac..303f6ae7c4189 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -35,6 +35,7 @@ #include "xe_guc_klv_helpers.h" #include "xe_guc_log.h" #include "xe_guc_pc.h" +#include "xe_guc_rc.h" #include "xe_guc_relay.h" #include "xe_guc_submit.h" #include "xe_memirq.h" @@ -881,6 +882,10 @@ int xe_guc_init_post_hwconfig(struct xe_guc *guc) if (ret) return ret; + ret = xe_guc_rc_init(guc); + if (ret) + return ret; + ret = xe_guc_engine_activity_init(guc); if (ret) return ret; @@ -1631,6 +1636,7 @@ void xe_guc_stop_prepare(struct xe_guc *guc) if (!IS_SRIOV_VF(guc_to_xe(guc))) { int err; + xe_guc_rc_disable(guc); err = xe_guc_pc_stop(&guc->pc); xe_gt_WARN(guc_to_gt(guc), err, "Failed to stop GuC PC: %pe\n", ERR_PTR(err)); diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index 5e5495a39a3c9..c8313e308f962 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -92,6 +92,17 @@ * Render-C states is also a GuC PC feature that is now enabled in Xe for * all platforms. * + * Implementation details: + * ----------------------- + * The implementation for GuC Power Management features is split as follows: + * + * xe_guc_rc: Logic for handling GuC RC + * xe_gt_idle: Host side logic for RC6 and Coarse Power gating (CPG) + * xe_guc_pc: Logic for all other SLPC related features + * + * There is some cross interaction between these where host C6 will need to be + * enabled when we plan to skip GuC RC. Also, the GuC RC mode is currently + * overridden through 0x3003 which is an SLPC H2G call. */ static struct xe_guc *pc_to_guc(struct xe_guc_pc *pc) @@ -253,22 +264,6 @@ static int pc_action_unset_param(struct xe_guc_pc *pc, u8 id) return ret; } -static int pc_action_setup_gucrc(struct xe_guc_pc *pc, u32 mode) -{ - struct xe_guc_ct *ct = pc_to_ct(pc); - u32 action[] = { - GUC_ACTION_HOST2GUC_SETUP_PC_GUCRC, - mode, - }; - int ret; - - ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0); - if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) - xe_gt_err(pc_to_gt(pc), "GuC RC enable mode=%u failed: %pe\n", - mode, ERR_PTR(ret)); - return ret; -} - static u32 decode_freq(u32 raw) { return DIV_ROUND_CLOSEST(raw * GT_FREQUENCY_MULTIPLIER, @@ -1050,30 +1045,6 @@ int xe_guc_pc_restore_stashed_freq(struct xe_guc_pc *pc) return ret; } -/** - * xe_guc_pc_gucrc_disable - Disable GuC RC - * @pc: Xe_GuC_PC instance - * - * Disables GuC RC by taking control of RC6 back from GuC. - * - * Return: 0 on success, negative error code on error. - */ -int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc) -{ - struct xe_device *xe = pc_to_xe(pc); - struct xe_gt *gt = pc_to_gt(pc); - int ret = 0; - - if (xe->info.skip_guc_pc) - return 0; - - ret = pc_action_setup_gucrc(pc, GUCRC_HOST_CONTROL); - if (ret) - return ret; - - return xe_gt_idle_disable_c6(gt); -} - /** * xe_guc_pc_override_gucrc_mode - override GUCRC mode * @pc: Xe_GuC_PC instance @@ -1247,9 +1218,6 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) return -ETIMEDOUT; if (xe->info.skip_guc_pc) { - if (xe->info.platform != XE_PVC) - xe_gt_idle_enable_c6(gt); - /* Request max possible since dynamic freq mgmt is not enabled */ pc_set_cur_freq(pc, UINT_MAX); return 0; @@ -1291,15 +1259,6 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) if (ret) return ret; - if (xe->info.platform == XE_PVC) { - xe_guc_pc_gucrc_disable(pc); - return 0; - } - - ret = pc_action_setup_gucrc(pc, GUCRC_FIRMWARE_CONTROL); - if (ret) - return ret; - /* Enable SLPC Optimized Strategy for compute */ ret = pc_action_set_strategy(pc, SLPC_OPTIMIZED_STRATEGY_COMPUTE); @@ -1319,10 +1278,8 @@ int xe_guc_pc_stop(struct xe_guc_pc *pc) { struct xe_device *xe = pc_to_xe(pc); - if (xe->info.skip_guc_pc) { - xe_gt_idle_disable_c6(pc_to_gt(pc)); + if (xe->info.skip_guc_pc) return 0; - } mutex_lock(&pc->freq_lock); pc->freq_ready = false; @@ -1344,7 +1301,6 @@ static void xe_guc_pc_fini_hw(void *arg) return; CLASS(xe_force_wake, fw_ref)(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL); - xe_guc_pc_gucrc_disable(pc); XE_WARN_ON(xe_guc_pc_stop(pc)); /* Bind requested freq to mert_freq_cap before unload */ diff --git a/drivers/gpu/drm/xe/xe_guc_pc.h b/drivers/gpu/drm/xe/xe_guc_pc.h index 0e31396f103cd..1b95873b262e3 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.h +++ b/drivers/gpu/drm/xe/xe_guc_pc.h @@ -15,7 +15,6 @@ struct drm_printer; int xe_guc_pc_init(struct xe_guc_pc *pc); int xe_guc_pc_start(struct xe_guc_pc *pc); int xe_guc_pc_stop(struct xe_guc_pc *pc); -int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc); int xe_guc_pc_override_gucrc_mode(struct xe_guc_pc *pc, enum slpc_gucrc_mode mode); int xe_guc_pc_unset_gucrc_mode(struct xe_guc_pc *pc); void xe_guc_pc_print(struct xe_guc_pc *pc, struct drm_printer *p); diff --git a/drivers/gpu/drm/xe/xe_guc_rc.c b/drivers/gpu/drm/xe/xe_guc_rc.c new file mode 100644 index 0000000000000..6c4591e712d9d --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_rc.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include + +#include "abi/guc_actions_slpc_abi.h" +#include "xe_device.h" +#include "xe_force_wake.h" +#include "xe_gt.h" +#include "xe_gt_idle.h" +#include "xe_gt_printk.h" +#include "xe_guc.h" +#include "xe_guc_ct.h" +#include "xe_guc_rc.h" +#include "xe_pm.h" + +/** + * DOC: GuC RC (Render C-states) + * + * GuC handles the GT transition to deeper C-states in conjunction with Pcode. + * GuC RC can be enabled independently of the frequency component in SLPC, + * which is also controlled by GuC. + * + * This file will contain all H2G related logic for handling Render C-states. + * There are some calls to xe_gt_idle, where we enable host C6 when GuC RC is + * skipped. GuC RC is mostly independent of xe_guc_pc with the exception of + * functions that override the mode for which we have to rely on the SLPC H2G + * calls. + */ + +static int guc_action_setup_gucrc(struct xe_guc *guc, u32 control) +{ + u32 action[] = { + GUC_ACTION_HOST2GUC_SETUP_PC_GUCRC, + control, + }; + int ret; + + ret = xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0); + if (ret && !(xe_device_wedged(guc_to_xe(guc)) && ret == -ECANCELED)) + xe_gt_err(guc_to_gt(guc), + "GuC RC setup %s(%u) failed (%pe)\n", + control == GUCRC_HOST_CONTROL ? "HOST_CONTROL" : + control == GUCRC_FIRMWARE_CONTROL ? "FIRMWARE_CONTROL" : + "UNKNOWN", control, ERR_PTR(ret)); + return ret; +} + +/** + * xe_guc_rc_disable() - Disable GuC RC + * @guc: Xe GuC instance + * + * Disables GuC RC by taking control of RC6 back from GuC. + */ +void xe_guc_rc_disable(struct xe_guc *guc) +{ + struct xe_device *xe = guc_to_xe(guc); + struct xe_gt *gt = guc_to_gt(guc); + + if (!xe->info.skip_guc_pc && xe->info.platform != XE_PVC) + if (guc_action_setup_gucrc(guc, GUCRC_HOST_CONTROL)) + return; + + xe_gt_WARN_ON(gt, xe_gt_idle_disable_c6(gt)); +} + +static void xe_guc_rc_fini_hw(void *arg) +{ + struct xe_guc *guc = arg; + struct xe_device *xe = guc_to_xe(guc); + struct xe_gt *gt = guc_to_gt(guc); + + if (xe_device_wedged(xe)) + return; + + CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); + xe_guc_rc_disable(guc); +} + +/** + * xe_guc_rc_init() - Init GuC RC + * @guc: Xe GuC instance + * + * Add callback action for GuC RC + * + * Return: 0 on success, negative error code on error. + */ +int xe_guc_rc_init(struct xe_guc *guc) +{ + struct xe_device *xe = guc_to_xe(guc); + struct xe_gt *gt = guc_to_gt(guc); + + xe_gt_assert(gt, xe_device_uc_enabled(xe)); + + return devm_add_action_or_reset(xe->drm.dev, xe_guc_rc_fini_hw, guc); +} + +/** + * xe_guc_rc_enable() - Enable GuC RC feature if applicable + * @guc: Xe GuC instance + * + * Enables GuC RC feature. + * + * Return: 0 on success, negative error code on error. + */ +int xe_guc_rc_enable(struct xe_guc *guc) +{ + struct xe_device *xe = guc_to_xe(guc); + struct xe_gt *gt = guc_to_gt(guc); + + xe_gt_assert(gt, xe_device_uc_enabled(xe)); + + CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); + if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) + return -ETIMEDOUT; + + if (xe->info.platform == XE_PVC) { + xe_guc_rc_disable(guc); + return 0; + } + + if (xe->info.skip_guc_pc) { + xe_gt_idle_enable_c6(gt); + return 0; + } + + return guc_action_setup_gucrc(guc, GUCRC_FIRMWARE_CONTROL); +} diff --git a/drivers/gpu/drm/xe/xe_guc_rc.h b/drivers/gpu/drm/xe/xe_guc_rc.h new file mode 100644 index 0000000000000..2e7e15e2be506 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_rc.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_GUC_RC_H_ +#define _XE_GUC_RC_H_ + +struct xe_guc; + +int xe_guc_rc_init(struct xe_guc *guc); +int xe_guc_rc_enable(struct xe_guc *guc); +void xe_guc_rc_disable(struct xe_guc *guc); + +#endif diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c index 3f63c2a7e86de..d9aa845a308d5 100644 --- a/drivers/gpu/drm/xe/xe_uc.c +++ b/drivers/gpu/drm/xe/xe_uc.c @@ -13,6 +13,7 @@ #include "xe_gt_sriov_vf.h" #include "xe_guc.h" #include "xe_guc_pc.h" +#include "xe_guc_rc.h" #include "xe_guc_engine_activity.h" #include "xe_huc.h" #include "xe_sriov.h" @@ -214,6 +215,10 @@ int xe_uc_load_hw(struct xe_uc *uc) if (ret) goto err_out; + ret = xe_guc_rc_enable(&uc->guc); + if (ret) + goto err_out; + xe_guc_engine_activity_enable_stats(&uc->guc); /* We don't fail the driver load if HuC fails to auth */ @@ -242,11 +247,6 @@ int xe_uc_reset_prepare(struct xe_uc *uc) return xe_guc_reset_prepare(&uc->guc); } -void xe_uc_gucrc_disable(struct xe_uc *uc) -{ - XE_WARN_ON(xe_guc_pc_gucrc_disable(&uc->guc.pc)); -} - void xe_uc_stop_prepare(struct xe_uc *uc) { xe_gsc_stop_prepare(&uc->gsc); diff --git a/drivers/gpu/drm/xe/xe_uc.h b/drivers/gpu/drm/xe/xe_uc.h index 5398da1a8097c..255a54a8f876c 100644 --- a/drivers/gpu/drm/xe/xe_uc.h +++ b/drivers/gpu/drm/xe/xe_uc.h @@ -12,7 +12,6 @@ int xe_uc_init_noalloc(struct xe_uc *uc); int xe_uc_init(struct xe_uc *uc); int xe_uc_init_post_hwconfig(struct xe_uc *uc); int xe_uc_load_hw(struct xe_uc *uc); -void xe_uc_gucrc_disable(struct xe_uc *uc); int xe_uc_reset_prepare(struct xe_uc *uc); void xe_uc_runtime_resume(struct xe_uc *uc); void xe_uc_runtime_suspend(struct xe_uc *uc);