1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <drm/drm_managed.h> 7 8 #include "abi/guc_actions_abi.h" 9 #include "regs/xe_gt_regs.h" 10 11 #include "xe_bo.h" 12 #include "xe_force_wake.h" 13 #include "xe_gt_printk.h" 14 #include "xe_guc.h" 15 #include "xe_guc_engine_activity.h" 16 #include "xe_guc_ct.h" 17 #include "xe_hw_engine.h" 18 #include "xe_map.h" 19 #include "xe_mmio.h" 20 #include "xe_sriov_pf_helpers.h" 21 #include "xe_trace_guc.h" 22 23 #define TOTAL_QUANTA 0x8000 24 25 static struct iosys_map engine_activity_map(struct xe_guc *guc, struct xe_hw_engine *hwe, 26 unsigned int index) 27 { 28 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 29 struct engine_activity_buffer *buffer; 30 u16 guc_class = xe_hwe_to_guc_class(hwe); 31 u16 guc_logical_instance = xe_hwe_guc_logical_instance(hwe); 32 size_t offset; 33 34 if (engine_activity->num_functions) { 35 buffer = &engine_activity->function_buffer; 36 offset = sizeof(struct guc_engine_activity_data) * index; 37 } else { 38 buffer = &engine_activity->device_buffer; 39 offset = 0; 40 } 41 42 offset += offsetof(struct guc_engine_activity_data, 43 engine_activity[guc_class][guc_logical_instance]); 44 45 return IOSYS_MAP_INIT_OFFSET(&buffer->activity_bo->vmap, offset); 46 } 47 48 static struct iosys_map engine_metadata_map(struct xe_guc *guc, 49 unsigned int index) 50 { 51 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 52 struct engine_activity_buffer *buffer; 53 size_t offset; 54 55 if (engine_activity->num_functions) { 56 buffer = &engine_activity->function_buffer; 57 offset = sizeof(struct guc_engine_activity_metadata) * index; 58 } else { 59 buffer = &engine_activity->device_buffer; 60 offset = 0; 61 } 62 63 return IOSYS_MAP_INIT_OFFSET(&buffer->metadata_bo->vmap, offset); 64 } 65 66 static int allocate_engine_activity_group(struct xe_guc *guc) 67 { 68 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 69 struct xe_device *xe = guc_to_xe(guc); 70 u32 num_activity_group; 71 72 /* 73 * An additional activity group is allocated for PF 74 */ 75 num_activity_group = IS_SRIOV_PF(xe) ? xe_sriov_pf_get_totalvfs(xe) + 1 : 1; 76 77 engine_activity->eag = drmm_kcalloc(&xe->drm, num_activity_group, 78 sizeof(struct engine_activity_group), GFP_KERNEL); 79 80 if (!engine_activity->eag) 81 return -ENOMEM; 82 83 engine_activity->num_activity_group = num_activity_group; 84 85 return 0; 86 } 87 88 static int allocate_engine_activity_buffers(struct xe_guc *guc, 89 struct engine_activity_buffer *buffer, 90 int count) 91 { 92 u32 metadata_size = sizeof(struct guc_engine_activity_metadata) * count; 93 u32 size = sizeof(struct guc_engine_activity_data) * count; 94 struct xe_gt *gt = guc_to_gt(guc); 95 struct xe_tile *tile = gt_to_tile(gt); 96 struct xe_bo *bo, *metadata_bo; 97 98 metadata_bo = xe_bo_create_pin_map_novm(gt_to_xe(gt), tile, PAGE_ALIGN(metadata_size), 99 ttm_bo_type_kernel, XE_BO_FLAG_SYSTEM | 100 XE_BO_FLAG_GGTT | XE_BO_FLAG_GGTT_INVALIDATE, 101 false); 102 103 if (IS_ERR(metadata_bo)) 104 return PTR_ERR(metadata_bo); 105 106 bo = xe_bo_create_pin_map_novm(gt_to_xe(gt), tile, PAGE_ALIGN(size), 107 ttm_bo_type_kernel, XE_BO_FLAG_VRAM_IF_DGFX(tile) | 108 XE_BO_FLAG_GGTT | XE_BO_FLAG_GGTT_INVALIDATE, false); 109 110 if (IS_ERR(bo)) { 111 xe_bo_unpin_map_no_vm(metadata_bo); 112 return PTR_ERR(bo); 113 } 114 115 buffer->metadata_bo = metadata_bo; 116 buffer->activity_bo = bo; 117 return 0; 118 } 119 120 static void free_engine_activity_buffers(struct engine_activity_buffer *buffer) 121 { 122 xe_bo_unpin_map_no_vm(buffer->metadata_bo); 123 xe_bo_unpin_map_no_vm(buffer->activity_bo); 124 } 125 126 static bool is_engine_activity_supported(struct xe_guc *guc) 127 { 128 struct xe_uc_fw_version *version = &guc->fw.versions.found[XE_UC_FW_VER_COMPATIBILITY]; 129 struct xe_uc_fw_version required = { .major = 1, .minor = 14, .patch = 1 }; 130 struct xe_gt *gt = guc_to_gt(guc); 131 132 if (IS_SRIOV_VF(gt_to_xe(gt))) { 133 xe_gt_info(gt, "engine activity stats not supported on VFs\n"); 134 return false; 135 } 136 137 /* engine activity stats is supported from GuC interface version (1.14.1) */ 138 if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER_STRUCT(required)) { 139 xe_gt_info(gt, 140 "engine activity stats unsupported in GuC interface v%u.%u.%u, need v%u.%u.%u or higher\n", 141 version->major, version->minor, version->patch, required.major, 142 required.minor, required.patch); 143 return false; 144 } 145 146 return true; 147 } 148 149 static struct engine_activity *hw_engine_to_engine_activity(struct xe_hw_engine *hwe, 150 unsigned int index) 151 { 152 struct xe_guc *guc = &hwe->gt->uc.guc; 153 struct engine_activity_group *eag = &guc->engine_activity.eag[index]; 154 u16 guc_class = xe_hwe_to_guc_class(hwe); 155 u16 guc_logical_instance = xe_hwe_guc_logical_instance(hwe); 156 157 return &eag->engine[guc_class][guc_logical_instance]; 158 } 159 160 static u64 cpu_ns_to_guc_tsc_tick(ktime_t ns, u32 freq) 161 { 162 return mul_u64_u32_div(ns, freq, NSEC_PER_SEC); 163 } 164 165 #define read_engine_activity_record(xe_, map_, field_) \ 166 xe_map_rd_field(xe_, map_, 0, struct guc_engine_activity, field_) 167 168 #define read_metadata_record(xe_, map_, field_) \ 169 xe_map_rd_field(xe_, map_, 0, struct guc_engine_activity_metadata, field_) 170 171 static u64 get_engine_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 172 unsigned int index) 173 { 174 struct engine_activity *ea = hw_engine_to_engine_activity(hwe, index); 175 struct guc_engine_activity *cached_activity = &ea->activity; 176 struct guc_engine_activity_metadata *cached_metadata = &ea->metadata; 177 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 178 struct iosys_map activity_map, metadata_map; 179 struct xe_device *xe = guc_to_xe(guc); 180 struct xe_gt *gt = guc_to_gt(guc); 181 u32 last_update_tick, global_change_num; 182 u64 active_ticks, gpm_ts; 183 u16 change_num; 184 185 activity_map = engine_activity_map(guc, hwe, index); 186 metadata_map = engine_metadata_map(guc, index); 187 global_change_num = read_metadata_record(xe, &metadata_map, global_change_num); 188 189 /* GuC has not initialized activity data yet, return 0 */ 190 if (!global_change_num) 191 goto update; 192 193 if (global_change_num == cached_metadata->global_change_num) 194 goto update; 195 196 cached_metadata->global_change_num = global_change_num; 197 change_num = read_engine_activity_record(xe, &activity_map, change_num); 198 199 if (!change_num || change_num == cached_activity->change_num) 200 goto update; 201 202 /* read engine activity values */ 203 last_update_tick = read_engine_activity_record(xe, &activity_map, last_update_tick); 204 active_ticks = read_engine_activity_record(xe, &activity_map, active_ticks); 205 206 /* activity calculations */ 207 ea->running = !!last_update_tick; 208 ea->total += active_ticks - cached_activity->active_ticks; 209 ea->active = 0; 210 211 /* cache the counter */ 212 cached_activity->change_num = change_num; 213 cached_activity->last_update_tick = last_update_tick; 214 cached_activity->active_ticks = active_ticks; 215 216 update: 217 if (ea->running) { 218 gpm_ts = xe_mmio_read64_2x32(>->mmio, MISC_STATUS_0) >> 219 engine_activity->gpm_timestamp_shift; 220 ea->active = lower_32_bits(gpm_ts) - cached_activity->last_update_tick; 221 } 222 223 trace_xe_guc_engine_activity(xe, ea, hwe->name, hwe->instance); 224 225 return ea->total + ea->active; 226 } 227 228 static u64 get_engine_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, unsigned int index) 229 { 230 struct engine_activity *ea = hw_engine_to_engine_activity(hwe, index); 231 struct guc_engine_activity_metadata *cached_metadata = &ea->metadata; 232 struct guc_engine_activity *cached_activity = &ea->activity; 233 struct iosys_map activity_map, metadata_map; 234 struct xe_device *xe = guc_to_xe(guc); 235 ktime_t now, cpu_delta; 236 u64 numerator; 237 u16 quanta_ratio; 238 239 activity_map = engine_activity_map(guc, hwe, index); 240 metadata_map = engine_metadata_map(guc, index); 241 242 if (!cached_metadata->guc_tsc_frequency_hz) 243 cached_metadata->guc_tsc_frequency_hz = read_metadata_record(xe, &metadata_map, 244 guc_tsc_frequency_hz); 245 246 quanta_ratio = read_engine_activity_record(xe, &activity_map, quanta_ratio); 247 cached_activity->quanta_ratio = quanta_ratio; 248 249 /* Total ticks calculations */ 250 now = ktime_get(); 251 cpu_delta = now - ea->last_cpu_ts; 252 ea->last_cpu_ts = now; 253 numerator = (ea->quanta_remainder_ns + cpu_delta) * cached_activity->quanta_ratio; 254 ea->quanta_ns += numerator / TOTAL_QUANTA; 255 ea->quanta_remainder_ns = numerator % TOTAL_QUANTA; 256 ea->quanta = cpu_ns_to_guc_tsc_tick(ea->quanta_ns, cached_metadata->guc_tsc_frequency_hz); 257 258 trace_xe_guc_engine_activity(xe, ea, hwe->name, hwe->instance); 259 260 return ea->quanta; 261 } 262 263 static int enable_engine_activity_stats(struct xe_guc *guc) 264 { 265 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 266 struct engine_activity_buffer *buffer = &engine_activity->device_buffer; 267 u32 action[] = { 268 XE_GUC_ACTION_SET_DEVICE_ENGINE_ACTIVITY_BUFFER, 269 xe_bo_ggtt_addr(buffer->metadata_bo), 270 0, 271 xe_bo_ggtt_addr(buffer->activity_bo), 272 0, 273 }; 274 275 /* Blocking here to ensure the buffers are ready before reading them */ 276 return xe_guc_ct_send_block(&guc->ct, action, ARRAY_SIZE(action)); 277 } 278 279 static int enable_function_engine_activity_stats(struct xe_guc *guc, bool enable) 280 { 281 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 282 u32 metadata_ggtt_addr = 0, ggtt_addr = 0, num_functions = 0; 283 struct engine_activity_buffer *buffer = &engine_activity->function_buffer; 284 u32 action[6]; 285 int len = 0; 286 287 if (enable) { 288 metadata_ggtt_addr = xe_bo_ggtt_addr(buffer->metadata_bo); 289 ggtt_addr = xe_bo_ggtt_addr(buffer->activity_bo); 290 num_functions = engine_activity->num_functions; 291 } 292 293 action[len++] = XE_GUC_ACTION_SET_FUNCTION_ENGINE_ACTIVITY_BUFFER; 294 action[len++] = num_functions; 295 action[len++] = metadata_ggtt_addr; 296 action[len++] = 0; 297 action[len++] = ggtt_addr; 298 action[len++] = 0; 299 300 /* Blocking here to ensure the buffers are ready before reading them */ 301 return xe_guc_ct_send_block(&guc->ct, action, ARRAY_SIZE(action)); 302 } 303 304 static void engine_activity_set_cpu_ts(struct xe_guc *guc, unsigned int index) 305 { 306 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 307 struct engine_activity_group *eag = &engine_activity->eag[index]; 308 int i, j; 309 310 xe_gt_assert(guc_to_gt(guc), index < engine_activity->num_activity_group); 311 312 for (i = 0; i < GUC_MAX_ENGINE_CLASSES; i++) 313 for (j = 0; j < GUC_MAX_INSTANCES_PER_CLASS; j++) 314 eag->engine[i][j].last_cpu_ts = ktime_get(); 315 } 316 317 static u32 gpm_timestamp_shift(struct xe_gt *gt) 318 { 319 u32 reg; 320 321 reg = xe_mmio_read32(>->mmio, RPM_CONFIG0); 322 323 return 3 - REG_FIELD_GET(RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK, reg); 324 } 325 326 static bool is_function_valid(struct xe_guc *guc, unsigned int fn_id) 327 { 328 struct xe_device *xe = guc_to_xe(guc); 329 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 330 331 if (!IS_SRIOV_PF(xe) && fn_id) 332 return false; 333 334 if (engine_activity->num_functions && fn_id >= engine_activity->num_functions) 335 return false; 336 337 return true; 338 } 339 340 static int engine_activity_disable_function_stats(struct xe_guc *guc) 341 { 342 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 343 struct engine_activity_buffer *buffer = &engine_activity->function_buffer; 344 int ret; 345 346 if (!engine_activity->num_functions) 347 return 0; 348 349 ret = enable_function_engine_activity_stats(guc, false); 350 if (ret) 351 return ret; 352 353 free_engine_activity_buffers(buffer); 354 engine_activity->num_functions = 0; 355 356 return 0; 357 } 358 359 static int engine_activity_enable_function_stats(struct xe_guc *guc, int num_vfs) 360 { 361 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 362 struct engine_activity_buffer *buffer = &engine_activity->function_buffer; 363 int ret, i; 364 365 if (!num_vfs) 366 return 0; 367 368 /* This includes 1 PF and num_vfs */ 369 engine_activity->num_functions = num_vfs + 1; 370 371 ret = allocate_engine_activity_buffers(guc, buffer, engine_activity->num_functions); 372 if (ret) 373 return ret; 374 375 ret = enable_function_engine_activity_stats(guc, true); 376 if (ret) { 377 free_engine_activity_buffers(buffer); 378 engine_activity->num_functions = 0; 379 return ret; 380 } 381 382 /* skip PF as it was already setup */ 383 for (i = 1; i < engine_activity->num_functions; i++) 384 engine_activity_set_cpu_ts(guc, i); 385 386 return 0; 387 } 388 389 /** 390 * xe_guc_engine_activity_active_ticks - Get engine active ticks 391 * @guc: The GuC object 392 * @hwe: The hw_engine object 393 * @fn_id: function id to report on 394 * 395 * Return: accumulated ticks @hwe was active since engine activity stats were enabled. 396 */ 397 u64 xe_guc_engine_activity_active_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 398 unsigned int fn_id) 399 { 400 if (!xe_guc_engine_activity_supported(guc)) 401 return 0; 402 403 if (!is_function_valid(guc, fn_id)) 404 return 0; 405 406 return get_engine_active_ticks(guc, hwe, fn_id); 407 } 408 409 /** 410 * xe_guc_engine_activity_total_ticks - Get engine total ticks 411 * @guc: The GuC object 412 * @hwe: The hw_engine object 413 * @fn_id: function id to report on 414 * 415 * Return: accumulated quanta of ticks allocated for the engine 416 */ 417 u64 xe_guc_engine_activity_total_ticks(struct xe_guc *guc, struct xe_hw_engine *hwe, 418 unsigned int fn_id) 419 { 420 if (!xe_guc_engine_activity_supported(guc)) 421 return 0; 422 423 if (!is_function_valid(guc, fn_id)) 424 return 0; 425 426 return get_engine_total_ticks(guc, hwe, fn_id); 427 } 428 429 /** 430 * xe_guc_engine_activity_supported - Check support for engine activity stats 431 * @guc: The GuC object 432 * 433 * Engine activity stats is supported from GuC interface version (1.14.1) 434 * 435 * Return: true if engine activity stats supported, false otherwise 436 */ 437 bool xe_guc_engine_activity_supported(struct xe_guc *guc) 438 { 439 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 440 441 return engine_activity->supported; 442 } 443 444 /** 445 * xe_guc_engine_activity_function_stats - Enable/Disable per-function engine activity stats 446 * @guc: The GuC object 447 * @num_vfs: number of vfs 448 * @enable: true to enable, false otherwise 449 * 450 * Return: 0 on success, negative error code otherwise 451 */ 452 int xe_guc_engine_activity_function_stats(struct xe_guc *guc, int num_vfs, bool enable) 453 { 454 if (!xe_guc_engine_activity_supported(guc)) 455 return 0; 456 457 if (enable) 458 return engine_activity_enable_function_stats(guc, num_vfs); 459 460 return engine_activity_disable_function_stats(guc); 461 } 462 463 /** 464 * xe_guc_engine_activity_enable_stats - Enable engine activity stats 465 * @guc: The GuC object 466 * 467 * Enable engine activity stats and set initial timestamps 468 */ 469 void xe_guc_engine_activity_enable_stats(struct xe_guc *guc) 470 { 471 int ret; 472 473 if (!xe_guc_engine_activity_supported(guc)) 474 return; 475 476 ret = enable_engine_activity_stats(guc); 477 if (ret) 478 xe_gt_err(guc_to_gt(guc), "failed to enable activity stats: %pe\n", ERR_PTR(ret)); 479 else 480 engine_activity_set_cpu_ts(guc, 0); 481 } 482 483 static void engine_activity_fini(void *arg) 484 { 485 struct xe_guc_engine_activity *engine_activity = arg; 486 struct engine_activity_buffer *buffer = &engine_activity->device_buffer; 487 488 free_engine_activity_buffers(buffer); 489 } 490 491 /** 492 * xe_guc_engine_activity_init - Initialize the engine activity data 493 * @guc: The GuC object 494 * 495 * Return: 0 on success, negative error code otherwise. 496 */ 497 int xe_guc_engine_activity_init(struct xe_guc *guc) 498 { 499 struct xe_guc_engine_activity *engine_activity = &guc->engine_activity; 500 struct xe_gt *gt = guc_to_gt(guc); 501 int ret; 502 503 engine_activity->supported = is_engine_activity_supported(guc); 504 if (!engine_activity->supported) 505 return 0; 506 507 ret = allocate_engine_activity_group(guc); 508 if (ret) { 509 xe_gt_err(gt, "failed to allocate engine activity group (%pe)\n", ERR_PTR(ret)); 510 return ret; 511 } 512 513 ret = allocate_engine_activity_buffers(guc, &engine_activity->device_buffer, 1); 514 if (ret) { 515 xe_gt_err(gt, "failed to allocate engine activity buffers (%pe)\n", ERR_PTR(ret)); 516 return ret; 517 } 518 519 engine_activity->gpm_timestamp_shift = gpm_timestamp_shift(gt); 520 521 return devm_add_action_or_reset(gt_to_xe(gt)->drm.dev, engine_activity_fini, 522 engine_activity); 523 } 524