[PATCH v3 11/15] media: vsp1: Fix du_complete race condition issue

From: Paul Elder

Date: Thu Oct 15 2026 - 04:07:02 EST


From: Phong Hoang <phong.hoang.wz@xxxxxxxxxxx>

vsp1_du_pipeline_frame_end() runs in hardirq context and tests
drm_pipe->du_complete before calling it. vsp1_du_setup_lif() clears
the same pointer on the CRTC-disable path while holding only drm->lock,
a mutex that does not serialize against the IRQ. On SMP, du_complete
can be cleared between the NULL check and the call, leading to NULL
pointer dereference.

Therefore, fixing this issue by using READ_ONCE()/WRITE_ONCE() for
du_complete and ensuring du_private is initialized first.

Signed-off-by: Phong Hoang <phong.hoang.wz@xxxxxxxxxxx>
Reviewed-by: Paul Elder <paul.elder+renesas@xxxxxxxxxxxxxxxx>
Signed-off-by: Paul Elder <paul.elder+renesas@xxxxxxxxxxxxxxxx>
---
drivers/media/platform/renesas/vsp1/vsp1_drm.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
index 9cd5c025d2be8461bd76e14b15f990eb8bfa2909..3dcb83df46f485ecc94334e7a48871e2368a3527 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
@@ -35,8 +35,10 @@ static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe,
unsigned int completion)
{
struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
+ void (*du_complete)(void *data, unsigned int status, u32 crc);

- if (drm_pipe->du_complete) {
+ du_complete = READ_ONCE(drm_pipe->du_complete);
+ if (du_complete) {
struct vsp1_entity *uif = drm_pipe->uif;
unsigned int status = completion
& (VSP1_DU_STATUS_COMPLETE |
@@ -44,7 +46,7 @@ static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe,
u32 crc;

crc = uif ? vsp1_uif_get_crc(to_uif(&uif->subdev)) : 0;
- drm_pipe->du_complete(drm_pipe->du_private, status, crc);
+ du_complete(drm_pipe->du_private, status, crc);
}

if (completion & VSP1_DL_FRAME_END_INTERNAL) {
@@ -694,8 +696,8 @@ int vsp1_du_enable(struct device *dev, unsigned int pipe_index,
* Register a callback to allow us to notify the DRM driver of frame
* completion events.
*/
- drm_pipe->du_complete = cfg->callback;
drm_pipe->du_private = cfg->callback_data;
+ WRITE_ONCE(drm_pipe->du_complete, cfg->callback);

/* Disable the display interrupts. */
vsp1_write(vsp1, VI6_DISP_IRQ_STA(pipe_index), 0);
@@ -764,7 +766,7 @@ int vsp1_du_disable(struct device *dev, unsigned int pipe_index)
brx->inputs[rpf->brx_input].rpf = NULL;
}

- drm_pipe->du_complete = NULL;
+ WRITE_ONCE(drm_pipe->du_complete, NULL);
pipe->num_inputs = 0;

dev_dbg(vsp1->dev, "%s: pipe %u: releasing %s\n",

--
2.47.3