* [PATCH 01/16] drm/msm/a8xx: Fix the ticks used in submit traces
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 9:48 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 02/16] drm/msm/a6xx: Switch to preemption safe AO counter Akhil P Oommen
` (15 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
GMU_ALWAYS_ON_COUNTER_* registers got moved in A8x, but currently, A6x
register offsets are used in the submit traces instead of A8x offsets.
To fix this, refactor a bit and use adreno_gpu->funcs->get_timestamp()
everywhere.
While we are at it, update a8xx_gmu_get_timestamp() to use the GMU AO
counter.
Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support")
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 6 ++----
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 6 ++----
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 15 ++++++-------
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 2 +-
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 26 ++++++++++++-----------
drivers/gpu/drm/msm/adreno/adreno_gpu.c | 6 ++----
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +-
drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml | 6 ++++--
8 files changed, 32 insertions(+), 37 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
index db06c06067ae..0ed8bf2b5dd5 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -604,11 +604,9 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) {
return 0;
}
-static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 a4xx_get_timestamp(struct msm_gpu *gpu)
{
- *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
-
- return 0;
+ return gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
}
static u64 a4xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 56eaff2ee4e4..79a441e91fa1 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1435,11 +1435,9 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu)
return 0;
}
-static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 a5xx_get_timestamp(struct msm_gpu *gpu)
{
- *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO);
-
- return 0;
+ return gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO);
}
struct a5xx_crashdumper {
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 2129d230a92b..14d5b5e266f7 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -404,7 +404,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence)));
OUT_RING(ring, submit->seqno);
- trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu));
+ trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu));
a6xx_flush(gpu, ring);
}
@@ -614,7 +614,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
}
- trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu));
+ trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu));
a6xx_flush(gpu, ring);
@@ -2414,20 +2414,17 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
return 0;
}
-static int a6xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 a6xx_gmu_get_timestamp(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
- *value = read_gmu_ao_counter(a6xx_gpu);
-
- return 0;
+ return read_gmu_ao_counter(a6xx_gpu);
}
-static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 a6xx_get_timestamp(struct msm_gpu *gpu)
{
- *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER);
- return 0;
+ return gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER);
}
static struct msm_ringbuffer *a6xx_active_ring(struct msm_gpu *gpu)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 4eaa04711246..a4434a6a56dd 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -320,7 +320,7 @@ int a6xx_zap_shader_init(struct msm_gpu *gpu);
void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off);
int a8xx_fault_handler(void *arg, unsigned long iova, int flags, void *data);
void a8xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
-int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value);
+u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu);
u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate);
int a8xx_gpu_feature_probe(struct msm_gpu *gpu);
void a8xx_gpu_get_slice_info(struct msm_gpu *gpu);
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index b1887e0cf698..987c99097d40 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -1174,23 +1174,25 @@ void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_
gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0);
}
-int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+static u64 read_gmu_ao_counter(struct a6xx_gpu *a6xx_gpu)
{
- struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
- struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
-
- mutex_lock(&a6xx_gpu->gmu.lock);
-
- /* Force the GPU power on so we can read this register */
- a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
+ u64 count_hi, count_lo, temp;
- *value = gpu_read64(gpu, REG_A8XX_CP_ALWAYS_ON_COUNTER);
+ do {
+ count_hi = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H);
+ count_lo = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_L);
+ temp = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H);
+ } while (unlikely(count_hi != temp));
- a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
+ return (count_hi << 32) | count_lo;
+}
- mutex_unlock(&a6xx_gpu->gmu.lock);
+u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
- return 0;
+ return read_gmu_ao_counter(a6xx_gpu);
}
u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index d5fe6f6f0dec..1bc0e570bd12 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -391,13 +391,11 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
return 0;
case MSM_PARAM_TIMESTAMP:
if (adreno_gpu->funcs->get_timestamp) {
- int ret;
-
pm_runtime_get_sync(&gpu->pdev->dev);
- ret = adreno_gpu->funcs->get_timestamp(gpu, value);
+ *value = (uint64_t) adreno_gpu->funcs->get_timestamp(gpu);
pm_runtime_put_autosuspend(&gpu->pdev->dev);
- return ret;
+ return 0;
}
return -EINVAL;
case MSM_PARAM_PRIORITIES:
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 1d0145f8b3ec..c08725ed54c4 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -79,7 +79,7 @@ struct adreno_gpu;
struct adreno_gpu_funcs {
struct msm_gpu_funcs base;
struct msm_gpu *(*init)(struct drm_device *dev);
- int (*get_timestamp)(struct msm_gpu *gpu, uint64_t *value);
+ u64 (*get_timestamp)(struct msm_gpu *gpu);
void (*bus_halt)(struct adreno_gpu *adreno_gpu, bool gx_off);
int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data);
};
diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
index c4e00b1263cd..33404eb18fd0 100644
--- a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
+++ b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml
@@ -141,8 +141,10 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x1f9f0" name="GMU_BOOT_KMD_LM_HANDSHAKE"/>
<reg32 offset="0x1f957" name="GMU_LLM_GLM_SLEEP_CTRL"/>
<reg32 offset="0x1f958" name="GMU_LLM_GLM_SLEEP_STATUS"/>
- <reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L"/>
- <reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H"/>
+ <reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L" variants="A6XX-A7XX"/>
+ <reg32 offset="0x1f840" name="GMU_ALWAYS_ON_COUNTER_L" variants="A8XX-"/>
+ <reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H" variants="A6XX-A7XX"/>
+ <reg32 offset="0x1f841" name="GMU_ALWAYS_ON_COUNTER_H" variants="A8XX-"/>
<reg32 offset="0x1f8c3" name="GMU_GMU_PWR_COL_KEEPALIVE" variants="A6XX-A7XX"/>
<reg32 offset="0x1f7e4" name="GMU_GMU_PWR_COL_KEEPALIVE" variants="A8XX-"/>
<reg32 offset="0x1f8c4" name="GMU_PWR_COL_PREEMPT_KEEPALIVE" variants="A6XX-A7XX"/>
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 01/16] drm/msm/a8xx: Fix the ticks used in submit traces
2026-03-23 20:12 ` [PATCH 01/16] drm/msm/a8xx: Fix the ticks used in submit traces Akhil P Oommen
@ 2026-03-24 9:48 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 9:48 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> GMU_ALWAYS_ON_COUNTER_* registers got moved in A8x, but currently, A6x
> register offsets are used in the submit traces instead of A8x offsets.
> To fix this, refactor a bit and use adreno_gpu->funcs->get_timestamp()
> everywhere.
>
> While we are at it, update a8xx_gmu_get_timestamp() to use the GMU AO
> counter.
>
> Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support")
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
[...]
> -static int a6xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
> +static u64 a6xx_gmu_get_timestamp(struct msm_gpu *gpu)
> {
> struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
>
> - *value = read_gmu_ao_counter(a6xx_gpu);
> -
> - return 0;
> + return read_gmu_ao_counter(a6xx_gpu);
Can we instead make read_gmu_ao_counter() take a struct msm_gpu * and drop
this wrapper? Other callers also already have a ptr of that type
[...]
> -int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
> +static u64 read_gmu_ao_counter(struct a6xx_gpu *a6xx_gpu)
Similarly here (also I know this is a static symbol, but keeping an
a8xx_ prefix would be nice
[...]
> case MSM_PARAM_TIMESTAMP:
> if (adreno_gpu->funcs->get_timestamp) {
> - int ret;
> -
> pm_runtime_get_sync(&gpu->pdev->dev);
> - ret = adreno_gpu->funcs->get_timestamp(gpu, value);
> + *value = (uint64_t) adreno_gpu->funcs->get_timestamp(gpu);
"u64", I think checkpathch will also warn about whitespace after a typecast
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/a8xx: Fix the ticks used in submit traces
2026-03-23 20:12 ` [PATCH 01/16] drm/msm/a8xx: Fix the ticks used in submit traces Akhil P Oommen
2026-03-24 9:48 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Good cleanup. The `get_timestamp()` interface change from `int (*get_timestamp)(struct msm_gpu *gpu, uint64_t *value)` to `u64 (*get_timestamp)(struct msm_gpu *gpu)` is a nice simplification — the function never actually failed.
The new `read_gmu_ao_counter()` in a8xx_gpu.c uses the classic hi-lo-hi pattern for 64-bit reads:
```c
do {
count_hi = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H);
count_lo = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_L);
temp = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H);
} while (unlikely(count_hi != temp));
```
This correctly avoids the OOB set/clear that the old code required. The register XML updates for the A8XX variant offsets look correct.
**Nit:** The cast in `adreno_gpu.c` is unnecessary:
```c
*value = (uint64_t) adreno_gpu->funcs->get_timestamp(gpu);
```
The function already returns `u64`, so the cast is redundant.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 02/16] drm/msm/a6xx: Switch to preemption safe AO counter
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
2026-03-23 20:12 ` [PATCH 01/16] drm/msm/a8xx: Fix the ticks used in submit traces Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 9:51 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 03/16] drm/msm/a6xx: Correct OOB usage Akhil P Oommen
` (14 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
CP_ALWAYS_ON_COUNTER is not save-restored during preemption, so it won't
provide accurate data about the 'submit' when preemption is enabled.
Switch to CP_ALWAYS_ON_CONTEXT which is preemption safe.
Fixes: e7ae83da4a28 ("drm/msm/a6xx: Implement preemption for a7xx targets")
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 14d5b5e266f7..93bf2c40bfb9 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -345,7 +345,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
* GPU registers so we need to add 0x1a800 to the register value on A630
* to get the right value from PM4.
*/
- get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER,
+ get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT,
rbmemptr_stats(ring, index, alwayson_start));
/* Invalidate CCU depth and color */
@@ -386,7 +386,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP(0),
rbmemptr_stats(ring, index, cpcycles_end));
- get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER,
+ get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT,
rbmemptr_stats(ring, index, alwayson_end));
/* Write the fence to the scratch register */
@@ -478,10 +478,10 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
if (adreno_is_a8xx(adreno_gpu)) {
rbbm_perfctr_cp0 = REG_A8XX_RBBM_PERFCTR_CP(0);
- cp_always_on_counter = REG_A8XX_CP_ALWAYS_ON_COUNTER;
+ cp_always_on_counter = REG_A8XX_CP_ALWAYS_ON_CONTEXT;
} else {
rbbm_perfctr_cp0 = REG_A7XX_RBBM_PERFCTR_CP(0);
- cp_always_on_counter = REG_A6XX_CP_ALWAYS_ON_COUNTER;
+ cp_always_on_counter = REG_A6XX_CP_ALWAYS_ON_CONTEXT;
}
get_stats_counter(ring, rbbm_perfctr_cp0, rbmemptr_stats(ring, index, cpcycles_start));
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 02/16] drm/msm/a6xx: Switch to preemption safe AO counter
2026-03-23 20:12 ` [PATCH 02/16] drm/msm/a6xx: Switch to preemption safe AO counter Akhil P Oommen
@ 2026-03-24 9:51 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 9:51 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> CP_ALWAYS_ON_COUNTER is not save-restored during preemption, so it won't
> provide accurate data about the 'submit' when preemption is enabled.
> Switch to CP_ALWAYS_ON_CONTEXT which is preemption safe.
>
> Fixes: e7ae83da4a28 ("drm/msm/a6xx: Implement preemption for a7xx targets")
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index 14d5b5e266f7..93bf2c40bfb9 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -345,7 +345,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
> * GPU registers so we need to add 0x1a800 to the register value on A630
> * to get the right value from PM4.
> */
> - get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER,
> + get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT,
> rbmemptr_stats(ring, index, alwayson_start));
>
> /* Invalidate CCU depth and color */
> @@ -386,7 +386,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
>
> get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP(0),
> rbmemptr_stats(ring, index, cpcycles_end));
> - get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER,
> + get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT,
> rbmemptr_stats(ring, index, alwayson_end));
>
> /* Write the fence to the scratch register */
> @@ -478,10 +478,10 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
>
> if (adreno_is_a8xx(adreno_gpu)) {
> rbbm_perfctr_cp0 = REG_A8XX_RBBM_PERFCTR_CP(0);
> - cp_always_on_counter = REG_A8XX_CP_ALWAYS_ON_COUNTER;
> + cp_always_on_counter = REG_A8XX_CP_ALWAYS_ON_CONTEXT;
I'm a little worried about mixing the names here - KGSL uses both of
these registers (A6XX_KERNEL_PROFILE vs A6XX_KERNEL_PROFILE_CONTEXT)
to track different fields of the struct adreno_drawobj_profile_entry
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/a6xx: Switch to preemption safe AO counter
2026-03-23 20:12 ` [PATCH 02/16] drm/msm/a6xx: Switch to preemption safe AO counter Akhil P Oommen
2026-03-24 9:51 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Straightforward fix switching from `CP_ALWAYS_ON_COUNTER` to `CP_ALWAYS_ON_CONTEXT` which is save/restored during preemption. The Fixes tag is appropriate.
No issues.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 03/16] drm/msm/a6xx: Correct OOB usage
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
2026-03-23 20:12 ` [PATCH 01/16] drm/msm/a8xx: Fix the ticks used in submit traces Akhil P Oommen
2026-03-23 20:12 ` [PATCH 02/16] drm/msm/a6xx: Switch to preemption safe AO counter Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 04/16] drm/msm/a6xx: Add support for Debug HFI Q Akhil P Oommen
` (13 subsequent siblings)
16 siblings, 1 reply; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
During the GMU resume sequence, using another OOB other than OOB_GPU may
confuse the internal state of GMU firmware. To align more strictly with
the downstream sequence, move the sysprof related OOB setup after the
OOB_GPU is cleared.
Fixes: 62cd0fa6990b ("drm/msm/adreno: Disable IFPC when sysprof is active")
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 5 -----
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 6 ++++++
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 6 ++++++
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 9662201cd2e9..690d3e53e273 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -1236,11 +1236,6 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
/* Set the GPU to the current freq */
a6xx_gmu_set_initial_freq(gpu, gmu);
- if (refcount_read(&gpu->sysprof_active) > 1) {
- ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
- if (!ret)
- set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
- }
out:
/* On failure, shut down the GMU to leave it in a good state */
if (ret) {
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 93bf2c40bfb9..897522778fd4 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -1603,6 +1603,12 @@ static int hw_init(struct msm_gpu *gpu)
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER);
}
+ if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) {
+ ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
+ if (!ret)
+ set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
+ }
+
return ret;
}
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index 987c99097d40..d414f24ddbd9 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -711,6 +711,12 @@ static int hw_init(struct msm_gpu *gpu)
*/
a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
+ if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) {
+ ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET);
+ if (!ret)
+ set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status);
+ }
+
return ret;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Claude review: drm/msm/a6xx: Correct OOB usage
2026-03-23 20:12 ` [PATCH 03/16] drm/msm/a6xx: Correct OOB usage Akhil P Oommen
@ 2026-03-24 21:32 ` Claude Code Review Bot
0 siblings, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Moves the sysprof OOB setup from `a6xx_gmu_resume()` to `hw_init()` to avoid confusing the GMU firmware state during resume.
**Minor concern:** In `a6xx_gmu.c`, the removal leaves:
```c
out:
/* On failure, shut down the GMU to leave it in a good state */
if (ret) {
```
There's now a blank line before `out:`, which is fine stylistically but worth noting the label now follows directly after the set_initial_freq call with no intervening code.
The a8xx copy in `a8xx_gpu.c` adds the same pattern — both check `!ret` correctly.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 04/16] drm/msm/a6xx: Add support for Debug HFI Q
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (2 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 03/16] drm/msm/a6xx: Correct OOB usage Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 05/16] drm/msm/adreno: Coredump on GPU/GMU init failures Akhil P Oommen
` (12 subsequent siblings)
16 siblings, 1 reply; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
Add the Debug HFI Queue which contains the F2H messages posted from the
GMU firmware. Having this data in coredump is useful to debug firmware
issues.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 2 +-
drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +-
drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 16 +++++++++++++---
drivers/gpu/drm/msm/adreno/a6xx_hfi.h | 2 ++
4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index 2af074c8e8cf..dd0614b19aac 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -110,7 +110,7 @@ struct a6xx_gmu {
unsigned long freq;
- struct a6xx_hfi_queue queues[2];
+ struct a6xx_hfi_queue queues[HFI_MAX_QUEUES];
bool initialized;
bool hung;
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
index d2d6b2fd3cba..018c164ad980 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
@@ -57,7 +57,7 @@ struct a6xx_gpu_state {
struct msm_gpu_state_bo *gmu_hfi;
struct msm_gpu_state_bo *gmu_debug;
- s32 hfi_queue_history[2][HFI_HISTORY_SZ];
+ s32 hfi_queue_history[HFI_MAX_QUEUES][HFI_HISTORY_SZ];
struct list_head objs;
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
index 53cfdf4e6c34..2daaa340366d 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
@@ -1056,8 +1056,8 @@ void a6xx_hfi_init(struct a6xx_gmu *gmu)
struct a6xx_gmu_bo *hfi = &gmu->hfi;
struct a6xx_hfi_queue_table_header *table = hfi->virt;
struct a6xx_hfi_queue_header *headers = hfi->virt + sizeof(*table);
+ int table_size, idx;
u64 offset;
- int table_size;
/*
* The table size is the size of the table header plus all of the queue
@@ -1076,12 +1076,22 @@ void a6xx_hfi_init(struct a6xx_gmu *gmu)
table->active_queues = ARRAY_SIZE(gmu->queues);
/* Command queue */
+ idx = 0;
offset = SZ_4K;
- a6xx_hfi_queue_init(&gmu->queues[0], &headers[0], hfi->virt + offset,
+ a6xx_hfi_queue_init(&gmu->queues[idx], &headers[idx], hfi->virt + offset,
hfi->iova + offset, 0);
/* GMU response queue */
+ idx++;
offset += SZ_4K;
- a6xx_hfi_queue_init(&gmu->queues[1], &headers[1], hfi->virt + offset,
+ a6xx_hfi_queue_init(&gmu->queues[idx], &headers[idx], hfi->virt + offset,
hfi->iova + offset, gmu->legacy ? 4 : 1);
+
+ /* GMU Debug queue */
+ idx++;
+ offset += SZ_4K;
+ a6xx_hfi_queue_init(&gmu->queues[idx], &headers[idx], hfi->virt + offset,
+ hfi->iova + offset, gmu->legacy ? 5 : 2);
+
+ WARN_ON(idx >= HFI_MAX_QUEUES);
}
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
index 6f9f74a0bc85..19f6eca2c8c9 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
@@ -4,6 +4,8 @@
#ifndef _A6XX_HFI_H_
#define _A6XX_HFI_H_
+#define HFI_MAX_QUEUES 3
+
struct a6xx_hfi_queue_table_header {
u32 version;
u32 size; /* Size of the queue table in dwords */
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Claude review: drm/msm/a6xx: Add support for Debug HFI Q
2026-03-23 20:12 ` [PATCH 04/16] drm/msm/a6xx: Add support for Debug HFI Q Akhil P Oommen
@ 2026-03-24 21:32 ` Claude Code Review Bot
0 siblings, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Adds a third HFI queue (Debug) for F2H messages from GMU firmware, useful for coredump debugging.
**Bug:** The WARN_ON check is off-by-one:
```c
WARN_ON(idx >= HFI_MAX_QUEUES);
```
At this point `idx` is 2 and `HFI_MAX_QUEUES` is 3, so `2 >= 3` is false — the WARN never fires. This check should be `WARN_ON(idx + 1 > HFI_MAX_QUEUES)` or should appear *after* the idx++ to catch overflow, or better yet, just use a `static_assert` or BUILD_BUG_ON at compile time since the array sizes are all compile-time constants. As written, the WARN_ON doesn't protect against anything.
**Note:** The HFI memory BO size should be verified — previously 2 queues at 4K each (8K within the HFI BO), now 3 queues needing 12K of payload space plus the table header. The BO allocation happens elsewhere and should be checked to be large enough.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 05/16] drm/msm/adreno: Coredump on GPU/GMU init failures
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (3 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 04/16] drm/msm/a6xx: Add support for Debug HFI Q Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 9:53 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers Akhil P Oommen
` (11 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
Capture coredump on GPU or GMU errors during initialization to help in
debugging the issues. To be consistent with the locks while calling
msm_gpu_crashstate_capture(), call pm_runtime_get(gpu) always with
msm_gpu->lock.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 1 +
drivers/gpu/drm/msm/adreno/adreno_device.c | 7 +++++--
drivers/gpu/drm/msm/adreno/adreno_gpu.c | 2 ++
drivers/gpu/drm/msm/msm_gpu.c | 5 +++--
drivers/gpu/drm/msm/msm_gpu.h | 2 ++
5 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 690d3e53e273..6d511dc54e43 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -1240,6 +1240,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
/* On failure, shut down the GMU to leave it in a good state */
if (ret) {
disable_irq(gmu->gmu_irq);
+ msm_gpu_crashstate_capture(gpu, NULL, NULL, NULL, NULL);
a6xx_rpmh_stop(gmu);
pm_runtime_put(gmu->gxpd);
pm_runtime_put(gmu->dev);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 4edfe80c5be7..85b3e1f0e4fa 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -105,6 +105,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
*/
pm_runtime_enable(&pdev->dev);
+ mutex_lock(&gpu->lock);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
pm_runtime_put_noidle(&pdev->dev);
@@ -112,15 +113,15 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
goto err_disable_rpm;
}
- mutex_lock(&gpu->lock);
ret = msm_gpu_hw_init(gpu);
- mutex_unlock(&gpu->lock);
if (ret) {
+ msm_gpu_crashstate_capture(gpu, NULL, NULL, NULL, NULL);
DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret);
goto err_put_rpm;
}
pm_runtime_put_autosuspend(&pdev->dev);
+ mutex_unlock(&gpu->lock);
#ifdef CONFIG_DEBUG_FS
if (gpu->funcs->debugfs_init) {
@@ -136,6 +137,8 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
err_disable_rpm:
pm_runtime_disable(&pdev->dev);
+ mutex_unlock(&gpu->lock);
+
return NULL;
}
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 1bc0e570bd12..10d9e5f40640 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -391,9 +391,11 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
return 0;
case MSM_PARAM_TIMESTAMP:
if (adreno_gpu->funcs->get_timestamp) {
+ mutex_lock(&gpu->lock);
pm_runtime_get_sync(&gpu->pdev->dev);
*value = (uint64_t) adreno_gpu->funcs->get_timestamp(gpu);
pm_runtime_put_autosuspend(&gpu->pdev->dev);
+ mutex_unlock(&gpu->lock);
return 0;
}
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 995549d0bbbc..472db2c916f9 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -361,7 +361,7 @@ static void crashstate_get_vm_logs(struct msm_gpu_state *state, struct msm_gem_v
mutex_unlock(&vm->mmu_lock);
}
-static void msm_gpu_crashstate_capture(struct msm_gpu *gpu,
+void msm_gpu_crashstate_capture(struct msm_gpu *gpu,
struct msm_gem_submit *submit, struct msm_gpu_fault_info *fault_info,
char *comm, char *cmd)
{
@@ -886,7 +886,8 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
pm_runtime_get_sync(&gpu->pdev->dev);
- msm_gpu_hw_init(gpu);
+ if (msm_gpu_hw_init(gpu))
+ msm_gpu_crashstate_capture(gpu, NULL, NULL, NULL, NULL);
submit->seqno = submit->hw_fence->seqno;
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 666cf499b7ec..eb5b3a7b81f9 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -747,6 +747,8 @@ static inline void msm_gpu_crashstate_put(struct msm_gpu *gpu)
}
void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_info *fault_info);
+void msm_gpu_crashstate_capture(struct msm_gpu *gpu, struct msm_gem_submit *submit,
+ struct msm_gpu_fault_info *fault_info, char *comm, char *cmd);
/*
* Simple macro to semi-cleanly add the MAP_PRIV flag for targets that can
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 05/16] drm/msm/adreno: Coredump on GPU/GMU init failures
2026-03-23 20:12 ` [PATCH 05/16] drm/msm/adreno: Coredump on GPU/GMU init failures Akhil P Oommen
@ 2026-03-24 9:53 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 9:53 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> Capture coredump on GPU or GMU errors during initialization to help in
> debugging the issues. To be consistent with the locks while calling
> msm_gpu_crashstate_capture(), call pm_runtime_get(gpu) always with
> msm_gpu->lock.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
> drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 1 +
> drivers/gpu/drm/msm/adreno/adreno_device.c | 7 +++++--
> drivers/gpu/drm/msm/adreno/adreno_gpu.c | 2 ++
> drivers/gpu/drm/msm/msm_gpu.c | 5 +++--
> drivers/gpu/drm/msm/msm_gpu.h | 2 ++
> 5 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> index 690d3e53e273..6d511dc54e43 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> @@ -1240,6 +1240,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
> /* On failure, shut down the GMU to leave it in a good state */
> if (ret) {
> disable_irq(gmu->gmu_irq);
> + msm_gpu_crashstate_capture(gpu, NULL, NULL, NULL, NULL);
> a6xx_rpmh_stop(gmu);
> pm_runtime_put(gmu->gxpd);
> pm_runtime_put(gmu->dev);
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
> index 4edfe80c5be7..85b3e1f0e4fa 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_device.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
> @@ -105,6 +105,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
> */
> pm_runtime_enable(&pdev->dev);
>
> + mutex_lock(&gpu->lock);
guared(mutex)(&gpu->lock) will let you drop the subsequent
jump-to-unlock
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/adreno: Coredump on GPU/GMU init failures
2026-03-23 20:12 ` [PATCH 05/16] drm/msm/adreno: Coredump on GPU/GMU init failures Akhil P Oommen
2026-03-24 9:53 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Locking concern in `adreno_load_gpu()`**: The mutex_lock is moved before `pm_runtime_get_sync()` and the unlock is split into two paths. Looking at the error path:
```c
err_put_rpm:
pm_runtime_put_sync_suspend(&pdev->dev);
err_disable_rpm:
pm_runtime_disable(&pdev->dev);
mutex_unlock(&gpu->lock);
return NULL;
```
If `pm_runtime_get_sync()` fails, we jump to `err_disable_rpm` where `mutex_unlock` is called — this is correct. If `msm_gpu_hw_init()` fails, we jump to `err_put_rpm` which falls through to `err_disable_rpm` and also unlocks — also correct. The success path unlocks after `pm_runtime_put_autosuspend`. So the locking looks correct on all paths.
**Concern in `adreno_gpu.c`**: Adding `mutex_lock(&gpu->lock)` around the `MSM_PARAM_TIMESTAMP` path in `adreno_get_param()` — this may introduce lock ordering issues if callers already hold locks. This should be documented or verified against all call sites.
**In `msm_gpu.c`**: Calling `msm_gpu_crashstate_capture()` from `msm_gpu_submit()` when `msm_gpu_hw_init()` fails — is `gpu->lock` held here? The submit path typically holds `gpu->lock`, so this should be fine for the crashstate_capture assertion.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (4 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 05/16] drm/msm/adreno: Coredump on GPU/GMU init failures Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-23 20:45 ` Rob Clark
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 07/16] drm/msm/a6xx: Use packed structs for HFI Akhil P Oommen
` (10 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
To avoid harmful compiler optimizations and IO reordering in the HW, use
barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI
queue index variables.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
index 2daaa340366d..aef00c2dd137 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
@@ -34,7 +34,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
struct a6xx_hfi_queue_header *header = queue->header;
u32 i, hdr, index = header->read_index;
- if (header->read_index == header->write_index) {
+ if (header->read_index == READ_ONCE(header->write_index)) {
header->rx_request = 1;
return 0;
}
@@ -62,7 +62,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
if (!gmu->legacy)
index = ALIGN(index, 4) % header->size;
- header->read_index = index;
+ /* Ensure all memory operations are complete before updating the read index */
+ dma_mb();
+
+ WRITE_ONCE(header->read_index, index);
return HFI_HEADER_SIZE(hdr);
}
@@ -74,7 +77,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
spin_lock(&queue->lock);
- space = CIRC_SPACE(header->write_index, header->read_index,
+ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index),
header->size);
if (space < dwords) {
header->dropped++;
@@ -95,7 +98,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
queue->data[index] = 0xfafafafa;
}
- header->write_index = index;
+ /* Ensure all memory operations are complete before updating the write index */
+ dma_mb();
+
+ WRITE_ONCE(header->write_index, index);
spin_unlock(&queue->lock);
gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01);
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers
2026-03-23 20:12 ` [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers Akhil P Oommen
@ 2026-03-23 20:45 ` Rob Clark
2026-03-23 21:29 ` Dmitry Baryshkov
2026-03-23 21:35 ` Akhil P Oommen
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 2 replies; 52+ messages in thread
From: Rob Clark @ 2026-03-23 20:45 UTC (permalink / raw)
To: Akhil P Oommen
Cc: Sean Paul, Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Marijn Suijten, David Airlie, Simona Vetter,
Antonino Maniscalco, Connor Abbott, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, linux-arm-msm, dri-devel,
freedreno, linux-kernel
On Mon, Mar 23, 2026 at 1:13 PM Akhil P Oommen <akhilpo@oss.qualcomm.com> wrote:
>
> To avoid harmful compiler optimizations and IO reordering in the HW, use
> barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI
> queue index variables.
This feels a bit like it should have Fixes: ?
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
> drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++----
> 1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
> index 2daaa340366d..aef00c2dd137 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
> @@ -34,7 +34,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
> struct a6xx_hfi_queue_header *header = queue->header;
> u32 i, hdr, index = header->read_index;
>
> - if (header->read_index == header->write_index) {
> + if (header->read_index == READ_ONCE(header->write_index)) {
> header->rx_request = 1;
> return 0;
> }
> @@ -62,7 +62,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
> if (!gmu->legacy)
> index = ALIGN(index, 4) % header->size;
>
> - header->read_index = index;
> + /* Ensure all memory operations are complete before updating the read index */
> + dma_mb();
> +
> + WRITE_ONCE(header->read_index, index);
> return HFI_HEADER_SIZE(hdr);
> }
>
> @@ -74,7 +77,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
>
> spin_lock(&queue->lock);
>
> - space = CIRC_SPACE(header->write_index, header->read_index,
> + space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index),
> header->size);
> if (space < dwords) {
> header->dropped++;
> @@ -95,7 +98,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
> queue->data[index] = 0xfafafafa;
> }
>
> - header->write_index = index;
> + /* Ensure all memory operations are complete before updating the write index */
> + dma_mb();
> +
> + WRITE_ONCE(header->write_index, index);
> spin_unlock(&queue->lock);
>
> gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01);
>
> --
> 2.51.0
>
^ permalink raw reply [flat|nested] 52+ messages in thread* Re: [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers
2026-03-23 20:45 ` Rob Clark
@ 2026-03-23 21:29 ` Dmitry Baryshkov
2026-03-23 21:35 ` Akhil P Oommen
1 sibling, 0 replies; 52+ messages in thread
From: Dmitry Baryshkov @ 2026-03-23 21:29 UTC (permalink / raw)
To: Rob Clark
Cc: Akhil P Oommen, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Mon, Mar 23, 2026 at 01:45:16PM -0700, Rob Clark wrote:
> On Mon, Mar 23, 2026 at 1:13 PM Akhil P Oommen <akhilpo@oss.qualcomm.com> wrote:
> >
> > To avoid harmful compiler optimizations and IO reordering in the HW, use
> > barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI
> > queue index variables.
>
> This feels a bit like it should have Fixes: ?
And as a friendly reminder, if it is a Fix, please move it towards the
start of the series.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers
2026-03-23 20:45 ` Rob Clark
2026-03-23 21:29 ` Dmitry Baryshkov
@ 2026-03-23 21:35 ` Akhil P Oommen
1 sibling, 0 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 21:35 UTC (permalink / raw)
To: rob.clark
Cc: Sean Paul, Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Marijn Suijten, David Airlie, Simona Vetter,
Antonino Maniscalco, Connor Abbott, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, linux-arm-msm, dri-devel,
freedreno, linux-kernel
On 3/24/2026 2:15 AM, Rob Clark wrote:
> On Mon, Mar 23, 2026 at 1:13 PM Akhil P Oommen <akhilpo@oss.qualcomm.com> wrote:
>>
>> To avoid harmful compiler optimizations and IO reordering in the HW, use
>> barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI
>> queue index variables.
>
> This feels a bit like it should have Fixes: ?
Ack. Will update in v2.
-Akhil
>
>> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
>> ---
>> drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++----
>> 1 file changed, 10 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
>> index 2daaa340366d..aef00c2dd137 100644
>> --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
>> +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
>> @@ -34,7 +34,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
>> struct a6xx_hfi_queue_header *header = queue->header;
>> u32 i, hdr, index = header->read_index;
>>
>> - if (header->read_index == header->write_index) {
>> + if (header->read_index == READ_ONCE(header->write_index)) {
>> header->rx_request = 1;
>> return 0;
>> }
>> @@ -62,7 +62,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu,
>> if (!gmu->legacy)
>> index = ALIGN(index, 4) % header->size;
>>
>> - header->read_index = index;
>> + /* Ensure all memory operations are complete before updating the read index */
>> + dma_mb();
>> +
>> + WRITE_ONCE(header->read_index, index);
>> return HFI_HEADER_SIZE(hdr);
>> }
>>
>> @@ -74,7 +77,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
>>
>> spin_lock(&queue->lock);
>>
>> - space = CIRC_SPACE(header->write_index, header->read_index,
>> + space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index),
>> header->size);
>> if (space < dwords) {
>> header->dropped++;
>> @@ -95,7 +98,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu,
>> queue->data[index] = 0xfafafafa;
>> }
>>
>> - header->write_index = index;
>> + /* Ensure all memory operations are complete before updating the write index */
>> + dma_mb();
>> +
>> + WRITE_ONCE(header->write_index, index);
>> spin_unlock(&queue->lock);
>>
>> gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01);
>>
>> --
>> 2.51.0
>>
^ permalink raw reply [flat|nested] 52+ messages in thread
* Claude review: drm/msm/a6xx: Use barriers while updating HFI Q headers
2026-03-23 20:12 ` [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers Akhil P Oommen
2026-03-23 20:45 ` Rob Clark
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Good defensive change. The `dma_mb()` barriers and `READ_ONCE`/`WRITE_ONCE` are appropriate for the shared memory HFI queues between CPU and GMU firmware.
**Nit:** Extra space in comments: `" Ensure all memory..."` — two spaces after `/*`.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 07/16] drm/msm/a6xx: Use packed structs for HFI
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (5 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 06/16] drm/msm/a6xx: Use barriers while updating HFI Q headers Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 08/16] drm/msm/a6xx: Update HFI definitions Akhil P Oommen
` (9 subsequent siblings)
16 siblings, 1 reply; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
HFI related structs define the ABI between the KMD and the GMU firmware.
So, use packed structures to avoid unintended compiler inserted padding.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_hfi.h | 40 +++++++++++++++++------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
index 19f6eca2c8c9..217708b03f6f 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
@@ -13,7 +13,7 @@ struct a6xx_hfi_queue_table_header {
u32 qhdr_size; /* Size of the queue headers */
u32 num_queues; /* Number of total queues */
u32 active_queues; /* Number of active queues */
-};
+} __packed;
struct a6xx_hfi_queue_header {
u32 status;
@@ -28,7 +28,7 @@ struct a6xx_hfi_queue_header {
u32 tx_request;
u32 read_index;
u32 write_index;
-};
+} __packed;
struct a6xx_hfi_queue {
struct a6xx_hfi_queue_header *header;
@@ -74,7 +74,7 @@ struct a6xx_hfi_msg_response {
u32 ret_header;
u32 error;
u32 payload[HFI_RESPONSE_PAYLOAD_SIZE];
-};
+} __packed;
#define HFI_F2H_MSG_ERROR 100
@@ -82,7 +82,7 @@ struct a6xx_hfi_msg_error {
u32 header;
u32 code;
u32 payload[2];
-};
+} __packed;
#define HFI_H2F_MSG_INIT 0
@@ -92,27 +92,27 @@ struct a6xx_hfi_msg_gmu_init_cmd {
u32 dbg_buffer_addr;
u32 dbg_buffer_size;
u32 boot_state;
-};
+} __packed;
#define HFI_H2F_MSG_FW_VERSION 1
struct a6xx_hfi_msg_fw_version {
u32 header;
u32 supported_version;
-};
+} __packed;
#define HFI_H2F_MSG_PERF_TABLE 4
struct perf_level {
u32 vote;
u32 freq;
-};
+} __packed;
struct perf_gx_level {
u32 vote;
u32 acd;
u32 freq;
-};
+} __packed;
struct a6xx_hfi_msg_perf_table_v1 {
u32 header;
@@ -121,7 +121,7 @@ struct a6xx_hfi_msg_perf_table_v1 {
struct perf_level gx_votes[16];
struct perf_level cx_votes[4];
-};
+} __packed;
struct a6xx_hfi_msg_perf_table {
u32 header;
@@ -130,7 +130,7 @@ struct a6xx_hfi_msg_perf_table {
struct perf_gx_level gx_votes[16];
struct perf_level cx_votes[4];
-};
+} __packed;
#define HFI_H2F_MSG_BW_TABLE 3
@@ -145,13 +145,13 @@ struct a6xx_hfi_msg_bw_table {
u32 cnoc_cmds_data[2][6];
u32 ddr_cmds_addrs[8];
u32 ddr_cmds_data[16][8];
-};
+} __packed;
#define HFI_H2F_MSG_TEST 5
struct a6xx_hfi_msg_test {
u32 header;
-};
+} __packed;
#define HFI_H2F_MSG_ACD 7
#define MAX_ACD_STRIDE 2
@@ -163,13 +163,13 @@ struct a6xx_hfi_acd_table {
u32 stride;
u32 num_levels;
u32 data[16 * MAX_ACD_STRIDE];
-};
+} __packed;
#define HFI_H2F_MSG_START 10
struct a6xx_hfi_msg_start {
u32 header;
-};
+} __packed;
#define HFI_H2F_FEATURE_CTRL 11
@@ -178,14 +178,14 @@ struct a6xx_hfi_msg_feature_ctrl {
u32 feature;
u32 enable;
u32 data;
-};
+} __packed;
#define HFI_H2F_MSG_CORE_FW_START 14
struct a6xx_hfi_msg_core_fw_start {
u32 header;
u32 handle;
-};
+} __packed;
#define HFI_H2F_MSG_TABLE 15
@@ -193,7 +193,7 @@ struct a6xx_hfi_table_entry {
u32 count;
u32 stride;
u32 data[];
-};
+} __packed;
struct a6xx_hfi_table {
u32 header;
@@ -202,7 +202,7 @@ struct a6xx_hfi_table {
#define HFI_TABLE_BW_VOTE 0
#define HFI_TABLE_GPU_PERF 1
struct a6xx_hfi_table_entry entry[];
-};
+} __packed;
#define HFI_H2F_MSG_GX_BW_PERF_VOTE 30
@@ -211,7 +211,7 @@ struct a6xx_hfi_gx_bw_perf_vote_cmd {
u32 ack_type;
u32 freq;
u32 bw;
-};
+} __packed;
#define AB_VOTE_MASK GENMASK(31, 16)
#define MAX_AB_VOTE (FIELD_MAX(AB_VOTE_MASK) - 1)
@@ -224,6 +224,6 @@ struct a6xx_hfi_prep_slumber_cmd {
u32 header;
u32 bw;
u32 freq;
-};
+} __packed;
#endif
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 08/16] drm/msm/a6xx: Update HFI definitions
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (6 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 07/16] drm/msm/a6xx: Use packed structs for HFI Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 10:00 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 09/16] drm/msm/adreno: Implement gx_is_on() for A8x Akhil P Oommen
` (8 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
Update the HFI definitions to support additional GMU based power
features.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 3 -
drivers/gpu/drm/msm/adreno/a6xx_hfi.h | 113 +++++++++++++++++++++++++++++++++-
2 files changed, 111 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
index aef00c2dd137..d613bf00e3f8 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c
@@ -851,7 +851,6 @@ static int a6xx_hfi_feature_ctrl_msg(struct a6xx_gmu *gmu, u32 feature, u32 enab
return a6xx_hfi_send_msg(gmu, HFI_H2F_FEATURE_CTRL, &msg, sizeof(msg), NULL, 0);
}
-#define HFI_FEATURE_IFPC 9
#define IFPC_LONG_HYST 0x1680
static int a6xx_hfi_enable_ifpc(struct a6xx_gmu *gmu)
@@ -862,8 +861,6 @@ static int a6xx_hfi_enable_ifpc(struct a6xx_gmu *gmu)
return a6xx_hfi_feature_ctrl_msg(gmu, HFI_FEATURE_IFPC, 1, IFPC_LONG_HYST);
}
-#define HFI_FEATURE_ACD 12
-
static int a6xx_hfi_enable_acd(struct a6xx_gmu *gmu)
{
struct a6xx_hfi_acd_table *acd_table = &gmu->acd_table;
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
index 217708b03f6f..917b9c9e9906 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h
@@ -165,6 +165,42 @@ struct a6xx_hfi_acd_table {
u32 data[16 * MAX_ACD_STRIDE];
} __packed;
+#define CLX_DATA(irated, num_phases, clx_path, extd_intf) \
+ ((extd_intf << 29) | \
+ (clx_path << 28) | \
+ (num_phases << 22) | \
+ (irated << 16))
+
+struct a6xx_hfi_clx_domain_v2 {
+ /**
+ * @data: BITS[0:15] Migration time
+ * BITS[16:21] Current rating
+ * BITS[22:27] Phases for domain
+ * BITS[28:28] Path notification
+ * BITS[29:31] Extra features
+ */
+ u32 data;
+ /** @clxt: CLX time in microseconds */
+ u32 clxt;
+ /** @clxh: CLH time in microseconds */
+ u32 clxh;
+ /** @urg_mode: Urgent HW throttle mode of operation */
+ u32 urg_mode;
+ /** @lkg_en: Enable leakage current estimate */
+ u32 lkg_en;
+ /** curr_budget: Current Budget */
+ u32 curr_budget;
+} __packed;
+
+#define HFI_H2F_MSG_CLX_TBL 8
+
+#define MAX_CLX_DOMAINS 2
+struct a6xx_hfi_clx_table_v2_cmd {
+ u32 hdr;
+ u32 version;
+ struct a6xx_hfi_clx_domain_v2 domain[MAX_CLX_DOMAINS];
+} __packed;
+
#define HFI_H2F_MSG_START 10
struct a6xx_hfi_msg_start {
@@ -176,6 +212,41 @@ struct a6xx_hfi_msg_start {
struct a6xx_hfi_msg_feature_ctrl {
u32 header;
u32 feature;
+#define HFI_FEATURE_DCVS 0
+#define HFI_FEATURE_HWSCHED 1
+#define HFI_FEATURE_PREEMPTION 2
+#define HFI_FEATURE_CLOCKS_ON 3
+#define HFI_FEATURE_BUS_ON 4
+#define HFI_FEATURE_RAIL_ON 5
+#define HFI_FEATURE_HWCG 6
+#define HFI_FEATURE_LM 7
+#define HFI_FEATURE_THROTTLE 8
+#define HFI_FEATURE_IFPC 9
+#define HFI_FEATURE_NAP 10
+#define HFI_FEATURE_BCL 11
+#define HFI_FEATURE_ACD 12
+#define HFI_FEATURE_DIDT 13
+#define HFI_FEATURE_DEPRECATED 14
+#define HFI_FEATURE_CB 15
+#define HFI_FEATURE_KPROF 16
+#define HFI_FEATURE_BAIL_OUT_TIMER 17
+#define HFI_FEATURE_GMU_STATS 18
+#define HFI_FEATURE_DBQ 19
+#define HFI_FEATURE_MINBW 20
+#define HFI_FEATURE_CLX 21
+#define HFI_FEATURE_LSR 23
+#define HFI_FEATURE_LPAC 24
+#define HFI_FEATURE_HW_FENCE 25
+#define HFI_FEATURE_PERF_NORETAIN 26
+#define HFI_FEATURE_DMS 27
+#define HFI_FEATURE_THERMAL 28
+#define HFI_FEATURE_AQE 29
+#define HFI_FEATURE_TDCVS 30
+#define HFI_FEATURE_DCE 31
+#define HFI_FEATURE_IFF_PCLX 32
+#define HFI_FEATURE_SOFT_RESET 0x10000001
+#define HFI_FEATURE_DCVS_PROFILE 0x10000002
+#define HFI_FEATURE_FAST_CTX_DESTROY 0x10000003
u32 enable;
u32 data;
} __packed;
@@ -199,8 +270,17 @@ struct a6xx_hfi_table {
u32 header;
u32 version;
u32 type;
-#define HFI_TABLE_BW_VOTE 0
-#define HFI_TABLE_GPU_PERF 1
+#define HFI_TABLE_BW_VOTE 0
+#define HFI_TABLE_GPU_PERF 1
+#define HFI_TABLE_DIDT 2
+#define HFI_TABLE_ACD 3
+#define HFI_TABLE_CLX_V1 4 /* Unused */
+#define HFI_TABLE_CLX_V2 5
+#define HFI_TABLE_THERM 6
+#define HFI_TABLE_DCVS 7
+#define HFI_TABLE_SYS_TIME 8
+#define HFI_TABLE_GMU_DCVS 9
+#define HFI_TABLE_LIMITS_MIT 10
struct a6xx_hfi_table_entry entry[];
} __packed;
@@ -226,4 +306,33 @@ struct a6xx_hfi_prep_slumber_cmd {
u32 freq;
} __packed;
+struct a6xx_hfi_limits_cfg {
+ u32 enable;
+ u32 msg_path;
+ u32 lkg_en;
+ /**
+ * @mode: BIT[0]: 0 = (static) throttle to fixed sid level
+ * 1 = (dynamic) throttle to sid lievel calculated by HW
+ * BIT[1]: 0 = Mx
+ * 1 = Bx
+ */
+ u32 mode;
+ u32 sid;
+ /** @mit_time: mitigation time in microseconds */
+ u32 mit_time;
+ /** @curr_limit: Max current in mA during mitigation */
+ u32 curr_limit;
+} __packed;
+
+struct a6xx_hfi_limits_tbl {
+ u8 feature_id;
+#define GMU_MIT_IFF 0
+#define GMU_MIT_PCLX 1
+ u8 domain;
+#define GMU_GX_DOMAIN 0
+#define GMU_MX_DOMAIN 1
+ u16 feature_rev;
+ struct a6xx_hfi_limits_cfg cfg;
+} __packed;
+
#endif
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 08/16] drm/msm/a6xx: Update HFI definitions
2026-03-23 20:12 ` [PATCH 08/16] drm/msm/a6xx: Update HFI definitions Akhil P Oommen
@ 2026-03-24 10:00 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 10:00 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> Update the HFI definitions to support additional GMU based power
> features.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
[...]
> +#define CLX_DATA(irated, num_phases, clx_path, extd_intf) \
> + ((extd_intf << 29) | \
> + (clx_path << 28) | \
> + (num_phases << 22) | \
> + (irated << 16))
> +
> +struct a6xx_hfi_clx_domain_v2 {
> + /**
> + * @data: BITS[0:15] Migration time
> + * BITS[16:21] Current rating
> + * BITS[22:27] Phases for domain
> + * BITS[28:28] Path notification
> + * BITS[29:31] Extra features
> + */
My first thought would be to define these as bitfields, i.e.
u16 mitigation_time
u8 current_rating : 6;
u8 num_phases : 6;
u8 path_notification : 1;
u8 extra_features : 3;
(hopefully I counted them right)
You would then not need custom macros to set/get the data
> + u32 data;
> + /** @clxt: CLX time in microseconds */
slash-star-star implies kerneldoc, which this isn't - but it would
be appreciated, see e.g. struct qcom_icc_provider in
drivers/interconnect/qcom/icc-rpmh.h
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/a6xx: Update HFI definitions
2026-03-23 20:12 ` [PATCH 08/16] drm/msm/a6xx: Update HFI definitions Akhil P Oommen
2026-03-24 10:00 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Adds new HFI feature constants, CLX table structures, and limits mitigation table structures. The `#define` moves from local to header scope are clean.
**Nit:** The `CLX_DATA` macro has a potential issue with operator precedence — the shifts should use parenthesized arguments:
```c
#define CLX_DATA(irated, num_phases, clx_path, extd_intf) \
((extd_intf << 29) | ...
```
Should be `(((extd_intf) << 29) | ((clx_path) << 28) | ...)` to be safe. Though if this is only used with literal constants it's fine in practice.
**Note:** There's a typo in the `a6xx_hfi_limits_cfg` docs: `"sid lievel"` should be `"sid level"`.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 09/16] drm/msm/adreno: Implement gx_is_on() for A8x
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (7 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 08/16] drm/msm/a6xx: Update HFI definitions Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 10:03 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 10/16] drm/msm/a6xx: Fix gpu init from secure world Akhil P Oommen
` (7 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
A8x has a diverged enough for a separate implementation of gx_is_on()
check. Add that and move them to the adreno func table.
Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support")
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 25 +++++++++++++++++++++----
drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 4 +++-
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 6 +++++-
drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 4 ++--
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
5 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 6d511dc54e43..cd6609bb66fe 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -91,10 +91,10 @@ bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu)
}
/* Check to see if the GX rail is still powered */
-bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
+bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu)
{
- struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
- struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
u32 val;
/* This can be called from gpu state code so make sure GMU is valid */
@@ -117,6 +117,23 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
}
+bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu)
+{
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+ u32 val;
+
+ /* This can be called from gpu state code so make sure GMU is valid */
+ if (!gmu->initialized)
+ return false;
+
+ val = gmu_read(gmu, REG_A8XX_GMU_PWR_CLK_STATUS);
+
+ return !(val &
+ (A8XX_GMU_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF |
+ A8XX_GMU_PWR_CLK_STATUS_GX_HM_CLK_OFF));
+}
+
void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp,
bool suspended)
{
@@ -240,7 +257,7 @@ static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu)
if (val == local) {
if (gmu->idle_level != GMU_IDLE_STATE_IFPC ||
- !a6xx_gmu_gx_is_on(gmu))
+ !adreno_gpu->funcs->gx_is_on(adreno_gpu))
return true;
}
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index dd0614b19aac..9a5464fa6a07 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -10,6 +10,7 @@
#include <linux/notifier.h>
#include <linux/soc/qcom/qcom_aoss.h>
#include "msm_drv.h"
+#include "adreno_gpu.h"
#include "a6xx_hfi.h"
struct a6xx_gmu_bo {
@@ -231,7 +232,8 @@ void a6xx_hfi_stop(struct a6xx_gmu *gmu);
int a6xx_hfi_send_prep_slumber(struct a6xx_gmu *gmu);
int a6xx_hfi_set_freq(struct a6xx_gmu *gmu, u32 perf_index, u32 bw_index);
-bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu);
+bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu);
+bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu);
bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu);
void a6xx_sptprac_disable(struct a6xx_gmu *gmu);
int a6xx_sptprac_enable(struct a6xx_gmu *gmu);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 897522778fd4..cdecd91094c6 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -1641,7 +1641,7 @@ static void a6xx_recover(struct msm_gpu *gpu)
adreno_dump_info(gpu);
- if (a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) {
+ if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) {
/* Sometimes crashstate capture is skipped, so SQE should be halted here again */
gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3);
@@ -2768,6 +2768,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = {
.get_timestamp = a6xx_gmu_get_timestamp,
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
+ .gx_is_on = a6xx_gmu_gx_is_on,
};
const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
@@ -2800,6 +2801,7 @@ const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
.get_timestamp = a6xx_get_timestamp,
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
+ .gx_is_on = a6xx_gmu_gx_is_on,
};
const struct adreno_gpu_funcs a7xx_gpu_funcs = {
@@ -2834,6 +2836,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
.get_timestamp = a6xx_gmu_get_timestamp,
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
+ .gx_is_on = a6xx_gmu_gx_is_on,
};
const struct adreno_gpu_funcs a8xx_gpu_funcs = {
@@ -2861,4 +2864,5 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
.get_timestamp = a8xx_gmu_get_timestamp,
.bus_halt = a8xx_bus_clear_pending_transactions,
.mmu_fault_handler = a8xx_fault_handler,
+ .gx_is_on = a8xx_gmu_gx_is_on,
};
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
index 018c164ad980..c0b9661131e8 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
@@ -1251,7 +1251,7 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu,
_a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gpucc_reg,
&a6xx_state->gmu_registers[2], false);
- if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
+ if (!adreno_gpu->funcs->gx_is_on(adreno_gpu))
return;
/* Set the fence to ALLOW mode so we can access the registers */
@@ -1608,7 +1608,7 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
}
/* If GX isn't on the rest of the data isn't going to be accessible */
- if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
+ if (!adreno_gpu->funcs->gx_is_on(adreno_gpu))
return &a6xx_state->base;
/* Halt SQE first */
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index c08725ed54c4..29097e6b4253 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -82,6 +82,7 @@ struct adreno_gpu_funcs {
u64 (*get_timestamp)(struct msm_gpu *gpu);
void (*bus_halt)(struct adreno_gpu *adreno_gpu, bool gx_off);
int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data);
+ bool (*gx_is_on)(struct adreno_gpu *adreno_gpu);
};
struct adreno_reglist {
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 09/16] drm/msm/adreno: Implement gx_is_on() for A8x
2026-03-23 20:12 ` [PATCH 09/16] drm/msm/adreno: Implement gx_is_on() for A8x Akhil P Oommen
@ 2026-03-24 10:03 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 10:03 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> A8x has a diverged enough for a separate implementation of gx_is_on()
> check. Add that and move them to the adreno func table.
>
> Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support")
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
Fair, but then it'd also make sense to do so for a7 which also
ignores SPTPRAC and has a different bitfields vs a6
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/adreno: Implement gx_is_on() for A8x
2026-03-23 20:12 ` [PATCH 09/16] drm/msm/adreno: Implement gx_is_on() for A8x Akhil P Oommen
2026-03-24 10:03 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Good refactoring — moves `gx_is_on()` to the adreno_gpu_funcs vtable so A8xx can provide its own implementation using `REG_A8XX_GMU_PWR_CLK_STATUS`.
The function signature change from `struct a6xx_gmu *` to `struct adreno_gpu *` is clean and all callers are updated.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 10/16] drm/msm/a6xx: Fix gpu init from secure world
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (8 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 09/16] drm/msm/adreno: Implement gx_is_on() for A8x Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 10:07 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 11/16] drm/msm/a8xx: Add SKU table for A840 Akhil P Oommen
` (6 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
A7XX_GEN2 and newer GPUs requires initialization of few configurations
related to features/power from secure world. The SCM call to do this
should be triggered after GDSC and clocks are enabled. So, keep this
sequence to a6xx_gmu_resume instead of the probe.
Fixes: 14b27d5df3ea ("drm/msm/a7xx: Initialize a750 "software fuse"")
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 58 ++++++++++++++++++++++++++++++++++
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 59 -----------------------------------
2 files changed, 58 insertions(+), 59 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index cd6609bb66fe..61af3b212ba4 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -3,6 +3,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/interconnect.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -1174,6 +1175,59 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
dev_pm_opp_put(gpu_opp);
}
+static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu)
+{
+ struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
+ struct msm_gpu *gpu = &adreno_gpu->base;
+ u32 fuse_val;
+ int ret;
+
+ if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
+ /*
+ * Assume that if qcom scm isn't available, that whatever
+ * replacement allows writing the fuse register ourselves.
+ * Users of alternative firmware need to make sure this
+ * register is writeable or indicate that it's not somehow.
+ * Print a warning because if you mess this up you're about to
+ * crash horribly.
+ */
+ if (!qcom_scm_is_available()) {
+ dev_warn_once(gpu->dev->dev,
+ "SCM is not available, poking fuse register\n");
+ a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE,
+ A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING |
+ A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND |
+ A7XX_CX_MISC_SW_FUSE_VALUE_LPAC);
+ adreno_gpu->has_ray_tracing = true;
+ return 0;
+ }
+
+ ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ |
+ QCOM_SCM_GPU_TSENSE_EN_REQ);
+ if (ret) {
+ dev_warn_once(gpu->dev->dev,
+ "SCM call failed\n");
+ return ret;
+ }
+
+ /*
+ * On A7XX_GEN3 and newer, raytracing may be disabled by the
+ * firmware, find out whether that's the case. The scm call
+ * above sets the fuse register.
+ */
+ fuse_val = a6xx_llc_read(a6xx_gpu,
+ REG_A7XX_CX_MISC_SW_FUSE_VALUE);
+ adreno_gpu->has_ray_tracing =
+ !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING);
+ } else if (adreno_is_a740(adreno_gpu)) {
+ /* Raytracing is always enabled on a740 */
+ adreno_gpu->has_ray_tracing = true;
+ }
+
+ return 0;
+}
+
+
int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
@@ -1208,6 +1262,10 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
return ret;
}
+ ret = a6xx_gmu_secure_init(a6xx_gpu);
+ if (ret)
+ return ret;
+
/* Read the slice info on A8x GPUs */
a8xx_gpu_get_slice_info(gpu);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index cdecd91094c6..cbc803d90673 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -10,7 +10,6 @@
#include <linux/bitfield.h>
#include <linux/devfreq.h>
-#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/pm_domain.h>
#include <linux/soc/qcom/llcc-qcom.h>
@@ -2158,56 +2157,6 @@ static void a6xx_llc_slices_init(struct platform_device *pdev,
a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL);
}
-static int a7xx_cx_mem_init(struct a6xx_gpu *a6xx_gpu)
-{
- struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
- struct msm_gpu *gpu = &adreno_gpu->base;
- u32 fuse_val;
- int ret;
-
- if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
- /*
- * Assume that if qcom scm isn't available, that whatever
- * replacement allows writing the fuse register ourselves.
- * Users of alternative firmware need to make sure this
- * register is writeable or indicate that it's not somehow.
- * Print a warning because if you mess this up you're about to
- * crash horribly.
- */
- if (!qcom_scm_is_available()) {
- dev_warn_once(gpu->dev->dev,
- "SCM is not available, poking fuse register\n");
- a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE,
- A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING |
- A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND |
- A7XX_CX_MISC_SW_FUSE_VALUE_LPAC);
- adreno_gpu->has_ray_tracing = true;
- return 0;
- }
-
- ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ |
- QCOM_SCM_GPU_TSENSE_EN_REQ);
- if (ret)
- return ret;
-
- /*
- * On A7XX_GEN3 and newer, raytracing may be disabled by the
- * firmware, find out whether that's the case. The scm call
- * above sets the fuse register.
- */
- fuse_val = a6xx_llc_read(a6xx_gpu,
- REG_A7XX_CX_MISC_SW_FUSE_VALUE);
- adreno_gpu->has_ray_tracing =
- !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING);
- } else if (adreno_is_a740(adreno_gpu)) {
- /* Raytracing is always enabled on a740 */
- adreno_gpu->has_ray_tracing = true;
- }
-
- return 0;
-}
-
-
#define GBIF_CLIENT_HALT_MASK BIT(0)
#define GBIF_ARB_HALT_MASK BIT(1)
#define VBIF_XIN_HALT_CTRL0_MASK GENMASK(3, 0)
@@ -2711,14 +2660,6 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
return ERR_PTR(ret);
}
- if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
- ret = a7xx_cx_mem_init(a6xx_gpu);
- if (ret) {
- a6xx_destroy(&(a6xx_gpu->base.base));
- return ERR_PTR(ret);
- }
- }
-
adreno_gpu->uche_trap_base = 0x1fffffffff000ull;
msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu,
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 10/16] drm/msm/a6xx: Fix gpu init from secure world
2026-03-23 20:12 ` [PATCH 10/16] drm/msm/a6xx: Fix gpu init from secure world Akhil P Oommen
@ 2026-03-24 10:07 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 10:07 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> A7XX_GEN2 and newer GPUs requires initialization of few configurations
> related to features/power from secure world. The SCM call to do this
> should be triggered after GDSC and clocks are enabled. So, keep this
> sequence to a6xx_gmu_resume instead of the probe.
>
> Fixes: 14b27d5df3ea ("drm/msm/a7xx: Initialize a750 "software fuse"")
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
This now makes this happen on *every GMU resume*, which sounds
undesirable (kgsl does this in gen7_gmu_first_boot)
Similarly, we call a8xx_gpu_get_slice_info() on *every resume*
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/a6xx: Fix gpu init from secure world
2026-03-23 20:12 ` [PATCH 10/16] drm/msm/a6xx: Fix gpu init from secure world Akhil P Oommen
2026-03-24 10:07 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Moves the SCM call from probe time to `a6xx_gmu_resume()`. The rationale is that GDSC/clocks must be on for the SCM call.
**Concern:** This means the SCM call now happens on every resume, not just once at probe. The `dev_warn_once` in the SCM-unavailable path suggests the original intent was one-time init. If the SCM call is idempotent this is fine, but it adds resume latency. Also, `has_ray_tracing` gets set on every resume — if something could change it between suspend/resume, that's intentional; otherwise it's wasted work.
**Nit:** The error message has a double space: `"SCM call failed\n"`.
**Missing error handling:** If `a6xx_gmu_secure_init()` fails during resume, the code returns early without cleaning up the GMU state that was already initialized in the preceding steps of `a6xx_gmu_resume()`.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 11/16] drm/msm/a8xx: Add SKU table for A840
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (9 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 10/16] drm/msm/a6xx: Fix gpu init from secure world Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85 Akhil P Oommen
` (5 subsequent siblings)
16 siblings, 1 reply; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
Add the SKU table in the catalog for A840 GPU. This data helps to pick
the correct bin from the OPP table based on the speed_bin fuse value.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
index 38561f26837e..f6b9792531a6 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
@@ -1954,6 +1954,12 @@ static const struct adreno_info a8xx_gpus[] = {
},
},
.preempt_record_size = 19708 * SZ_1K,
+ .speedbins = ADRENO_SPEEDBINS(
+ { 0, 0 },
+ { 273, 1 },
+ { 252, 2 },
+ { 221, 3 },
+ ),
}
};
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (10 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 11/16] drm/msm/a8xx: Add SKU table for A840 Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-23 20:37 ` Rob Clark
` (3 more replies)
2026-03-23 20:12 ` [PATCH 13/16] drm/msm/a8xx: Implement IFPC support for A840 Akhil P Oommen
` (4 subsequent siblings)
16 siblings, 4 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
Adreno X2-85 series present in Glymur chipset supports a new mechanism
for SKU detection. A new CX_MISC register exposes the combined (or
final) speedbin value from both HW fuse register and the Soft Fuse
register.
Implement this new SKU detection along with a new quirk to identify the
GPUs that has SOFT SKU support. Also, enable this quirk for Adreno X2-85
and add its SKU table to the catalog.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 6 ++++
drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 9 +++++-
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 41 ++++++++++++++++++++++-----
drivers/gpu/drm/msm/adreno/adreno_gpu.c | 5 ----
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
drivers/gpu/drm/msm/registers/adreno/a6xx.xml | 4 +++
6 files changed, 53 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 79a441e91fa1..d7ed3225f635 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1731,6 +1731,7 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
struct adreno_gpu *adreno_gpu;
struct msm_gpu *gpu;
unsigned int nr_rings;
+ u32 speedbin;
int ret;
a5xx_gpu = kzalloc(sizeof(*a5xx_gpu), GFP_KERNEL);
@@ -1757,6 +1758,11 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
return ERR_PTR(ret);
}
+ /* Set the speedbin value that is passed to userspace */
+ if (adreno_read_speedbin(&pdev->dev, &speedbin) || !speedbin)
+ speedbin = 0xffff;
+ adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
+
msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu,
a5xx_fault_handler);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
index f6b9792531a6..758bc7bd31f6 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
@@ -1902,7 +1902,8 @@ static const struct adreno_info a8xx_gpus[] = {
.gmem = 21 * SZ_1M,
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
- ADRENO_QUIRK_HAS_HW_APRIV,
+ ADRENO_QUIRK_HAS_HW_APRIV |
+ ADRENO_QUIRK_SOFTFUSE,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &x285_protect,
@@ -1922,6 +1923,12 @@ static const struct adreno_info a8xx_gpus[] = {
{ /* sentinel */ },
},
},
+ .speedbins = ADRENO_SPEEDBINS(
+ { 0, 0 },
+ { 388, 1 },
+ { 357, 2 },
+ { 284, 3 },
+ ),
}, {
.chip_ids = ADRENO_CHIP_IDS(0x44050a01),
.family = ADRENO_8XX_GEN2,
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index cbc803d90673..0fe6d803e628 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2552,13 +2552,33 @@ static u32 fuse_to_supp_hw(const struct adreno_info *info, u32 fuse)
return UINT_MAX;
}
-static int a6xx_set_supported_hw(struct device *dev, const struct adreno_info *info)
+static int a6xx_read_speedbin(struct device *dev, struct a6xx_gpu *a6xx_gpu,
+ const struct adreno_info *info, u32 *speedbin)
+{
+ int ret;
+
+ /* Use speedbin fuse if present. Otherwise, fallback to softfuse */
+ ret = adreno_read_speedbin(dev, speedbin);
+ if (ret != -ENOENT)
+ return ret;
+
+ if (info->quirks & ADRENO_QUIRK_SOFTFUSE) {
+ *speedbin = a6xx_llc_read(a6xx_gpu, REG_A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS);
+ *speedbin = A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS_FINALFREQLIMIT(*speedbin);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int a6xx_set_supported_hw(struct device *dev, struct a6xx_gpu *a6xx_gpu,
+ const struct adreno_info *info)
{
u32 supp_hw;
u32 speedbin;
int ret;
- ret = adreno_read_speedbin(dev, &speedbin);
+ ret = a6xx_read_speedbin(dev, a6xx_gpu, info, &speedbin);
/*
* -ENOENT means that the platform doesn't support speedbin which is
* fine
@@ -2592,11 +2612,13 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = priv->gpu_pdev;
struct adreno_platform_config *config = pdev->dev.platform_data;
+ const struct adreno_info *info = config->info;
struct device_node *node;
struct a6xx_gpu *a6xx_gpu;
struct adreno_gpu *adreno_gpu;
struct msm_gpu *gpu;
extern int enable_preemption;
+ u32 speedbin;
bool is_a7xx;
int ret, nr_rings = 1;
@@ -2619,14 +2641,14 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
adreno_gpu->gmu_is_wrapper = of_device_is_compatible(node, "qcom,adreno-gmu-wrapper");
adreno_gpu->base.hw_apriv =
- !!(config->info->quirks & ADRENO_QUIRK_HAS_HW_APRIV);
+ !!(info->quirks & ADRENO_QUIRK_HAS_HW_APRIV);
/* gpu->info only gets assigned in adreno_gpu_init(). A8x is included intentionally */
- is_a7xx = config->info->family >= ADRENO_7XX_GEN1;
+ is_a7xx = info->family >= ADRENO_7XX_GEN1;
a6xx_llc_slices_init(pdev, a6xx_gpu, is_a7xx);
- ret = a6xx_set_supported_hw(&pdev->dev, config->info);
+ ret = a6xx_set_supported_hw(&pdev->dev, a6xx_gpu, info);
if (ret) {
a6xx_llc_slices_destroy(a6xx_gpu);
kfree(a6xx_gpu);
@@ -2634,15 +2656,20 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
}
if ((enable_preemption == 1) || (enable_preemption == -1 &&
- (config->info->quirks & ADRENO_QUIRK_PREEMPTION)))
+ (info->quirks & ADRENO_QUIRK_PREEMPTION)))
nr_rings = 4;
- ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, nr_rings);
+ ret = adreno_gpu_init(dev, pdev, adreno_gpu, info->funcs, nr_rings);
if (ret) {
a6xx_destroy(&(a6xx_gpu->base.base));
return ERR_PTR(ret);
}
+ /* Set the speedbin value that is passed to userspace */
+ if (a6xx_read_speedbin(&pdev->dev, a6xx_gpu, info, &speedbin) || !speedbin)
+ speedbin = 0xffff;
+ adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
+
/*
* For now only clamp to idle freq for devices where this is known not
* to cause power supply issues:
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 10d9e5f40640..826661cb7988 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -1184,7 +1184,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct msm_gpu_config adreno_gpu_config = { 0 };
struct msm_gpu *gpu = &adreno_gpu->base;
const char *gpu_name;
- u32 speedbin;
int ret;
adreno_gpu->funcs = funcs;
@@ -1213,10 +1212,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
devm_pm_opp_set_clkname(dev, "core");
}
- if (adreno_read_speedbin(dev, &speedbin) || !speedbin)
- speedbin = 0xffff;
- adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
-
gpu_name = devm_kasprintf(dev, GFP_KERNEL, "%"ADRENO_CHIPID_FMT,
ADRENO_CHIPID_ARGS(config->chip_id));
if (!gpu_name)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 29097e6b4253..044ed4d49aa7 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -63,6 +63,7 @@ enum adreno_family {
#define ADRENO_QUIRK_PREEMPTION BIT(5)
#define ADRENO_QUIRK_4GB_VA BIT(6)
#define ADRENO_QUIRK_IFPC BIT(7)
+#define ADRENO_QUIRK_SOFTFUSE BIT(8)
/* Helper for formating the chip_id in the way that userspace tools like
* crashdec expect.
diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml
index 3941e7510754..2309870f5031 100644
--- a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml
+++ b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml
@@ -5016,6 +5016,10 @@ by a particular renderpass/blit.
<bitfield pos="1" name="LPAC" type="boolean"/>
<bitfield pos="2" name="RAYTRACING" type="boolean"/>
</reg32>
+ <reg32 offset="0x0405" name="CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS" variants="A8XX-">
+ <bitfield high="8" low="0" name="FINALFREQLIMIT"/>
+ <bitfield pos="24" name="SOFTSKUDISABLED" type="boolean"/>
+ </reg32>
</domain>
</database>
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85
2026-03-23 20:12 ` [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85 Akhil P Oommen
@ 2026-03-23 20:37 ` Rob Clark
2026-03-23 21:34 ` Akhil P Oommen
2026-03-23 21:34 ` Dmitry Baryshkov
` (2 subsequent siblings)
3 siblings, 1 reply; 52+ messages in thread
From: Rob Clark @ 2026-03-23 20:37 UTC (permalink / raw)
To: Akhil P Oommen
Cc: Sean Paul, Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Marijn Suijten, David Airlie, Simona Vetter,
Antonino Maniscalco, Connor Abbott, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, linux-arm-msm, dri-devel,
freedreno, linux-kernel
On Mon, Mar 23, 2026 at 1:13 PM Akhil P Oommen <akhilpo@oss.qualcomm.com> wrote:
>
> Adreno X2-85 series present in Glymur chipset supports a new mechanism
> for SKU detection. A new CX_MISC register exposes the combined (or
> final) speedbin value from both HW fuse register and the Soft Fuse
> register.
>
> Implement this new SKU detection along with a new quirk to identify the
> GPUs that has SOFT SKU support. Also, enable this quirk for Adreno X2-85
> and add its SKU table to the catalog.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
> drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 6 ++++
> drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 9 +++++-
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 41 ++++++++++++++++++++++-----
> drivers/gpu/drm/msm/adreno/adreno_gpu.c | 5 ----
> drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
> drivers/gpu/drm/msm/registers/adreno/a6xx.xml | 4 +++
> 6 files changed, 53 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
> index 79a441e91fa1..d7ed3225f635 100644
> --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
> @@ -1731,6 +1731,7 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
> struct adreno_gpu *adreno_gpu;
> struct msm_gpu *gpu;
> unsigned int nr_rings;
> + u32 speedbin;
> int ret;
>
> a5xx_gpu = kzalloc(sizeof(*a5xx_gpu), GFP_KERNEL);
> @@ -1757,6 +1758,11 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
> return ERR_PTR(ret);
> }
>
> + /* Set the speedbin value that is passed to userspace */
> + if (adreno_read_speedbin(&pdev->dev, &speedbin) || !speedbin)
> + speedbin = 0xffff;
> + adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
> +
I will confess to not expecting to see a5xx changes in a patch adding
x2-85 sku detection :-)
Maybe split the code-motion out of adreno_gpu_init() into it's own commit?
BR,
-R
> msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu,
> a5xx_fault_handler);
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
> index f6b9792531a6..758bc7bd31f6 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
> @@ -1902,7 +1902,8 @@ static const struct adreno_info a8xx_gpus[] = {
> .gmem = 21 * SZ_1M,
> .inactive_period = DRM_MSM_INACTIVE_PERIOD,
> .quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
> - ADRENO_QUIRK_HAS_HW_APRIV,
> + ADRENO_QUIRK_HAS_HW_APRIV |
> + ADRENO_QUIRK_SOFTFUSE,
> .funcs = &a8xx_gpu_funcs,
> .a6xx = &(const struct a6xx_info) {
> .protect = &x285_protect,
> @@ -1922,6 +1923,12 @@ static const struct adreno_info a8xx_gpus[] = {
> { /* sentinel */ },
> },
> },
> + .speedbins = ADRENO_SPEEDBINS(
> + { 0, 0 },
> + { 388, 1 },
> + { 357, 2 },
> + { 284, 3 },
> + ),
> }, {
> .chip_ids = ADRENO_CHIP_IDS(0x44050a01),
> .family = ADRENO_8XX_GEN2,
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index cbc803d90673..0fe6d803e628 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -2552,13 +2552,33 @@ static u32 fuse_to_supp_hw(const struct adreno_info *info, u32 fuse)
> return UINT_MAX;
> }
>
> -static int a6xx_set_supported_hw(struct device *dev, const struct adreno_info *info)
> +static int a6xx_read_speedbin(struct device *dev, struct a6xx_gpu *a6xx_gpu,
> + const struct adreno_info *info, u32 *speedbin)
> +{
> + int ret;
> +
> + /* Use speedbin fuse if present. Otherwise, fallback to softfuse */
> + ret = adreno_read_speedbin(dev, speedbin);
> + if (ret != -ENOENT)
> + return ret;
> +
> + if (info->quirks & ADRENO_QUIRK_SOFTFUSE) {
> + *speedbin = a6xx_llc_read(a6xx_gpu, REG_A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS);
> + *speedbin = A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS_FINALFREQLIMIT(*speedbin);
> + return 0;
> + }
> +
> + return -ENOENT;
> +}
> +
> +static int a6xx_set_supported_hw(struct device *dev, struct a6xx_gpu *a6xx_gpu,
> + const struct adreno_info *info)
> {
> u32 supp_hw;
> u32 speedbin;
> int ret;
>
> - ret = adreno_read_speedbin(dev, &speedbin);
> + ret = a6xx_read_speedbin(dev, a6xx_gpu, info, &speedbin);
> /*
> * -ENOENT means that the platform doesn't support speedbin which is
> * fine
> @@ -2592,11 +2612,13 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
> struct msm_drm_private *priv = dev->dev_private;
> struct platform_device *pdev = priv->gpu_pdev;
> struct adreno_platform_config *config = pdev->dev.platform_data;
> + const struct adreno_info *info = config->info;
> struct device_node *node;
> struct a6xx_gpu *a6xx_gpu;
> struct adreno_gpu *adreno_gpu;
> struct msm_gpu *gpu;
> extern int enable_preemption;
> + u32 speedbin;
> bool is_a7xx;
> int ret, nr_rings = 1;
>
> @@ -2619,14 +2641,14 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
> adreno_gpu->gmu_is_wrapper = of_device_is_compatible(node, "qcom,adreno-gmu-wrapper");
>
> adreno_gpu->base.hw_apriv =
> - !!(config->info->quirks & ADRENO_QUIRK_HAS_HW_APRIV);
> + !!(info->quirks & ADRENO_QUIRK_HAS_HW_APRIV);
>
> /* gpu->info only gets assigned in adreno_gpu_init(). A8x is included intentionally */
> - is_a7xx = config->info->family >= ADRENO_7XX_GEN1;
> + is_a7xx = info->family >= ADRENO_7XX_GEN1;
>
> a6xx_llc_slices_init(pdev, a6xx_gpu, is_a7xx);
>
> - ret = a6xx_set_supported_hw(&pdev->dev, config->info);
> + ret = a6xx_set_supported_hw(&pdev->dev, a6xx_gpu, info);
> if (ret) {
> a6xx_llc_slices_destroy(a6xx_gpu);
> kfree(a6xx_gpu);
> @@ -2634,15 +2656,20 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
> }
>
> if ((enable_preemption == 1) || (enable_preemption == -1 &&
> - (config->info->quirks & ADRENO_QUIRK_PREEMPTION)))
> + (info->quirks & ADRENO_QUIRK_PREEMPTION)))
> nr_rings = 4;
>
> - ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, nr_rings);
> + ret = adreno_gpu_init(dev, pdev, adreno_gpu, info->funcs, nr_rings);
> if (ret) {
> a6xx_destroy(&(a6xx_gpu->base.base));
> return ERR_PTR(ret);
> }
>
> + /* Set the speedbin value that is passed to userspace */
> + if (a6xx_read_speedbin(&pdev->dev, a6xx_gpu, info, &speedbin) || !speedbin)
> + speedbin = 0xffff;
> + adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
> +
> /*
> * For now only clamp to idle freq for devices where this is known not
> * to cause power supply issues:
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> index 10d9e5f40640..826661cb7988 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> @@ -1184,7 +1184,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
> struct msm_gpu_config adreno_gpu_config = { 0 };
> struct msm_gpu *gpu = &adreno_gpu->base;
> const char *gpu_name;
> - u32 speedbin;
> int ret;
>
> adreno_gpu->funcs = funcs;
> @@ -1213,10 +1212,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
> devm_pm_opp_set_clkname(dev, "core");
> }
>
> - if (adreno_read_speedbin(dev, &speedbin) || !speedbin)
> - speedbin = 0xffff;
> - adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
> -
> gpu_name = devm_kasprintf(dev, GFP_KERNEL, "%"ADRENO_CHIPID_FMT,
> ADRENO_CHIPID_ARGS(config->chip_id));
> if (!gpu_name)
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> index 29097e6b4253..044ed4d49aa7 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> @@ -63,6 +63,7 @@ enum adreno_family {
> #define ADRENO_QUIRK_PREEMPTION BIT(5)
> #define ADRENO_QUIRK_4GB_VA BIT(6)
> #define ADRENO_QUIRK_IFPC BIT(7)
> +#define ADRENO_QUIRK_SOFTFUSE BIT(8)
>
> /* Helper for formating the chip_id in the way that userspace tools like
> * crashdec expect.
> diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml
> index 3941e7510754..2309870f5031 100644
> --- a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml
> +++ b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml
> @@ -5016,6 +5016,10 @@ by a particular renderpass/blit.
> <bitfield pos="1" name="LPAC" type="boolean"/>
> <bitfield pos="2" name="RAYTRACING" type="boolean"/>
> </reg32>
> + <reg32 offset="0x0405" name="CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS" variants="A8XX-">
> + <bitfield high="8" low="0" name="FINALFREQLIMIT"/>
> + <bitfield pos="24" name="SOFTSKUDISABLED" type="boolean"/>
> + </reg32>
> </domain>
>
> </database>
>
> --
> 2.51.0
>
^ permalink raw reply [flat|nested] 52+ messages in thread* Re: [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85
2026-03-23 20:37 ` Rob Clark
@ 2026-03-23 21:34 ` Akhil P Oommen
0 siblings, 0 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 21:34 UTC (permalink / raw)
To: rob.clark
Cc: Sean Paul, Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Marijn Suijten, David Airlie, Simona Vetter,
Antonino Maniscalco, Connor Abbott, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, linux-arm-msm, dri-devel,
freedreno, linux-kernel
On 3/24/2026 2:07 AM, Rob Clark wrote:
> On Mon, Mar 23, 2026 at 1:13 PM Akhil P Oommen <akhilpo@oss.qualcomm.com> wrote:
>>
>> Adreno X2-85 series present in Glymur chipset supports a new mechanism
>> for SKU detection. A new CX_MISC register exposes the combined (or
>> final) speedbin value from both HW fuse register and the Soft Fuse
>> register.
>>
>> Implement this new SKU detection along with a new quirk to identify the
>> GPUs that has SOFT SKU support. Also, enable this quirk for Adreno X2-85
>> and add its SKU table to the catalog.
>>
>> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
>> ---
>> drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 6 ++++
>> drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 9 +++++-
>> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 41 ++++++++++++++++++++++-----
>> drivers/gpu/drm/msm/adreno/adreno_gpu.c | 5 ----
>> drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
>> drivers/gpu/drm/msm/registers/adreno/a6xx.xml | 4 +++
>> 6 files changed, 53 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
>> index 79a441e91fa1..d7ed3225f635 100644
>> --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
>> +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
>> @@ -1731,6 +1731,7 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
>> struct adreno_gpu *adreno_gpu;
>> struct msm_gpu *gpu;
>> unsigned int nr_rings;
>> + u32 speedbin;
>> int ret;
>>
>> a5xx_gpu = kzalloc(sizeof(*a5xx_gpu), GFP_KERNEL);
>> @@ -1757,6 +1758,11 @@ static struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
>> return ERR_PTR(ret);
>> }
>>
>> + /* Set the speedbin value that is passed to userspace */
>> + if (adreno_read_speedbin(&pdev->dev, &speedbin) || !speedbin)
>> + speedbin = 0xffff;
>> + adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
>> +
>
> I will confess to not expecting to see a5xx changes in a patch adding
> x2-85 sku detection :-)
>
> Maybe split the code-motion out of adreno_gpu_init() into it's own commit?
>
I forgot to mention the refactor part in the commit message. Ack. Will
split this patch.
-Akhil
> BR,
> -R
>
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85
2026-03-23 20:12 ` [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85 Akhil P Oommen
2026-03-23 20:37 ` Rob Clark
@ 2026-03-23 21:34 ` Dmitry Baryshkov
2026-03-24 10:09 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
3 siblings, 0 replies; 52+ messages in thread
From: Dmitry Baryshkov @ 2026-03-23 21:34 UTC (permalink / raw)
To: Akhil P Oommen
Cc: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Tue, Mar 24, 2026 at 01:42:24AM +0530, Akhil P Oommen wrote:
> Adreno X2-85 series present in Glymur chipset supports a new mechanism
> for SKU detection. A new CX_MISC register exposes the combined (or
> final) speedbin value from both HW fuse register and the Soft Fuse
> register.
>
> Implement this new SKU detection along with a new quirk to identify the
> GPUs that has SOFT SKU support. Also, enable this quirk for Adreno X2-85
SOFT SKU -> Soft fuse?
> and add its SKU table to the catalog.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
> drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 6 ++++
> drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 9 +++++-
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 41 ++++++++++++++++++++++-----
> drivers/gpu/drm/msm/adreno/adreno_gpu.c | 5 ----
> drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
> drivers/gpu/drm/msm/registers/adreno/a6xx.xml | 4 +++
> 6 files changed, 53 insertions(+), 13 deletions(-)
>
> @@ -1213,10 +1212,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
> devm_pm_opp_set_clkname(dev, "core");
> }
>
> - if (adreno_read_speedbin(dev, &speedbin) || !speedbin)
> - speedbin = 0xffff;
> - adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
> -
You have removed this from the generic code and then added it to a5xx
and a6xx+. Wouldn't this cause a change on a2xx - a4xx?
> gpu_name = devm_kasprintf(dev, GFP_KERNEL, "%"ADRENO_CHIPID_FMT,
> ADRENO_CHIPID_ARGS(config->chip_id));
> if (!gpu_name)
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85
2026-03-23 20:12 ` [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85 Akhil P Oommen
2026-03-23 20:37 ` Rob Clark
2026-03-23 21:34 ` Dmitry Baryshkov
@ 2026-03-24 10:09 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
3 siblings, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 10:09 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> Adreno X2-85 series present in Glymur chipset supports a new mechanism
> for SKU detection. A new CX_MISC register exposes the combined (or
> final) speedbin value from both HW fuse register and the Soft Fuse
> register.
>
> Implement this new SKU detection along with a new quirk to identify the
> GPUs that has SOFT SKU support. Also, enable this quirk for Adreno X2-85
> and add its SKU table to the catalog.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
[...]
> + /* Set the speedbin value that is passed to userspace */
> + if (adreno_read_speedbin(&pdev->dev, &speedbin) || !speedbin)
> + speedbin = 0xffff;
> + adreno_gpu->speedbin = (uint16_t) (0xffff & speedbin);
FWIW this is lower_16_bits()
[...]
> + if (info->quirks & ADRENO_QUIRK_SOFTFUSE) {
> + *speedbin = a6xx_llc_read(a6xx_gpu, REG_A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS);
> + *speedbin = A8XX_CX_MISC_SW_FUSE_FREQ_LIMIT_STATUS_FINALFREQLIMIT(*speedbin);
Do we need to act upon the other field here (SOFTSKUDISABLED)?
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/a6xx: Add SKU detection support for X2-85
2026-03-23 20:12 ` [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85 Akhil P Oommen
` (2 preceding siblings ...)
2026-03-24 10:09 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
3 siblings, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Adds `ADRENO_QUIRK_SOFTFUSE` and a new CX_MISC register for soft-SKU detection on X2-85.
**Issue:** The speedbin reading was moved out of `adreno_gpu_init()` into driver-specific init functions (a5xx, a6xx). The a5xx change adds the code that was previously in `adreno_gpu_init()`, but this means any other GPU family (a4xx?) that relied on the common code in `adreno_gpu_init()` would lose speedbin support. Verify no regressions for older GPUs.
The new `a6xx_read_speedbin()` function properly falls back: first tries fuse, then soft-fuse via CX_MISC register if the SOFTFUSE quirk is set.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 13/16] drm/msm/a8xx: Implement IFPC support for A840
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (11 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 12/16] drm/msm/a6xx: Add SKU detection support for X2-85 Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 10:13 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 14/16] drm/msm/a8xx: Preemption " Akhil P Oommen
` (3 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
Implement pwrup reglist support and add the necessary register
configurations to enable IFPC support on A840
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 185 +++++++++++++++++++++++++++++-
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 97 +++++++++++++++-
2 files changed, 280 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
index 758bc7bd31f6..53548f6e891b 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
@@ -1891,6 +1891,185 @@ static const struct adreno_reglist a840_gbif[] = {
{ },
};
+static const uint32_t a840_pwrup_reglist_regs[] = {
+ REG_A7XX_SP_HLSQ_TIMEOUT_THRESHOLD_DP,
+ REG_A7XX_SP_READ_SEL,
+ REG_A6XX_UCHE_MODE_CNTL,
+ REG_A8XX_UCHE_VARB_IDLE_TIMEOUT,
+ REG_A8XX_UCHE_GBIF_GX_CONFIG,
+ REG_A8XX_UCHE_CCHE_MODE_CNTL,
+ REG_A8XX_UCHE_CCHE_CACHE_WAYS,
+ REG_A8XX_UCHE_CACHE_WAYS,
+ REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN,
+ REG_A8XX_UCHE_CCHE_GC_GMEM_RANGE_MIN + 1,
+ REG_A8XX_UCHE_CCHE_LPAC_GMEM_RANGE_MIN,
+ REG_A8XX_UCHE_CCHE_LPAC_GMEM_RANGE_MIN + 1,
+ REG_A8XX_UCHE_CCHE_TRAP_BASE,
+ REG_A8XX_UCHE_CCHE_TRAP_BASE + 1,
+ REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE,
+ REG_A8XX_UCHE_CCHE_WRITE_THRU_BASE + 1,
+ REG_A8XX_UCHE_HW_DBG_CNTL,
+ REG_A8XX_UCHE_WRITE_THRU_BASE,
+ REG_A8XX_UCHE_WRITE_THRU_BASE + 1,
+ REG_A8XX_UCHE_TRAP_BASE,
+ REG_A8XX_UCHE_TRAP_BASE + 1,
+ REG_A8XX_UCHE_CLIENT_PF,
+ REG_A8XX_RB_CMP_NC_MODE_CNTL,
+ REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN,
+ REG_A8XX_SP_HLSQ_GC_GMEM_RANGE_MIN + 1,
+ REG_A6XX_TPL1_NC_MODE_CNTL,
+ REG_A6XX_TPL1_DBG_ECO_CNTL,
+ REG_A6XX_TPL1_DBG_ECO_CNTL1,
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(0),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(1),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(2),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(3),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(4),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(5),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(6),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(7),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(8),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(9),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(10),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(11),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(12),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(13),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(14),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(15),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(16),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(17),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(18),
+ REG_A8XX_TPL1_BICUBIC_WEIGHTS_TABLE(19),
+};
+DECLARE_ADRENO_REGLIST_LIST(a840_pwrup_reglist);
+
+static const u32 a840_ifpc_reglist_regs[] = {
+ REG_A8XX_RBBM_NC_MODE_CNTL,
+ REG_A8XX_RBBM_SLICE_NC_MODE_CNTL,
+ REG_A6XX_SP_NC_MODE_CNTL,
+ REG_A6XX_SP_CHICKEN_BITS,
+ REG_A8XX_SP_SS_CHICKEN_BITS_0,
+ REG_A7XX_SP_CHICKEN_BITS_1,
+ REG_A7XX_SP_CHICKEN_BITS_2,
+ REG_A7XX_SP_CHICKEN_BITS_3,
+ REG_A8XX_SP_CHICKEN_BITS_4,
+ REG_A6XX_SP_PERFCTR_SHADER_MASK,
+ REG_A8XX_RBBM_SLICE_PERFCTR_CNTL,
+ REG_A8XX_RBBM_SLICE_INTERFACE_HANG_INT_CNTL,
+ REG_A7XX_SP_HLSQ_DBG_ECO_CNTL,
+ REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_1,
+ REG_A7XX_SP_HLSQ_DBG_ECO_CNTL_2,
+ REG_A8XX_SP_HLSQ_DBG_ECO_CNTL_3,
+ REG_A8XX_SP_HLSQ_LPAC_GMEM_RANGE_MIN,
+ REG_A8XX_SP_HLSQ_LPAC_GMEM_RANGE_MIN + 1,
+ REG_A8XX_CP_INTERRUPT_STATUS_MASK_GLOBAL,
+ REG_A8XX_RBBM_PERFCTR_CNTL,
+ REG_A8XX_CP_PROTECT_GLOBAL(0),
+ REG_A8XX_CP_PROTECT_GLOBAL(1),
+ REG_A8XX_CP_PROTECT_GLOBAL(2),
+ REG_A8XX_CP_PROTECT_GLOBAL(3),
+ REG_A8XX_CP_PROTECT_GLOBAL(4),
+ REG_A8XX_CP_PROTECT_GLOBAL(5),
+ REG_A8XX_CP_PROTECT_GLOBAL(6),
+ REG_A8XX_CP_PROTECT_GLOBAL(7),
+ REG_A8XX_CP_PROTECT_GLOBAL(8),
+ REG_A8XX_CP_PROTECT_GLOBAL(9),
+ REG_A8XX_CP_PROTECT_GLOBAL(10),
+ REG_A8XX_CP_PROTECT_GLOBAL(11),
+ REG_A8XX_CP_PROTECT_GLOBAL(12),
+ REG_A8XX_CP_PROTECT_GLOBAL(13),
+ REG_A8XX_CP_PROTECT_GLOBAL(14),
+ REG_A8XX_CP_PROTECT_GLOBAL(15),
+ REG_A8XX_CP_PROTECT_GLOBAL(16),
+ REG_A8XX_CP_PROTECT_GLOBAL(17),
+ REG_A8XX_CP_PROTECT_GLOBAL(18),
+ REG_A8XX_CP_PROTECT_GLOBAL(19),
+ REG_A8XX_CP_PROTECT_GLOBAL(20),
+ REG_A8XX_CP_PROTECT_GLOBAL(21),
+ REG_A8XX_CP_PROTECT_GLOBAL(22),
+ REG_A8XX_CP_PROTECT_GLOBAL(23),
+ REG_A8XX_CP_PROTECT_GLOBAL(24),
+ REG_A8XX_CP_PROTECT_GLOBAL(25),
+ REG_A8XX_CP_PROTECT_GLOBAL(26),
+ REG_A8XX_CP_PROTECT_GLOBAL(27),
+ REG_A8XX_CP_PROTECT_GLOBAL(28),
+ REG_A8XX_CP_PROTECT_GLOBAL(29),
+ REG_A8XX_CP_PROTECT_GLOBAL(30),
+ REG_A8XX_CP_PROTECT_GLOBAL(31),
+ REG_A8XX_CP_PROTECT_GLOBAL(32),
+ REG_A8XX_CP_PROTECT_GLOBAL(33),
+ REG_A8XX_CP_PROTECT_GLOBAL(34),
+ REG_A8XX_CP_PROTECT_GLOBAL(35),
+ REG_A8XX_CP_PROTECT_GLOBAL(36),
+ REG_A8XX_CP_PROTECT_GLOBAL(37),
+ REG_A8XX_CP_PROTECT_GLOBAL(38),
+ REG_A8XX_CP_PROTECT_GLOBAL(39),
+ REG_A8XX_CP_PROTECT_GLOBAL(40),
+ REG_A8XX_CP_PROTECT_GLOBAL(41),
+ REG_A8XX_CP_PROTECT_GLOBAL(42),
+ REG_A8XX_CP_PROTECT_GLOBAL(43),
+ REG_A8XX_CP_PROTECT_GLOBAL(44),
+ REG_A8XX_CP_PROTECT_GLOBAL(45),
+ REG_A8XX_CP_PROTECT_GLOBAL(46),
+ REG_A8XX_CP_PROTECT_GLOBAL(47),
+ REG_A8XX_CP_PROTECT_GLOBAL(48),
+ REG_A8XX_CP_PROTECT_GLOBAL(49),
+ REG_A8XX_CP_PROTECT_GLOBAL(50),
+ REG_A8XX_CP_PROTECT_GLOBAL(51),
+ REG_A8XX_CP_PROTECT_GLOBAL(52),
+ REG_A8XX_CP_PROTECT_GLOBAL(53),
+ REG_A8XX_CP_PROTECT_GLOBAL(54),
+ REG_A8XX_CP_PROTECT_GLOBAL(55),
+ REG_A8XX_CP_PROTECT_GLOBAL(56),
+ REG_A8XX_CP_PROTECT_GLOBAL(57),
+ REG_A8XX_CP_PROTECT_GLOBAL(58),
+ REG_A8XX_CP_PROTECT_GLOBAL(59),
+ REG_A8XX_CP_PROTECT_GLOBAL(60),
+ REG_A8XX_CP_PROTECT_GLOBAL(61),
+ REG_A8XX_CP_PROTECT_GLOBAL(62),
+ REG_A8XX_CP_PROTECT_GLOBAL(63),
+};
+DECLARE_ADRENO_REGLIST_LIST(a840_ifpc_reglist);
+
+static const struct adreno_reglist_pipe a840_dyn_pwrup_reglist_regs[] = {
+ { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_GRAS_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_2, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_3, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_4, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_VIS_STREAM_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A7XX_RB_CCU_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0, BIT(PIPE_BR)},
+ { REG_A8XX_RB_CCU_NC_MODE_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A8XX_RB_CMP_NC_MODE_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A6XX_RB_RBP_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A6XX_RB_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A7XX_VFD_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_BV_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_BR_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_LP_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_CP_HW_FAULT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) |
+ BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) |
+ BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) },
+ { REG_A8XX_CP_INTERRUPT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) |
+ BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) |
+ BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) },
+ { REG_A8XX_CP_PROTECT_CNTL_PIPE, 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC)},
+ { REG_A8XX_CP_PROTECT_PIPE(15), 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC) },
+ { REG_A8XX_RB_GC_GMEM_PROTECT, 0, BIT(PIPE_BR) },
+ { REG_A8XX_RB_LPAC_GMEM_PROTECT, 0, BIT(PIPE_BR) },
+ { REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0, BIT(PIPE_BR) },
+};
+DECLARE_ADRENO_REGLIST_PIPE_LIST(a840_dyn_pwrup_reglist);
+
static const struct adreno_info a8xx_gpus[] = {
{
.chip_ids = ADRENO_CHIP_IDS(0x44070001),
@@ -1940,11 +2119,15 @@ static const struct adreno_info a8xx_gpus[] = {
.gmem = 18 * SZ_1M,
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
- ADRENO_QUIRK_HAS_HW_APRIV,
+ ADRENO_QUIRK_HAS_HW_APRIV |
+ ADRENO_QUIRK_IFPC,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &a840_protect,
.nonctxt_reglist = a840_nonctxt_regs,
+ .pwrup_reglist = &a840_pwrup_reglist,
+ .dyn_pwrup_reglist = &a840_dyn_pwrup_reglist,
+ .ifpc_reglist = &a840_ifpc_reglist,
.gbif_cx = a840_gbif,
.max_slices = 3,
.gmu_chipid = 0x8020100,
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index d414f24ddbd9..b1784e0819c1 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -173,7 +173,7 @@ void a8xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
/* Update HW if this is the current ring and we are not in preempt*/
if (!a6xx_in_preempt(a6xx_gpu)) {
if (a6xx_gpu->cur_ring == ring)
- gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr);
+ a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
else
ring->restore_wptr = true;
} else {
@@ -386,8 +386,87 @@ static void a8xx_nonctxt_config(struct msm_gpu *gpu, u32 *gmem_protect)
a8xx_aperture_clear(gpu);
}
+static void a8xx_patch_pwrup_reglist(struct msm_gpu *gpu)
+{
+ const struct adreno_reglist_pipe_list *dyn_pwrup_reglist;
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ const struct adreno_reglist_list *reglist;
+ void *ptr = a6xx_gpu->pwrup_reglist_ptr;
+ struct cpu_gpu_lock *lock = ptr;
+ u32 *dest = (u32 *)&lock->regs[0];
+ u32 dyn_pwrup_reglist_count = 0;
+ int i;
+
+ lock->gpu_req = lock->cpu_req = lock->turn = 0;
+
+ reglist = adreno_gpu->info->a6xx->ifpc_reglist;
+ if (reglist) {
+ lock->ifpc_list_len = reglist->count;
+
+ /*
+ * For each entry in each of the lists, write the offset and the current
+ * register value into the GPU buffer
+ */
+ for (i = 0; i < reglist->count; i++) {
+ *dest++ = reglist->regs[i];
+ *dest++ = gpu_read(gpu, reglist->regs[i]);
+ }
+ }
+
+ reglist = adreno_gpu->info->a6xx->pwrup_reglist;
+ if (reglist) {
+ lock->preemption_list_len = reglist->count;
+
+ for (i = 0; i < reglist->count; i++) {
+ *dest++ = reglist->regs[i];
+ *dest++ = gpu_read(gpu, reglist->regs[i]);
+ }
+ }
+
+ /*
+ * The overall register list is composed of
+ * 1. Static IFPC-only registers
+ * 2. Static IFPC + preemption registers
+ * 3. Dynamic IFPC + preemption registers (ex: perfcounter selects)
+ *
+ * The first two lists are static. Size of these lists are stored as
+ * number of pairs in ifpc_list_len and preemption_list_len
+ * respectively. With concurrent binning, Some of the perfcounter
+ * registers being virtualized, CP needs to know the pipe id to program
+ * the aperture inorder to restore the same. Thus, third list is a
+ * dynamic list with triplets as
+ * (<aperture, shifted 12 bits> <address> <data>), and the length is
+ * stored as number for triplets in dynamic_list_len.
+ */
+ dyn_pwrup_reglist = adreno_gpu->info->a6xx->dyn_pwrup_reglist;
+ if (!dyn_pwrup_reglist)
+ goto done;
+
+ for (u32 pipe_id = PIPE_BR; pipe_id <= PIPE_DDE_BV; pipe_id++) {
+ for (i = 0; i < dyn_pwrup_reglist->count; i++) {
+ if ((dyn_pwrup_reglist->regs[i].pipe & BIT(pipe_id)) == 0)
+ continue;
+ *dest++ = A8XX_CP_APERTURE_CNTL_HOST_PIPEID(pipe_id);
+ *dest++ = dyn_pwrup_reglist->regs[i].offset;
+ *dest++ = a8xx_read_pipe_slice(gpu,
+ pipe_id,
+ a8xx_get_first_slice(a6xx_gpu),
+ dyn_pwrup_reglist->regs[i].offset);
+ dyn_pwrup_reglist_count++;
+ }
+ }
+
+ lock->dynamic_list_len = dyn_pwrup_reglist_count;
+
+done:
+ a8xx_aperture_clear(gpu);
+}
+
static int a8xx_cp_init(struct msm_gpu *gpu)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
struct msm_ringbuffer *ring = gpu->rb[0];
u32 mask;
@@ -409,6 +488,9 @@ static int a8xx_cp_init(struct msm_gpu *gpu)
/* Disable save/restore of performance counters across preemption */
mask |= BIT(6);
+ /* Enable the register init list with the spinlock */
+ mask |= BIT(8);
+
OUT_RING(ring, mask);
/* Enable multiple hardware contexts */
@@ -420,6 +502,14 @@ static int a8xx_cp_init(struct msm_gpu *gpu)
/* Operation mode mask */
OUT_RING(ring, 0x00000002);
+ /* Lo address */
+ OUT_RING(ring, lower_32_bits(a6xx_gpu->pwrup_reglist_iova));
+ /* Hi address */
+ OUT_RING(ring, upper_32_bits(a6xx_gpu->pwrup_reglist_iova));
+
+ /* Enable dyn pwrup list with triplets (offset, value, pipe) */
+ OUT_RING(ring, BIT(31));
+
a6xx_flush(gpu, ring);
return a8xx_idle(gpu, ring) ? 0 : -EINVAL;
}
@@ -702,6 +792,11 @@ static int hw_init(struct msm_gpu *gpu)
WARN_ON(!gmem_protect);
a8xx_aperture_clear(gpu);
+ if (!a6xx_gpu->pwrup_reglist_emitted) {
+ a8xx_patch_pwrup_reglist(gpu);
+ a6xx_gpu->pwrup_reglist_emitted = true;
+ }
+
/* Enable hardware clockgating */
a8xx_set_hwcg(gpu, true);
out:
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 13/16] drm/msm/a8xx: Implement IFPC support for A840
2026-03-23 20:12 ` [PATCH 13/16] drm/msm/a8xx: Implement IFPC support for A840 Akhil P Oommen
@ 2026-03-24 10:13 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 10:13 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> Implement pwrup reglist support and add the necessary register
> configurations to enable IFPC support on A840
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
[...]
> + for (u32 pipe_id = PIPE_BR; pipe_id <= PIPE_DDE_BV; pipe_id++) {
> + for (i = 0; i < dyn_pwrup_reglist->count; i++) {
> + if ((dyn_pwrup_reglist->regs[i].pipe & BIT(pipe_id)) == 0)
that's a nitty pet peeve, but I'd check for if (!(...)) instead
[...]
> + continue;
> + *dest++ = A8XX_CP_APERTURE_CNTL_HOST_PIPEID(pipe_id);
> + *dest++ = dyn_pwrup_reglist->regs[i].offset;
> + *dest++ = a8xx_read_pipe_slice(gpu,
> + pipe_id,
> + a8xx_get_first_slice(a6xx_gpu),
Only the first slice?
[...]
> + /* Lo address */
> + OUT_RING(ring, lower_32_bits(a6xx_gpu->pwrup_reglist_iova));
> + /* Hi address */
> + OUT_RING(ring, upper_32_bits(a6xx_gpu->pwrup_reglist_iova));
> +
> + /* Enable dyn pwrup list with triplets (offset, value, pipe) */
> + OUT_RING(ring, BIT(31));
I believe you need to patch OUT_PKT7() with the updated cmd count
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/a8xx: Implement IFPC support for A840
2026-03-23 20:12 ` [PATCH 13/16] drm/msm/a8xx: Implement IFPC support for A840 Akhil P Oommen
2026-03-24 10:13 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Large patch adding pwrup/ifpc/dynamic register lists and the `a8xx_patch_pwrup_reglist()` function.
**Key change:** `a8xx_flush()` now uses `a6xx_fenced_write()` for `CP_RB_WPTR` instead of plain `gpu_write()`. This is needed for IFPC to ensure the GPU is awake.
The `a8xx_patch_pwrup_reglist()` function follows the same pattern as the A7xx version. The register lists are large but this is expected for IFPC support.
**CP_INIT change:** `BIT(8)` is added to enable the register init list with spinlock. Three new `OUT_RING` calls add the reglist address and dynamic list enablement. This should be verified against the CP_INIT packet format for A8xx.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 14/16] drm/msm/a8xx: Preemption support for A840
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (12 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 13/16] drm/msm/a8xx: Implement IFPC support for A840 Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 10:18 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 15/16] drm/msm/a6xx: Enable Preemption on X2-85 Akhil P Oommen
` (2 subsequent siblings)
16 siblings, 2 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
The programing sequence related to preemption is unchanged from A7x. But
there is some code churn due to register shuffling in A8x. So, split out
the common code into a header file for code sharing and add/update
additional changes required to support preemption feature on A8x GPUs.
Finally, enable the preemption quirk in A840's catalog to enable this
feature.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/Makefile | 1 +
drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 1 +
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 7 +-
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 5 +
drivers/gpu/drm/msm/adreno/a6xx_preempt.c | 77 +--------
drivers/gpu/drm/msm/adreno/a6xx_preempt.h | 82 ++++++++++
drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 37 ++++-
drivers/gpu/drm/msm/adreno/a8xx_preempt.c | 262 ++++++++++++++++++++++++++++++
8 files changed, 392 insertions(+), 80 deletions(-)
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 8b94c5f1cb68..ba45e99be05b 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -25,6 +25,7 @@ adreno-y := \
adreno/a6xx_hfi.o \
adreno/a6xx_preempt.o \
adreno/a8xx_gpu.o \
+ adreno/a8xx_preempt.o \
adreno-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
index 53548f6e891b..21f5a685196b 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
@@ -2120,6 +2120,7 @@ static const struct adreno_info a8xx_gpus[] = {
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
ADRENO_QUIRK_HAS_HW_APRIV |
+ ADRENO_QUIRK_PREEMPTION |
ADRENO_QUIRK_IFPC,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 0fe6d803e628..df739fd744ab 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -408,7 +408,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
a6xx_flush(gpu, ring);
}
-static void a6xx_emit_set_pseudo_reg(struct msm_ringbuffer *ring,
+void a6xx_emit_set_pseudo_reg(struct msm_ringbuffer *ring,
struct a6xx_gpu *a6xx_gpu, struct msm_gpu_submitqueue *queue)
{
u64 preempt_postamble;
@@ -618,7 +618,10 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
a6xx_flush(gpu, ring);
/* Check to see if we need to start preemption */
- a6xx_preempt_trigger(gpu);
+ if (adreno_is_a8xx(adreno_gpu))
+ a8xx_preempt_trigger(gpu);
+ else
+ a6xx_preempt_trigger(gpu);
}
static void a6xx_set_hwcg(struct msm_gpu *gpu, bool state)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index a4434a6a56dd..eb431e5e00b1 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -278,6 +278,8 @@ void a6xx_preempt_hw_init(struct msm_gpu *gpu);
void a6xx_preempt_trigger(struct msm_gpu *gpu);
void a6xx_preempt_irq(struct msm_gpu *gpu);
void a6xx_preempt_fini(struct msm_gpu *gpu);
+void a6xx_emit_set_pseudo_reg(struct msm_ringbuffer *ring,
+ struct a6xx_gpu *a6xx_gpu, struct msm_gpu_submitqueue *queue);
int a6xx_preempt_submitqueue_setup(struct msm_gpu *gpu,
struct msm_gpu_submitqueue *queue);
void a6xx_preempt_submitqueue_close(struct msm_gpu *gpu,
@@ -327,6 +329,9 @@ void a8xx_gpu_get_slice_info(struct msm_gpu *gpu);
int a8xx_hw_init(struct msm_gpu *gpu);
irqreturn_t a8xx_irq(struct msm_gpu *gpu);
void a8xx_llc_activate(struct a6xx_gpu *a6xx_gpu);
+void a8xx_preempt_hw_init(struct msm_gpu *gpu);
+void a8xx_preempt_trigger(struct msm_gpu *gpu);
+void a8xx_preempt_irq(struct msm_gpu *gpu);
bool a8xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
void a8xx_recover(struct msm_gpu *gpu);
#endif /* __A6XX_GPU_H__ */
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c
index 747a22afad9f..df4cbf42e9a4 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c
@@ -6,85 +6,10 @@
#include "msm_gem.h"
#include "a6xx_gpu.h"
#include "a6xx_gmu.xml.h"
+#include "a6xx_preempt.h"
#include "msm_mmu.h"
#include "msm_gpu_trace.h"
-/*
- * Try to transition the preemption state from old to new. Return
- * true on success or false if the original state wasn't 'old'
- */
-static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu,
- enum a6xx_preempt_state old, enum a6xx_preempt_state new)
-{
- enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state,
- old, new);
-
- return (cur == old);
-}
-
-/*
- * Force the preemption state to the specified state. This is used in cases
- * where the current state is known and won't change
- */
-static inline void set_preempt_state(struct a6xx_gpu *gpu,
- enum a6xx_preempt_state new)
-{
- /*
- * preempt_state may be read by other cores trying to trigger a
- * preemption or in the interrupt handler so barriers are needed
- * before...
- */
- smp_mb__before_atomic();
- atomic_set(&gpu->preempt_state, new);
- /* ... and after*/
- smp_mb__after_atomic();
-}
-
-/* Write the most recent wptr for the given ring into the hardware */
-static inline void update_wptr(struct a6xx_gpu *a6xx_gpu, struct msm_ringbuffer *ring)
-{
- unsigned long flags;
- uint32_t wptr;
-
- spin_lock_irqsave(&ring->preempt_lock, flags);
-
- if (ring->restore_wptr) {
- wptr = get_wptr(ring);
-
- a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
-
- ring->restore_wptr = false;
- }
-
- spin_unlock_irqrestore(&ring->preempt_lock, flags);
-}
-
-/* Return the highest priority ringbuffer with something in it */
-static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu)
-{
- struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
- struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
-
- unsigned long flags;
- int i;
-
- for (i = 0; i < gpu->nr_rings; i++) {
- bool empty;
- struct msm_ringbuffer *ring = gpu->rb[i];
-
- spin_lock_irqsave(&ring->preempt_lock, flags);
- empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring));
- if (!empty && ring == a6xx_gpu->cur_ring)
- empty = ring->memptrs->fence == a6xx_gpu->last_seqno[i];
- spin_unlock_irqrestore(&ring->preempt_lock, flags);
-
- if (!empty)
- return ring;
- }
-
- return NULL;
-}
-
static void a6xx_preempt_timer(struct timer_list *t)
{
struct a6xx_gpu *a6xx_gpu = timer_container_of(a6xx_gpu, t,
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.h b/drivers/gpu/drm/msm/adreno/a6xx_preempt.h
new file mode 100644
index 000000000000..4e69ed038403
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2023 Collabora, Ltd. */
+/* Copyright (c) 2024 Valve Corporation */
+/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
+
+/*
+ * Try to transition the preemption state from old to new. Return
+ * true on success or false if the original state wasn't 'old'
+ */
+static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu,
+ enum a6xx_preempt_state old, enum a6xx_preempt_state new)
+{
+ enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state,
+ old, new);
+
+ return (cur == old);
+}
+
+/*
+ * Force the preemption state to the specified state. This is used in cases
+ * where the current state is known and won't change
+ */
+static inline void set_preempt_state(struct a6xx_gpu *gpu,
+ enum a6xx_preempt_state new)
+{
+ /*
+ * preempt_state may be read by other cores trying to trigger a
+ * preemption or in the interrupt handler so barriers are needed
+ * before...
+ */
+ smp_mb__before_atomic();
+ atomic_set(&gpu->preempt_state, new);
+ /* ... and after*/
+ smp_mb__after_atomic();
+}
+
+/* Write the most recent wptr for the given ring into the hardware */
+static inline void update_wptr(struct a6xx_gpu *a6xx_gpu, struct msm_ringbuffer *ring)
+{
+ unsigned long flags;
+ uint32_t wptr;
+
+ spin_lock_irqsave(&ring->preempt_lock, flags);
+
+ if (ring->restore_wptr) {
+ wptr = get_wptr(ring);
+
+ a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
+
+ ring->restore_wptr = false;
+ }
+
+ spin_unlock_irqrestore(&ring->preempt_lock, flags);
+}
+
+/* Return the highest priority ringbuffer with something in it */
+static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < gpu->nr_rings; i++) {
+ bool empty;
+ struct msm_ringbuffer *ring = gpu->rb[i];
+
+ spin_lock_irqsave(&ring->preempt_lock, flags);
+ empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring));
+ if (!empty && ring == a6xx_gpu->cur_ring)
+ empty = ring->memptrs->fence == a6xx_gpu->last_seqno[i];
+ spin_unlock_irqrestore(&ring->preempt_lock, flags);
+
+ if (!empty)
+ return ring;
+ }
+
+ return NULL;
+}
+
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index b1784e0819c1..3ab4c1d79fdb 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -463,6 +463,34 @@ static void a8xx_patch_pwrup_reglist(struct msm_gpu *gpu)
a8xx_aperture_clear(gpu);
}
+static int a8xx_preempt_start(struct msm_gpu *gpu)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct msm_ringbuffer *ring = gpu->rb[0];
+
+ if (gpu->nr_rings <= 1)
+ return 0;
+
+ /* Turn CP protection off */
+ OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1);
+ OUT_RING(ring, 0);
+
+ a6xx_emit_set_pseudo_reg(ring, a6xx_gpu, NULL);
+
+ /* Yield the floor on command completion */
+ OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4);
+ OUT_RING(ring, 0x00);
+ OUT_RING(ring, 0x00);
+ OUT_RING(ring, 0x00);
+ /* Generate interrupt on preemption completion */
+ OUT_RING(ring, 0x00);
+
+ a6xx_flush(gpu, ring);
+
+ return a8xx_idle(gpu, ring) ? 0 : -EINVAL;
+}
+
static int a8xx_cp_init(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -738,6 +766,8 @@ static int hw_init(struct msm_gpu *gpu)
gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR, shadowptr(a6xx_gpu, gpu->rb[0]));
gpu_write64(gpu, REG_A8XX_CP_RB_RPTR_ADDR_BV, rbmemptr(gpu->rb[0], bv_rptr));
+ a8xx_preempt_hw_init(gpu);
+
for (i = 0; i < gpu->nr_rings; i++)
a6xx_gpu->shadow[i] = 0;
@@ -800,6 +830,9 @@ static int hw_init(struct msm_gpu *gpu)
/* Enable hardware clockgating */
a8xx_set_hwcg(gpu, true);
out:
+ /* Last step - yield the ringbuffer */
+ a8xx_preempt_start(gpu);
+
/*
* Tell the GMU that we are done touching the GPU and it can start power
* management
@@ -1209,11 +1242,11 @@ irqreturn_t a8xx_irq(struct msm_gpu *gpu)
if (status & A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) {
msm_gpu_retire(gpu);
- a6xx_preempt_trigger(gpu);
+ a8xx_preempt_trigger(gpu);
}
if (status & A6XX_RBBM_INT_0_MASK_CP_SW)
- a6xx_preempt_irq(gpu);
+ a8xx_preempt_irq(gpu);
return IRQ_HANDLED;
}
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_preempt.c b/drivers/gpu/drm/msm/adreno/a8xx_preempt.c
new file mode 100644
index 000000000000..05cd847242f3
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a8xx_preempt.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
+
+#include "msm_gem.h"
+#include "a6xx_gpu.h"
+#include "a6xx_gmu.xml.h"
+#include "a6xx_preempt.h"
+#include "msm_mmu.h"
+#include "msm_gpu_trace.h"
+
+static void preempt_prepare_postamble(struct a6xx_gpu *a6xx_gpu)
+{
+ u32 *postamble = a6xx_gpu->preempt_postamble_ptr;
+ u32 count = 0;
+
+ postamble[count++] = PKT7(CP_REG_RMW, 3);
+ postamble[count++] = REG_A8XX_RBBM_PERFCTR_SRAM_INIT_CMD;
+ postamble[count++] = 0;
+ postamble[count++] = 1;
+
+ postamble[count++] = PKT7(CP_WAIT_REG_MEM, 6);
+ postamble[count++] = CP_WAIT_REG_MEM_0_FUNCTION(WRITE_EQ);
+ postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_LO(
+ REG_A8XX_RBBM_PERFCTR_SRAM_INIT_STATUS);
+ postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_HI(0);
+ postamble[count++] = CP_WAIT_REG_MEM_3_REF(0x1);
+ postamble[count++] = CP_WAIT_REG_MEM_4_MASK(0x1);
+ postamble[count++] = CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(0);
+
+ a6xx_gpu->preempt_postamble_len = count;
+
+ a6xx_gpu->postamble_enabled = true;
+}
+
+static void preempt_disable_postamble(struct a6xx_gpu *a6xx_gpu)
+{
+ u32 *postamble = a6xx_gpu->preempt_postamble_ptr;
+
+ /*
+ * Disable the postamble by replacing the first packet header with a NOP
+ * that covers the whole buffer.
+ */
+ *postamble = PKT7(CP_NOP, (a6xx_gpu->preempt_postamble_len - 1));
+
+ a6xx_gpu->postamble_enabled = false;
+}
+
+/*
+ * Set preemption keepalive vote. Please note that this vote is different from the one used in
+ * a8xx_irq()
+ */
+static void a8xx_preempt_keepalive_vote(struct msm_gpu *gpu, bool on)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+
+ if (adreno_has_gmu_wrapper(adreno_gpu))
+ return;
+
+ gmu_write(&a6xx_gpu->gmu, REG_A8XX_GMU_PWR_COL_PREEMPT_KEEPALIVE, on);
+}
+
+void a8xx_preempt_irq(struct msm_gpu *gpu)
+{
+ uint32_t status;
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct drm_device *dev = gpu->dev;
+
+ if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING))
+ return;
+
+ /* Delete the preemption watchdog timer */
+ timer_delete(&a6xx_gpu->preempt_timer);
+
+ /*
+ * The hardware should be setting the stop bit of CP_CONTEXT_SWITCH_CNTL
+ * to zero before firing the interrupt, but there is a non zero chance
+ * of a hardware condition or a software race that could set it again
+ * before we have a chance to finish. If that happens, log and go for
+ * recovery
+ */
+ status = gpu_read(gpu, REG_A8XX_CP_CONTEXT_SWITCH_CNTL);
+ if (unlikely(status & A8XX_CP_CONTEXT_SWITCH_CNTL_STOP)) {
+ DRM_DEV_ERROR(&gpu->pdev->dev,
+ "!!!!!!!!!!!!!!!! preemption faulted !!!!!!!!!!!!!! irq\n");
+ set_preempt_state(a6xx_gpu, PREEMPT_FAULTED);
+ dev_err(dev->dev, "%s: Preemption failed to complete\n",
+ gpu->name);
+ kthread_queue_work(gpu->worker, &gpu->recover_work);
+ return;
+ }
+
+ a6xx_gpu->cur_ring = a6xx_gpu->next_ring;
+ a6xx_gpu->next_ring = NULL;
+
+ set_preempt_state(a6xx_gpu, PREEMPT_FINISH);
+
+ update_wptr(a6xx_gpu, a6xx_gpu->cur_ring);
+
+ set_preempt_state(a6xx_gpu, PREEMPT_NONE);
+
+ a8xx_preempt_keepalive_vote(gpu, false);
+
+ trace_msm_gpu_preemption_irq(a6xx_gpu->cur_ring->id);
+
+ /*
+ * Retrigger preemption to avoid a deadlock that might occur when preemption
+ * is skipped due to it being already in flight when requested.
+ */
+ a8xx_preempt_trigger(gpu);
+}
+
+void a8xx_preempt_hw_init(struct msm_gpu *gpu)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ int i;
+
+ /* No preemption if we only have one ring */
+ if (gpu->nr_rings == 1)
+ return;
+
+ for (i = 0; i < gpu->nr_rings; i++) {
+ struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[i];
+
+ record_ptr->wptr = 0;
+ record_ptr->rptr = 0;
+ record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]);
+ record_ptr->info = 0;
+ record_ptr->data = 0;
+ record_ptr->rbase = gpu->rb[i]->iova;
+ }
+
+ /* Write a 0 to signal that we aren't switching pagetables */
+ gpu_write64(gpu, REG_A8XX_CP_CONTEXT_SWITCH_SMMU_INFO, 0);
+
+ /* Enable the GMEM save/restore feature for preemption */
+ gpu_write(gpu, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0x1);
+
+ /* Reset the preemption state */
+ set_preempt_state(a6xx_gpu, PREEMPT_NONE);
+
+ spin_lock_init(&a6xx_gpu->eval_lock);
+
+ /* Always come up on rb 0 */
+ a6xx_gpu->cur_ring = gpu->rb[0];
+}
+
+void a8xx_preempt_trigger(struct msm_gpu *gpu)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ unsigned long flags;
+ struct msm_ringbuffer *ring;
+ unsigned int cntl;
+ bool sysprof;
+
+ if (gpu->nr_rings == 1)
+ return;
+
+ /*
+ * Lock to make sure another thread attempting preemption doesn't skip it
+ * while we are still evaluating the next ring. This makes sure the other
+ * thread does start preemption if we abort it and avoids a soft lock.
+ */
+ spin_lock_irqsave(&a6xx_gpu->eval_lock, flags);
+
+ /*
+ * Try to start preemption by moving from NONE to START. If
+ * unsuccessful, a preemption is already in flight
+ */
+ if (!try_preempt_state(a6xx_gpu, PREEMPT_NONE, PREEMPT_START)) {
+ spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags);
+ return;
+ }
+
+ cntl = A8XX_CP_CONTEXT_SWITCH_CNTL_LEVEL(a6xx_gpu->preempt_level);
+
+ if (a6xx_gpu->skip_save_restore)
+ cntl |= A8XX_CP_CONTEXT_SWITCH_CNTL_SKIP_SAVE_RESTORE;
+
+ if (a6xx_gpu->uses_gmem)
+ cntl |= A8XX_CP_CONTEXT_SWITCH_CNTL_USES_GMEM;
+
+ cntl |= A8XX_CP_CONTEXT_SWITCH_CNTL_STOP;
+
+ /* Get the next ring to preempt to */
+ ring = get_next_ring(gpu);
+
+ /*
+ * If no ring is populated or the highest priority ring is the current
+ * one do nothing except to update the wptr to the latest and greatest
+ */
+ if (!ring || (a6xx_gpu->cur_ring == ring)) {
+ set_preempt_state(a6xx_gpu, PREEMPT_FINISH);
+ update_wptr(a6xx_gpu, a6xx_gpu->cur_ring);
+ set_preempt_state(a6xx_gpu, PREEMPT_NONE);
+ spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags);
+
+ spin_lock_irqsave(&ring->preempt_lock, flags);
+
+ struct a7xx_cp_smmu_info *smmu_info_ptr =
+ a6xx_gpu->preempt_smmu[ring->id];
+ struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[ring->id];
+ u64 ttbr0 = ring->memptrs->ttbr0;
+ u32 context_idr = ring->memptrs->context_idr;
+
+ smmu_info_ptr->ttbr0 = ttbr0;
+ smmu_info_ptr->context_idr = context_idr;
+ record_ptr->wptr = get_wptr(ring);
+
+ /*
+ * The GPU will write the wptr we set above when we preempt. Reset
+ * restore_wptr to make sure that we don't write WPTR to the same
+ * thing twice. It's still possible subsequent submissions will update
+ * wptr again, in which case they will set the flag to true. This has
+ * to be protected by the lock for setting the flag and updating wptr
+ * to be atomic.
+ */
+ ring->restore_wptr = false;
+
+ trace_msm_gpu_preemption_trigger(a6xx_gpu->cur_ring->id, ring->id);
+
+ spin_unlock_irqrestore(&ring->preempt_lock, flags);
+
+ /* Set the keepalive bit to keep the GPU ON until preemption is complete */
+ a8xx_preempt_keepalive_vote(gpu, true);
+
+ a6xx_fenced_write(a6xx_gpu,
+ REG_A8XX_CP_CONTEXT_SWITCH_SMMU_INFO, a6xx_gpu->preempt_smmu_iova[ring->id],
+ BIT(1), true);
+
+ a6xx_fenced_write(a6xx_gpu,
+ REG_A8XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR,
+ a6xx_gpu->preempt_iova[ring->id], BIT(1), true);
+
+ a6xx_gpu->next_ring = ring;
+
+ /* Start a timer to catch a stuck preemption */
+ mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000));
+
+ /* Enable or disable postamble as needed */
+ sysprof = refcount_read(&a6xx_gpu->base.base.sysprof_active) > 1;
+
+ if (!sysprof && !a6xx_gpu->postamble_enabled)
+ preempt_prepare_postamble(a6xx_gpu);
+
+ if (sysprof && a6xx_gpu->postamble_enabled)
+ preempt_disable_postamble(a6xx_gpu);
+
+ /* Set the preemption state to triggered */
+ set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED);
+
+ /* Trigger the preemption */
+ a6xx_fenced_write(a6xx_gpu, REG_A8XX_CP_CONTEXT_SWITCH_CNTL, cntl, BIT(1), false);
+}
+
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 14/16] drm/msm/a8xx: Preemption support for A840
2026-03-23 20:12 ` [PATCH 14/16] drm/msm/a8xx: Preemption " Akhil P Oommen
@ 2026-03-24 10:18 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 10:18 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> The programing sequence related to preemption is unchanged from A7x. But
> there is some code churn due to register shuffling in A8x. So, split out
> the common code into a header file for code sharing and add/update
> additional changes required to support preemption feature on A8x GPUs.
>
> Finally, enable the preemption quirk in A840's catalog to enable this
> feature.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
[...]
> + /* ... and after*/
ultra nit: space before comment end marker, please
[...]
> +static int a8xx_preempt_start(struct msm_gpu *gpu)
> +{
> + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
> + struct msm_ringbuffer *ring = gpu->rb[0];
> +
> + if (gpu->nr_rings <= 1)
Can this ever be < 1?
> +static void a8xx_preempt_keepalive_vote(struct msm_gpu *gpu, bool on)
> +{
> + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
> +
> + if (adreno_has_gmu_wrapper(adreno_gpu))
> + return;
Are we going to have any a8xx+gmuwrapper?
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread* Claude review: drm/msm/a8xx: Preemption support for A840
2026-03-23 20:12 ` [PATCH 14/16] drm/msm/a8xx: Preemption " Akhil P Oommen
2026-03-24 10:18 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
1 sibling, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Splits common preemption helpers into `a6xx_preempt.h` and adds `a8xx_preempt.c`.
**Header file concern:** `a6xx_preempt.h` contains `static` (non-inline) function `get_next_ring()`. This will cause "defined but not used" warnings or duplicate symbols if any translation unit includes the header but doesn't call the function. It should be `static inline`.
**In `a8xx_preempt_trigger()`:** The preemption timer is set to 10 seconds (`msecs_to_jiffies(10000)`) — the a6xx version uses the same, so this is consistent.
**In `a8xx_gpu.c`:** `a8xx_preempt_start()` is called in `hw_init()` under the `out:` label, meaning it runs even on error paths when `ret` is non-zero. This seems intentional (matching A7xx behavior) but could be problematic if hw_init failed.
**In `a7xx_submit()`:** The dispatch between `a8xx_preempt_trigger()` and `a6xx_preempt_trigger()` is done with a runtime check. This could be a vtable entry instead, but it's fine for now.
**Duplicate error message in `a8xx_preempt_irq()`:**
```c
DRM_DEV_ERROR(&gpu->pdev->dev,
"!!!!!!!!!!!!!!!! preemption faulted !!!!!!!!!!!!!! irq\n");
...
dev_err(dev->dev, "%s: Preemption failed to complete\n",
gpu->name);
```
Two error messages for the same condition is excessive. The first one with the exclamation marks should probably be removed or at least toned down.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 15/16] drm/msm/a6xx: Enable Preemption on X2-85
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (13 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 14/16] drm/msm/a8xx: Preemption " Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2026-03-23 20:12 ` [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support Akhil P Oommen
2026-03-24 21:32 ` Claude review: drm/msm: A8xx Support - Batch 2 Claude Code Review Bot
16 siblings, 1 reply; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
Add the save-restore register lists and set the necessary quirk flags
in the catalog to enable the Preemption feature on Adreno X2-85 GPU.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 42 +++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
index 21f5a685196b..550ff3a9b82e 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
@@ -1761,6 +1761,44 @@ static const u32 x285_protect_regs[] = {
DECLARE_ADRENO_PROTECT(x285_protect, 15);
+static const struct adreno_reglist_pipe x285_dyn_pwrup_reglist_regs[] = {
+ { REG_A8XX_GRAS_TSEFE_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_GRAS_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A6XX_PC_AUTO_VERTEX_STRIDE, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_2, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_3, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CHICKEN_BITS_4, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_CONTEXT_SWITCH_STABILIZE_CNTL_1, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_PC_VIS_STREAM_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A7XX_RB_CCU_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A7XX_RB_CCU_DBG_ECO_CNTL, 0, BIT(PIPE_BR)},
+ { REG_A8XX_RB_CCU_NC_MODE_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A8XX_RB_CMP_NC_MODE_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A6XX_RB_RBP_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A8XX_RB_RESOLVE_PREFETCH_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A8XX_RB_CMP_DBG_ECO_CNTL, 0, BIT(PIPE_BR) },
+ { REG_A7XX_VFD_DBG_ECO_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_BV_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_BR_THRESHOLD, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_BUSY_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VFD_CB_LP_REQ_CNT, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_VPC_FLATSHADE_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) },
+ { REG_A8XX_CP_HW_FAULT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) |
+ BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) |
+ BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) },
+ { REG_A8XX_CP_INTERRUPT_STATUS_MASK_PIPE, 0, BIT(PIPE_BR) |
+ BIT(PIPE_BV) | BIT(PIPE_LPAC) | BIT(PIPE_AQE0) |
+ BIT(PIPE_AQE1) | BIT(PIPE_DDE_BR) | BIT(PIPE_DDE_BV) },
+ { REG_A8XX_CP_PROTECT_CNTL_PIPE, 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC)},
+ { REG_A8XX_CP_PROTECT_PIPE(15), 0, BIT(PIPE_BR) | BIT(PIPE_BV) | BIT(PIPE_LPAC) },
+ { REG_A8XX_RB_GC_GMEM_PROTECT, 0, BIT(PIPE_BR) },
+ { REG_A8XX_RB_LPAC_GMEM_PROTECT, 0, BIT(PIPE_BR) },
+ { REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, 0, BIT(PIPE_BR) },
+};
+DECLARE_ADRENO_REGLIST_PIPE_LIST(x285_dyn_pwrup_reglist);
+
static const struct adreno_reglist_pipe a840_nonctxt_regs[] = {
{ REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
{ REG_A8XX_GRAS_DBG_ECO_CNTL, 0x00000800, BIT(PIPE_BV) | BIT(PIPE_BR) },
@@ -2082,11 +2120,15 @@ static const struct adreno_info a8xx_gpus[] = {
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
ADRENO_QUIRK_HAS_HW_APRIV |
+ ADRENO_QUIRK_PREEMPTION |
ADRENO_QUIRK_SOFTFUSE,
.funcs = &a8xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.protect = &x285_protect,
.nonctxt_reglist = x285_nonctxt_regs,
+ .pwrup_reglist = &a840_pwrup_reglist,
+ .dyn_pwrup_reglist = &x285_dyn_pwrup_reglist,
+ .ifpc_reglist = &a840_ifpc_reglist,
.gbif_cx = a840_gbif,
.max_slices = 4,
.gmu_chipid = 0x8010100,
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Claude review: drm/msm/a6xx: Enable Preemption on X2-85
2026-03-23 20:12 ` [PATCH 15/16] drm/msm/a6xx: Enable Preemption on X2-85 Akhil P Oommen
@ 2026-03-24 21:32 ` Claude Code Review Bot
0 siblings, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Adds `x285_dyn_pwrup_reglist` and enables preemption for X2-85.
**Observation:** The `x285_dyn_pwrup_reglist_regs` is almost identical to `a840_dyn_pwrup_reglist_regs` from patch 13. The differences are:
- X2-85 is missing `REG_A6XX_RB_DBG_ECO_CNTL` and `REG_A6XX_RB_RBP_CNTL` entries that A840 has with `BIT(PIPE_BV)|BIT(PIPE_BR)`, and X2-85 `REG_A6XX_RB_RBP_CNTL` only has `BIT(PIPE_BR)`.
The X2-85 also reuses `a840_pwrup_reglist` and `a840_ifpc_reglist` which is fine.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (14 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 15/16] drm/msm/a6xx: Enable Preemption on X2-85 Akhil P Oommen
@ 2026-03-23 20:12 ` Akhil P Oommen
2026-03-23 21:36 ` Dmitry Baryshkov
` (2 more replies)
2026-03-24 21:32 ` Claude review: drm/msm: A8xx Support - Batch 2 Claude Code Review Bot
16 siblings, 3 replies; 52+ messages in thread
From: Akhil P Oommen @ 2026-03-23 20:12 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Akhil P Oommen
AQE (Applicaton Qrisc Engine) is required to support VK ray-pipeline. Two
conditions should be met to use this HW:
1. AQE firmware should be loaded and programmed
2. Preemption support
Expose a new MSM_PARAM to allow userspace to query its support.
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 13 +++++++++++++
drivers/gpu/drm/msm/adreno/adreno_gpu.c | 4 ++++
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
include/uapi/drm/msm_drm.h | 1 +
4 files changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index df739fd744ab..224b2f7cc8d3 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2610,6 +2610,17 @@ static int a6xx_set_supported_hw(struct device *dev, struct a6xx_gpu *a6xx_gpu,
return 0;
}
+static bool a6xx_aqe_is_enabled(struct adreno_gpu *adreno_gpu)
+{
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+
+ /*
+ * AQE uses preemption context record as scratch pad, so check if
+ * preemption is enabled
+ */
+ return (adreno_gpu->base.nr_rings > 1) && !!a6xx_gpu->aqe_bo;
+}
+
static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
@@ -2808,6 +2819,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
.gx_is_on = a6xx_gmu_gx_is_on,
+ .aqe_is_enabled = a6xx_aqe_is_enabled,
};
const struct adreno_gpu_funcs a8xx_gpu_funcs = {
@@ -2836,4 +2848,5 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
.bus_halt = a8xx_bus_clear_pending_transactions,
.mmu_fault_handler = a8xx_fault_handler,
.gx_is_on = a8xx_gmu_gx_is_on,
+ .aqe_is_enabled = a6xx_aqe_is_enabled,
};
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 826661cb7988..f7289a9ee0bb 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -443,6 +443,10 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
case MSM_PARAM_HAS_PRR:
*value = adreno_smmu_has_prr(gpu);
return 0;
+ case MSM_PARAM_AQE:
+ *value = (adreno_gpu->funcs->aqe_is_enabled &&
+ adreno_gpu->funcs->aqe_is_enabled(adreno_gpu)) ? 1 : 0;
+ return 0;
default:
return UERR(EINVAL, drm, "%s: invalid param: %u", gpu->name, param);
}
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 044ed4d49aa7..c0ee544ce257 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -84,6 +84,7 @@ struct adreno_gpu_funcs {
void (*bus_halt)(struct adreno_gpu *adreno_gpu, bool gx_off);
int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data);
bool (*gx_is_on)(struct adreno_gpu *adreno_gpu);
+ bool (*aqe_is_enabled)(struct adreno_gpu *adreno_gpu);
};
struct adreno_reglist {
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 5c67294edc95..b99098792371 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -117,6 +117,7 @@ struct drm_msm_timespec {
* ioctl will throw -EPIPE.
*/
#define MSM_PARAM_EN_VM_BIND 0x16 /* WO, once */
+#define MSM_PARAM_AQE 0x17 /* RO */
/* For backwards compat. The original support for preemption was based on
* a single ring per priority level so # of priority levels equals the #
--
2.51.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support
2026-03-23 20:12 ` [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support Akhil P Oommen
@ 2026-03-23 21:36 ` Dmitry Baryshkov
2026-03-23 22:54 ` Connor Abbott
2026-03-24 10:19 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2 siblings, 1 reply; 52+ messages in thread
From: Dmitry Baryshkov @ 2026-03-23 21:36 UTC (permalink / raw)
To: Akhil P Oommen
Cc: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Tue, Mar 24, 2026 at 01:42:28AM +0530, Akhil P Oommen wrote:
> AQE (Applicaton Qrisc Engine) is required to support VK ray-pipeline. Two
> conditions should be met to use this HW:
> 1. AQE firmware should be loaded and programmed
> 2. Preemption support
>
> Expose a new MSM_PARAM to allow userspace to query its support.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 13 +++++++++++++
> drivers/gpu/drm/msm/adreno/adreno_gpu.c | 4 ++++
> drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
> include/uapi/drm/msm_drm.h | 1 +
> 4 files changed, 19 insertions(+)
>
> diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
> index 5c67294edc95..b99098792371 100644
> --- a/include/uapi/drm/msm_drm.h
> +++ b/include/uapi/drm/msm_drm.h
> @@ -117,6 +117,7 @@ struct drm_msm_timespec {
> * ioctl will throw -EPIPE.
> */
> #define MSM_PARAM_EN_VM_BIND 0x16 /* WO, once */
> +#define MSM_PARAM_AQE 0x17 /* RO */
>
> /* For backwards compat. The original support for preemption was based on
> * a single ring per priority level so # of priority levels equals the #
>
I think this also requires a version bump in msm_drv.c
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread* Re: [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support
2026-03-23 21:36 ` Dmitry Baryshkov
@ 2026-03-23 22:54 ` Connor Abbott
0 siblings, 0 replies; 52+ messages in thread
From: Connor Abbott @ 2026-03-23 22:54 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
linux-arm-msm, dri-devel, freedreno, linux-kernel
On Mon, Mar 23, 2026 at 5:36 PM Dmitry Baryshkov
<dmitry.baryshkov@oss.qualcomm.com> wrote:
>
> On Tue, Mar 24, 2026 at 01:42:28AM +0530, Akhil P Oommen wrote:
> > AQE (Applicaton Qrisc Engine) is required to support VK ray-pipeline. Two
> > conditions should be met to use this HW:
> > 1. AQE firmware should be loaded and programmed
> > 2. Preemption support
> >
> > Expose a new MSM_PARAM to allow userspace to query its support.
> >
> > Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> > ---
> > drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 13 +++++++++++++
> > drivers/gpu/drm/msm/adreno/adreno_gpu.c | 4 ++++
> > drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 +
> > include/uapi/drm/msm_drm.h | 1 +
> > 4 files changed, 19 insertions(+)
> >
> > diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
> > index 5c67294edc95..b99098792371 100644
> > --- a/include/uapi/drm/msm_drm.h
> > +++ b/include/uapi/drm/msm_drm.h
> > @@ -117,6 +117,7 @@ struct drm_msm_timespec {
> > * ioctl will throw -EPIPE.
> > */
> > #define MSM_PARAM_EN_VM_BIND 0x16 /* WO, once */
> > +#define MSM_PARAM_AQE 0x17 /* RO */
> >
> > /* For backwards compat. The original support for preemption was based on
> > * a single ring per priority level so # of priority levels equals the #
> >
>
> I think this also requires a version bump in msm_drv.c
Not really. We can just assume it's not there if the ioctl returns
-EINVAL, like the other queries we've added recently.
Connor
>
>
> --
> With best wishes
> Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support
2026-03-23 20:12 ` [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support Akhil P Oommen
2026-03-23 21:36 ` Dmitry Baryshkov
@ 2026-03-24 10:19 ` Konrad Dybcio
2026-03-24 21:32 ` Claude review: " Claude Code Review Bot
2 siblings, 0 replies; 52+ messages in thread
From: Konrad Dybcio @ 2026-03-24 10:19 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Antonino Maniscalco, Connor Abbott,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel
On 3/23/26 9:12 PM, Akhil P Oommen wrote:
> AQE (Applicaton Qrisc Engine) is required to support VK ray-pipeline. Two
> conditions should be met to use this HW:
> 1. AQE firmware should be loaded and programmed
> 2. Preemption support
>
> Expose a new MSM_PARAM to allow userspace to query its support.
>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
[...]
> + case MSM_PARAM_AQE:
> + *value = (adreno_gpu->funcs->aqe_is_enabled &&
> + adreno_gpu->funcs->aqe_is_enabled(adreno_gpu)) ? 1 : 0;
&& already makes this a boolean
Konrad
^ permalink raw reply [flat|nested] 52+ messages in thread
* Claude review: drm/msm/adreno: Expose a PARAM to check AQE support
2026-03-23 20:12 ` [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support Akhil P Oommen
2026-03-23 21:36 ` Dmitry Baryshkov
2026-03-24 10:19 ` Konrad Dybcio
@ 2026-03-24 21:32 ` Claude Code Review Bot
2 siblings, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Adds `MSM_PARAM_AQE` (0x17) UAPI parameter to query AQE (Application QRISC Engine) support. The check requires both preemption enabled (nr_rings > 1) and AQE firmware loaded (aqe_bo != NULL).
**Typo in commit message:** "Applicaton Qrisc" should be "Application QRISC".
**UAPI concern:** New UAPI should typically have documentation in the header or commit message about what the value means to userspace. The comment `/* RO */` is minimal.
**Extra space:**
```c
*value = (adreno_gpu->funcs->aqe_is_enabled &&
```
Two spaces after `=`.
**Note:** `aqe_is_enabled` is only set for `a7xx_gpu_funcs` and `a8xx_gpu_funcs`, not for `a6xx_gpu_funcs` or `a6xx_gmuwrapper_funcs`. The NULL check in `adreno_get_param()` handles this correctly by returning 0.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread
* Claude review: drm/msm: A8xx Support - Batch 2
2026-03-23 20:12 [PATCH 00/16] drm/msm: A8xx Support - Batch 2 Akhil P Oommen
` (15 preceding siblings ...)
2026-03-23 20:12 ` [PATCH 16/16] drm/msm/adreno: Expose a PARAM to check AQE support Akhil P Oommen
@ 2026-03-24 21:32 ` Claude Code Review Bot
16 siblings, 0 replies; 52+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 21:32 UTC (permalink / raw)
To: dri-devel-reviews
Overall Series Review
Subject: drm/msm: A8xx Support - Batch 2
Author: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Patches: 35
Reviewed: 2026-03-25T07:32:07.645335
---
This is a 16-patch series from Akhil P Oommen (Qualcomm) adding "Batch 2" features for A8xx GPU support in the MSM/Adreno DRM driver. The series includes bugfixes (patches 1-3), infrastructure improvements (patches 4-8), and new features: gx_is_on for A8x (9), secure init fix (10), SKU tables (11-12), IFPC (13), preemption (14-15), and AQE UAPI (16).
Overall the series is reasonable and follows existing driver patterns. There are some issues worth flagging:
**Concerns:**
- Patch 5 (coredump on init failures) changes locking semantics in `adreno_load_gpu()` with a potential double-unlock on the error path
- Patch 4 has an off-by-one WARN_ON check
- Patch 10 moves code to run on every resume rather than once at probe, which has correctness and performance implications
- Patch 14 puts static inline functions with non-trivial logic in a header that gets included from two .c files, which could cause linker issues or code bloat
- The x285/a840 dyn_pwrup_reglist tables (patches 13, 15) are nearly identical — should consider sharing
---
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 52+ messages in thread