On 15/05/2025 16:00, Christian König wrote:
Sometimes drivers need to be able to submit multiple jobs which depend on
each other to different schedulers at the same time, but using
drm_sched_job_add_dependency() can't fail any more after the first job is
initialized.
This function preallocate memory for dependency slots so that no ENOMEM
can come later while adding dependencies.
v2: rework implementation an documentation
v3: rework from scratch, use separate function to add preallocated deps
Signed-off-by: Christian König <christian.koe...@amd.com>
---
drivers/gpu/drm/scheduler/sched_main.c | 45 ++++++++++++++++++++++++++
include/drm/gpu_scheduler.h | 4 +++
2 files changed, 49 insertions(+)
diff --git a/drivers/gpu/drm/scheduler/sched_main.c
b/drivers/gpu/drm/scheduler/sched_main.c
index f7118497e47a..b95e7089aa70 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -858,6 +858,51 @@ void drm_sched_job_arm(struct drm_sched_job *job)
}
EXPORT_SYMBOL(drm_sched_job_arm);
+/**
+ * drm_sched_job_prealloc_dependency_slot - avoid ENOMEM on adding dependencies
+ * @job: scheduler job where dependencies will be added
+ * @id: id for the allocated slot
+ *
+ * Sometimes drivers need to be able to submit multiple jobs which depend on
+ * each other to different schedulers at the same time, but using
+ * drm_sched_job_add_dependency() can't fail any more after the first job is
+ * initialized.
+ *
+ * This function preallocate memory for a dependency slot so that no ENOMEM can
+ * come later while adding dependencies. The index of the preallocated slot is
+ * returned in @id.
+ *
+ * Return:
+ * 0 on success, or an error on failing to expand the array.
+ */
+int drm_sched_job_prealloc_dependency_slot(struct drm_sched_job *job,
+ u32 *id)
+{
+ return xa_alloc(&job->dependencies, id, NULL, xa_limit_32b, GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_sched_job_prealloc_dependency_slot);
+
+/**
+ * drm_sched_job_add_prealloc_dep - add dependency to preallocated slot
+ * @job: scheduler job where dependencies will be added
+ * @id: the preallocated slot index
+ * @fence: the dependency to add
+ *
+ * Consumes @fence and adds it to the preallocated slot dependency.
+ */
+void drm_sched_job_add_prealloc_dep(struct drm_sched_job *job, u32 id,
+ struct dma_fence *fence)
+{
+ fence = xa_store(&job->dependencies, id, fence, GFP_ATOMIC);
Add assert that the passed id exists (was preallocated) and is NULL?
Also, if someone preallocates and does not consume the slot will that
confuse the iteration in drm_sched_job_dependency()?
Regards,
Tvrtko
+ /*
+ * Be defensive just in case driver messed it up and used preallocated
+ * slot twice.
+ */
+ if (WARN_ON(fence))
+ dma_fence_put(fence);
+}
+EXPORT_SYMBOL(drm_sched_job_add_prealloc_dep);
+
/**
* drm_sched_job_add_dependency - adds the fence as a job dependency
* @job: scheduler job to add the dependencies to
diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
index d860db087ea5..0286e0934317 100644
--- a/include/drm/gpu_scheduler.h
+++ b/include/drm/gpu_scheduler.h
@@ -632,6 +632,10 @@ int drm_sched_job_init(struct drm_sched_job *job,
u32 credits, void *owner);
void drm_sched_job_arm(struct drm_sched_job *job);
void drm_sched_entity_push_job(struct drm_sched_job *sched_job);
+int drm_sched_job_prealloc_dependency_slot(struct drm_sched_job *job,
+ u32 *id);
+void drm_sched_job_add_prealloc_dep(struct drm_sched_job *job, u32 id,
+ struct dma_fence *fence);
int drm_sched_job_add_dependency(struct drm_sched_job *job,
struct dma_fence *fence);
int drm_sched_job_add_syncobj_dependency(struct drm_sched_job *job,