Merge tag 'drm-next-5.5-2019-11-01' of git://people.freedesktop.org/~agd5f/linux...
[linux-2.6-microblaze.git] / drivers / gpu / drm / scheduler / sched_main.c
index 9a0ee74..2af6445 100644 (file)
@@ -479,6 +479,7 @@ void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
        struct drm_sched_job *s_job, *tmp;
        uint64_t guilty_context;
        bool found_guilty = false;
+       struct dma_fence *fence;
 
        list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) {
                struct drm_sched_fence *s_fence = s_job->s_fence;
@@ -492,7 +493,16 @@ void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
                        dma_fence_set_error(&s_fence->finished, -ECANCELED);
 
                dma_fence_put(s_job->s_fence->parent);
-               s_job->s_fence->parent = sched->ops->run_job(s_job);
+               fence = sched->ops->run_job(s_job);
+
+               if (IS_ERR_OR_NULL(fence)) {
+                       s_job->s_fence->parent = NULL;
+                       dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
+               } else {
+                       s_job->s_fence->parent = fence;
+               }
+
+
        }
 }
 EXPORT_SYMBOL(drm_sched_resubmit_jobs);
@@ -622,43 +632,41 @@ static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb)
 }
 
 /**
- * drm_sched_cleanup_jobs - destroy finished jobs
+ * drm_sched_get_cleanup_job - fetch the next finished job to be destroyed
  *
  * @sched: scheduler instance
  *
- * Remove all finished jobs from the mirror list and destroy them.
+ * Returns the next finished job from the mirror list (if there is one)
+ * ready for it to be destroyed.
  */
-static void drm_sched_cleanup_jobs(struct drm_gpu_scheduler *sched)
+static struct drm_sched_job *
+drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched)
 {
+       struct drm_sched_job *job;
        unsigned long flags;
 
        /* Don't destroy jobs while the timeout worker is running */
        if (sched->timeout != MAX_SCHEDULE_TIMEOUT &&
            !cancel_delayed_work(&sched->work_tdr))
-               return;
-
+               return NULL;
 
-       while (!list_empty(&sched->ring_mirror_list)) {
-               struct drm_sched_job *job;
+       spin_lock_irqsave(&sched->job_list_lock, flags);
 
-               job = list_first_entry(&sched->ring_mirror_list,
+       job = list_first_entry_or_null(&sched->ring_mirror_list,
                                       struct drm_sched_job, node);
-               if (!dma_fence_is_signaled(&job->s_fence->finished))
-                       break;
 
-               spin_lock_irqsave(&sched->job_list_lock, flags);
+       if (job && dma_fence_is_signaled(&job->s_fence->finished)) {
                /* remove job from ring_mirror_list */
                list_del_init(&job->node);
-               spin_unlock_irqrestore(&sched->job_list_lock, flags);
-
-               sched->ops->free_job(job);
+       } else {
+               job = NULL;
+               /* queue timeout for next job */
+               drm_sched_start_timeout(sched);
        }
 
-       /* queue timeout for next job */
-       spin_lock_irqsave(&sched->job_list_lock, flags);
-       drm_sched_start_timeout(sched);
        spin_unlock_irqrestore(&sched->job_list_lock, flags);
 
+       return job;
 }
 
 /**
@@ -698,12 +706,19 @@ static int drm_sched_main(void *param)
                struct drm_sched_fence *s_fence;
                struct drm_sched_job *sched_job;
                struct dma_fence *fence;
+               struct drm_sched_job *cleanup_job = NULL;
 
                wait_event_interruptible(sched->wake_up_worker,
-                                        (drm_sched_cleanup_jobs(sched),
+                                        (cleanup_job = drm_sched_get_cleanup_job(sched)) ||
                                         (!drm_sched_blocked(sched) &&
                                          (entity = drm_sched_select_entity(sched))) ||
-                                        kthread_should_stop()));
+                                        kthread_should_stop());
+
+               if (cleanup_job) {
+                       sched->ops->free_job(cleanup_job);
+                       /* queue timeout for next job */
+                       drm_sched_start_timeout(sched);
+               }
 
                if (!entity)
                        continue;
@@ -720,7 +735,7 @@ static int drm_sched_main(void *param)
                fence = sched->ops->run_job(sched_job);
                drm_sched_fence_scheduled(s_fence);
 
-               if (fence) {
+               if (!IS_ERR_OR_NULL(fence)) {
                        s_fence->parent = dma_fence_get(fence);
                        r = dma_fence_add_callback(fence, &sched_job->cb,
                                                   drm_sched_process_job);
@@ -730,8 +745,11 @@ static int drm_sched_main(void *param)
                                DRM_ERROR("fence add callback failed (%d)\n",
                                          r);
                        dma_fence_put(fence);
-               } else
+               } else {
+
+                       dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
                        drm_sched_process_job(NULL, &sched_job->cb);
+               }
 
                wake_up(&sched->job_scheduled);
        }