mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-14 14:12:46 -04:00
drm/v3d: Clear queue->active_job when v3d_fence_create() fails
The run_job() callbacks for BIN, RENDER, TFU and CSD assign the incoming
job to queue->active_job before calling v3d_fence_create(). If
v3d_fence_create() fails, the callback returns NULL without clearing
active_job, leaving a dangling pointer.
Create a failure path in all run_job() callbacks that clears the active
job before returning NULL. The BIN path takes queue->queue_lock around the
clear as it races against v3d_overflow_mem_work(); RENDER, TFU and CSD
paths have no concurrent reader, so the clear is lock-free.
Fixes: a783a09ee7 ("drm/v3d: Refactor job management.")
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Link: https://patch.msgid.link/20260604-v3d-sched-misc-fixes-v4-2-c068f5bf5ccf@igalia.com
Signed-off-by: Maíra Canal <mcanal@igalia.com>
This commit is contained in:
@@ -189,15 +189,11 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
|
||||
struct v3d_dev *v3d = job->base.v3d;
|
||||
struct v3d_queue_state *queue = &v3d->queue[V3D_BIN];
|
||||
struct drm_device *dev = &v3d->drm;
|
||||
struct dma_fence *fence;
|
||||
struct dma_fence *fence = NULL;
|
||||
unsigned long irqflags;
|
||||
|
||||
if (unlikely(job->base.base.s_fence->finished.error)) {
|
||||
spin_lock_irqsave(&queue->queue_lock, irqflags);
|
||||
queue->active_job = NULL;
|
||||
spin_unlock_irqrestore(&queue->queue_lock, irqflags);
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(job->base.base.s_fence->finished.error))
|
||||
goto out_clean_job;
|
||||
|
||||
/* Lock required around bin_job update vs
|
||||
* v3d_overflow_mem_work().
|
||||
@@ -214,7 +210,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
|
||||
|
||||
fence = v3d_fence_create(v3d, V3D_BIN);
|
||||
if (IS_ERR(fence))
|
||||
return NULL;
|
||||
goto out_clean_job;
|
||||
|
||||
if (job->base.irq_fence)
|
||||
dma_fence_put(job->base.irq_fence);
|
||||
@@ -242,6 +238,12 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
|
||||
V3D_CORE_WRITE(0, V3D_CLE_CT0QEA, job->end);
|
||||
|
||||
return fence;
|
||||
|
||||
out_clean_job:
|
||||
spin_lock_irqsave(&queue->queue_lock, irqflags);
|
||||
queue->active_job = NULL;
|
||||
spin_unlock_irqrestore(&queue->queue_lock, irqflags);
|
||||
return fence;
|
||||
}
|
||||
|
||||
static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
|
||||
@@ -249,12 +251,10 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
|
||||
struct v3d_render_job *job = to_render_job(sched_job);
|
||||
struct v3d_dev *v3d = job->base.v3d;
|
||||
struct drm_device *dev = &v3d->drm;
|
||||
struct dma_fence *fence;
|
||||
struct dma_fence *fence = NULL;
|
||||
|
||||
if (unlikely(job->base.base.s_fence->finished.error)) {
|
||||
v3d->queue[V3D_RENDER].active_job = NULL;
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(job->base.base.s_fence->finished.error))
|
||||
goto out_clean_job;
|
||||
|
||||
v3d->queue[V3D_RENDER].active_job = &job->base;
|
||||
|
||||
@@ -268,7 +268,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
|
||||
|
||||
fence = v3d_fence_create(v3d, V3D_RENDER);
|
||||
if (IS_ERR(fence))
|
||||
return NULL;
|
||||
goto out_clean_job;
|
||||
|
||||
if (job->base.irq_fence)
|
||||
dma_fence_put(job->base.irq_fence);
|
||||
@@ -289,6 +289,10 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
|
||||
V3D_CORE_WRITE(0, V3D_CLE_CT1QEA, job->end);
|
||||
|
||||
return fence;
|
||||
|
||||
out_clean_job:
|
||||
v3d->queue[V3D_RENDER].active_job = NULL;
|
||||
return fence;
|
||||
}
|
||||
|
||||
static struct dma_fence *
|
||||
@@ -297,18 +301,16 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)
|
||||
struct v3d_tfu_job *job = to_tfu_job(sched_job);
|
||||
struct v3d_dev *v3d = job->base.v3d;
|
||||
struct drm_device *dev = &v3d->drm;
|
||||
struct dma_fence *fence;
|
||||
struct dma_fence *fence = NULL;
|
||||
|
||||
if (unlikely(job->base.base.s_fence->finished.error)) {
|
||||
v3d->queue[V3D_TFU].active_job = NULL;
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(job->base.base.s_fence->finished.error))
|
||||
goto out_clean_job;
|
||||
|
||||
v3d->queue[V3D_TFU].active_job = &job->base;
|
||||
|
||||
fence = v3d_fence_create(v3d, V3D_TFU);
|
||||
if (IS_ERR(fence))
|
||||
return NULL;
|
||||
goto out_clean_job;
|
||||
|
||||
if (job->base.irq_fence)
|
||||
dma_fence_put(job->base.irq_fence);
|
||||
@@ -336,6 +338,10 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)
|
||||
V3D_WRITE(V3D_TFU_ICFG(v3d->ver), job->args.icfg | V3D_TFU_ICFG_IOC);
|
||||
|
||||
return fence;
|
||||
|
||||
out_clean_job:
|
||||
v3d->queue[V3D_TFU].active_job = NULL;
|
||||
return fence;
|
||||
}
|
||||
|
||||
static struct dma_fence *
|
||||
@@ -344,13 +350,11 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
|
||||
struct v3d_csd_job *job = to_csd_job(sched_job);
|
||||
struct v3d_dev *v3d = job->base.v3d;
|
||||
struct drm_device *dev = &v3d->drm;
|
||||
struct dma_fence *fence;
|
||||
struct dma_fence *fence = NULL;
|
||||
int i, csd_cfg0_reg;
|
||||
|
||||
if (unlikely(job->base.base.s_fence->finished.error)) {
|
||||
v3d->queue[V3D_CSD].active_job = NULL;
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(job->base.base.s_fence->finished.error))
|
||||
goto out_clean_job;
|
||||
|
||||
v3d->queue[V3D_CSD].active_job = &job->base;
|
||||
|
||||
@@ -358,7 +362,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
|
||||
|
||||
fence = v3d_fence_create(v3d, V3D_CSD);
|
||||
if (IS_ERR(fence))
|
||||
return NULL;
|
||||
goto out_clean_job;
|
||||
|
||||
if (job->base.irq_fence)
|
||||
dma_fence_put(job->base.irq_fence);
|
||||
@@ -385,6 +389,10 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
|
||||
V3D_CORE_WRITE(0, csd_cfg0_reg, job->args.cfg[0]);
|
||||
|
||||
return fence;
|
||||
|
||||
out_clean_job:
|
||||
v3d->queue[V3D_CSD].active_job = NULL;
|
||||
return fence;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
Reference in New Issue
Block a user