Re: [PATCH] drm/etnaviv: Flush the tile status cache through both the PE and BLT

From: Lucas Stach

Date: Wed Nov 04 2026 - 06:03:40 EST


Am Montag, dem 02.11.2026 um 11:18 +0100 schrieb Christian Gmeiner:
> From: Christian Gmeiner <cgmeiner@xxxxxxxxxx>
>
> Since commit f232d9ec029c ("drm/etnaviv: fix TS cache flushing on GPUs
> with BLT engine"), jobs on GPUs with a BLT engine use a BLT command to
> flush the tile status cache instead of TS_FLUSH_CACHE, which is broken
> on most of these GPUs.
>
> GC7000 r6008/r6009 and GC8200 r6401 are the other way around:
> TS_FLUSH_CACHE works, but the BLT command does not flush the cache.
> The vendor driver handles these GPUs using TS_FLUSH_CACHE, but the
> etnaviv kernel driver has no way to identify them.
>
> As a result, dirty tile status cache lines survive the end of a job.
> They are written back by the next cache flush, using the page table of
> the job issuing it. If that job belongs to another process, the write
> goes to the wrong address space.
>
> On GC7000 r6009 this causes MMU faults and GPU recoveries blamed on an
> innocent process. I see around 1100 per run of a multisample
> depth/stencil test running alongside two other GPU clients.
>
> Emit both flushes at the end of every job on GPUs with a BLT engine.
> Whichever does not work on a given GPU is a no-op. Since dirty lines
> are only written back once, this costs one additional state load per
> job.
>
> Fixes: f232d9ec029c ("drm/etnaviv: fix TS cache flushing on GPUs with BLT engine")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Christian Gmeiner <cgmeiner@xxxxxxxxxx>

Reviewed-by: Lucas Stach <l.stach@xxxxxxxxxxxxxx>

> ---
> drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 40 ++++++++++++++------------------
> 1 file changed, 18 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
> index 03b2576af67f..99c91a9eecf1 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
> @@ -168,6 +168,17 @@ u16 etnaviv_buffer_config_pta(struct etnaviv_gpu *gpu, unsigned short id)
> return buffer->user_size / 8;
> }
>
> +static void etnaviv_cmd_flush_ts(struct etnaviv_cmdbuf *buffer, bool has_blt)
> +{
> + CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH);
> +
> + if (has_blt) {
> + CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
> + CMD_LOAD_STATE(buffer, VIVS_BLT_SET_COMMAND, 0x1);
> + CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
> + }
> +}
> +
> void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
> {
> struct etnaviv_cmdbuf *buffer = &gpu->buffer;
> @@ -191,7 +202,7 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
> unsigned int dwords = 7;
>
> if (has_blt)
> - dwords += 10;
> + dwords += 11;
>
> link_target = etnaviv_buffer_reserve(gpu, buffer, dwords);
>
> @@ -204,16 +215,8 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
> CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
> }
> CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush);
> - if (gpu->exec_state == ETNA_PIPE_3D) {
> - if (has_blt) {
> - CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
> - CMD_LOAD_STATE(buffer, VIVS_BLT_SET_COMMAND, 0x1);
> - CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
> - } else {
> - CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
> - VIVS_TS_FLUSH_CACHE_FLUSH);
> - }
> - }
> + if (gpu->exec_state == ETNA_PIPE_3D)
> + etnaviv_cmd_flush_ts(buffer, has_blt);
> CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
> CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
> if (has_blt) {
> @@ -400,12 +403,12 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,
> return_dwords = 7;
>
> /*
> - * When the BLT engine is present we need 6 more dwords in the return
> + * When the BLT engine is present we need 7 more dwords in the return
> * target: 3 enable/flush/disable + 4 enable/semaphore stall/disable,
> - * but we don't need the normal TS flush state.
> + * on top of the normal TS flush state.
> */
> if (has_blt)
> - return_dwords += 6;
> + return_dwords += 7;
>
> return_target = etnaviv_buffer_reserve(gpu, buffer, return_dwords);
> CMD_LINK(cmdbuf, return_dwords, return_target);
> @@ -422,14 +425,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,
> VIVS_GL_FLUSH_CACHE_DEPTH |
> VIVS_GL_FLUSH_CACHE_COLOR |
> VIVS_GL_FLUSH_CACHE_SHADER_L1);
> - if (has_blt) {
> - CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
> - CMD_LOAD_STATE(buffer, VIVS_BLT_SET_COMMAND, 0x1);
> - CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
> - } else {
> - CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
> - VIVS_TS_FLUSH_CACHE_FLUSH);
> - }
> + etnaviv_cmd_flush_ts(buffer, has_blt);
> }
> CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
> CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
>
> ---
> base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
> change-id: 20261102-etna-pe-ts-flush-ffa01363b98c
>
> Best regards,