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_gt_idle.h" 11 #include "xe_pm.h" 12 #include "xe_pmu.h" 13 14 /** 15 * DOC: Xe PMU (Performance Monitoring Unit) 16 * 17 * Expose events/counters like GT-C6 residency and GT frequency to user land via 18 * the perf interface. Events are per device. The GT can be selected with an 19 * extra config sub-field (bits 60-63). 20 * 21 * All events are listed in sysfs: 22 * 23 * $ ls -ld /sys/bus/event_source/devices/xe_* 24 * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/events/ 25 * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/format/ 26 * 27 * The format directory has info regarding the configs that can be used. 28 * The standard perf tool can be used to grep for a certain event as well. 29 * Example: 30 * 31 * $ perf list | grep gt-c6 32 * 33 * To sample a specific event for a GT at regular intervals: 34 * 35 * $ perf stat -e <event_name,gt=> -I <interval> 36 */ 37 38 #define XE_PMU_EVENT_GT_MASK GENMASK_ULL(63, 60) 39 #define XE_PMU_EVENT_ID_MASK GENMASK_ULL(11, 0) 40 41 static unsigned int config_to_event_id(u64 config) 42 { 43 return FIELD_GET(XE_PMU_EVENT_ID_MASK, config); 44 } 45 46 static unsigned int config_to_gt_id(u64 config) 47 { 48 return FIELD_GET(XE_PMU_EVENT_GT_MASK, config); 49 } 50 51 #define XE_PMU_EVENT_GT_C6_RESIDENCY 0x01 52 53 static struct xe_gt *event_to_gt(struct perf_event *event) 54 { 55 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 56 u64 gt = config_to_gt_id(event->attr.config); 57 58 return xe_device_get_gt(xe, gt); 59 } 60 61 static bool event_supported(struct xe_pmu *pmu, unsigned int gt, 62 unsigned int id) 63 { 64 if (gt >= XE_MAX_GT_PER_TILE) 65 return false; 66 67 return id < sizeof(pmu->supported_events) * BITS_PER_BYTE && 68 pmu->supported_events & BIT_ULL(id); 69 } 70 71 static void xe_pmu_event_destroy(struct perf_event *event) 72 { 73 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 74 75 drm_WARN_ON(&xe->drm, event->parent); 76 xe_pm_runtime_put(xe); 77 drm_dev_put(&xe->drm); 78 } 79 80 static int xe_pmu_event_init(struct perf_event *event) 81 { 82 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 83 struct xe_pmu *pmu = &xe->pmu; 84 unsigned int id, gt; 85 86 if (!pmu->registered) 87 return -ENODEV; 88 89 if (event->attr.type != event->pmu->type) 90 return -ENOENT; 91 92 /* unsupported modes and filters */ 93 if (event->attr.sample_period) /* no sampling */ 94 return -EINVAL; 95 96 if (event->cpu < 0) 97 return -EINVAL; 98 99 gt = config_to_gt_id(event->attr.config); 100 id = config_to_event_id(event->attr.config); 101 if (!event_supported(pmu, gt, id)) 102 return -ENOENT; 103 104 if (has_branch_stack(event)) 105 return -EOPNOTSUPP; 106 107 if (!event->parent) { 108 drm_dev_get(&xe->drm); 109 xe_pm_runtime_get(xe); 110 event->destroy = xe_pmu_event_destroy; 111 } 112 113 return 0; 114 } 115 116 static u64 __xe_pmu_event_read(struct perf_event *event) 117 { 118 struct xe_gt *gt = event_to_gt(event); 119 120 if (!gt) 121 return 0; 122 123 switch (config_to_event_id(event->attr.config)) { 124 case XE_PMU_EVENT_GT_C6_RESIDENCY: 125 return xe_gt_idle_residency_msec(>->gtidle); 126 } 127 128 return 0; 129 } 130 131 static void xe_pmu_event_update(struct perf_event *event) 132 { 133 struct hw_perf_event *hwc = &event->hw; 134 u64 prev, new; 135 136 prev = local64_read(&hwc->prev_count); 137 do { 138 new = __xe_pmu_event_read(event); 139 } while (!local64_try_cmpxchg(&hwc->prev_count, &prev, new)); 140 141 local64_add(new - prev, &event->count); 142 } 143 144 static void xe_pmu_event_read(struct perf_event *event) 145 { 146 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 147 struct xe_pmu *pmu = &xe->pmu; 148 149 if (!pmu->registered) { 150 event->hw.state = PERF_HES_STOPPED; 151 return; 152 } 153 154 xe_pmu_event_update(event); 155 } 156 157 static void xe_pmu_enable(struct perf_event *event) 158 { 159 /* 160 * Store the current counter value so we can report the correct delta 161 * for all listeners. Even when the event was already enabled and has 162 * an existing non-zero value. 163 */ 164 local64_set(&event->hw.prev_count, __xe_pmu_event_read(event)); 165 } 166 167 static void xe_pmu_event_start(struct perf_event *event, int flags) 168 { 169 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 170 struct xe_pmu *pmu = &xe->pmu; 171 172 if (!pmu->registered) 173 return; 174 175 xe_pmu_enable(event); 176 event->hw.state = 0; 177 } 178 179 static void xe_pmu_event_stop(struct perf_event *event, int flags) 180 { 181 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 182 struct xe_pmu *pmu = &xe->pmu; 183 184 if (pmu->registered) 185 if (flags & PERF_EF_UPDATE) 186 xe_pmu_event_update(event); 187 188 event->hw.state = PERF_HES_STOPPED; 189 } 190 191 static int xe_pmu_event_add(struct perf_event *event, int flags) 192 { 193 struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 194 struct xe_pmu *pmu = &xe->pmu; 195 196 if (!pmu->registered) 197 return -ENODEV; 198 199 if (flags & PERF_EF_START) 200 xe_pmu_event_start(event, flags); 201 202 return 0; 203 } 204 205 static void xe_pmu_event_del(struct perf_event *event, int flags) 206 { 207 xe_pmu_event_stop(event, PERF_EF_UPDATE); 208 } 209 210 PMU_FORMAT_ATTR(gt, "config:60-63"); 211 PMU_FORMAT_ATTR(event, "config:0-11"); 212 213 static struct attribute *pmu_format_attrs[] = { 214 &format_attr_event.attr, 215 &format_attr_gt.attr, 216 NULL, 217 }; 218 219 static const struct attribute_group pmu_format_attr_group = { 220 .name = "format", 221 .attrs = pmu_format_attrs, 222 }; 223 224 static ssize_t event_attr_show(struct device *dev, 225 struct device_attribute *attr, char *buf) 226 { 227 struct perf_pmu_events_attr *pmu_attr = 228 container_of(attr, struct perf_pmu_events_attr, attr); 229 230 return sprintf(buf, "event=%#04llx\n", pmu_attr->id); 231 } 232 233 #define XE_EVENT_ATTR(name_, v_, id_) \ 234 PMU_EVENT_ATTR(name_, pmu_event_ ## v_, id_, event_attr_show) 235 236 #define XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ 237 PMU_EVENT_ATTR_STRING(name_.unit, pmu_event_unit_ ## v_, unit_) 238 239 #define XE_EVENT_ATTR_GROUP(v_, id_, ...) \ 240 static struct attribute *pmu_attr_ ##v_[] = { \ 241 __VA_ARGS__, \ 242 NULL \ 243 }; \ 244 static umode_t is_visible_##v_(struct kobject *kobj, \ 245 struct attribute *attr, int idx) \ 246 { \ 247 struct perf_pmu_events_attr *pmu_attr; \ 248 struct xe_pmu *pmu; \ 249 \ 250 pmu_attr = container_of(attr, typeof(*pmu_attr), attr.attr); \ 251 pmu = container_of(dev_get_drvdata(kobj_to_dev(kobj)), \ 252 typeof(*pmu), base); \ 253 \ 254 return event_supported(pmu, 0, id_) ? attr->mode : 0; \ 255 } \ 256 static const struct attribute_group pmu_group_ ##v_ = { \ 257 .name = "events", \ 258 .attrs = pmu_attr_ ## v_, \ 259 .is_visible = is_visible_ ## v_, \ 260 } 261 262 #define XE_EVENT_ATTR_SIMPLE(name_, v_, id_, unit_) \ 263 XE_EVENT_ATTR(name_, v_, id_) \ 264 XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ 265 XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr, \ 266 &pmu_event_unit_ ##v_.attr.attr) 267 268 #define XE_EVENT_ATTR_NOUNIT(name_, v_, id_) \ 269 XE_EVENT_ATTR(name_, v_, id_) \ 270 XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr) 271 272 XE_EVENT_ATTR_SIMPLE(gt-c6-residency, gt_c6_residency, XE_PMU_EVENT_GT_C6_RESIDENCY, "ms"); 273 274 static struct attribute *pmu_empty_event_attrs[] = { 275 /* Empty - all events are added as groups with .attr_update() */ 276 NULL, 277 }; 278 279 static const struct attribute_group pmu_events_attr_group = { 280 .name = "events", 281 .attrs = pmu_empty_event_attrs, 282 }; 283 284 static const struct attribute_group *pmu_events_attr_update[] = { 285 &pmu_group_gt_c6_residency, 286 NULL, 287 }; 288 289 static void set_supported_events(struct xe_pmu *pmu) 290 { 291 struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 292 293 if (!xe->info.skip_guc_pc) 294 pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_GT_C6_RESIDENCY); 295 } 296 297 /** 298 * xe_pmu_unregister() - Remove/cleanup PMU registration 299 * @arg: Ptr to pmu 300 */ 301 static void xe_pmu_unregister(void *arg) 302 { 303 struct xe_pmu *pmu = arg; 304 struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 305 306 if (!pmu->registered) 307 return; 308 309 pmu->registered = false; 310 311 perf_pmu_unregister(&pmu->base); 312 kfree(pmu->name); 313 } 314 315 /** 316 * xe_pmu_register() - Define basic PMU properties for Xe and add event callbacks. 317 * @pmu: the PMU object 318 * 319 * Returns 0 on success and an appropriate error code otherwise 320 */ 321 int xe_pmu_register(struct xe_pmu *pmu) 322 { 323 struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 324 static const struct attribute_group *attr_groups[] = { 325 &pmu_format_attr_group, 326 &pmu_events_attr_group, 327 NULL 328 }; 329 int ret = -ENOMEM; 330 char *name; 331 332 BUILD_BUG_ON(XE_MAX_GT_PER_TILE != XE_PMU_MAX_GT); 333 334 if (IS_SRIOV_VF(xe)) 335 return 0; 336 337 name = kasprintf(GFP_KERNEL, "xe_%s", 338 dev_name(xe->drm.dev)); 339 if (!name) 340 goto err; 341 342 /* tools/perf reserves colons as special. */ 343 strreplace(name, ':', '_'); 344 345 pmu->name = name; 346 pmu->base.attr_groups = attr_groups; 347 pmu->base.attr_update = pmu_events_attr_update; 348 pmu->base.scope = PERF_PMU_SCOPE_SYS_WIDE; 349 pmu->base.module = THIS_MODULE; 350 pmu->base.task_ctx_nr = perf_invalid_context; 351 pmu->base.event_init = xe_pmu_event_init; 352 pmu->base.add = xe_pmu_event_add; 353 pmu->base.del = xe_pmu_event_del; 354 pmu->base.start = xe_pmu_event_start; 355 pmu->base.stop = xe_pmu_event_stop; 356 pmu->base.read = xe_pmu_event_read; 357 358 set_supported_events(pmu); 359 360 ret = perf_pmu_register(&pmu->base, pmu->name, -1); 361 if (ret) 362 goto err_name; 363 364 pmu->registered = true; 365 366 return devm_add_action_or_reset(xe->drm.dev, xe_pmu_unregister, pmu); 367 368 err_name: 369 kfree(name); 370 err: 371 drm_err(&xe->drm, "Failed to register PMU (ret=%d)!\n", ret); 372 373 return ret; 374 } 375