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

drm/xe: Add support for per-function engine activity

Add support for function level engine activity stats.
Engine activity stats are enabled when VF's are enabled

v2: remove unnecessary initialization
move offset to improve code readability (Umesh)
remove global for function engine activity (Lucas)

v3: fix commit message (Michal)

v4: remove enable function parameter
fix kernel-doc (Umesh)

Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Riana Tauro <riana.tauro@intel.com>
Reviewed-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250311071759.2117211-2-riana.tauro@intel.com
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>

authored by

Riana Tauro and committed by
Lucas De Marchi
2de3f38f f2d7e9ba

+192 -33
+1
drivers/gpu/drm/xe/abi/guc_actions_abi.h
··· 141 141 XE_GUC_ACTION_CLIENT_SOFT_RESET = 0x5507, 142 142 XE_GUC_ACTION_SET_ENG_UTIL_BUFF = 0x550A, 143 143 XE_GUC_ACTION_SET_DEVICE_ENGINE_ACTIVITY_BUFFER = 0x550C, 144 + XE_GUC_ACTION_SET_FUNCTION_ENGINE_ACTIVITY_BUFFER = 0x550D, 144 145 XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR = 0x6000, 145 146 XE_GUC_ACTION_REPORT_PAGE_FAULT_REQ_DESC = 0x6002, 146 147 XE_GUC_ACTION_PAGE_FAULT_RES_DESC = 0x6003,
+172 -28
drivers/gpu/drm/xe/xe_guc_engine_activity.c
··· 17 17 #include "xe_hw_engine.h" 18 18 #include "xe_map.h" 19 19 #include "xe_mmio.h" 20 + #include "xe_sriov_pf_helpers.h" 20 21 #include "xe_trace_guc.h" 21 22 22 23 #define TOTAL_QUANTA 0x8000 23 24 24 - static struct iosys_map engine_activity_map(struct xe_guc *guc, struct xe_hw_engine *hwe) 25 + static struct iosys_map engine_activity_map(struct xe_guc *guc, struct xe_hw_engine *hwe, 26 + unsigned int index) 25 27 { 26 28 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 27 - struct engine_activity_buffer *buffer = &engine_activity->device_buffer; 29 + struct engine_activity_buffer *buffer; 28 30 u16 guc_class = xe_engine_class_to_guc_class(hwe->class); 29 31 size_t offset; 30 32 31 - offset = offsetof(struct guc_engine_activity_data, 33 + if (engine_activity->num_functions) { 34 + buffer = &engine_activity->function_buffer; 35 + offset = sizeof(struct guc_engine_activity_data) * index; 36 + } else { 37 + buffer = &engine_activity->device_buffer; 38 + offset = 0; 39 + } 40 + 41 + offset += offsetof(struct guc_engine_activity_data, 32 42 engine_activity[guc_class][hwe->logical_instance]); 33 43 34 44 return IOSYS_MAP_INIT_OFFSET(&buffer->activity_bo->vmap, offset); 35 45 } 36 46 37 - static struct iosys_map engine_metadata_map(struct xe_guc *guc) 47 + static struct iosys_map engine_metadata_map(struct xe_guc *guc, 48 + unsigned int index) 38 49 { 39 50 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 40 - struct engine_activity_buffer *buffer = &engine_activity->device_buffer; 51 + struct engine_activity_buffer *buffer; 52 + size_t offset; 41 53 42 - return buffer->metadata_bo->vmap; 54 + if (engine_activity->num_functions) { 55 + buffer = &engine_activity->function_buffer; 56 + offset = sizeof(struct guc_engine_activity_metadata) * index; 57 + } else { 58 + buffer = &engine_activity->device_buffer; 59 + offset = 0; 60 + } 61 + 62 + return IOSYS_MAP_INIT_OFFSET(&buffer->metadata_bo->vmap, offset); 43 63 } 44 64 45 65 static int allocate_engine_activity_group(struct xe_guc *guc) 46 66 { 47 67 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 48 68 struct xe_device *xe = guc_to_xe(guc); 49 - u32 num_activity_group = 1; /* Will be modified for VF */ 69 + u32 num_activity_group; 70 + 71 + /* 72 + * An additional activity group is allocated for PF 73 + */ 74 + num_activity_group = IS_SRIOV_PF(xe) ? xe_sriov_pf_get_totalvfs(xe) + 1 : 1; 50 75 51 76 engine_activity->eag = drmm_kcalloc(&xe->drm, num_activity_group, 52 77 sizeof(struct engine_activity_group), GFP_KERNEL); ··· 85 60 } 86 61 87 62 static int allocate_engine_activity_buffers(struct xe_guc *guc, 88 - struct engine_activity_buffer *buffer) 63 + struct engine_activity_buffer *buffer, 64 + int count) 89 65 { 90 - u32 metadata_size = sizeof(struct guc_engine_activity_metadata); 91 - u32 size = sizeof(struct guc_engine_activity_data); 66 + u32 metadata_size = sizeof(struct guc_engine_activity_metadata) * count; 67 + u32 size = sizeof(struct guc_engine_activity_data) * count; 92 68 struct xe_gt *gt = guc_to_gt(guc); 93 69 struct xe_tile *tile = gt_to_tile(gt); 94 70 struct xe_bo *bo, *metadata_bo; ··· 144 118 return true; 145 119 } 146 120 147 - static struct engine_activity *hw_engine_to_engine_activity(struct xe_hw_engine *hwe) 121 + static struct engine_activity *hw_engine_to_engine_activity(struct xe_hw_engine *hwe, 122 + unsigned int index) 148 123 { 149 124 struct xe_guc *guc = &hwe->gt->uc.guc; 150 - struct engine_activity_group *eag = &guc->engine_activity.eag[0]; 125 + struct engine_activity_group *eag = &guc->engine_activity.eag[index]; 151 126 u16 guc_class = xe_engine_class_to_guc_class(hwe->class); 152 127 153 128 return &eag->engine[guc_class][hwe->logical_instance]; ··· 165 138 #define read_metadata_record(xe_, map_, field_) \ 166 139 xe_map_rd_field(xe_, map_, 0, struct guc_engine_activity_metadata, field_) 167 140 168 - static u64 get_engine_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe) 141 + static u64 get_engine_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 142 + unsigned int index) 169 143 { 170 - struct engine_activity *ea = hw_engine_to_engine_activity(hwe); 144 + struct engine_activity *ea = hw_engine_to_engine_activity(hwe, index); 171 145 struct guc_engine_activity *cached_activity = &ea->activity; 172 146 struct guc_engine_activity_metadata *cached_metadata = &ea->metadata; 173 147 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; ··· 179 151 u64 active_ticks, gpm_ts; 180 152 u16 change_num; 181 153 182 - activity_map = engine_activity_map(guc, hwe); 183 - metadata_map = engine_metadata_map(guc); 154 + activity_map = engine_activity_map(guc, hwe, index); 155 + metadata_map = engine_metadata_map(guc, index); 184 156 global_change_num = read_metadata_record(xe, &metadata_map, global_change_num); 185 157 186 158 /* GuC has not initialized activity data yet, return 0 */ ··· 222 194 return ea->total + ea->active; 223 195 } 224 196 225 - static u64 get_engine_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe) 197 + static u64 get_engine_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, unsigned int index) 226 198 { 227 - struct engine_activity *ea = hw_engine_to_engine_activity(hwe); 199 + struct engine_activity *ea = hw_engine_to_engine_activity(hwe, index); 228 200 struct guc_engine_activity_metadata *cached_metadata = &ea->metadata; 229 201 struct guc_engine_activity *cached_activity = &ea->activity; 230 202 struct iosys_map activity_map, metadata_map; ··· 233 205 u64 numerator; 234 206 u16 quanta_ratio; 235 207 236 - activity_map = engine_activity_map(guc, hwe); 237 - metadata_map = engine_metadata_map(guc); 208 + activity_map = engine_activity_map(guc, hwe, index); 209 + metadata_map = engine_metadata_map(guc, index); 238 210 239 211 if (!cached_metadata->guc_tsc_frequency_hz) 240 212 cached_metadata->guc_tsc_frequency_hz = read_metadata_record(xe, &metadata_map, ··· 273 245 return xe_guc_ct_send_block(&guc->ct, action, ARRAY_SIZE(action)); 274 246 } 275 247 276 - static void engine_activity_set_cpu_ts(struct xe_guc *guc) 248 + static int enable_function_engine_activity_stats(struct xe_guc *guc, bool enable) 277 249 { 278 250 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 279 - struct engine_activity_group *eag = &engine_activity->eag[0]; 251 + u32 metadata_ggtt_addr = 0, ggtt_addr = 0, num_functions = 0; 252 + struct engine_activity_buffer *buffer = &engine_activity->function_buffer; 253 + u32 action[6]; 254 + int len = 0; 255 + 256 + if (enable) { 257 + metadata_ggtt_addr = xe_bo_ggtt_addr(buffer->metadata_bo); 258 + ggtt_addr = xe_bo_ggtt_addr(buffer->activity_bo); 259 + num_functions = engine_activity->num_functions; 260 + } 261 + 262 + action[len++] = XE_GUC_ACTION_SET_FUNCTION_ENGINE_ACTIVITY_BUFFER; 263 + action[len++] = num_functions; 264 + action[len++] = metadata_ggtt_addr; 265 + action[len++] = 0; 266 + action[len++] = ggtt_addr; 267 + action[len++] = 0; 268 + 269 + /* Blocking here to ensure the buffers are ready before reading them */ 270 + return xe_guc_ct_send_block(&guc->ct, action, ARRAY_SIZE(action)); 271 + } 272 + 273 + static void engine_activity_set_cpu_ts(struct xe_guc *guc, unsigned int index) 274 + { 275 + struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 276 + struct engine_activity_group *eag = &engine_activity->eag[index]; 280 277 int i, j; 281 278 282 279 for (i = 0; i < GUC_MAX_ENGINE_CLASSES; i++) ··· 318 265 return 3 - REG_FIELD_GET(RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK, reg); 319 266 } 320 267 268 + static bool is_function_valid(struct xe_guc *guc, unsigned int fn_id) 269 + { 270 + struct xe_device *xe = guc_to_xe(guc); 271 + struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 272 + 273 + if (!IS_SRIOV_PF(xe) && fn_id) 274 + return false; 275 + 276 + if (engine_activity->num_functions && fn_id >= engine_activity->num_functions) 277 + return false; 278 + 279 + return true; 280 + } 281 + 282 + static int engine_activity_disable_function_stats(struct xe_guc *guc) 283 + { 284 + struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 285 + struct engine_activity_buffer *buffer = &engine_activity->function_buffer; 286 + int ret; 287 + 288 + if (!engine_activity->num_functions) 289 + return 0; 290 + 291 + ret = enable_function_engine_activity_stats(guc, false); 292 + if (ret) 293 + return ret; 294 + 295 + free_engine_activity_buffers(buffer); 296 + engine_activity->num_functions = 0; 297 + 298 + return 0; 299 + } 300 + 301 + static int engine_activity_enable_function_stats(struct xe_guc *guc, int num_vfs) 302 + { 303 + struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 304 + struct engine_activity_buffer *buffer = &engine_activity->function_buffer; 305 + int ret, i; 306 + 307 + if (!num_vfs) 308 + return 0; 309 + 310 + /* This includes 1 PF and num_vfs */ 311 + engine_activity->num_functions = num_vfs + 1; 312 + 313 + ret = allocate_engine_activity_buffers(guc, buffer, engine_activity->num_functions); 314 + if (ret) 315 + return ret; 316 + 317 + ret = enable_function_engine_activity_stats(guc, true); 318 + if (ret) { 319 + free_engine_activity_buffers(buffer); 320 + engine_activity->num_functions = 0; 321 + return ret; 322 + } 323 + 324 + for (i = 0; i < engine_activity->num_functions; i++) 325 + engine_activity_set_cpu_ts(guc, i + 1); 326 + 327 + return 0; 328 + } 329 + 321 330 /** 322 331 * xe_guc_engine_activity_active_ticks - Get engine active ticks 323 332 * @guc: The GuC object 324 333 * @hwe: The hw_engine object 334 + * @fn_id: function id to report on 325 335 * 326 336 * Return: accumulated ticks @hwe was active since engine activity stats were enabled. 327 337 */ 328 - u64 xe_guc_engine_activity_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe) 338 + u64 xe_guc_engine_activity_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 339 + unsigned int fn_id) 329 340 { 330 341 if (!xe_guc_engine_activity_supported(guc)) 331 342 return 0; 332 343 333 - return get_engine_active_ticks(guc, hwe); 344 + if (!is_function_valid(guc, fn_id)) 345 + return 0; 346 + 347 + return get_engine_active_ticks(guc, hwe, fn_id); 334 348 } 335 349 336 350 /** 337 351 * xe_guc_engine_activity_total_ticks - Get engine total ticks 338 352 * @guc: The GuC object 339 353 * @hwe: The hw_engine object 354 + * @fn_id: function id to report on 340 355 * 341 356 * Return: accumulated quanta of ticks allocated for the engine 342 357 */ 343 - u64 xe_guc_engine_activity_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe) 358 + u64 xe_guc_engine_activity_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 359 + unsigned int fn_id) 344 360 { 345 361 if (!xe_guc_engine_activity_supported(guc)) 346 362 return 0; 347 363 348 - return get_engine_total_ticks(guc, hwe); 364 + if (!is_function_valid(guc, fn_id)) 365 + return 0; 366 + 367 + return get_engine_total_ticks(guc, hwe, fn_id); 349 368 } 350 369 351 370 /** ··· 433 308 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 434 309 435 310 return engine_activity->supported; 311 + } 312 + 313 + /** 314 + * xe_guc_engine_activity_function_stats - Enable/Disable per-function engine activity stats 315 + * @guc: The GuC object 316 + * @num_vfs: number of vfs 317 + * @enable: true to enable, false otherwise 318 + * 319 + * Return: 0 on success, negative error code otherwise 320 + */ 321 + int xe_guc_engine_activity_function_stats(struct xe_guc *guc, int num_vfs, bool enable) 322 + { 323 + if (!xe_guc_engine_activity_supported(guc)) 324 + return 0; 325 + 326 + if (enable) 327 + return engine_activity_enable_function_stats(guc, num_vfs); 328 + 329 + return engine_activity_disable_function_stats(guc); 436 330 } 437 331 438 332 /** ··· 471 327 if (ret) 472 328 xe_gt_err(guc_to_gt(guc), "failed to enable activity stats%d\n", ret); 473 329 else 474 - engine_activity_set_cpu_ts(guc); 330 + engine_activity_set_cpu_ts(guc, 0); 475 331 } 476 332 477 333 static void engine_activity_fini(void *arg) ··· 504 360 return ret; 505 361 } 506 362 507 - ret = allocate_engine_activity_buffers(guc, &engine_activity->device_buffer); 363 + ret = allocate_engine_activity_buffers(guc, &engine_activity->device_buffer, 1); 508 364 if (ret) { 509 365 xe_gt_err(gt, "failed to allocate engine activity buffers (%pe)\n", ERR_PTR(ret)); 510 366 return ret;
+5 -2
drivers/gpu/drm/xe/xe_guc_engine_activity.h
··· 14 14 int xe_guc_engine_activity_init(struct xe_guc *guc); 15 15 bool xe_guc_engine_activity_supported(struct xe_guc *guc); 16 16 void xe_guc_engine_activity_enable_stats(struct xe_guc *guc); 17 - u64 xe_guc_engine_activity_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe); 18 - u64 xe_guc_engine_activity_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe); 17 + int xe_guc_engine_activity_function_stats(struct xe_guc *guc, int num_vfs, bool enable); 18 + u64 xe_guc_engine_activity_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 19 + unsigned int fn_id); 20 + u64 xe_guc_engine_activity_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 21 + unsigned int fn_id); 19 22 #endif
+11 -1
drivers/gpu/drm/xe/xe_guc_engine_activity_types.h
··· 79 79 /** @num_activity_group: number of activity groups */ 80 80 u32 num_activity_group; 81 81 82 + /** @num_functions: number of functions */ 83 + u32 num_functions; 84 + 82 85 /** @supported: indicates support for engine activity stats */ 83 86 bool supported; 84 87 85 - /** @eag: holds the device level engine activity data */ 88 + /** 89 + * @eag: holds the device level engine activity data in native mode. 90 + * In SRIOV mode, points to an array with entries which holds the engine 91 + * activity data for PF and VF's 92 + */ 86 93 struct engine_activity_group *eag; 87 94 88 95 /** @device_buffer: buffer object for global engine activity */ 89 96 struct engine_activity_buffer device_buffer; 97 + 98 + /** @function_buffer: buffer object for per-function engine activity */ 99 + struct engine_activity_buffer function_buffer; 90 100 }; 91 101 #endif 92 102
+3 -2
drivers/gpu/drm/xe/xe_pmu.c
··· 245 245 u64 val = 0; 246 246 247 247 hwe = event_to_hwe(event); 248 + 248 249 if (config_to_event_id(event->attr.config) == XE_PMU_EVENT_ENGINE_ACTIVE_TICKS) 249 - val = xe_guc_engine_activity_active_ticks(&gt->uc.guc, hwe); 250 + val = xe_guc_engine_activity_active_ticks(&gt->uc.guc, hwe, 0); 250 251 else 251 - val = xe_guc_engine_activity_total_ticks(&gt->uc.guc, hwe); 252 + val = xe_guc_engine_activity_total_ticks(&gt->uc.guc, hwe, 0); 252 253 253 254 return val; 254 255 }