Added the panthor_perf system initialization and unplug code for subsystem-level handling in subsequent patches. Userspace session handling is done at the pfile level, via a pool of sessions.
Signed-off-by: Lukas Zapolskas <[email protected]> --- drivers/gpu/drm/panthor/panthor_device.c | 2 + drivers/gpu/drm/panthor/panthor_device.h | 9 +++- drivers/gpu/drm/panthor/panthor_drv.c | 9 ++++ drivers/gpu/drm/panthor/panthor_perf.c | 85 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_perf.h | 6 +++ 5 files changed, 110 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index 2877d47c6717..535383ef629f 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -95,6 +95,7 @@ void panthor_device_unplug(struct panthor_device *ptdev) /* Now, try to cleanly shutdown the GPU before the device resources * get reclaimed. */ + panthor_perf_unplug(ptdev); panthor_sched_unplug(ptdev); panthor_fw_unplug(ptdev); panthor_mmu_unplug(ptdev); @@ -310,6 +311,7 @@ int panthor_device_init(struct panthor_device *ptdev) err_disable_autosuspend: pm_runtime_dont_use_autosuspend(ptdev->base.dev); + panthor_perf_unplug(ptdev); err_unplug_sched: panthor_sched_unplug(ptdev); diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index d93b182a3d9b..085254a60fc4 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -29,10 +29,11 @@ struct panthor_hw; struct panthor_job; struct panthor_mmu; struct panthor_fw; -struct panthor_perfcnt; struct panthor_pwr; +struct panthor_perf; struct panthor_vm; struct panthor_vm_pool; +struct panthor_perf_pool; /** * struct panthor_soc_data - Panthor SoC Data @@ -323,6 +324,9 @@ struct panthor_device { atomic_t recovery_needed; } pm; + /** @perf: Performance counter management data. */ + struct panthor_perf *perf; + /** @profile_mask: User-set profiling flags for job accounting. */ u32 profile_mask; @@ -377,6 +381,9 @@ struct panthor_file { /** @groups: Scheduling group pool attached to this file. */ struct panthor_group_pool *groups; + /** @sessions: Perf session pool attached to this file. */ + struct panthor_perf_pool *sessions; + /** @stats: cycle and timestamp measures for job execution. */ struct panthor_gpu_usage stats; }; diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index b6b55b0f2ff5..3e62142d7ebd 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -37,6 +37,7 @@ #include "panthor_gpu.h" #include "panthor_heap.h" #include "panthor_mmu.h" +#include "panthor_perf.h" #include "panthor_sched.h" /** @@ -1635,9 +1636,16 @@ panthor_open(struct drm_device *ddev, struct drm_file *file) if (ret) goto err_destroy_vm_pool; + ret = panthor_perf_pool_create(pfile); + if (ret) + goto err_destroy_group_pool; + file->driver_priv = pfile; return 0; +err_destroy_group_pool: + panthor_group_pool_destroy(pfile); + err_destroy_vm_pool: panthor_vm_pool_destroy(pfile); @@ -1651,6 +1659,7 @@ panthor_postclose(struct drm_device *ddev, struct drm_file *file) { struct panthor_file *pfile = file->driver_priv; + panthor_perf_pool_destroy(pfile); panthor_group_pool_destroy(pfile); panthor_vm_pool_destroy(pfile); diff --git a/drivers/gpu/drm/panthor/panthor_perf.c b/drivers/gpu/drm/panthor/panthor_perf.c index cbfe1ca5872d..ba466e22c50d 100644 --- a/drivers/gpu/drm/panthor/panthor_perf.c +++ b/drivers/gpu/drm/panthor/panthor_perf.c @@ -3,7 +3,9 @@ /* Copyright 2025 Arm ltd. */ #include <linux/bitops.h> +#include <drm/drm_managed.h> #include <drm/panthor_drm.h> +#include <drm/drm_print.h> #include "panthor_device.h" #include "panthor_fw.h" @@ -23,11 +25,26 @@ */ #define PANTHOR_HW_COUNTER_SIZE (sizeof(u32)) +#define MAX_SESSIONS_PER_FILE 1 + struct panthor_perf_counter_block { struct drm_panthor_perf_block_header header; u64 counters[]; }; +struct panthor_perf { + /** @info: Pointer to the previously initialized perf info. */ + struct drm_panthor_perf_info *info; +}; + +struct panthor_perf_pool { + /** @session_range: The number of sessions supported at a time. */ + struct xa_limit session_range; + + /** @xa: Xarray used to manage session handles. */ + struct xarray xa; +}; + static size_t get_annotated_block_size(size_t counters_per_block) { return struct_size_t(struct panthor_perf_counter_block, counters, counters_per_block); @@ -74,14 +91,82 @@ static void panthor_perf_info_init(struct panthor_device *const ptdev) * panthor_perf_init - Initialize the performance counter subsystem. * @ptdev: Panthor device * + * The performance counters require the FW interface to be available to setup the + * sampling ringbuffers, so this must be called only after FW is initialized. + * * Return: 0 on success, negative error code on failure. */ int panthor_perf_init(struct panthor_device *ptdev) { + struct panthor_perf *perf; + int ret = 0; + if (!ptdev) return -EINVAL; panthor_perf_info_init(ptdev); + perf = drmm_kzalloc(&ptdev->base, sizeof(*perf), GFP_KERNEL); + if (!perf) + return -ENOMEM; + + drm_info(&ptdev->base, "Performance counter subsystem initialized"); + + perf->info = &ptdev->perf_info; + ptdev->perf = perf; + + return ret; +} + +/** + * panthor_perf_unplug - Terminate the performance counter subsystem. + * @ptdev: Panthor device. + * + * Release the performance counter hardware resources. The control structure is + * released with the DRM device. + */ +void panthor_perf_unplug(struct panthor_device *ptdev) +{ + struct panthor_perf *perf = ptdev->perf; + + if (!perf) + return; + + ptdev->perf = NULL; +} + +int panthor_perf_pool_create(struct panthor_file *pfile) +{ + struct panthor_perf_pool *pool; + + pool = kzalloc_obj(*pool); + if (!pool) + return -ENOMEM; + + xa_init_flags(&pool->xa, XA_FLAGS_ALLOC); + + pool->session_range.min = 0; + pool->session_range.max = MAX_SESSIONS_PER_FILE - 1; + + pfile->sessions = pool; + return 0; } + +void panthor_perf_pool_destroy(struct panthor_file *pfile) +{ + struct panthor_perf_pool *pool = pfile->sessions; + + if (IS_ERR_OR_NULL(pool)) + return; + + if (!xa_empty(&pool->xa)) { + drm_err(&pfile->ptdev->base, + "Performance counter sessions active when unplugging the driver!"); + } + + xa_destroy(&pool->xa); + kfree(pool); + + pfile->sessions = NULL; +} diff --git a/drivers/gpu/drm/panthor/panthor_perf.h b/drivers/gpu/drm/panthor/panthor_perf.h index 3c32c24c164c..ad01fc88f18f 100644 --- a/drivers/gpu/drm/panthor/panthor_perf.h +++ b/drivers/gpu/drm/panthor/panthor_perf.h @@ -8,8 +8,14 @@ #include <linux/types.h> struct panthor_device; +struct panthor_file; +struct panthor_perf_pool; + +int panthor_perf_pool_create(struct panthor_file *pfile); +void panthor_perf_pool_destroy(struct panthor_file *pfile); int panthor_perf_init(struct panthor_device *ptdev); +void panthor_perf_unplug(struct panthor_device *ptdev); #endif /* __PANTHOR_PERF_H__ */ -- 2.43.0
