drm/amdgpu: cleanup and fix scheduler fence handling v2

v2: rebased

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com> (v1)
Reviewed-by: Chunming Zhou <david1.zhou@amd.com>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
index 787b93d..039bd1f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
@@ -43,16 +43,9 @@
 	return r;
 }
 
-static void amdgpu_fence_sched_cb(struct fence *f, struct fence_cb *cb)
-{
-	struct amd_sched_job *sched_job =
-		container_of(cb, struct amd_sched_job, cb);
-	amd_sched_process_job(sched_job);
-}
-
-static void amdgpu_sched_run_job(struct amd_gpu_scheduler *sched,
-				 struct amd_sched_entity *entity,
-				 struct amd_sched_job *job)
+static struct fence *amdgpu_sched_run_job(struct amd_gpu_scheduler *sched,
+					  struct amd_sched_entity *entity,
+					  struct amd_sched_job *job)
 {
 	int r = 0;
 	struct amdgpu_cs_parser *sched_job;
@@ -60,7 +53,7 @@
 
 	if (!job || !job->job) {
 		DRM_ERROR("job is null\n");
-		return;
+		return NULL;
 	}
 	sched_job = (struct amdgpu_cs_parser *)job->job;
 	mutex_lock(&sched_job->job_lock);
@@ -70,12 +63,7 @@
 			       sched_job->filp);
 	if (r)
 		goto err;
-	fence = sched_job->ibs[sched_job->num_ibs - 1].fence;
-	if (fence_add_callback(&fence->base,
-			       &job->cb, amdgpu_fence_sched_cb)) {
-		DRM_ERROR("fence add callback failed\n");
-		goto err;
-	}
+	fence = amdgpu_fence_ref(sched_job->ibs[sched_job->num_ibs - 1].fence);
 
 	if (sched_job->run_job) {
 		r = sched_job->run_job(sched_job);
@@ -86,11 +74,13 @@
 	amd_sched_emit(entity, sched_job->ibs[sched_job->num_ibs - 1].sequence);
 
 	mutex_unlock(&sched_job->job_lock);
-	return;
+	return &fence->base;
+
 err:
 	DRM_ERROR("Run job error\n");
 	mutex_unlock(&sched_job->job_lock);
 	schedule_work(&sched_job->job_work);
+	return NULL;
 }
 
 static void amdgpu_sched_process_job(struct amd_gpu_scheduler *sched, void *job)
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
index eb3b099..438dc23 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
@@ -175,9 +175,9 @@
  * return 0 if succeed. negative error code on failure
 */
 int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
-			    struct amd_sched_entity *entity,
-			    struct amd_run_queue *rq,
-			    uint32_t jobs)
+			  struct amd_sched_entity *entity,
+			  struct amd_run_queue *rq,
+			  uint32_t jobs)
 {
 	uint64_t seq_ring = 0;
 
@@ -353,6 +353,24 @@
 	return 0;
 }
 
+static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)
+{
+	struct amd_sched_job *sched_job =
+		container_of(cb, struct amd_sched_job, cb);
+	struct amd_gpu_scheduler *sched;
+	unsigned long flags;
+
+	sched = sched_job->sched;
+	spin_lock_irqsave(&sched->queue_lock, flags);
+	list_del(&sched_job->list);
+	atomic64_dec(&sched->hw_rq_count);
+	spin_unlock_irqrestore(&sched->queue_lock, flags);
+
+	sched->ops->process_job(sched, sched_job->job);
+	kfree(sched_job);
+	wake_up_interruptible(&sched->wait_queue);
+}
+
 static int amd_sched_main(void *param)
 {
 	int r;
@@ -365,6 +383,8 @@
 
 	while (!kthread_should_stop()) {
 		struct amd_sched_job *sched_job = NULL;
+		struct fence *fence;
+
 		wait_event_interruptible(sched->wait_queue,
 					 is_scheduler_ready(sched) &&
 					 (c_entity = select_context(sched)));
@@ -388,37 +408,22 @@
 			spin_unlock_irqrestore(&sched->queue_lock, flags);
 		}
 		mutex_lock(&sched->sched_lock);
-		sched->ops->run_job(sched, c_entity, sched_job);
+		fence = sched->ops->run_job(sched, c_entity, sched_job);
+		if (fence) {
+			r = fence_add_callback(fence, &sched_job->cb,
+					       amd_sched_process_job);
+			if (r == -ENOENT)
+				amd_sched_process_job(fence, &sched_job->cb);
+			else if (r)
+				DRM_ERROR("fence add callback failed (%d)\n", r);
+			fence_put(fence);
+		}
 		mutex_unlock(&sched->sched_lock);
 	}
 	return 0;
 }
 
 /**
- * ISR to handle EOP inetrrupts
- *
- * @sched: gpu scheduler
- *
-*/
-void amd_sched_process_job(struct amd_sched_job *sched_job)
-{
-	unsigned long flags;
-	struct amd_gpu_scheduler *sched;
-
-	if (!sched_job)
-		return;
-	sched = sched_job->sched;
-	spin_lock_irqsave(&sched->queue_lock, flags);
-	list_del(&sched_job->list);
-	atomic64_dec(&sched->hw_rq_count);
-	spin_unlock_irqrestore(&sched->queue_lock, flags);
-
-	sched->ops->process_job(sched, sched_job->job);
-	kfree(sched_job);
-	wake_up_interruptible(&sched->wait_queue);
-}
-
-/**
  * Create a gpu scheduler
  *
  * @device	The device context for this scheduler
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
index a3e29df..e7cc40a 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
@@ -87,9 +87,9 @@
 	int (*prepare_job)(struct amd_gpu_scheduler *sched,
 			   struct amd_sched_entity *c_entity,
 			   void *job);
-	void (*run_job)(struct amd_gpu_scheduler *sched,
-			struct amd_sched_entity *c_entity,
-			struct amd_sched_job *job);
+	struct fence *(*run_job)(struct amd_gpu_scheduler *sched,
+				 struct amd_sched_entity *c_entity,
+				 struct amd_sched_job *job);
 	void (*process_job)(struct amd_gpu_scheduler *sched, void *job);
 };
 
@@ -132,7 +132,6 @@
 			bool intr,
 			long timeout);
 
-void amd_sched_process_job(struct amd_sched_job *sched_job);
 uint64_t amd_sched_get_handled_seq(struct amd_gpu_scheduler *sched);
 
 int amd_sched_entity_init(struct amd_gpu_scheduler *sched,