summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaíra Canal <mcanal@igalia.com>2026-06-04 17:32:25 -0300
committerMaíra Canal <mcanal@igalia.com>2026-06-09 14:43:59 -0300
commit7d64136e0f08c108434962d5a4c0c038c034caaa (patch)
treed9b03de6b4ea0f8124c79da82c1a09bd7ecc96f2
parente6145cfc299e7ed7abe1c92b3c16a3fcd58ea49e (diff)
drm/v3d: Ensure atomic submissions in v3d_submit_jobs()
Currently, v3d_submit_jobs() arms and pushes each job one at a time, wiring dependencies between consecutive jobs after each push. If drm_sched_job_add_dependency() fails midway, the already-pushed jobs are scheduler-owned and will be submitted to the GPU for execution, even though the subsequent jobs won't be submitted. This breaks the atomicity of the submissions, as only some of the jobs from a submission would be submitted to the hardware, while the other part fails. Restructure v3d_submit_jobs() into three phases: (1) arm all jobs belonging to a given submission, (2) wire inter-job dependencies, and (3) push all jobs to the scheduler unconditionally. Phase (2) can fail; on failure, it marks every armed job finished fence with an error, so that run_job() callbacks skip hardware execution. This guarantees that every armed job is always pushed, either to run or to be skipped, and it also ensures the atomicity of a submission. Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> Link: https://patch.msgid.link/20260604-v3d-sched-misc-fixes-v4-12-c068f5bf5ccf@igalia.com Signed-off-by: Maíra Canal <mcanal@igalia.com>
-rw-r--r--drivers/gpu/drm/v3d/v3d_sched.c6
-rw-r--r--drivers/gpu/drm/v3d/v3d_submit.c65
2 files changed, 39 insertions, 32 deletions
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
index 7f9a71022e5e..53deae1a2eda 100644
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -657,6 +657,9 @@ v3d_cpu_job_run(struct drm_sched_job *sched_job)
struct v3d_cpu_job *job = to_cpu_job(sched_job);
struct v3d_dev *v3d = job->base.v3d;
+ if (unlikely(job->base.base.s_fence->finished.error))
+ return NULL;
+
if (job->job_type >= ARRAY_SIZE(cpu_job_function)) {
drm_dbg(&v3d->drm, "Unknown CPU job: %d\n", job->job_type);
return NULL;
@@ -680,6 +683,9 @@ v3d_cache_clean_job_run(struct drm_sched_job *sched_job)
struct v3d_job *job = to_v3d_job(sched_job);
struct v3d_dev *v3d = job->v3d;
+ if (unlikely(job->base.s_fence->finished.error))
+ return NULL;
+
v3d_job_start_stats(job);
v3d_clean_caches(v3d);
diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c
index cee48acd25d9..ee2ac2540ed5 100644
--- a/drivers/gpu/drm/v3d/v3d_submit.c
+++ b/drivers/gpu/drm/v3d/v3d_submit.c
@@ -368,19 +368,6 @@ v3d_submit_process_post_deps(struct v3d_submit *submit, struct drm_syncobj *sync
}
}
-static void
-v3d_push_job(struct v3d_job *job)
-{
- drm_sched_job_arm(&job->base);
-
- job->done_fence = dma_fence_get(&job->base.s_fence->finished);
-
- /* put by scheduler job completion */
- kref_get(&job->refcount);
-
- drm_sched_entity_push_job(&job->base);
-}
-
static int
v3d_submit_jobs(struct v3d_submit *submit, struct drm_syncobj *sync_out,
struct v3d_submit_ext *se)
@@ -393,16 +380,23 @@ v3d_submit_jobs(struct v3d_submit *submit, struct drm_syncobj *sync_out,
for (int i = 0; i < submit->job_count; i++) {
struct v3d_job *job = submit->jobs[i];
- v3d_push_job(job);
+ drm_sched_job_arm(&job->base);
+ job->done_fence = dma_fence_get(&job->base.s_fence->finished);
- if (i + 1 < submit->job_count) {
- ret = drm_sched_job_add_dependency(&submit->jobs[i + 1]->base,
- dma_fence_get(job->done_fence));
- if (ret)
- goto err;
- }
+ /* put by scheduler job completion */
+ kref_get(&job->refcount);
+ }
+
+ for (int i = 1; i < submit->job_count; i++) {
+ ret = drm_sched_job_add_dependency(&submit->jobs[i]->base,
+ dma_fence_get(submit->jobs[i - 1]->done_fence));
+ if (ret)
+ goto err;
}
+ for (int i = 0; i < submit->job_count; i++)
+ drm_sched_entity_push_job(&submit->jobs[i]->base);
+
mutex_unlock(&v3d->sched_lock);
v3d_submit_attach_object_fences(submit);
@@ -414,7 +408,18 @@ v3d_submit_jobs(struct v3d_submit *submit, struct drm_syncobj *sync_out,
return 0;
err:
+ /* Mark every armed job as failed so run_job() skips execution */
+ for (int i = 0; i < submit->job_count; i++)
+ dma_fence_set_error(&submit->jobs[i]->base.s_fence->finished, ret);
+
+ for (int i = 0; i < submit->job_count; i++)
+ drm_sched_entity_push_job(&submit->jobs[i]->base);
+
mutex_unlock(&v3d->sched_lock);
+
+ v3d_submit_unlock_reservations(submit);
+ v3d_submit_put_jobs(submit);
+
return ret;
}
@@ -1102,14 +1107,13 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
ret = v3d_submit_jobs(&submit, sync_out, &se);
if (ret)
- goto fail_unreserve;
+ goto fail_submit;
return 0;
-fail_unreserve:
- v3d_submit_unlock_reservations(&submit);
fail:
v3d_submit_cleanup_jobs(&submit);
+fail_submit:
v3d_submit_put_post_deps(sync_out, &se);
return ret;
@@ -1200,14 +1204,13 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
ret = v3d_submit_jobs(&submit, sync_out, &se);
if (ret)
- goto fail_unreserve;
+ goto fail_submit;
return 0;
-fail_unreserve:
- v3d_submit_unlock_reservations(&submit);
fail:
v3d_submit_cleanup_jobs(&submit);
+fail_submit:
v3d_submit_put_post_deps(sync_out, &se);
return ret;
@@ -1276,14 +1279,13 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
ret = v3d_submit_jobs(&submit, sync_out, &se);
if (ret)
- goto fail_unreserve;
+ goto fail_submit;
return 0;
-fail_unreserve:
- v3d_submit_unlock_reservations(&submit);
fail:
v3d_submit_cleanup_jobs(&submit);
+fail_submit:
v3d_submit_put_post_deps(sync_out, &se);
return ret;
@@ -1384,14 +1386,13 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data,
ret = v3d_submit_jobs(&submit, NULL, &se);
if (ret)
- goto fail_unreserve;
+ goto fail_submit;
return 0;
-fail_unreserve:
- v3d_submit_unlock_reservations(&submit);
fail:
v3d_submit_cleanup_jobs(&submit);
+fail_submit:
v3d_submit_put_post_deps(NULL, &se);
return ret;