[PATCH 11/13] drm/msm/a6xx+: Add support to configure perfcntrs
From: Rob Clark
Date: Mon Apr 20 2026 - 18:31:29 EST
Add support to configure counter SELect regs. In some cases the reg
writes need to happen while the GPU is idle. And for a7xx+, in some
cases SEL regs need to be configured from BV or BR aperture. The
easiest way to deal with this is to configure from the RB.
Signed-off-by: Rob Clark <robin.clark@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 66 +++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 415902f6e5d7..0149eba403e4 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2535,6 +2535,68 @@ static bool a6xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
return progress;
}
+static void
+a6xx_perfcntr_configure(struct msm_gpu *gpu, struct msm_ringbuffer *ring,
+ const struct msm_perfcntr_stream *stream)
+{
+ enum adreno_pipe pipe = PIPE_NONE;
+
+ for (unsigned i = 0; i < stream->nr_groups; i++) {
+ unsigned group_idx = msm_perfcntr_group_idx(stream, i);
+ unsigned base = msm_perfcntr_counter_base(stream, group_idx);
+
+ const struct msm_perfcntr_group *group =
+ &gpu->perfcntr_groups[group_idx];
+
+ struct msm_perfcntr_group_state *group_state =
+ gpu->perfcntrs->groups[group_idx];
+
+ if (group->pipe != pipe) {
+ pipe = group->pipe;
+
+ OUT_PKT7(ring, CP_THREAD_CONTROL, 1);
+
+ if (pipe == PIPE_BR) {
+ OUT_RING(ring, CP_SET_THREAD_BR);
+ } else if (pipe == PIPE_BV) {
+ OUT_RING(ring, CP_SET_THREAD_BV);
+ } else {
+ OUT_RING(ring, CP_SET_THREAD_BOTH);
+ }
+ }
+
+ const struct msm_perfcntr_counter *counter = &group->counters[base];
+ unsigned nr = group_state->allocated_counters;
+ OUT_PKT4(ring, counter->select_reg, nr);
+ for (unsigned c = 0; c < nr; c++)
+ OUT_RING(ring, group_state->countables[c]);
+
+ for (unsigned s = 0; i < ARRAY_SIZE(counter->slice_select_regs); s++) {
+ if (!counter->slice_select_regs[s])
+ break;
+
+ OUT_PKT4(ring, counter->slice_select_regs[s], nr);
+ for (unsigned c = 0; c < nr; c++)
+ OUT_RING(ring, group_state->countables[c]);
+ }
+ }
+
+ if (pipe != PIPE_NONE) {
+ OUT_PKT7(ring, CP_THREAD_CONTROL, 1);
+ OUT_RING(ring, CP_SET_THREAD_BOTH);
+ }
+
+ a6xx_flush_yield(gpu, ring);
+
+ /* Check to see if we need to start preemption */
+ if (adreno_is_a8xx(to_adreno_gpu(gpu)))
+ a8xx_preempt_trigger(gpu);
+ else
+ a6xx_preempt_trigger(gpu);
+
+ a6xx_idle(gpu, ring);
+}
+
static u32 fuse_to_supp_hw(const struct adreno_info *info, u32 fuse)
{
if (!info->speedbins)
@@ -2753,6 +2815,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = {
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
+ .perfcntr_configure = a6xx_perfcntr_configure,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_gmu_get_timestamp,
@@ -2786,6 +2849,7 @@ const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
.create_private_vm = a6xx_create_private_vm,
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
+ .perfcntr_configure = a6xx_perfcntr_configure,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_get_timestamp,
@@ -2822,6 +2886,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
.get_rptr = a6xx_get_rptr,
.progress = a6xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
+ .perfcntr_configure = a6xx_perfcntr_configure,
},
.init = a6xx_gpu_init,
.get_timestamp = a6xx_gmu_get_timestamp,
@@ -2852,6 +2917,7 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
.get_rptr = a6xx_get_rptr,
.progress = a8xx_progress,
.sysprof_setup = a6xx_gmu_sysprof_setup,
+ .perfcntr_configure = a6xx_perfcntr_configure,
},
.init = a6xx_gpu_init,
.get_timestamp = a8xx_gmu_get_timestamp,
--
2.53.0