diff options
Diffstat (limited to 'drivers/gpu/drm/etnaviv/etnaviv_sched.c')
| -rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_sched.c | 148 |
1 files changed, 52 insertions, 96 deletions
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 19826e504efc..df4232d7e135 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -11,64 +11,13 @@ #include "etnaviv_gpu.h" #include "etnaviv_sched.h" #include "state.xml.h" +#include "state_hi.xml.h" static int etnaviv_job_hang_limit = 0; module_param_named(job_hang_limit, etnaviv_job_hang_limit, int , 0444); static int etnaviv_hw_jobs_limit = 4; module_param_named(hw_job_limit, etnaviv_hw_jobs_limit, int , 0444); -static struct dma_fence * -etnaviv_sched_dependency(struct drm_sched_job *sched_job, - struct drm_sched_entity *entity) -{ - struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); - struct dma_fence *fence; - int i; - - if (unlikely(submit->in_fence)) { - fence = submit->in_fence; - submit->in_fence = NULL; - - if (!dma_fence_is_signaled(fence)) - return fence; - - dma_fence_put(fence); - } - - for (i = 0; i < submit->nr_bos; i++) { - struct etnaviv_gem_submit_bo *bo = &submit->bos[i]; - int j; - - if (bo->excl) { - fence = bo->excl; - bo->excl = NULL; - - if (!dma_fence_is_signaled(fence)) - return fence; - - dma_fence_put(fence); - } - - for (j = 0; j < bo->nr_shared; j++) { - if (!bo->shared[j]) - continue; - - fence = bo->shared[j]; - bo->shared[j] = NULL; - - if (!dma_fence_is_signaled(fence)) - return fence; - - dma_fence_put(fence); - } - kfree(bo->shared); - bo->nr_shared = 0; - bo->shared = NULL; - } - - return NULL; -} - static struct dma_fence *etnaviv_sched_run_job(struct drm_sched_job *sched_job) { struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); @@ -87,18 +36,15 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job { struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); struct etnaviv_gpu *gpu = submit->gpu; - u32 dma_addr; + u32 dma_addr, primid = 0; int change; - /* block scheduler */ - drm_sched_stop(&gpu->sched, sched_job); - /* - * If the GPU managed to complete this jobs fence, the timout is - * spurious. Bail out. + * If the GPU managed to complete this jobs fence, the timeout has + * fired before free-job worker. The timeout is spurious, so bail out. */ if (dma_fence_is_signaled(submit->out_fence)) - goto out_no_timeout; + return DRM_GPU_SCHED_STAT_NO_HANG; /* * If the GPU is still making forward progress on the front-end (which @@ -107,27 +53,40 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job */ dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); change = dma_addr - gpu->hangcheck_dma_addr; - if (change < 0 || change > 16) { + if (submit->exec_state == ETNA_PIPE_3D) { + /* guard against concurrent usage from perfmon_sample */ + mutex_lock(&gpu->lock); + gpu_write(gpu, VIVS_MC_PROFILE_CONFIG0, + VIVS_MC_PROFILE_CONFIG0_FE_CURRENT_PRIM << + VIVS_MC_PROFILE_CONFIG0_FE__SHIFT); + primid = gpu_read(gpu, VIVS_MC_PROFILE_FE_READ); + mutex_unlock(&gpu->lock); + } + if (gpu->state == ETNA_GPU_STATE_RUNNING && + (gpu->completed_fence != gpu->hangcheck_fence || + change < 0 || change > 16 || + (submit->exec_state == ETNA_PIPE_3D && + gpu->hangcheck_primid != primid))) { gpu->hangcheck_dma_addr = dma_addr; - goto out_no_timeout; + gpu->hangcheck_primid = primid; + gpu->hangcheck_fence = gpu->completed_fence; + return DRM_GPU_SCHED_STAT_NO_HANG; } + /* block scheduler */ + drm_sched_stop(&gpu->sched, sched_job); + if(sched_job) drm_sched_increase_karma(sched_job); /* get the GPU back into the init state */ etnaviv_core_dump(submit); - etnaviv_gpu_recover_hang(gpu); + etnaviv_gpu_recover_hang(submit); drm_sched_resubmit_jobs(&gpu->sched); - drm_sched_start(&gpu->sched, true); - return DRM_GPU_SCHED_STAT_NOMINAL; - -out_no_timeout: - /* restart scheduler after GPU is usable again */ - drm_sched_start(&gpu->sched, true); - return DRM_GPU_SCHED_STAT_NOMINAL; + drm_sched_start(&gpu->sched, 0); + return DRM_GPU_SCHED_STAT_RESET; } static void etnaviv_sched_free_job(struct drm_sched_job *sched_job) @@ -140,61 +99,58 @@ static void etnaviv_sched_free_job(struct drm_sched_job *sched_job) } static const struct drm_sched_backend_ops etnaviv_sched_ops = { - .dependency = etnaviv_sched_dependency, .run_job = etnaviv_sched_run_job, .timedout_job = etnaviv_sched_timedout_job, .free_job = etnaviv_sched_free_job, }; -int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, - struct etnaviv_gem_submit *submit) +int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit) { - int ret = 0; + struct etnaviv_gpu *gpu = submit->gpu; + int ret; /* - * Hold the fence lock across the whole operation to avoid jobs being + * Hold the sched lock across the whole operation to avoid jobs being * pushed out of order with regard to their sched fence seqnos as - * allocated in drm_sched_job_init. + * allocated in drm_sched_job_arm. */ - mutex_lock(&submit->gpu->fence_lock); + mutex_lock(&gpu->sched_lock); - ret = drm_sched_job_init(&submit->sched_job, sched_entity, - submit->ctx); - if (ret) - goto out_unlock; + drm_sched_job_arm(&submit->sched_job); submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished); - submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr, - submit->out_fence, 0, - INT_MAX, GFP_KERNEL); - if (submit->out_fence_id < 0) { + ret = xa_alloc_cyclic(&gpu->user_fences, &submit->out_fence_id, + submit->out_fence, xa_limit_32b, + &gpu->next_user_fence, GFP_KERNEL); + if (ret < 0) { drm_sched_job_cleanup(&submit->sched_job); - ret = -ENOMEM; goto out_unlock; } /* the scheduler holds on to the job now */ kref_get(&submit->refcount); - drm_sched_entity_push_job(&submit->sched_job, sched_entity); + drm_sched_entity_push_job(&submit->sched_job); out_unlock: - mutex_unlock(&submit->gpu->fence_lock); + mutex_unlock(&gpu->sched_lock); return ret; } int etnaviv_sched_init(struct etnaviv_gpu *gpu) { - int ret; - - ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, - etnaviv_hw_jobs_limit, etnaviv_job_hang_limit, - msecs_to_jiffies(500), NULL, dev_name(gpu->dev)); - if (ret) - return ret; - - return 0; + const struct drm_sched_init_args args = { + .ops = &etnaviv_sched_ops, + .num_rqs = DRM_SCHED_PRIORITY_COUNT, + .credit_limit = etnaviv_hw_jobs_limit, + .hang_limit = etnaviv_job_hang_limit, + .timeout = msecs_to_jiffies(500), + .name = dev_name(gpu->dev), + .dev = gpu->dev, + }; + + return drm_sched_init(&gpu->sched, &args); } void etnaviv_sched_fini(struct etnaviv_gpu *gpu) |
