Skip to content

Commit 257adf5

Browse files
committed
drm/v3d: Flush MMU TLB and cache during runtime resume
v3d_mmu_set_page_table() ends by calling v3d_mmu_flush_all() to flush the MMU cache and clear the TLB after reprogramming V3D_MMU_PT_PA_BASE. v3d_mmu_flush_all() is gated by pm_runtime_get_if_active(), which returns 0 unless runtime_status == RPM_ACTIVE. v3d_mmu_set_page_table() is called from two paths that *know* V3D is reachable, but where the runtime PM status might be wrong: 1. v3d_power_resume(): the runtime resume callback itself, where runtime_status is RPM_RESUMING. 2. v3d_reset(): called from the DRM scheduler timeout handler with the hung job's pm_runtime reference held, so RPM_ACTIVE, but here we don't need to take an extra reference for the duration of the flush either. In the first case pm_runtime_get_if_active() returns 0, the flush is silently skipped, and V3D resumes executing with whatever MMUC/TLB state happened to survive the last reset. This can leave stale translations live across runtime PM cycles, manifesting as random GPU hangs. Split the actual flush sequence into a helper that does the writes unconditionally, and have v3d_mmu_set_page_table() call it directly. Fixes: 458f2a7 ("drm/v3d: Introduce Runtime Power Management") Link: https://patch.msgid.link/20260530-v3d-fix-rpi4-freezes-v1-2-c2c8307da6ce@igalia.com Signed-off-by: Maíra Canal <mcanal@igalia.com> Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
1 parent f412fe5 commit 257adf5

1 file changed

Lines changed: 22 additions & 9 deletions

File tree

drivers/gpu/drm/v3d/v3d_mmu.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ static bool v3d_mmu_is_aligned(u32 page, u32 page_address, size_t alignment)
3737
IS_ALIGNED(page_address, alignment >> V3D_MMU_PAGE_SHIFT);
3838
}
3939

40-
int v3d_mmu_flush_all(struct v3d_dev *v3d)
40+
/*
41+
* Issue the MMUC flush and TLB clear unconditionally. The caller must
42+
* already know that V3D is reachable. In particular, this is used from
43+
* the runtime resume callback.
44+
*/
45+
static int v3d_mmu_flush_all_locked(struct v3d_dev *v3d)
4146
{
42-
int ret = 0;
43-
44-
/* Flush the PTs only if we're already awake */
45-
if (!pm_runtime_get_if_active(v3d->drm.dev))
46-
return 0;
47+
int ret;
4748

4849
V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_FLUSH |
4950
V3D_MMUC_CONTROL_ENABLE);
@@ -52,7 +53,7 @@ int v3d_mmu_flush_all(struct v3d_dev *v3d)
5253
V3D_MMUC_CONTROL_FLUSHING), 100);
5354
if (ret) {
5455
dev_err(v3d->drm.dev, "MMUC flush wait idle failed\n");
55-
goto pm_put;
56+
return ret;
5657
}
5758

5859
V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) |
@@ -63,7 +64,19 @@ int v3d_mmu_flush_all(struct v3d_dev *v3d)
6364
if (ret)
6465
dev_err(v3d->drm.dev, "MMU TLB clear wait idle failed\n");
6566

66-
pm_put:
67+
return ret;
68+
}
69+
70+
int v3d_mmu_flush_all(struct v3d_dev *v3d)
71+
{
72+
int ret;
73+
74+
/* Flush the PTs only if we're already awake */
75+
if (!pm_runtime_get_if_active(v3d->drm.dev))
76+
return 0;
77+
78+
ret = v3d_mmu_flush_all_locked(v3d);
79+
6780
v3d_pm_runtime_put(v3d);
6881
return ret;
6982
}
@@ -85,7 +98,7 @@ int v3d_mmu_set_page_table(struct v3d_dev *v3d)
8598
V3D_MMU_ILLEGAL_ADDR_ENABLE);
8699
V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_ENABLE);
87100

88-
return v3d_mmu_flush_all(v3d);
101+
return v3d_mmu_flush_all_locked(v3d);
89102
}
90103

91104
void v3d_mmu_insert_ptes(struct v3d_bo *bo)

0 commit comments

Comments
 (0)