@@ -1218,15 +1218,19 @@ static void drm_sched_run_job_work(struct work_struct *w)
drm_sched_fence_scheduled(s_fence, fence);
if (!IS_ERR_OR_NULL(fence)) {
- /* Drop for original kref_init of the fence */
- dma_fence_put(fence);
-
r = dma_fence_add_callback(fence, &sched_job->cb,
drm_sched_job_done_cb);
if (r == -ENOENT)
drm_sched_job_done(sched_job, fence->error);
else if (r)
DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n", r);
+
+ /*
+ * s_fence took a new reference to fence in the call to
+ * drm_sched_fence_scheduled() above. The reference passed by
+ * run_job() above is now not needed any longer. Drop it.
+ */
+ dma_fence_put(fence);
} else {
drm_sched_job_done(sched_job, IS_ERR(fence) ?
PTR_ERR(fence) : 0);
@@ -420,10 +420,21 @@ struct drm_sched_backend_ops {
struct drm_sched_entity *s_entity);
/**
- * @run_job: Called to execute the job once all of the dependencies
- * have been resolved. This may be called multiple times, if
- * timedout_job() has happened and drm_sched_job_recovery()
- * decides to try it again.
+ * @run_job: Called to execute the job once all of the dependencies
+ * have been resolved. This may be called multiple times, if
+ * timedout_job() has happened and drm_sched_job_recovery() decides to
+ * try it again.
+ *
+ * @sched_job: the job to run
+ *
+ * Returns: dma_fence the driver must signal once the hardware has
+ * completed the job ("hardware fence").
+ *
+ * Note that the scheduler expects to 'inherit' its own reference to
+ * this fence from the callback. It does not invoke an extra
+ * dma_fence_get() on it. Consequently, this callback must take a
+ * reference for the scheduler, and additional ones for the driver's
+ * respective needs.
*/
struct dma_fence *(*run_job)(struct drm_sched_job *sched_job);