1011c1e24SVinay Belgaumkar // SPDX-License-Identifier: MIT 2011c1e24SVinay Belgaumkar /* 3011c1e24SVinay Belgaumkar * Copyright © 2025 Intel Corporation 4011c1e24SVinay Belgaumkar */ 5011c1e24SVinay Belgaumkar 6011c1e24SVinay Belgaumkar #include <drm/drm_drv.h> 7011c1e24SVinay Belgaumkar #include <linux/device.h> 8011c1e24SVinay Belgaumkar 9011c1e24SVinay Belgaumkar #include "xe_device.h" 10*c7f2b8bfSRiana Tauro #include "xe_force_wake.h" 11897286f2SVinay Belgaumkar #include "xe_gt_idle.h" 126978c5f5SRiana Tauro #include "xe_guc_engine_activity.h" 136978c5f5SRiana Tauro #include "xe_hw_engine.h" 144ee64041SLucas De Marchi #include "xe_pm.h" 15011c1e24SVinay Belgaumkar #include "xe_pmu.h" 16011c1e24SVinay Belgaumkar 17011c1e24SVinay Belgaumkar /** 18011c1e24SVinay Belgaumkar * DOC: Xe PMU (Performance Monitoring Unit) 19011c1e24SVinay Belgaumkar * 206978c5f5SRiana Tauro * Expose events/counters like GT-C6 residency, GT frequency and per-class-engine 216978c5f5SRiana Tauro * activity to user land via the perf interface. Events are per device. 22011c1e24SVinay Belgaumkar * 23011c1e24SVinay Belgaumkar * All events are listed in sysfs: 24011c1e24SVinay Belgaumkar * 25011c1e24SVinay Belgaumkar * $ ls -ld /sys/bus/event_source/devices/xe_* 26011c1e24SVinay Belgaumkar * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/events/ 27011c1e24SVinay Belgaumkar * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/format/ 28011c1e24SVinay Belgaumkar * 296978c5f5SRiana Tauro * The following format parameters are available to read events, 306978c5f5SRiana Tauro * but only few are valid with each event: 316978c5f5SRiana Tauro * 326978c5f5SRiana Tauro * gt[60:63] Selects gt for the event 336978c5f5SRiana Tauro * engine_class[20:27] Selects engine-class for event 346978c5f5SRiana Tauro * engine_instance[12:19] Selects the engine-instance for the event 356978c5f5SRiana Tauro * 366978c5f5SRiana Tauro * For engine specific events (engine-*), gt, engine_class and engine_instance parameters must be 376978c5f5SRiana Tauro * set as populated by DRM_XE_DEVICE_QUERY_ENGINES. 386978c5f5SRiana Tauro * 396978c5f5SRiana Tauro * For gt specific events (gt-*) gt parameter must be passed. All other parameters will be 0. 406978c5f5SRiana Tauro * 41011c1e24SVinay Belgaumkar * The standard perf tool can be used to grep for a certain event as well. 42011c1e24SVinay Belgaumkar * Example: 43011c1e24SVinay Belgaumkar * 44011c1e24SVinay Belgaumkar * $ perf list | grep gt-c6 45011c1e24SVinay Belgaumkar * 46011c1e24SVinay Belgaumkar * To sample a specific event for a GT at regular intervals: 47011c1e24SVinay Belgaumkar * 48011c1e24SVinay Belgaumkar * $ perf stat -e <event_name,gt=> -I <interval> 49011c1e24SVinay Belgaumkar */ 50011c1e24SVinay Belgaumkar 51011c1e24SVinay Belgaumkar #define XE_PMU_EVENT_GT_MASK GENMASK_ULL(63, 60) 526978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_CLASS_MASK GENMASK_ULL(27, 20) 536978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_INSTANCE_MASK GENMASK_ULL(19, 12) 54011c1e24SVinay Belgaumkar #define XE_PMU_EVENT_ID_MASK GENMASK_ULL(11, 0) 55011c1e24SVinay Belgaumkar 56011c1e24SVinay Belgaumkar static unsigned int config_to_event_id(u64 config) 57011c1e24SVinay Belgaumkar { 58011c1e24SVinay Belgaumkar return FIELD_GET(XE_PMU_EVENT_ID_MASK, config); 59011c1e24SVinay Belgaumkar } 60011c1e24SVinay Belgaumkar 616978c5f5SRiana Tauro static unsigned int config_to_engine_class(u64 config) 626978c5f5SRiana Tauro { 636978c5f5SRiana Tauro return FIELD_GET(XE_PMU_EVENT_ENGINE_CLASS_MASK, config); 646978c5f5SRiana Tauro } 656978c5f5SRiana Tauro 666978c5f5SRiana Tauro static unsigned int config_to_engine_instance(u64 config) 676978c5f5SRiana Tauro { 686978c5f5SRiana Tauro return FIELD_GET(XE_PMU_EVENT_ENGINE_INSTANCE_MASK, config); 696978c5f5SRiana Tauro } 706978c5f5SRiana Tauro 71011c1e24SVinay Belgaumkar static unsigned int config_to_gt_id(u64 config) 72011c1e24SVinay Belgaumkar { 73011c1e24SVinay Belgaumkar return FIELD_GET(XE_PMU_EVENT_GT_MASK, config); 74011c1e24SVinay Belgaumkar } 75011c1e24SVinay Belgaumkar 76897286f2SVinay Belgaumkar #define XE_PMU_EVENT_GT_C6_RESIDENCY 0x01 776978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_ACTIVE_TICKS 0x02 786978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_TOTAL_TICKS 0x03 79897286f2SVinay Belgaumkar 80011c1e24SVinay Belgaumkar static struct xe_gt *event_to_gt(struct perf_event *event) 81011c1e24SVinay Belgaumkar { 82011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 83011c1e24SVinay Belgaumkar u64 gt = config_to_gt_id(event->attr.config); 84011c1e24SVinay Belgaumkar 85011c1e24SVinay Belgaumkar return xe_device_get_gt(xe, gt); 86011c1e24SVinay Belgaumkar } 87011c1e24SVinay Belgaumkar 886978c5f5SRiana Tauro static struct xe_hw_engine *event_to_hwe(struct perf_event *event) 896978c5f5SRiana Tauro { 906978c5f5SRiana Tauro struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 916978c5f5SRiana Tauro struct drm_xe_engine_class_instance eci; 926978c5f5SRiana Tauro u64 config = event->attr.config; 936978c5f5SRiana Tauro struct xe_hw_engine *hwe; 946978c5f5SRiana Tauro 956978c5f5SRiana Tauro eci.engine_class = config_to_engine_class(config); 966978c5f5SRiana Tauro eci.engine_instance = config_to_engine_instance(config); 976978c5f5SRiana Tauro eci.gt_id = config_to_gt_id(config); 986978c5f5SRiana Tauro 996978c5f5SRiana Tauro hwe = xe_hw_engine_lookup(xe, eci); 1006978c5f5SRiana Tauro if (!hwe || xe_hw_engine_is_reserved(hwe)) 1016978c5f5SRiana Tauro return NULL; 1026978c5f5SRiana Tauro 1036978c5f5SRiana Tauro return hwe; 1046978c5f5SRiana Tauro } 1056978c5f5SRiana Tauro 106*c7f2b8bfSRiana Tauro static bool is_engine_event(u64 config) 107*c7f2b8bfSRiana Tauro { 108*c7f2b8bfSRiana Tauro unsigned int event_id = config_to_event_id(config); 109*c7f2b8bfSRiana Tauro 110*c7f2b8bfSRiana Tauro return (event_id == XE_PMU_EVENT_ENGINE_TOTAL_TICKS || 111*c7f2b8bfSRiana Tauro event_id == XE_PMU_EVENT_ENGINE_ACTIVE_TICKS); 112*c7f2b8bfSRiana Tauro } 113*c7f2b8bfSRiana Tauro 114*c7f2b8bfSRiana Tauro static bool event_gt_forcewake(struct perf_event *event) 115*c7f2b8bfSRiana Tauro { 116*c7f2b8bfSRiana Tauro struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 117*c7f2b8bfSRiana Tauro u64 config = event->attr.config; 118*c7f2b8bfSRiana Tauro struct xe_gt *gt; 119*c7f2b8bfSRiana Tauro unsigned int *fw_ref; 120*c7f2b8bfSRiana Tauro 121*c7f2b8bfSRiana Tauro if (!is_engine_event(config)) 122*c7f2b8bfSRiana Tauro return true; 123*c7f2b8bfSRiana Tauro 124*c7f2b8bfSRiana Tauro gt = xe_device_get_gt(xe, config_to_gt_id(config)); 125*c7f2b8bfSRiana Tauro 126*c7f2b8bfSRiana Tauro fw_ref = kzalloc(sizeof(*fw_ref), GFP_KERNEL); 127*c7f2b8bfSRiana Tauro if (!fw_ref) 128*c7f2b8bfSRiana Tauro return false; 129*c7f2b8bfSRiana Tauro 130*c7f2b8bfSRiana Tauro *fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); 131*c7f2b8bfSRiana Tauro if (!*fw_ref) { 132*c7f2b8bfSRiana Tauro kfree(fw_ref); 133*c7f2b8bfSRiana Tauro return false; 134*c7f2b8bfSRiana Tauro } 135*c7f2b8bfSRiana Tauro 136*c7f2b8bfSRiana Tauro event->pmu_private = fw_ref; 137*c7f2b8bfSRiana Tauro 138*c7f2b8bfSRiana Tauro return true; 139*c7f2b8bfSRiana Tauro } 140*c7f2b8bfSRiana Tauro 141011c1e24SVinay Belgaumkar static bool event_supported(struct xe_pmu *pmu, unsigned int gt, 142011c1e24SVinay Belgaumkar unsigned int id) 143011c1e24SVinay Belgaumkar { 144011c1e24SVinay Belgaumkar if (gt >= XE_MAX_GT_PER_TILE) 145011c1e24SVinay Belgaumkar return false; 146011c1e24SVinay Belgaumkar 1476ea5bf16SLucas De Marchi return id < sizeof(pmu->supported_events) * BITS_PER_BYTE && 1486ea5bf16SLucas De Marchi pmu->supported_events & BIT_ULL(id); 149011c1e24SVinay Belgaumkar } 150011c1e24SVinay Belgaumkar 1516978c5f5SRiana Tauro static bool event_param_valid(struct perf_event *event) 1526978c5f5SRiana Tauro { 1536978c5f5SRiana Tauro struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 1546978c5f5SRiana Tauro unsigned int engine_class, engine_instance; 1556978c5f5SRiana Tauro u64 config = event->attr.config; 1566978c5f5SRiana Tauro struct xe_gt *gt; 1576978c5f5SRiana Tauro 1586978c5f5SRiana Tauro gt = xe_device_get_gt(xe, config_to_gt_id(config)); 1596978c5f5SRiana Tauro if (!gt) 1606978c5f5SRiana Tauro return false; 1616978c5f5SRiana Tauro 1626978c5f5SRiana Tauro engine_class = config_to_engine_class(config); 1636978c5f5SRiana Tauro engine_instance = config_to_engine_instance(config); 1646978c5f5SRiana Tauro 1656978c5f5SRiana Tauro switch (config_to_event_id(config)) { 1666978c5f5SRiana Tauro case XE_PMU_EVENT_GT_C6_RESIDENCY: 1676978c5f5SRiana Tauro if (engine_class || engine_instance) 1686978c5f5SRiana Tauro return false; 1696978c5f5SRiana Tauro break; 1706978c5f5SRiana Tauro case XE_PMU_EVENT_ENGINE_ACTIVE_TICKS: 1716978c5f5SRiana Tauro case XE_PMU_EVENT_ENGINE_TOTAL_TICKS: 1726978c5f5SRiana Tauro if (!event_to_hwe(event)) 1736978c5f5SRiana Tauro return false; 1746978c5f5SRiana Tauro break; 1756978c5f5SRiana Tauro } 1766978c5f5SRiana Tauro 1776978c5f5SRiana Tauro return true; 1786978c5f5SRiana Tauro } 1796978c5f5SRiana Tauro 180011c1e24SVinay Belgaumkar static void xe_pmu_event_destroy(struct perf_event *event) 181011c1e24SVinay Belgaumkar { 182011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 183*c7f2b8bfSRiana Tauro struct xe_gt *gt; 184*c7f2b8bfSRiana Tauro unsigned int *fw_ref = event->pmu_private; 185*c7f2b8bfSRiana Tauro 186*c7f2b8bfSRiana Tauro if (fw_ref) { 187*c7f2b8bfSRiana Tauro gt = xe_device_get_gt(xe, config_to_gt_id(event->attr.config)); 188*c7f2b8bfSRiana Tauro xe_force_wake_put(gt_to_fw(gt), *fw_ref); 189*c7f2b8bfSRiana Tauro kfree(fw_ref); 190*c7f2b8bfSRiana Tauro event->pmu_private = NULL; 191*c7f2b8bfSRiana Tauro } 192011c1e24SVinay Belgaumkar 193011c1e24SVinay Belgaumkar drm_WARN_ON(&xe->drm, event->parent); 1944ee64041SLucas De Marchi xe_pm_runtime_put(xe); 195011c1e24SVinay Belgaumkar drm_dev_put(&xe->drm); 196011c1e24SVinay Belgaumkar } 197011c1e24SVinay Belgaumkar 198011c1e24SVinay Belgaumkar static int xe_pmu_event_init(struct perf_event *event) 199011c1e24SVinay Belgaumkar { 200011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 201011c1e24SVinay Belgaumkar struct xe_pmu *pmu = &xe->pmu; 202011c1e24SVinay Belgaumkar unsigned int id, gt; 203011c1e24SVinay Belgaumkar 204011c1e24SVinay Belgaumkar if (!pmu->registered) 205011c1e24SVinay Belgaumkar return -ENODEV; 206011c1e24SVinay Belgaumkar 207011c1e24SVinay Belgaumkar if (event->attr.type != event->pmu->type) 208011c1e24SVinay Belgaumkar return -ENOENT; 209011c1e24SVinay Belgaumkar 210011c1e24SVinay Belgaumkar /* unsupported modes and filters */ 211011c1e24SVinay Belgaumkar if (event->attr.sample_period) /* no sampling */ 212011c1e24SVinay Belgaumkar return -EINVAL; 213011c1e24SVinay Belgaumkar 214011c1e24SVinay Belgaumkar if (event->cpu < 0) 215011c1e24SVinay Belgaumkar return -EINVAL; 216011c1e24SVinay Belgaumkar 217011c1e24SVinay Belgaumkar gt = config_to_gt_id(event->attr.config); 218011c1e24SVinay Belgaumkar id = config_to_event_id(event->attr.config); 219011c1e24SVinay Belgaumkar if (!event_supported(pmu, gt, id)) 220011c1e24SVinay Belgaumkar return -ENOENT; 221011c1e24SVinay Belgaumkar 222011c1e24SVinay Belgaumkar if (has_branch_stack(event)) 223011c1e24SVinay Belgaumkar return -EOPNOTSUPP; 224011c1e24SVinay Belgaumkar 2256978c5f5SRiana Tauro if (!event_param_valid(event)) 2266978c5f5SRiana Tauro return -ENOENT; 2276978c5f5SRiana Tauro 228011c1e24SVinay Belgaumkar if (!event->parent) { 229011c1e24SVinay Belgaumkar drm_dev_get(&xe->drm); 2304ee64041SLucas De Marchi xe_pm_runtime_get(xe); 231*c7f2b8bfSRiana Tauro if (!event_gt_forcewake(event)) { 232*c7f2b8bfSRiana Tauro xe_pm_runtime_put(xe); 233*c7f2b8bfSRiana Tauro drm_dev_put(&xe->drm); 234*c7f2b8bfSRiana Tauro return -EINVAL; 235*c7f2b8bfSRiana Tauro } 236011c1e24SVinay Belgaumkar event->destroy = xe_pmu_event_destroy; 237011c1e24SVinay Belgaumkar } 238011c1e24SVinay Belgaumkar 239011c1e24SVinay Belgaumkar return 0; 240011c1e24SVinay Belgaumkar } 241011c1e24SVinay Belgaumkar 2426978c5f5SRiana Tauro static u64 read_engine_events(struct xe_gt *gt, struct perf_event *event) 2436978c5f5SRiana Tauro { 2446978c5f5SRiana Tauro struct xe_hw_engine *hwe; 2456978c5f5SRiana Tauro u64 val = 0; 2466978c5f5SRiana Tauro 2476978c5f5SRiana Tauro hwe = event_to_hwe(event); 2486978c5f5SRiana Tauro if (config_to_event_id(event->attr.config) == XE_PMU_EVENT_ENGINE_ACTIVE_TICKS) 2496978c5f5SRiana Tauro val = xe_guc_engine_activity_active_ticks(>->uc.guc, hwe); 2506978c5f5SRiana Tauro else 2516978c5f5SRiana Tauro val = xe_guc_engine_activity_total_ticks(>->uc.guc, hwe); 2526978c5f5SRiana Tauro 2536978c5f5SRiana Tauro return val; 2546978c5f5SRiana Tauro } 2556978c5f5SRiana Tauro 256011c1e24SVinay Belgaumkar static u64 __xe_pmu_event_read(struct perf_event *event) 257011c1e24SVinay Belgaumkar { 258011c1e24SVinay Belgaumkar struct xe_gt *gt = event_to_gt(event); 259011c1e24SVinay Belgaumkar 260011c1e24SVinay Belgaumkar if (!gt) 261011c1e24SVinay Belgaumkar return 0; 262011c1e24SVinay Belgaumkar 263897286f2SVinay Belgaumkar switch (config_to_event_id(event->attr.config)) { 264897286f2SVinay Belgaumkar case XE_PMU_EVENT_GT_C6_RESIDENCY: 265897286f2SVinay Belgaumkar return xe_gt_idle_residency_msec(>->gtidle); 2666978c5f5SRiana Tauro case XE_PMU_EVENT_ENGINE_ACTIVE_TICKS: 2676978c5f5SRiana Tauro case XE_PMU_EVENT_ENGINE_TOTAL_TICKS: 2686978c5f5SRiana Tauro return read_engine_events(gt, event); 269897286f2SVinay Belgaumkar } 270897286f2SVinay Belgaumkar 271897286f2SVinay Belgaumkar return 0; 272011c1e24SVinay Belgaumkar } 273011c1e24SVinay Belgaumkar 274ef7ce393SLucas De Marchi static void xe_pmu_event_update(struct perf_event *event) 275011c1e24SVinay Belgaumkar { 276011c1e24SVinay Belgaumkar struct hw_perf_event *hwc = &event->hw; 277011c1e24SVinay Belgaumkar u64 prev, new; 278011c1e24SVinay Belgaumkar 279011c1e24SVinay Belgaumkar prev = local64_read(&hwc->prev_count); 280011c1e24SVinay Belgaumkar do { 281011c1e24SVinay Belgaumkar new = __xe_pmu_event_read(event); 282011c1e24SVinay Belgaumkar } while (!local64_try_cmpxchg(&hwc->prev_count, &prev, new)); 283011c1e24SVinay Belgaumkar 284011c1e24SVinay Belgaumkar local64_add(new - prev, &event->count); 285011c1e24SVinay Belgaumkar } 286011c1e24SVinay Belgaumkar 287ef7ce393SLucas De Marchi static void xe_pmu_event_read(struct perf_event *event) 288ef7ce393SLucas De Marchi { 289ef7ce393SLucas De Marchi struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 290ef7ce393SLucas De Marchi struct xe_pmu *pmu = &xe->pmu; 291ef7ce393SLucas De Marchi 292ef7ce393SLucas De Marchi if (!pmu->registered) { 293ef7ce393SLucas De Marchi event->hw.state = PERF_HES_STOPPED; 294ef7ce393SLucas De Marchi return; 295ef7ce393SLucas De Marchi } 296ef7ce393SLucas De Marchi 297ef7ce393SLucas De Marchi xe_pmu_event_update(event); 298ef7ce393SLucas De Marchi } 299ef7ce393SLucas De Marchi 300011c1e24SVinay Belgaumkar static void xe_pmu_enable(struct perf_event *event) 301011c1e24SVinay Belgaumkar { 302011c1e24SVinay Belgaumkar /* 303011c1e24SVinay Belgaumkar * Store the current counter value so we can report the correct delta 304011c1e24SVinay Belgaumkar * for all listeners. Even when the event was already enabled and has 305011c1e24SVinay Belgaumkar * an existing non-zero value. 306011c1e24SVinay Belgaumkar */ 307011c1e24SVinay Belgaumkar local64_set(&event->hw.prev_count, __xe_pmu_event_read(event)); 308011c1e24SVinay Belgaumkar } 309011c1e24SVinay Belgaumkar 310011c1e24SVinay Belgaumkar static void xe_pmu_event_start(struct perf_event *event, int flags) 311011c1e24SVinay Belgaumkar { 312011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 313011c1e24SVinay Belgaumkar struct xe_pmu *pmu = &xe->pmu; 314011c1e24SVinay Belgaumkar 315011c1e24SVinay Belgaumkar if (!pmu->registered) 316011c1e24SVinay Belgaumkar return; 317011c1e24SVinay Belgaumkar 318011c1e24SVinay Belgaumkar xe_pmu_enable(event); 319011c1e24SVinay Belgaumkar event->hw.state = 0; 320011c1e24SVinay Belgaumkar } 321011c1e24SVinay Belgaumkar 322011c1e24SVinay Belgaumkar static void xe_pmu_event_stop(struct perf_event *event, int flags) 323011c1e24SVinay Belgaumkar { 324011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 325011c1e24SVinay Belgaumkar struct xe_pmu *pmu = &xe->pmu; 326011c1e24SVinay Belgaumkar 327011c1e24SVinay Belgaumkar if (pmu->registered) 328011c1e24SVinay Belgaumkar if (flags & PERF_EF_UPDATE) 329ef7ce393SLucas De Marchi xe_pmu_event_update(event); 330011c1e24SVinay Belgaumkar 331011c1e24SVinay Belgaumkar event->hw.state = PERF_HES_STOPPED; 332011c1e24SVinay Belgaumkar } 333011c1e24SVinay Belgaumkar 334011c1e24SVinay Belgaumkar static int xe_pmu_event_add(struct perf_event *event, int flags) 335011c1e24SVinay Belgaumkar { 336011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); 337011c1e24SVinay Belgaumkar struct xe_pmu *pmu = &xe->pmu; 338011c1e24SVinay Belgaumkar 339011c1e24SVinay Belgaumkar if (!pmu->registered) 340011c1e24SVinay Belgaumkar return -ENODEV; 341011c1e24SVinay Belgaumkar 342011c1e24SVinay Belgaumkar if (flags & PERF_EF_START) 343011c1e24SVinay Belgaumkar xe_pmu_event_start(event, flags); 344011c1e24SVinay Belgaumkar 345011c1e24SVinay Belgaumkar return 0; 346011c1e24SVinay Belgaumkar } 347011c1e24SVinay Belgaumkar 348011c1e24SVinay Belgaumkar static void xe_pmu_event_del(struct perf_event *event, int flags) 349011c1e24SVinay Belgaumkar { 350011c1e24SVinay Belgaumkar xe_pmu_event_stop(event, PERF_EF_UPDATE); 351011c1e24SVinay Belgaumkar } 352011c1e24SVinay Belgaumkar 353011c1e24SVinay Belgaumkar PMU_FORMAT_ATTR(gt, "config:60-63"); 3546978c5f5SRiana Tauro PMU_FORMAT_ATTR(engine_class, "config:20-27"); 3556978c5f5SRiana Tauro PMU_FORMAT_ATTR(engine_instance, "config:12-19"); 356011c1e24SVinay Belgaumkar PMU_FORMAT_ATTR(event, "config:0-11"); 357011c1e24SVinay Belgaumkar 358011c1e24SVinay Belgaumkar static struct attribute *pmu_format_attrs[] = { 359011c1e24SVinay Belgaumkar &format_attr_event.attr, 3606978c5f5SRiana Tauro &format_attr_engine_class.attr, 3616978c5f5SRiana Tauro &format_attr_engine_instance.attr, 362011c1e24SVinay Belgaumkar &format_attr_gt.attr, 363011c1e24SVinay Belgaumkar NULL, 364011c1e24SVinay Belgaumkar }; 365011c1e24SVinay Belgaumkar 366011c1e24SVinay Belgaumkar static const struct attribute_group pmu_format_attr_group = { 367011c1e24SVinay Belgaumkar .name = "format", 368011c1e24SVinay Belgaumkar .attrs = pmu_format_attrs, 369011c1e24SVinay Belgaumkar }; 370011c1e24SVinay Belgaumkar 371897286f2SVinay Belgaumkar static ssize_t event_attr_show(struct device *dev, 3726ea5bf16SLucas De Marchi struct device_attribute *attr, char *buf) 3736ea5bf16SLucas De Marchi { 3746ea5bf16SLucas De Marchi struct perf_pmu_events_attr *pmu_attr = 3756ea5bf16SLucas De Marchi container_of(attr, struct perf_pmu_events_attr, attr); 3766ea5bf16SLucas De Marchi 3776ea5bf16SLucas De Marchi return sprintf(buf, "event=%#04llx\n", pmu_attr->id); 3786ea5bf16SLucas De Marchi } 3796ea5bf16SLucas De Marchi 3806ea5bf16SLucas De Marchi #define XE_EVENT_ATTR(name_, v_, id_) \ 3816ea5bf16SLucas De Marchi PMU_EVENT_ATTR(name_, pmu_event_ ## v_, id_, event_attr_show) 3826ea5bf16SLucas De Marchi 3836ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ 3846ea5bf16SLucas De Marchi PMU_EVENT_ATTR_STRING(name_.unit, pmu_event_unit_ ## v_, unit_) 3856ea5bf16SLucas De Marchi 3866ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_GROUP(v_, id_, ...) \ 3876ea5bf16SLucas De Marchi static struct attribute *pmu_attr_ ##v_[] = { \ 3886ea5bf16SLucas De Marchi __VA_ARGS__, \ 3896ea5bf16SLucas De Marchi NULL \ 3906ea5bf16SLucas De Marchi }; \ 3916ea5bf16SLucas De Marchi static umode_t is_visible_##v_(struct kobject *kobj, \ 3926ea5bf16SLucas De Marchi struct attribute *attr, int idx) \ 3936ea5bf16SLucas De Marchi { \ 3946ea5bf16SLucas De Marchi struct perf_pmu_events_attr *pmu_attr; \ 3956ea5bf16SLucas De Marchi struct xe_pmu *pmu; \ 3966ea5bf16SLucas De Marchi \ 3976ea5bf16SLucas De Marchi pmu_attr = container_of(attr, typeof(*pmu_attr), attr.attr); \ 3986ea5bf16SLucas De Marchi pmu = container_of(dev_get_drvdata(kobj_to_dev(kobj)), \ 3996ea5bf16SLucas De Marchi typeof(*pmu), base); \ 4006ea5bf16SLucas De Marchi \ 4016ea5bf16SLucas De Marchi return event_supported(pmu, 0, id_) ? attr->mode : 0; \ 4026ea5bf16SLucas De Marchi } \ 4036ea5bf16SLucas De Marchi static const struct attribute_group pmu_group_ ##v_ = { \ 4046ea5bf16SLucas De Marchi .name = "events", \ 4056ea5bf16SLucas De Marchi .attrs = pmu_attr_ ## v_, \ 4066ea5bf16SLucas De Marchi .is_visible = is_visible_ ## v_, \ 4076ea5bf16SLucas De Marchi } 4086ea5bf16SLucas De Marchi 4096ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_SIMPLE(name_, v_, id_, unit_) \ 4106ea5bf16SLucas De Marchi XE_EVENT_ATTR(name_, v_, id_) \ 4116ea5bf16SLucas De Marchi XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ 4126ea5bf16SLucas De Marchi XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr, \ 4136ea5bf16SLucas De Marchi &pmu_event_unit_ ##v_.attr.attr) 4146ea5bf16SLucas De Marchi 4156ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_NOUNIT(name_, v_, id_) \ 4166ea5bf16SLucas De Marchi XE_EVENT_ATTR(name_, v_, id_) \ 4176ea5bf16SLucas De Marchi XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr) 4186ea5bf16SLucas De Marchi 419897286f2SVinay Belgaumkar XE_EVENT_ATTR_SIMPLE(gt-c6-residency, gt_c6_residency, XE_PMU_EVENT_GT_C6_RESIDENCY, "ms"); 4206978c5f5SRiana Tauro XE_EVENT_ATTR_NOUNIT(engine-active-ticks, engine_active_ticks, XE_PMU_EVENT_ENGINE_ACTIVE_TICKS); 4216978c5f5SRiana Tauro XE_EVENT_ATTR_NOUNIT(engine-total-ticks, engine_total_ticks, XE_PMU_EVENT_ENGINE_TOTAL_TICKS); 422897286f2SVinay Belgaumkar 4236ea5bf16SLucas De Marchi static struct attribute *pmu_empty_event_attrs[] = { 4246ea5bf16SLucas De Marchi /* Empty - all events are added as groups with .attr_update() */ 425011c1e24SVinay Belgaumkar NULL, 426011c1e24SVinay Belgaumkar }; 427011c1e24SVinay Belgaumkar 428011c1e24SVinay Belgaumkar static const struct attribute_group pmu_events_attr_group = { 429011c1e24SVinay Belgaumkar .name = "events", 4306ea5bf16SLucas De Marchi .attrs = pmu_empty_event_attrs, 431011c1e24SVinay Belgaumkar }; 432011c1e24SVinay Belgaumkar 4336ea5bf16SLucas De Marchi static const struct attribute_group *pmu_events_attr_update[] = { 434897286f2SVinay Belgaumkar &pmu_group_gt_c6_residency, 4356978c5f5SRiana Tauro &pmu_group_engine_active_ticks, 4366978c5f5SRiana Tauro &pmu_group_engine_total_ticks, 4376ea5bf16SLucas De Marchi NULL, 4386ea5bf16SLucas De Marchi }; 4396ea5bf16SLucas De Marchi 4406ea5bf16SLucas De Marchi static void set_supported_events(struct xe_pmu *pmu) 4416ea5bf16SLucas De Marchi { 442897286f2SVinay Belgaumkar struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 4436978c5f5SRiana Tauro struct xe_gt *gt = xe_device_get_gt(xe, 0); 444897286f2SVinay Belgaumkar 445897286f2SVinay Belgaumkar if (!xe->info.skip_guc_pc) 446897286f2SVinay Belgaumkar pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_GT_C6_RESIDENCY); 4476978c5f5SRiana Tauro 4486978c5f5SRiana Tauro if (xe_guc_engine_activity_supported(>->uc.guc)) { 4496978c5f5SRiana Tauro pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_ENGINE_ACTIVE_TICKS); 4506978c5f5SRiana Tauro pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_ENGINE_TOTAL_TICKS); 4516978c5f5SRiana Tauro } 4526ea5bf16SLucas De Marchi } 4536ea5bf16SLucas De Marchi 454011c1e24SVinay Belgaumkar /** 455011c1e24SVinay Belgaumkar * xe_pmu_unregister() - Remove/cleanup PMU registration 456011c1e24SVinay Belgaumkar * @arg: Ptr to pmu 457011c1e24SVinay Belgaumkar */ 458011c1e24SVinay Belgaumkar static void xe_pmu_unregister(void *arg) 459011c1e24SVinay Belgaumkar { 460011c1e24SVinay Belgaumkar struct xe_pmu *pmu = arg; 461011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 462011c1e24SVinay Belgaumkar 463011c1e24SVinay Belgaumkar if (!pmu->registered) 464011c1e24SVinay Belgaumkar return; 465011c1e24SVinay Belgaumkar 466011c1e24SVinay Belgaumkar pmu->registered = false; 467011c1e24SVinay Belgaumkar 468011c1e24SVinay Belgaumkar perf_pmu_unregister(&pmu->base); 469011c1e24SVinay Belgaumkar kfree(pmu->name); 470011c1e24SVinay Belgaumkar } 471011c1e24SVinay Belgaumkar 472011c1e24SVinay Belgaumkar /** 473011c1e24SVinay Belgaumkar * xe_pmu_register() - Define basic PMU properties for Xe and add event callbacks. 474011c1e24SVinay Belgaumkar * @pmu: the PMU object 475011c1e24SVinay Belgaumkar * 476011c1e24SVinay Belgaumkar * Returns 0 on success and an appropriate error code otherwise 477011c1e24SVinay Belgaumkar */ 478011c1e24SVinay Belgaumkar int xe_pmu_register(struct xe_pmu *pmu) 479011c1e24SVinay Belgaumkar { 480011c1e24SVinay Belgaumkar struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); 481011c1e24SVinay Belgaumkar static const struct attribute_group *attr_groups[] = { 482011c1e24SVinay Belgaumkar &pmu_format_attr_group, 483011c1e24SVinay Belgaumkar &pmu_events_attr_group, 484011c1e24SVinay Belgaumkar NULL 485011c1e24SVinay Belgaumkar }; 486011c1e24SVinay Belgaumkar int ret = -ENOMEM; 487011c1e24SVinay Belgaumkar char *name; 488011c1e24SVinay Belgaumkar 489257a10c1SLucas De Marchi BUILD_BUG_ON(XE_MAX_GT_PER_TILE != XE_PMU_MAX_GT); 490257a10c1SLucas De Marchi 491011c1e24SVinay Belgaumkar if (IS_SRIOV_VF(xe)) 492011c1e24SVinay Belgaumkar return 0; 493011c1e24SVinay Belgaumkar 494011c1e24SVinay Belgaumkar name = kasprintf(GFP_KERNEL, "xe_%s", 495011c1e24SVinay Belgaumkar dev_name(xe->drm.dev)); 496011c1e24SVinay Belgaumkar if (!name) 497011c1e24SVinay Belgaumkar goto err; 498011c1e24SVinay Belgaumkar 499011c1e24SVinay Belgaumkar /* tools/perf reserves colons as special. */ 500011c1e24SVinay Belgaumkar strreplace(name, ':', '_'); 501011c1e24SVinay Belgaumkar 502011c1e24SVinay Belgaumkar pmu->name = name; 503011c1e24SVinay Belgaumkar pmu->base.attr_groups = attr_groups; 5046ea5bf16SLucas De Marchi pmu->base.attr_update = pmu_events_attr_update; 505011c1e24SVinay Belgaumkar pmu->base.scope = PERF_PMU_SCOPE_SYS_WIDE; 506011c1e24SVinay Belgaumkar pmu->base.module = THIS_MODULE; 507011c1e24SVinay Belgaumkar pmu->base.task_ctx_nr = perf_invalid_context; 508011c1e24SVinay Belgaumkar pmu->base.event_init = xe_pmu_event_init; 509011c1e24SVinay Belgaumkar pmu->base.add = xe_pmu_event_add; 510011c1e24SVinay Belgaumkar pmu->base.del = xe_pmu_event_del; 511011c1e24SVinay Belgaumkar pmu->base.start = xe_pmu_event_start; 512011c1e24SVinay Belgaumkar pmu->base.stop = xe_pmu_event_stop; 513011c1e24SVinay Belgaumkar pmu->base.read = xe_pmu_event_read; 514011c1e24SVinay Belgaumkar 5156ea5bf16SLucas De Marchi set_supported_events(pmu); 5166ea5bf16SLucas De Marchi 517011c1e24SVinay Belgaumkar ret = perf_pmu_register(&pmu->base, pmu->name, -1); 518011c1e24SVinay Belgaumkar if (ret) 519011c1e24SVinay Belgaumkar goto err_name; 520011c1e24SVinay Belgaumkar 521011c1e24SVinay Belgaumkar pmu->registered = true; 522011c1e24SVinay Belgaumkar 523011c1e24SVinay Belgaumkar return devm_add_action_or_reset(xe->drm.dev, xe_pmu_unregister, pmu); 524011c1e24SVinay Belgaumkar 525011c1e24SVinay Belgaumkar err_name: 526011c1e24SVinay Belgaumkar kfree(name); 527011c1e24SVinay Belgaumkar err: 528011c1e24SVinay Belgaumkar drm_err(&xe->drm, "Failed to register PMU (ret=%d)!\n", ret); 529011c1e24SVinay Belgaumkar 530011c1e24SVinay Belgaumkar return ret; 531011c1e24SVinay Belgaumkar } 532