Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <riana.tauro@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Reviewed-by: Riana Tauro <riana.tauro@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Link: https://patch.msgid.link/20260204014234.2867763-2-vinay.belgaumkar@intel.com

+172 -64
+3
Documentation/gpu/xe/xe_firmware.rst
··· 31 31 .. kernel-doc:: drivers/gpu/drm/xe/xe_guc_pc.c 32 32 :doc: GuC Power Conservation (PC) 33 33 34 + .. kernel-doc:: drivers/gpu/drm/xe/xe_guc_rc.c 35 + :doc: GuC Render C-states (GuC RC) 36 + 34 37 PCIe Gen5 Limitations 35 38 ===================== 36 39
+1
drivers/gpu/drm/xe/Makefile
··· 74 74 xe_guc_log.o \ 75 75 xe_guc_pagefault.o \ 76 76 xe_guc_pc.o \ 77 + xe_guc_rc.o \ 77 78 xe_guc_submit.o \ 78 79 xe_guc_tlb_inval.o \ 79 80 xe_heci_gsc.o \
-1
drivers/gpu/drm/xe/xe_gt.c
··· 849 849 if (IS_SRIOV_PF(gt_to_xe(gt))) 850 850 xe_gt_sriov_pf_stop_prepare(gt); 851 851 852 - xe_uc_gucrc_disable(&gt->uc); 853 852 xe_uc_stop_prepare(&gt->uc); 854 853 xe_pagefault_reset(gt_to_xe(gt), gt); 855 854
+6
drivers/gpu/drm/xe/xe_guc.c
··· 35 35 #include "xe_guc_klv_helpers.h" 36 36 #include "xe_guc_log.h" 37 37 #include "xe_guc_pc.h" 38 + #include "xe_guc_rc.h" 38 39 #include "xe_guc_relay.h" 39 40 #include "xe_guc_submit.h" 40 41 #include "xe_memirq.h" ··· 882 881 if (ret) 883 882 return ret; 884 883 884 + ret = xe_guc_rc_init(guc); 885 + if (ret) 886 + return ret; 887 + 885 888 ret = xe_guc_engine_activity_init(guc); 886 889 if (ret) 887 890 return ret; ··· 1636 1631 if (!IS_SRIOV_VF(guc_to_xe(guc))) { 1637 1632 int err; 1638 1633 1634 + xe_guc_rc_disable(guc); 1639 1635 err = xe_guc_pc_stop(&guc->pc); 1640 1636 xe_gt_WARN(guc_to_gt(guc), err, "Failed to stop GuC PC: %pe\n", 1641 1637 ERR_PTR(err));
+12 -56
drivers/gpu/drm/xe/xe_guc_pc.c
··· 92 92 * Render-C states is also a GuC PC feature that is now enabled in Xe for 93 93 * all platforms. 94 94 * 95 + * Implementation details: 96 + * ----------------------- 97 + * The implementation for GuC Power Management features is split as follows: 98 + * 99 + * xe_guc_rc: Logic for handling GuC RC 100 + * xe_gt_idle: Host side logic for RC6 and Coarse Power gating (CPG) 101 + * xe_guc_pc: Logic for all other SLPC related features 102 + * 103 + * There is some cross interaction between these where host C6 will need to be 104 + * enabled when we plan to skip GuC RC. Also, the GuC RC mode is currently 105 + * overridden through 0x3003 which is an SLPC H2G call. 95 106 */ 96 107 97 108 static struct xe_guc *pc_to_guc(struct xe_guc_pc *pc) ··· 261 250 xe_gt_err(pc_to_gt(pc), "GuC PC unset param failed: %pe", 262 251 ERR_PTR(ret)); 263 252 264 - return ret; 265 - } 266 - 267 - static int pc_action_setup_gucrc(struct xe_guc_pc *pc, u32 mode) 268 - { 269 - struct xe_guc_ct *ct = pc_to_ct(pc); 270 - u32 action[] = { 271 - GUC_ACTION_HOST2GUC_SETUP_PC_GUCRC, 272 - mode, 273 - }; 274 - int ret; 275 - 276 - ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0); 277 - if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) 278 - xe_gt_err(pc_to_gt(pc), "GuC RC enable mode=%u failed: %pe\n", 279 - mode, ERR_PTR(ret)); 280 253 return ret; 281 254 } 282 255 ··· 1046 1051 } 1047 1052 1048 1053 /** 1049 - * xe_guc_pc_gucrc_disable - Disable GuC RC 1050 - * @pc: Xe_GuC_PC instance 1051 - * 1052 - * Disables GuC RC by taking control of RC6 back from GuC. 1053 - * 1054 - * Return: 0 on success, negative error code on error. 1055 - */ 1056 - int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc) 1057 - { 1058 - struct xe_device *xe = pc_to_xe(pc); 1059 - struct xe_gt *gt = pc_to_gt(pc); 1060 - int ret = 0; 1061 - 1062 - if (xe->info.skip_guc_pc) 1063 - return 0; 1064 - 1065 - ret = pc_action_setup_gucrc(pc, GUCRC_HOST_CONTROL); 1066 - if (ret) 1067 - return ret; 1068 - 1069 - return xe_gt_idle_disable_c6(gt); 1070 - } 1071 - 1072 - /** 1073 1054 * xe_guc_pc_override_gucrc_mode - override GUCRC mode 1074 1055 * @pc: Xe_GuC_PC instance 1075 1056 * @mode: new value of the mode. ··· 1218 1247 return -ETIMEDOUT; 1219 1248 1220 1249 if (xe->info.skip_guc_pc) { 1221 - if (xe->info.platform != XE_PVC) 1222 - xe_gt_idle_enable_c6(gt); 1223 - 1224 1250 /* Request max possible since dynamic freq mgmt is not enabled */ 1225 1251 pc_set_cur_freq(pc, UINT_MAX); 1226 1252 return 0; ··· 1259 1291 if (ret) 1260 1292 return ret; 1261 1293 1262 - if (xe->info.platform == XE_PVC) { 1263 - xe_guc_pc_gucrc_disable(pc); 1264 - return 0; 1265 - } 1266 - 1267 - ret = pc_action_setup_gucrc(pc, GUCRC_FIRMWARE_CONTROL); 1268 - if (ret) 1269 - return ret; 1270 - 1271 1294 /* Enable SLPC Optimized Strategy for compute */ 1272 1295 ret = pc_action_set_strategy(pc, SLPC_OPTIMIZED_STRATEGY_COMPUTE); 1273 1296 ··· 1278 1319 { 1279 1320 struct xe_device *xe = pc_to_xe(pc); 1280 1321 1281 - if (xe->info.skip_guc_pc) { 1282 - xe_gt_idle_disable_c6(pc_to_gt(pc)); 1322 + if (xe->info.skip_guc_pc) 1283 1323 return 0; 1284 - } 1285 1324 1286 1325 mutex_lock(&pc->freq_lock); 1287 1326 pc->freq_ready = false; ··· 1301 1344 return; 1302 1345 1303 1346 CLASS(xe_force_wake, fw_ref)(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL); 1304 - xe_guc_pc_gucrc_disable(pc); 1305 1347 XE_WARN_ON(xe_guc_pc_stop(pc)); 1306 1348 1307 1349 /* Bind requested freq to mert_freq_cap before unload */
-1
drivers/gpu/drm/xe/xe_guc_pc.h
··· 15 15 int xe_guc_pc_init(struct xe_guc_pc *pc); 16 16 int xe_guc_pc_start(struct xe_guc_pc *pc); 17 17 int xe_guc_pc_stop(struct xe_guc_pc *pc); 18 - int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc); 19 18 int xe_guc_pc_override_gucrc_mode(struct xe_guc_pc *pc, enum slpc_gucrc_mode mode); 20 19 int xe_guc_pc_unset_gucrc_mode(struct xe_guc_pc *pc); 21 20 void xe_guc_pc_print(struct xe_guc_pc *pc, struct drm_printer *p);
+130
drivers/gpu/drm/xe/xe_guc_rc.c
··· 1 + // SPDX-License-Identifier: MIT 2 + /* 3 + * Copyright © 2026 Intel Corporation 4 + */ 5 + 6 + #include <drm/drm_print.h> 7 + 8 + #include "abi/guc_actions_slpc_abi.h" 9 + #include "xe_device.h" 10 + #include "xe_force_wake.h" 11 + #include "xe_gt.h" 12 + #include "xe_gt_idle.h" 13 + #include "xe_gt_printk.h" 14 + #include "xe_guc.h" 15 + #include "xe_guc_ct.h" 16 + #include "xe_guc_rc.h" 17 + #include "xe_pm.h" 18 + 19 + /** 20 + * DOC: GuC RC (Render C-states) 21 + * 22 + * GuC handles the GT transition to deeper C-states in conjunction with Pcode. 23 + * GuC RC can be enabled independently of the frequency component in SLPC, 24 + * which is also controlled by GuC. 25 + * 26 + * This file will contain all H2G related logic for handling Render C-states. 27 + * There are some calls to xe_gt_idle, where we enable host C6 when GuC RC is 28 + * skipped. GuC RC is mostly independent of xe_guc_pc with the exception of 29 + * functions that override the mode for which we have to rely on the SLPC H2G 30 + * calls. 31 + */ 32 + 33 + static int guc_action_setup_gucrc(struct xe_guc *guc, u32 control) 34 + { 35 + u32 action[] = { 36 + GUC_ACTION_HOST2GUC_SETUP_PC_GUCRC, 37 + control, 38 + }; 39 + int ret; 40 + 41 + ret = xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0); 42 + if (ret && !(xe_device_wedged(guc_to_xe(guc)) && ret == -ECANCELED)) 43 + xe_gt_err(guc_to_gt(guc), 44 + "GuC RC setup %s(%u) failed (%pe)\n", 45 + control == GUCRC_HOST_CONTROL ? "HOST_CONTROL" : 46 + control == GUCRC_FIRMWARE_CONTROL ? "FIRMWARE_CONTROL" : 47 + "UNKNOWN", control, ERR_PTR(ret)); 48 + return ret; 49 + } 50 + 51 + /** 52 + * xe_guc_rc_disable() - Disable GuC RC 53 + * @guc: Xe GuC instance 54 + * 55 + * Disables GuC RC by taking control of RC6 back from GuC. 56 + */ 57 + void xe_guc_rc_disable(struct xe_guc *guc) 58 + { 59 + struct xe_device *xe = guc_to_xe(guc); 60 + struct xe_gt *gt = guc_to_gt(guc); 61 + 62 + if (!xe->info.skip_guc_pc && xe->info.platform != XE_PVC) 63 + if (guc_action_setup_gucrc(guc, GUCRC_HOST_CONTROL)) 64 + return; 65 + 66 + xe_gt_WARN_ON(gt, xe_gt_idle_disable_c6(gt)); 67 + } 68 + 69 + static void xe_guc_rc_fini_hw(void *arg) 70 + { 71 + struct xe_guc *guc = arg; 72 + struct xe_device *xe = guc_to_xe(guc); 73 + struct xe_gt *gt = guc_to_gt(guc); 74 + 75 + if (xe_device_wedged(xe)) 76 + return; 77 + 78 + CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 79 + xe_guc_rc_disable(guc); 80 + } 81 + 82 + /** 83 + * xe_guc_rc_init() - Init GuC RC 84 + * @guc: Xe GuC instance 85 + * 86 + * Add callback action for GuC RC 87 + * 88 + * Return: 0 on success, negative error code on error. 89 + */ 90 + int xe_guc_rc_init(struct xe_guc *guc) 91 + { 92 + struct xe_device *xe = guc_to_xe(guc); 93 + struct xe_gt *gt = guc_to_gt(guc); 94 + 95 + xe_gt_assert(gt, xe_device_uc_enabled(xe)); 96 + 97 + return devm_add_action_or_reset(xe->drm.dev, xe_guc_rc_fini_hw, guc); 98 + } 99 + 100 + /** 101 + * xe_guc_rc_enable() - Enable GuC RC feature if applicable 102 + * @guc: Xe GuC instance 103 + * 104 + * Enables GuC RC feature. 105 + * 106 + * Return: 0 on success, negative error code on error. 107 + */ 108 + int xe_guc_rc_enable(struct xe_guc *guc) 109 + { 110 + struct xe_device *xe = guc_to_xe(guc); 111 + struct xe_gt *gt = guc_to_gt(guc); 112 + 113 + xe_gt_assert(gt, xe_device_uc_enabled(xe)); 114 + 115 + CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); 116 + if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) 117 + return -ETIMEDOUT; 118 + 119 + if (xe->info.platform == XE_PVC) { 120 + xe_guc_rc_disable(guc); 121 + return 0; 122 + } 123 + 124 + if (xe->info.skip_guc_pc) { 125 + xe_gt_idle_enable_c6(gt); 126 + return 0; 127 + } 128 + 129 + return guc_action_setup_gucrc(guc, GUCRC_FIRMWARE_CONTROL); 130 + }
+15
drivers/gpu/drm/xe/xe_guc_rc.h
··· 1 + /* SPDX-License-Identifier: MIT */ 2 + /* 3 + * Copyright © 2026 Intel Corporation 4 + */ 5 + 6 + #ifndef _XE_GUC_RC_H_ 7 + #define _XE_GUC_RC_H_ 8 + 9 + struct xe_guc; 10 + 11 + int xe_guc_rc_init(struct xe_guc *guc); 12 + int xe_guc_rc_enable(struct xe_guc *guc); 13 + void xe_guc_rc_disable(struct xe_guc *guc); 14 + 15 + #endif
+5 -5
drivers/gpu/drm/xe/xe_uc.c
··· 13 13 #include "xe_gt_sriov_vf.h" 14 14 #include "xe_guc.h" 15 15 #include "xe_guc_pc.h" 16 + #include "xe_guc_rc.h" 16 17 #include "xe_guc_engine_activity.h" 17 18 #include "xe_huc.h" 18 19 #include "xe_sriov.h" ··· 215 214 if (ret) 216 215 goto err_out; 217 216 217 + ret = xe_guc_rc_enable(&uc->guc); 218 + if (ret) 219 + goto err_out; 220 + 218 221 xe_guc_engine_activity_enable_stats(&uc->guc); 219 222 220 223 /* We don't fail the driver load if HuC fails to auth */ ··· 245 240 return 0; 246 241 247 242 return xe_guc_reset_prepare(&uc->guc); 248 - } 249 - 250 - void xe_uc_gucrc_disable(struct xe_uc *uc) 251 - { 252 - XE_WARN_ON(xe_guc_pc_gucrc_disable(&uc->guc.pc)); 253 243 } 254 244 255 245 void xe_uc_stop_prepare(struct xe_uc *uc)
-1
drivers/gpu/drm/xe/xe_uc.h
··· 12 12 int xe_uc_init(struct xe_uc *uc); 13 13 int xe_uc_init_post_hwconfig(struct xe_uc *uc); 14 14 int xe_uc_load_hw(struct xe_uc *uc); 15 - void xe_uc_gucrc_disable(struct xe_uc *uc); 16 15 int xe_uc_reset_prepare(struct xe_uc *uc); 17 16 void xe_uc_runtime_resume(struct xe_uc *uc); 18 17 void xe_uc_runtime_suspend(struct xe_uc *uc);