summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/lima/lima_sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/lima/lima_sched.c')
-rw-r--r--drivers/gpu/drm/lima/lima_sched.c86
1 files changed, 65 insertions, 21 deletions
diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c
index 5612d73f238f..9a1e6b9ecbe5 100644
--- a/drivers/gpu/drm/lima/lima_sched.c
+++ b/drivers/gpu/drm/lima/lima_sched.c
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
-#include <linux/dma-buf-map.h>
+#include <linux/hardirq.h>
+#include <linux/iosys-map.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
+#include <drm/drm_print.h>
+
#include "lima_devfreq.h"
#include "lima_drv.h"
#include "lima_sched.h"
@@ -112,7 +115,8 @@ static inline struct lima_sched_pipe *to_lima_pipe(struct drm_gpu_scheduler *sch
int lima_sched_task_init(struct lima_sched_task *task,
struct lima_sched_context *context,
struct lima_bo **bos, int num_bos,
- struct lima_vm *vm)
+ struct lima_vm *vm,
+ u64 drm_client_id)
{
int err, i;
@@ -123,7 +127,8 @@ int lima_sched_task_init(struct lima_sched_task *task,
for (i = 0; i < num_bos; i++)
drm_gem_object_get(&bos[i]->base.base);
- err = drm_sched_job_init(&task->base, &context->base, vm);
+ err = drm_sched_job_init(&task->base, &context->base, 1, vm,
+ drm_client_id);
if (err) {
kfree(task->bos);
return err;
@@ -153,19 +158,18 @@ void lima_sched_task_fini(struct lima_sched_task *task)
}
int lima_sched_context_init(struct lima_sched_pipe *pipe,
- struct lima_sched_context *context,
- atomic_t *guilty)
+ struct lima_sched_context *context)
{
struct drm_gpu_scheduler *sched = &pipe->base;
return drm_sched_entity_init(&context->base, DRM_SCHED_PRIORITY_NORMAL,
- &sched, 1, guilty);
+ &sched, 1, NULL);
}
void lima_sched_context_fini(struct lima_sched_pipe *pipe,
struct lima_sched_context *context)
{
- drm_sched_entity_fini(&context->base);
+ drm_sched_entity_destroy(&context->base);
}
struct dma_fence *lima_sched_context_queue_task(struct lima_sched_task *task)
@@ -284,7 +288,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
struct lima_dump_chunk_buffer *buffer_chunk;
u32 size, task_size, mem_size;
int i;
- struct dma_buf_map map;
+ struct iosys_map map;
int ret;
mutex_lock(&dev->error_task_list_lock);
@@ -371,7 +375,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
} else {
buffer_chunk->size = lima_bo_size(bo);
- ret = drm_gem_shmem_vmap(&bo->base, &map);
+ ret = drm_gem_vmap(&bo->base.base, &map);
if (ret) {
kvfree(et);
goto out;
@@ -379,7 +383,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
memcpy(buffer_chunk + 1, map.vaddr, buffer_chunk->size);
- drm_gem_shmem_vunmap(&bo->base, &map);
+ drm_gem_vunmap(&bo->base.base, &map);
}
buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size;
@@ -401,23 +405,57 @@ static enum drm_gpu_sched_stat lima_sched_timedout_job(struct drm_sched_job *job
struct lima_sched_pipe *pipe = to_lima_pipe(job->sched);
struct lima_sched_task *task = to_lima_task(job);
struct lima_device *ldev = pipe->ldev;
+ struct lima_ip *ip = pipe->processor[0];
+ int i;
+
+ /*
+ * If the GPU managed to complete this jobs fence, the timeout is
+ * spurious. Bail out.
+ */
+ if (dma_fence_is_signaled(task->fence)) {
+ DRM_WARN("%s spurious timeout\n", lima_ip_name(ip));
+ return DRM_GPU_SCHED_STAT_RESET;
+ }
+
+ /*
+ * Lima IRQ handler may take a long time to process an interrupt
+ * if there is another IRQ handler hogging the processing.
+ * In order to catch such cases and not report spurious Lima job
+ * timeouts, synchronize the IRQ handler and re-check the fence
+ * status.
+ */
+ for (i = 0; i < pipe->num_processor; i++)
+ synchronize_irq(pipe->processor[i]->irq);
+ if (pipe->bcast_processor)
+ synchronize_irq(pipe->bcast_processor->irq);
+
+ if (dma_fence_is_signaled(task->fence)) {
+ DRM_WARN("%s unexpectedly high interrupt latency\n", lima_ip_name(ip));
+ return DRM_GPU_SCHED_STAT_RESET;
+ }
+
+ /*
+ * The task might still finish while this timeout handler runs.
+ * To prevent a race condition on its completion, mask all irqs
+ * on the running core until the next hard reset completes.
+ */
+ pipe->task_mask_irq(pipe);
if (!pipe->error)
- DRM_ERROR("lima job timeout\n");
+ DRM_ERROR("%s job timeout\n", lima_ip_name(ip));
drm_sched_stop(&pipe->base, &task->base);
drm_sched_increase_karma(&task->base);
- lima_sched_build_error_task_list(task);
+ if (lima_max_error_tasks)
+ lima_sched_build_error_task_list(task);
pipe->task_error(pipe);
if (pipe->bcast_mmu)
lima_mmu_page_fault_resume(pipe->bcast_mmu);
else {
- int i;
-
for (i = 0; i < pipe->num_mmu; i++)
lima_mmu_page_fault_resume(pipe->mmu[i]);
}
@@ -429,9 +467,9 @@ static enum drm_gpu_sched_stat lima_sched_timedout_job(struct drm_sched_job *job
lima_pm_idle(ldev);
drm_sched_resubmit_jobs(&pipe->base);
- drm_sched_start(&pipe->base, true);
+ drm_sched_start(&pipe->base, 0);
- return DRM_GPU_SCHED_STAT_NOMINAL;
+ return DRM_GPU_SCHED_STAT_RESET;
}
static void lima_sched_free_job(struct drm_sched_job *job)
@@ -480,17 +518,23 @@ static void lima_sched_recover_work(struct work_struct *work)
int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
{
unsigned int timeout = lima_sched_timeout_ms > 0 ?
- lima_sched_timeout_ms : 500;
+ lima_sched_timeout_ms : 10000;
+ const struct drm_sched_init_args args = {
+ .ops = &lima_sched_ops,
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .credit_limit = 1,
+ .hang_limit = lima_job_hang_limit,
+ .timeout = msecs_to_jiffies(timeout),
+ .name = name,
+ .dev = pipe->ldev->dev,
+ };
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,
- lima_job_hang_limit,
- msecs_to_jiffies(timeout), NULL,
- NULL, name);
+ return drm_sched_init(&pipe->base, &args);
}
void lima_sched_pipe_fini(struct lima_sched_pipe *pipe)