1e93b6deeSLucas Stach /* 2e93b6deeSLucas Stach * Copyright (C) 2017 Etnaviv Project 3e93b6deeSLucas Stach * 4e93b6deeSLucas Stach * This program is free software; you can redistribute it and/or modify it 5e93b6deeSLucas Stach * under the terms of the GNU General Public License version 2 as published by 6e93b6deeSLucas Stach * the Free Software Foundation. 7e93b6deeSLucas Stach * 8e93b6deeSLucas Stach * This program is distributed in the hope that it will be useful, but WITHOUT 9e93b6deeSLucas Stach * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10e93b6deeSLucas Stach * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11e93b6deeSLucas Stach * more details. 12e93b6deeSLucas Stach * 13e93b6deeSLucas Stach * You should have received a copy of the GNU General Public License along with 14e93b6deeSLucas Stach * this program. If not, see <http://www.gnu.org/licenses/>. 15e93b6deeSLucas Stach */ 16e93b6deeSLucas Stach 17e93b6deeSLucas Stach #include <drm/gpu_scheduler.h> 18e93b6deeSLucas Stach #include <linux/kthread.h> 19e93b6deeSLucas Stach 20e93b6deeSLucas Stach #include "etnaviv_drv.h" 21e93b6deeSLucas Stach #include "etnaviv_gem.h" 22e93b6deeSLucas Stach #include "etnaviv_gpu.h" 23e93b6deeSLucas Stach 24e93b6deeSLucas Stach static int etnaviv_job_hang_limit = 0; 25e93b6deeSLucas Stach module_param_named(job_hang_limit, etnaviv_job_hang_limit, int , 0444); 26e93b6deeSLucas Stach static int etnaviv_hw_jobs_limit = 2; 27e93b6deeSLucas Stach module_param_named(hw_job_limit, etnaviv_hw_jobs_limit, int , 0444); 28e93b6deeSLucas Stach 29e93b6deeSLucas Stach static inline 30e93b6deeSLucas Stach struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job) 31e93b6deeSLucas Stach { 32e93b6deeSLucas Stach return container_of(sched_job, struct etnaviv_gem_submit, sched_job); 33e93b6deeSLucas Stach } 34e93b6deeSLucas Stach 35e93b6deeSLucas Stach struct dma_fence *etnaviv_sched_dependency(struct drm_sched_job *sched_job, 36e93b6deeSLucas Stach struct drm_sched_entity *entity) 37e93b6deeSLucas Stach { 38683da226SLucas Stach struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); 39683da226SLucas Stach struct dma_fence *fence; 40683da226SLucas Stach int i; 41683da226SLucas Stach 42683da226SLucas Stach if (unlikely(submit->in_fence)) { 43683da226SLucas Stach fence = submit->in_fence; 44683da226SLucas Stach submit->in_fence = NULL; 45683da226SLucas Stach 46683da226SLucas Stach if (!dma_fence_is_signaled(fence)) 47683da226SLucas Stach return fence; 48683da226SLucas Stach 49683da226SLucas Stach dma_fence_put(fence); 50683da226SLucas Stach } 51683da226SLucas Stach 52683da226SLucas Stach for (i = 0; i < submit->nr_bos; i++) { 53683da226SLucas Stach struct etnaviv_gem_submit_bo *bo = &submit->bos[i]; 54683da226SLucas Stach int j; 55683da226SLucas Stach 56683da226SLucas Stach if (bo->excl) { 57683da226SLucas Stach fence = bo->excl; 58683da226SLucas Stach bo->excl = NULL; 59683da226SLucas Stach 60683da226SLucas Stach if (!dma_fence_is_signaled(fence)) 61683da226SLucas Stach return fence; 62683da226SLucas Stach 63683da226SLucas Stach dma_fence_put(fence); 64683da226SLucas Stach } 65683da226SLucas Stach 66683da226SLucas Stach for (j = 0; j < bo->nr_shared; j++) { 67683da226SLucas Stach if (!bo->shared[j]) 68683da226SLucas Stach continue; 69683da226SLucas Stach 70683da226SLucas Stach fence = bo->shared[j]; 71683da226SLucas Stach bo->shared[j] = NULL; 72683da226SLucas Stach 73683da226SLucas Stach if (!dma_fence_is_signaled(fence)) 74683da226SLucas Stach return fence; 75683da226SLucas Stach 76683da226SLucas Stach dma_fence_put(fence); 77683da226SLucas Stach } 78683da226SLucas Stach kfree(bo->shared); 79683da226SLucas Stach bo->nr_shared = 0; 80683da226SLucas Stach bo->shared = NULL; 81683da226SLucas Stach } 82683da226SLucas Stach 83e93b6deeSLucas Stach return NULL; 84e93b6deeSLucas Stach } 85e93b6deeSLucas Stach 86e93b6deeSLucas Stach struct dma_fence *etnaviv_sched_run_job(struct drm_sched_job *sched_job) 87e93b6deeSLucas Stach { 88e93b6deeSLucas Stach struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); 89e93b6deeSLucas Stach struct dma_fence *fence; 90e93b6deeSLucas Stach 91e93b6deeSLucas Stach mutex_lock(&submit->gpu->lock); 92e93b6deeSLucas Stach list_add_tail(&submit->node, &submit->gpu->active_submit_list); 93e93b6deeSLucas Stach mutex_unlock(&submit->gpu->lock); 94e93b6deeSLucas Stach 95e93b6deeSLucas Stach fence = etnaviv_gpu_submit(submit); 96e93b6deeSLucas Stach if (!fence) { 97e93b6deeSLucas Stach etnaviv_submit_put(submit); 98e93b6deeSLucas Stach return NULL; 99e93b6deeSLucas Stach } 100e93b6deeSLucas Stach 101e93b6deeSLucas Stach return fence; 102e93b6deeSLucas Stach } 103e93b6deeSLucas Stach 104e93b6deeSLucas Stach static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job) 105e93b6deeSLucas Stach { 106e93b6deeSLucas Stach /* this replaces the hangcheck */ 107e93b6deeSLucas Stach } 108e93b6deeSLucas Stach 109e93b6deeSLucas Stach static void etnaviv_sched_free_job(struct drm_sched_job *sched_job) 110e93b6deeSLucas Stach { 111e93b6deeSLucas Stach struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); 112e93b6deeSLucas Stach 113e93b6deeSLucas Stach mutex_lock(&submit->gpu->lock); 114e93b6deeSLucas Stach list_del(&submit->node); 115e93b6deeSLucas Stach mutex_unlock(&submit->gpu->lock); 116e93b6deeSLucas Stach 117e93b6deeSLucas Stach etnaviv_submit_put(submit); 118e93b6deeSLucas Stach } 119e93b6deeSLucas Stach 120e93b6deeSLucas Stach static const struct drm_sched_backend_ops etnaviv_sched_ops = { 121e93b6deeSLucas Stach .dependency = etnaviv_sched_dependency, 122e93b6deeSLucas Stach .run_job = etnaviv_sched_run_job, 123e93b6deeSLucas Stach .timedout_job = etnaviv_sched_timedout_job, 124e93b6deeSLucas Stach .free_job = etnaviv_sched_free_job, 125e93b6deeSLucas Stach }; 126e93b6deeSLucas Stach 127e93b6deeSLucas Stach int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, 128e93b6deeSLucas Stach struct etnaviv_gem_submit *submit) 129e93b6deeSLucas Stach { 130e93b6deeSLucas Stach int ret; 131e93b6deeSLucas Stach 132e93b6deeSLucas Stach ret = drm_sched_job_init(&submit->sched_job, &submit->gpu->sched, 133e93b6deeSLucas Stach sched_entity, submit->cmdbuf.ctx); 134e93b6deeSLucas Stach if (ret) 135e93b6deeSLucas Stach return ret; 136e93b6deeSLucas Stach 137e93b6deeSLucas Stach submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished); 138e93b6deeSLucas Stach mutex_lock(&submit->gpu->fence_idr_lock); 139e93b6deeSLucas Stach submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr, 140e93b6deeSLucas Stach submit->out_fence, 0, 141e93b6deeSLucas Stach INT_MAX, GFP_KERNEL); 142e93b6deeSLucas Stach mutex_unlock(&submit->gpu->fence_idr_lock); 143e93b6deeSLucas Stach if (submit->out_fence_id < 0) 144e93b6deeSLucas Stach return -ENOMEM; 145e93b6deeSLucas Stach 146e93b6deeSLucas Stach /* the scheduler holds on to the job now */ 147e93b6deeSLucas Stach kref_get(&submit->refcount); 148e93b6deeSLucas Stach 149e93b6deeSLucas Stach drm_sched_entity_push_job(&submit->sched_job, sched_entity); 150e93b6deeSLucas Stach 151e93b6deeSLucas Stach return 0; 152e93b6deeSLucas Stach } 153e93b6deeSLucas Stach 154e93b6deeSLucas Stach int etnaviv_sched_init(struct etnaviv_gpu *gpu) 155e93b6deeSLucas Stach { 156e93b6deeSLucas Stach int ret; 157e93b6deeSLucas Stach 158e93b6deeSLucas Stach ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, 159e93b6deeSLucas Stach etnaviv_hw_jobs_limit, etnaviv_job_hang_limit, 160e93b6deeSLucas Stach msecs_to_jiffies(500), dev_name(gpu->dev)); 161e93b6deeSLucas Stach if (ret) 162e93b6deeSLucas Stach return ret; 163e93b6deeSLucas Stach 164e93b6deeSLucas Stach return 0; 165e93b6deeSLucas Stach } 166e93b6deeSLucas Stach 167e93b6deeSLucas Stach void etnaviv_sched_fini(struct etnaviv_gpu *gpu) 168e93b6deeSLucas Stach { 169e93b6deeSLucas Stach drm_sched_fini(&gpu->sched); 170e93b6deeSLucas Stach } 171