Merge tag 'drm-misc-next-2020-02-10' of git://anongit.freedesktop.org/drm/drm-misc...
[linux-2.6-microblaze.git] / drivers / gpu / drm / lima / lima_sched.c
index b561dd0..3886999 100644 (file)
@@ -313,6 +313,26 @@ static const struct drm_sched_backend_ops lima_sched_ops = {
        .free_job = lima_sched_free_job,
 };
 
+static void lima_sched_recover_work(struct work_struct *work)
+{
+       struct lima_sched_pipe *pipe =
+               container_of(work, struct lima_sched_pipe, recover_work);
+       int i;
+
+       for (i = 0; i < pipe->num_l2_cache; i++)
+               lima_l2_cache_flush(pipe->l2_cache[i]);
+
+       if (pipe->bcast_mmu) {
+               lima_mmu_flush_tlb(pipe->bcast_mmu);
+       } else {
+               for (i = 0; i < pipe->num_mmu; i++)
+                       lima_mmu_flush_tlb(pipe->mmu[i]);
+       }
+
+       if (pipe->task_recover(pipe))
+               drm_sched_fault(&pipe->base);
+}
+
 int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
 {
        unsigned int timeout = lima_sched_timeout_ms > 0 ?
@@ -321,6 +341,8 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
        pipe->fence_context = dma_fence_context_alloc(1);
        spin_lock_init(&pipe->fence_lock);
 
+       INIT_WORK(&pipe->recover_work, lima_sched_recover_work);
+
        return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0,
                              msecs_to_jiffies(timeout), name);
 }
@@ -332,11 +354,14 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe)
 
 void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)
 {
-       if (pipe->error)
-               drm_sched_fault(&pipe->base);
-       else {
-               struct lima_sched_task *task = pipe->current_task;
-
+       struct lima_sched_task *task = pipe->current_task;
+
+       if (pipe->error) {
+               if (task && task->recoverable)
+                       schedule_work(&pipe->recover_work);
+               else
+                       drm_sched_fault(&pipe->base);
+       } else {
                pipe->task_fini(pipe);
                dma_fence_signal(task->fence);
        }