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

drm/xe/guc: Add SLPC power profile interface

GuC has an interface to set a power profile for the SLPC algorithm.
Base mode is default and ensures a balanced performance, power_saving
mode has conservative up/down thresholds and is suitable for use with
apps that typically need to be power efficient. This will result in
lower GT frequencies, thus consuming lower power.

Selected power profile will be displayed in this format:

$ cat power_profile

[base] power_saving

$ echo power_saving > power_profile
$ cat power_profile

base [power_saving]

v2: Address review comments (Rodrigo)

Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://lore.kernel.org/r/20250903232120.390190-1-vinay.belgaumkar@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

authored by

Vinay Belgaumkar and committed by
Rodrigo Vivi
60d2b789 692a4802

+102
+5
drivers/gpu/drm/xe/abi/guc_actions_slpc_abi.h
··· 210 210 u8 reserved_mode_definition[4096]; 211 211 } __packed; 212 212 213 + enum slpc_power_profile { 214 + SLPC_POWER_PROFILE_BASE = 0x0, 215 + SLPC_POWER_PROFILE_POWER_SAVING = 0x1 216 + }; 217 + 213 218 /** 214 219 * DOC: SLPC H2G MESSAGE FORMAT 215 220 *
+26
drivers/gpu/drm/xe/xe_gt_freq.c
··· 227 227 } 228 228 static struct kobj_attribute attr_max_freq = __ATTR_RW(max_freq); 229 229 230 + static ssize_t power_profile_show(struct kobject *kobj, 231 + struct kobj_attribute *attr, 232 + char *buff) 233 + { 234 + struct device *dev = kobj_to_dev(kobj); 235 + 236 + xe_guc_pc_get_power_profile(dev_to_pc(dev), buff); 237 + 238 + return strlen(buff); 239 + } 240 + 241 + static ssize_t power_profile_store(struct kobject *kobj, 242 + struct kobj_attribute *attr, 243 + const char *buff, size_t count) 244 + { 245 + struct device *dev = kobj_to_dev(kobj); 246 + struct xe_guc_pc *pc = dev_to_pc(dev); 247 + int err; 248 + 249 + err = xe_guc_pc_set_power_profile(pc, buff); 250 + 251 + return err ?: count; 252 + } 253 + static struct kobj_attribute attr_power_profile = __ATTR_RW(power_profile); 254 + 230 255 static const struct attribute *freq_attrs[] = { 231 256 &attr_act_freq.attr, 232 257 &attr_cur_freq.attr, ··· 261 236 &attr_rpn_freq.attr, 262 237 &attr_min_freq.attr, 263 238 &attr_max_freq.attr, 239 + &attr_power_profile.attr, 264 240 NULL 265 241 }; 266 242
+67
drivers/gpu/drm/xe/xe_guc_pc.c
··· 79 79 * Xe driver enables SLPC with all of its defaults features and frequency 80 80 * selection, which varies per platform. 81 81 * 82 + * Power profiles add another level of control to SLPC. When power saving 83 + * profile is chosen, SLPC will use conservative thresholds to ramp frequency, 84 + * thus saving power. Base profile is default and ensures balanced performance 85 + * for any workload. 86 + * 82 87 * Render-C States: 83 88 * ================ 84 89 * ··· 1176 1171 return ret; 1177 1172 } 1178 1173 1174 + static const char *power_profile_to_string(struct xe_guc_pc *pc) 1175 + { 1176 + switch (pc->power_profile) { 1177 + case SLPC_POWER_PROFILE_BASE: 1178 + return "base"; 1179 + case SLPC_POWER_PROFILE_POWER_SAVING: 1180 + return "power_saving"; 1181 + default: 1182 + return "invalid"; 1183 + } 1184 + } 1185 + 1186 + void xe_guc_pc_get_power_profile(struct xe_guc_pc *pc, char *profile) 1187 + { 1188 + switch (pc->power_profile) { 1189 + case SLPC_POWER_PROFILE_BASE: 1190 + sprintf(profile, "[%s] %s\n", "base", "power_saving"); 1191 + break; 1192 + case SLPC_POWER_PROFILE_POWER_SAVING: 1193 + sprintf(profile, "%s [%s]\n", "base", "power_saving"); 1194 + break; 1195 + default: 1196 + sprintf(profile, "invalid"); 1197 + } 1198 + } 1199 + 1200 + int xe_guc_pc_set_power_profile(struct xe_guc_pc *pc, const char *buf) 1201 + { 1202 + int ret = 0; 1203 + u32 val; 1204 + 1205 + if (strncmp("base", buf, strlen("base")) == 0) 1206 + val = SLPC_POWER_PROFILE_BASE; 1207 + else if (strncmp("power_saving", buf, strlen("power_saving")) == 0) 1208 + val = SLPC_POWER_PROFILE_POWER_SAVING; 1209 + else 1210 + return -EINVAL; 1211 + 1212 + guard(mutex)(&pc->freq_lock); 1213 + xe_pm_runtime_get(pc_to_xe(pc)); 1214 + 1215 + ret = pc_action_set_param(pc, 1216 + SLPC_PARAM_POWER_PROFILE, 1217 + val); 1218 + if (ret) 1219 + xe_gt_err_once(pc_to_gt(pc), "Failed to set power profile to %d: %pe\n", 1220 + val, ERR_PTR(ret)); 1221 + else 1222 + pc->power_profile = val; 1223 + 1224 + xe_pm_runtime_put(pc_to_xe(pc)); 1225 + 1226 + return ret; 1227 + } 1228 + 1179 1229 /** 1180 1230 * xe_guc_pc_start - Start GuC's Power Conservation component 1181 1231 * @pc: Xe_GuC_PC instance ··· 1309 1249 /* Enable SLPC Optimized Strategy for compute */ 1310 1250 ret = pc_action_set_strategy(pc, SLPC_OPTIMIZED_STRATEGY_COMPUTE); 1311 1251 1252 + /* Set cached value of power_profile */ 1253 + ret = xe_guc_pc_set_power_profile(pc, power_profile_to_string(pc)); 1254 + if (unlikely(ret)) 1255 + xe_gt_err(gt, "Failed to set SLPC power profile: %pe\n", ERR_PTR(ret)); 1256 + 1312 1257 out: 1313 1258 xe_force_wake_put(gt_to_fw(gt), fw_ref); 1314 1259 return ret; ··· 1391 1326 return PTR_ERR(bo); 1392 1327 1393 1328 pc->bo = bo; 1329 + 1330 + pc->power_profile = SLPC_POWER_PROFILE_BASE; 1394 1331 1395 1332 return devm_add_action_or_reset(xe->drm.dev, xe_guc_pc_fini_hw, pc); 1396 1333 }
+2
drivers/gpu/drm/xe/xe_guc_pc.h
··· 31 31 int xe_guc_pc_set_min_freq(struct xe_guc_pc *pc, u32 freq); 32 32 int xe_guc_pc_get_max_freq(struct xe_guc_pc *pc, u32 *freq); 33 33 int xe_guc_pc_set_max_freq(struct xe_guc_pc *pc, u32 freq); 34 + int xe_guc_pc_set_power_profile(struct xe_guc_pc *pc, const char *buf); 35 + void xe_guc_pc_get_power_profile(struct xe_guc_pc *pc, char *profile); 34 36 35 37 enum xe_gt_idle_state xe_guc_pc_c_status(struct xe_guc_pc *pc); 36 38 u64 xe_guc_pc_rc6_residency(struct xe_guc_pc *pc);
+2
drivers/gpu/drm/xe/xe_guc_pc_types.h
··· 37 37 struct mutex freq_lock; 38 38 /** @freq_ready: Only handle freq changes, if they are really ready */ 39 39 bool freq_ready; 40 + /** @power_profile: Base or power_saving profile */ 41 + u32 power_profile; 40 42 }; 41 43 42 44 #endif /* _XE_GUC_PC_TYPES_H_ */