1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <drm/drm_drv.h> 7 #include <linux/device.h> 8 9 #include "xe_device.h" 10 #include "xe_force_wake.h" 11 #include "xe_gt_idle.h" 12 #include "xe_guc_engine_activity.h" 13 #include "xe_hw_engine.h" 14 #include "xe_pm.h" 15 #include "xe_pmu.h" 16 17 /** 18 * DOC: Xe PMU (Performance Monitoring Unit) 19 * 20 * Expose events/counters like GT-C6 residency, GT frequency and per-class-engine 21 * activity to user land via the perf interface. Events are per device. 22 * 23 * All events are listed in sysfs: 24 * 25 * $ ls -ld /sys/bus/event_source/devices/xe_* 26 * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/events/ 27 * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/format/ 28 * 29 * The following format parameters are available to read events, 30 * but only few are valid with each event: 31 * 32 * gt[60:63] Selects gt for the event 33 * engine_class[20:27] Selects engine-class for event 34 * engine_instance[12:19] Selects the engine-instance for the event 35 * 36 * For engine specific events (engine-*), gt, engine_class and engine_instance parameters must be 37 * set as populated by DRM_XE_DEVICE_QUERY_ENGINES. 38 * 39 * For gt specific events (gt-*) gt parameter must be passed. All other parameters will be 0. 40 * 41 * The standard perf tool can be used to grep for a certain event as well. 42 * Example: 43 * 44 * $ perf list | grep gt-c6 45 * 46 * To sample a specific event for a GT at regular intervals: 47 * 48 * $ perf stat -e <event_name,gt=> -I <interval> 49 */ 50 51 #define XE_PMU_EVENT_GT_MASK GENMASK_ULL(63, 60) 52 #define XE_PMU_EVENT_ENGINE_CLASS_MASK GENMASK_ULL(27, 20) 53 #define XE_PMU_EVENT_ENGINE_INSTANCE_MASK GENMASK_ULL(19, 12) 54 #define XE_PMU_EVENT_ID_MASK GENMASK_ULL(11, 0) 55 56 static unsigned int config_to_event_id(u64 config) 57 { 58 return FIELD_GET(XE_PMU_EVENT_ID_MASK, config); 59 } 60 61 static unsigned int config_to_engine_class(u64 config) 62 { 63 return FIELD_GET(XE_PMU_EVENT_ENGINE_CLASS_MASK, config); 64 } 65 66 static unsigned int config_to_engine_instance(u64 config) 67 { 68 return FIELD_GET(XE_PMU_EVENT_ENGINE_INSTANCE_MASK, config); 69 } 70 71 static unsigned int config_to_gt_id(u64 config) 72 { 73 return FIELD_GET(XE_PMU_EVENT_GT_MASK, config); 74 } 75 76 #define XE_PMU_EVENT_GT_C6_RESIDENCY 0x01 77 #define XE_PMU_EVENT_ENGINE_ACTIVE_TICKS 0x02 78 #define XE_PMU_EVENT_ENGINE_TOTAL_TICKS 0x03 79 80 static struct xe_gt *event_to_gt(struct perf_event *event) 81 { 82 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 83 u64 gt = config_to_gt_id(event->attr.config); 84 85 return xe_device_get_gt(xe, gt); 86 } 87 88 static struct xe_hw_engine *event_to_hwe(struct perf_event *event) 89 { 90 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 91 struct drm_xe_engine_class_instance eci; 92 u64 config = event->attr.config; 93 struct xe_hw_engine *hwe; 94 95 eci.engine_class = config_to_engine_class(config); 96 eci.engine_instance = config_to_engine_instance(config); 97 eci.gt_id = config_to_gt_id(config); 98 99 hwe = xe_hw_engine_lookup(xe, eci); 100 if (!hwe || xe_hw_engine_is_reserved(hwe)) 101 return NULL; 102 103 return hwe; 104 } 105 106 static bool is_engine_event(u64 config) 107 { 108 unsigned int event_id = config_to_event_id(config); 109 110 return (event_id == XE_PMU_EVENT_ENGINE_TOTAL_TICKS || 111 event_id == XE_PMU_EVENT_ENGINE_ACTIVE_TICKS); 112 } 113 114 static bool event_gt_forcewake(struct perf_event *event) 115 { 116 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 117 u64 config = event->attr.config; 118 struct xe_gt *gt; 119 unsigned int *fw_ref; 120 121 if (!is_engine_event(config)) 122 return true; 123 124 gt = xe_device_get_gt(xe, config_to_gt_id(config)); 125 126 fw_ref = kzalloc(sizeof(*fw_ref), GFP_KERNEL); 127 if (!fw_ref) 128 return false; 129 130 *fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); 131 if (!*fw_ref) { 132 kfree(fw_ref); 133 return false; 134 } 135 136 event->pmu_private = fw_ref; 137 138 return true; 139 } 140 141 static bool event_supported(struct xe_pmu *pmu, unsigned int gt, 142 unsigned int id) 143 { 144 if (gt >= XE_MAX_GT_PER_TILE) 145 return false; 146 147 return id < sizeof(pmu->supported_events) * BITS_PER_BYTE && 148 pmu->supported_events & BIT_ULL(id); 149 } 150 151 static bool event_param_valid(struct perf_event *event) 152 { 153 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 154 unsigned int engine_class, engine_instance; 155 u64 config = event->attr.config; 156 struct xe_gt *gt; 157 158 gt = xe_device_get_gt(xe, config_to_gt_id(config)); 159 if (!gt) 160 return false; 161 162 engine_class = config_to_engine_class(config); 163 engine_instance = config_to_engine_instance(config); 164 165 switch (config_to_event_id(config)) { 166 case XE_PMU_EVENT_GT_C6_RESIDENCY: 167 if (engine_class || engine_instance) 168 return false; 169 break; 170 case XE_PMU_EVENT_ENGINE_ACTIVE_TICKS: 171 case XE_PMU_EVENT_ENGINE_TOTAL_TICKS: 172 if (!event_to_hwe(event)) 173 return false; 174 break; 175 } 176 177 return true; 178 } 179 180 static void xe_pmu_event_destroy(struct perf_event *event) 181 { 182 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 183 struct xe_gt *gt; 184 unsigned int *fw_ref = event->pmu_private; 185 186 if (fw_ref) { 187 gt = xe_device_get_gt(xe, config_to_gt_id(event->attr.config)); 188 xe_force_wake_put(gt_to_fw(gt), *fw_ref); 189 kfree(fw_ref); 190 event->pmu_private = NULL; 191 } 192 193 drm_WARN_ON(&xe->drm, event->parent); 194 xe_pm_runtime_put(xe); 195 drm_dev_put(&xe->drm); 196 } 197 198 static int xe_pmu_event_init(struct perf_event *event) 199 { 200 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 201 struct xe_pmu *pmu = &xe->pmu; 202 unsigned int id, gt; 203 204 if (!pmu->registered) 205 return -ENODEV; 206 207 if (event->attr.type != event->pmu->type) 208 return -ENOENT; 209 210 /* unsupported modes and filters */ 211 if (event->attr.sample_period) /* no sampling */ 212 return -EINVAL; 213 214 if (event->cpu < 0) 215 return -EINVAL; 216 217 gt = config_to_gt_id(event->attr.config); 218 id = config_to_event_id(event->attr.config); 219 if (!event_supported(pmu, gt, id)) 220 return -ENOENT; 221 222 if (has_branch_stack(event)) 223 return -EOPNOTSUPP; 224 225 if (!event_param_valid(event)) 226 return -ENOENT; 227 228 if (!event->parent) { 229 drm_dev_get(&xe->drm); 230 xe_pm_runtime_get(xe); 231 if (!event_gt_forcewake(event)) { 232 xe_pm_runtime_put(xe); 233 drm_dev_put(&xe->drm); 234 return -EINVAL; 235 } 236 event->destroy = xe_pmu_event_destroy; 237 } 238 239 return 0; 240 } 241 242 static u64 read_engine_events(struct xe_gt *gt, struct perf_event *event) 243 { 244 struct xe_hw_engine *hwe; 245 u64 val = 0; 246 247 hwe = event_to_hwe(event); 248 249 if (config_to_event_id(event->attr.config) == XE_PMU_EVENT_ENGINE_ACTIVE_TICKS) 250 val = xe_guc_engine_activity_active_ticks(>->uc.guc, hwe, 0); 251 else 252 val = xe_guc_engine_activity_total_ticks(>->uc.guc, hwe, 0); 253 254 return val; 255 } 256 257 static u64 __xe_pmu_event_read(struct perf_event *event) 258 { 259 struct xe_gt *gt = event_to_gt(event); 260 261 if (!gt) 262 return 0; 263 264 switch (config_to_event_id(event->attr.config)) { 265 case XE_PMU_EVENT_GT_C6_RESIDENCY: 266 return xe_gt_idle_residency_msec(>->gtidle); 267 case XE_PMU_EVENT_ENGINE_ACTIVE_TICKS: 268 case XE_PMU_EVENT_ENGINE_TOTAL_TICKS: 269 return read_engine_events(gt, event); 270 } 271 272 return 0; 273 } 274 275 static void xe_pmu_event_update(struct perf_event *event) 276 { 277 struct hw_perf_event *hwc = &event->hw; 278 u64 prev, new; 279 280 prev = local64_read(&hwc->prev_count); 281 do { 282 new = __xe_pmu_event_read(event); 283 } while (!local64_try_cmpxchg(&hwc->prev_count, &prev, new)); 284 285 local64_add(new - prev, &event->count); 286 } 287 288 static void xe_pmu_event_read(struct perf_event *event) 289 { 290 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 291 struct xe_pmu *pmu = &xe->pmu; 292 293 if (!pmu->registered) { 294 event->hw.state = PERF_HES_STOPPED; 295 return; 296 } 297 298 xe_pmu_event_update(event); 299 } 300 301 static void xe_pmu_enable(struct perf_event *event) 302 { 303 /* 304 * Store the current counter value so we can report the correct delta 305 * for all listeners. Even when the event was already enabled and has 306 * an existing non-zero value. 307 */ 308 local64_set(&event->hw.prev_count, __xe_pmu_event_read(event)); 309 } 310 311 static void xe_pmu_event_start(struct perf_event *event, int flags) 312 { 313 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 314 struct xe_pmu *pmu = &xe->pmu; 315 316 if (!pmu->registered) 317 return; 318 319 xe_pmu_enable(event); 320 event->hw.state = 0; 321 } 322 323 static void xe_pmu_event_stop(struct perf_event *event, int flags) 324 { 325 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 326 struct xe_pmu *pmu = &xe->pmu; 327 328 if (pmu->registered) 329 if (flags & PERF_EF_UPDATE) 330 xe_pmu_event_update(event); 331 332 event->hw.state = PERF_HES_STOPPED; 333 } 334 335 static int xe_pmu_event_add(struct perf_event *event, int flags) 336 { 337 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 338 struct xe_pmu *pmu = &xe->pmu; 339 340 if (!pmu->registered) 341 return -ENODEV; 342 343 if (flags & PERF_EF_START) 344 xe_pmu_event_start(event, flags); 345 346 return 0; 347 } 348 349 static void xe_pmu_event_del(struct perf_event *event, int flags) 350 { 351 xe_pmu_event_stop(event, PERF_EF_UPDATE); 352 } 353 354 PMU_FORMAT_ATTR(gt, "config:60-63"); 355 PMU_FORMAT_ATTR(engine_class, "config:20-27"); 356 PMU_FORMAT_ATTR(engine_instance, "config:12-19"); 357 PMU_FORMAT_ATTR(event, "config:0-11"); 358 359 static struct attribute *pmu_format_attrs[] = { 360 &format_attr_event.attr, 361 &format_attr_engine_class.attr, 362 &format_attr_engine_instance.attr, 363 &format_attr_gt.attr, 364 NULL, 365 }; 366 367 static const struct attribute_group pmu_format_attr_group = { 368 .name = "format", 369 .attrs = pmu_format_attrs, 370 }; 371 372 static ssize_t event_attr_show(struct device *dev, 373 struct device_attribute *attr, char *buf) 374 { 375 struct perf_pmu_events_attr *pmu_attr = 376 container_of(attr, struct perf_pmu_events_attr, attr); 377 378 return sprintf(buf, "event=%#04llx\n", pmu_attr->id); 379 } 380 381 #define XE_EVENT_ATTR(name_, v_, id_) \ 382 PMU_EVENT_ATTR(name_, pmu_event_ ## v_, id_, event_attr_show) 383 384 #define XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ 385 PMU_EVENT_ATTR_STRING(name_.unit, pmu_event_unit_ ## v_, unit_) 386 387 #define XE_EVENT_ATTR_GROUP(v_, id_, ...) \ 388 static struct attribute *pmu_attr_ ##v_[] = { \ 389 __VA_ARGS__, \ 390 NULL \ 391 }; \ 392 static umode_t is_visible_##v_(struct kobject *kobj, \ 393 struct attribute *attr, int idx) \ 394 { \ 395 struct perf_pmu_events_attr *pmu_attr; \ 396 struct xe_pmu *pmu; \ 397 \ 398 pmu_attr = container_of(attr, typeof(*pmu_attr), attr.attr); \ 399 pmu = container_of(dev_get_drvdata(kobj_to_dev(kobj)), \ 400 typeof(*pmu), base); \ 401 \ 402 return event_supported(pmu, 0, id_) ? attr->mode : 0; \ 403 } \ 404 static const struct attribute_group pmu_group_ ##v_ = { \ 405 .name = "events", \ 406 .attrs = pmu_attr_ ## v_, \ 407 .is_visible = is_visible_ ## v_, \ 408 } 409 410 #define XE_EVENT_ATTR_SIMPLE(name_, v_, id_, unit_) \ 411 XE_EVENT_ATTR(name_, v_, id_) \ 412 XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ 413 XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr, \ 414 &pmu_event_unit_ ##v_.attr.attr) 415 416 #define XE_EVENT_ATTR_NOUNIT(name_, v_, id_) \ 417 XE_EVENT_ATTR(name_, v_, id_) \ 418 XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr) 419 420 XE_EVENT_ATTR_SIMPLE(gt-c6-residency, gt_c6_residency, XE_PMU_EVENT_GT_C6_RESIDENCY, "ms"); 421 XE_EVENT_ATTR_NOUNIT(engine-active-ticks, engine_active_ticks, XE_PMU_EVENT_ENGINE_ACTIVE_TICKS); 422 XE_EVENT_ATTR_NOUNIT(engine-total-ticks, engine_total_ticks, XE_PMU_EVENT_ENGINE_TOTAL_TICKS); 423 424 static struct attribute *pmu_empty_event_attrs[] = { 425 /* Empty - all events are added as groups with .attr_update() */ 426 NULL, 427 }; 428 429 static const struct attribute_group pmu_events_attr_group = { 430 .name = "events", 431 .attrs = pmu_empty_event_attrs, 432 }; 433 434 static const struct attribute_group *pmu_events_attr_update[] = { 435 &pmu_group_gt_c6_residency, 436 &pmu_group_engine_active_ticks, 437 &pmu_group_engine_total_ticks, 438 NULL, 439 }; 440 441 static void set_supported_events(struct xe_pmu *pmu) 442 { 443 struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 444 struct xe_gt *gt = xe_device_get_gt(xe, 0); 445 446 if (!xe->info.skip_guc_pc) 447 pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_GT_C6_RESIDENCY); 448 449 if (xe_guc_engine_activity_supported(>->uc.guc)) { 450 pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_ENGINE_ACTIVE_TICKS); 451 pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_ENGINE_TOTAL_TICKS); 452 } 453 } 454 455 /** 456 * xe_pmu_unregister() - Remove/cleanup PMU registration 457 * @arg: Ptr to pmu 458 */ 459 static void xe_pmu_unregister(void *arg) 460 { 461 struct xe_pmu *pmu = arg; 462 struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 463 464 if (!pmu->registered) 465 return; 466 467 pmu->registered = false; 468 469 perf_pmu_unregister(&pmu->base); 470 kfree(pmu->name); 471 } 472 473 /** 474 * xe_pmu_register() - Define basic PMU properties for Xe and add event callbacks. 475 * @pmu: the PMU object 476 * 477 * Returns 0 on success and an appropriate error code otherwise 478 */ 479 int xe_pmu_register(struct xe_pmu *pmu) 480 { 481 struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 482 static const struct attribute_group *attr_groups[] = { 483 &pmu_format_attr_group, 484 &pmu_events_attr_group, 485 NULL 486 }; 487 int ret = -ENOMEM; 488 char *name; 489 490 BUILD_BUG_ON(XE_MAX_GT_PER_TILE != XE_PMU_MAX_GT); 491 492 if (IS_SRIOV_VF(xe)) 493 return 0; 494 495 name = kasprintf(GFP_KERNEL, "xe_%s", 496 dev_name(xe->drm.dev)); 497 if (!name) 498 goto err; 499 500 /* tools/perf reserves colons as special. */ 501 strreplace(name, ':', '_'); 502 503 pmu->name = name; 504 pmu->base.attr_groups = attr_groups; 505 pmu->base.attr_update = pmu_events_attr_update; 506 pmu->base.scope = PERF_PMU_SCOPE_SYS_WIDE; 507 pmu->base.module = THIS_MODULE; 508 pmu->base.task_ctx_nr = perf_invalid_context; 509 pmu->base.event_init = xe_pmu_event_init; 510 pmu->base.add = xe_pmu_event_add; 511 pmu->base.del = xe_pmu_event_del; 512 pmu->base.start = xe_pmu_event_start; 513 pmu->base.stop = xe_pmu_event_stop; 514 pmu->base.read = xe_pmu_event_read; 515 516 set_supported_events(pmu); 517 518 ret = perf_pmu_register(&pmu->base, pmu->name, -1); 519 if (ret) 520 goto err_name; 521 522 pmu->registered = true; 523 524 return devm_add_action_or_reset(xe->drm.dev, xe_pmu_unregister, pmu); 525 526 err_name: 527 kfree(name); 528 err: 529 drm_err(&xe->drm, "Failed to register PMU (ret=%d)!\n", ret); 530 531 return ret; 532 } 533