162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/slab.h> 462306a36Sopenharmony_ci#include <drm/gpu_scheduler.h> 562306a36Sopenharmony_ci#include <drm/drm_syncobj.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "nouveau_drv.h" 862306a36Sopenharmony_ci#include "nouveau_gem.h" 962306a36Sopenharmony_ci#include "nouveau_mem.h" 1062306a36Sopenharmony_ci#include "nouveau_dma.h" 1162306a36Sopenharmony_ci#include "nouveau_exec.h" 1262306a36Sopenharmony_ci#include "nouveau_abi16.h" 1362306a36Sopenharmony_ci#include "nouveau_sched.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* FIXME 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * We want to make sure that jobs currently executing can't be deferred by 1862306a36Sopenharmony_ci * other jobs competing for the hardware. Otherwise we might end up with job 1962306a36Sopenharmony_ci * timeouts just because of too many clients submitting too many jobs. We don't 2062306a36Sopenharmony_ci * want jobs to time out because of system load, but because of the job being 2162306a36Sopenharmony_ci * too bulky. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * For now allow for up to 16 concurrent jobs in flight until we know how many 2462306a36Sopenharmony_ci * rings the hardware can process in parallel. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci#define NOUVEAU_SCHED_HW_SUBMISSIONS 16 2762306a36Sopenharmony_ci#define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciint 3062306a36Sopenharmony_cinouveau_job_init(struct nouveau_job *job, 3162306a36Sopenharmony_ci struct nouveau_job_args *args) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct nouveau_sched_entity *entity = args->sched_entity; 3462306a36Sopenharmony_ci int ret; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci job->file_priv = args->file_priv; 3762306a36Sopenharmony_ci job->cli = nouveau_cli(args->file_priv); 3862306a36Sopenharmony_ci job->entity = entity; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci job->sync = args->sync; 4162306a36Sopenharmony_ci job->resv_usage = args->resv_usage; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci job->ops = args->ops; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci job->in_sync.count = args->in_sync.count; 4662306a36Sopenharmony_ci if (job->in_sync.count) { 4762306a36Sopenharmony_ci if (job->sync) 4862306a36Sopenharmony_ci return -EINVAL; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci job->in_sync.data = kmemdup(args->in_sync.s, 5162306a36Sopenharmony_ci sizeof(*args->in_sync.s) * 5262306a36Sopenharmony_ci args->in_sync.count, 5362306a36Sopenharmony_ci GFP_KERNEL); 5462306a36Sopenharmony_ci if (!job->in_sync.data) 5562306a36Sopenharmony_ci return -ENOMEM; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci job->out_sync.count = args->out_sync.count; 5962306a36Sopenharmony_ci if (job->out_sync.count) { 6062306a36Sopenharmony_ci if (job->sync) { 6162306a36Sopenharmony_ci ret = -EINVAL; 6262306a36Sopenharmony_ci goto err_free_in_sync; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci job->out_sync.data = kmemdup(args->out_sync.s, 6662306a36Sopenharmony_ci sizeof(*args->out_sync.s) * 6762306a36Sopenharmony_ci args->out_sync.count, 6862306a36Sopenharmony_ci GFP_KERNEL); 6962306a36Sopenharmony_ci if (!job->out_sync.data) { 7062306a36Sopenharmony_ci ret = -ENOMEM; 7162306a36Sopenharmony_ci goto err_free_in_sync; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci job->out_sync.objs = kcalloc(job->out_sync.count, 7562306a36Sopenharmony_ci sizeof(*job->out_sync.objs), 7662306a36Sopenharmony_ci GFP_KERNEL); 7762306a36Sopenharmony_ci if (!job->out_sync.objs) { 7862306a36Sopenharmony_ci ret = -ENOMEM; 7962306a36Sopenharmony_ci goto err_free_out_sync; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci job->out_sync.chains = kcalloc(job->out_sync.count, 8362306a36Sopenharmony_ci sizeof(*job->out_sync.chains), 8462306a36Sopenharmony_ci GFP_KERNEL); 8562306a36Sopenharmony_ci if (!job->out_sync.chains) { 8662306a36Sopenharmony_ci ret = -ENOMEM; 8762306a36Sopenharmony_ci goto err_free_objs; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ret = drm_sched_job_init(&job->base, &entity->base, NULL); 9362306a36Sopenharmony_ci if (ret) 9462306a36Sopenharmony_ci goto err_free_chains; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci job->state = NOUVEAU_JOB_INITIALIZED; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cierr_free_chains: 10162306a36Sopenharmony_ci kfree(job->out_sync.chains); 10262306a36Sopenharmony_cierr_free_objs: 10362306a36Sopenharmony_ci kfree(job->out_sync.objs); 10462306a36Sopenharmony_cierr_free_out_sync: 10562306a36Sopenharmony_ci kfree(job->out_sync.data); 10662306a36Sopenharmony_cierr_free_in_sync: 10762306a36Sopenharmony_ci kfree(job->in_sync.data); 10862306a36Sopenharmony_cireturn ret; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_civoid 11262306a36Sopenharmony_cinouveau_job_free(struct nouveau_job *job) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci kfree(job->in_sync.data); 11562306a36Sopenharmony_ci kfree(job->out_sync.data); 11662306a36Sopenharmony_ci kfree(job->out_sync.objs); 11762306a36Sopenharmony_ci kfree(job->out_sync.chains); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_civoid nouveau_job_fini(struct nouveau_job *job) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci dma_fence_put(job->done_fence); 12362306a36Sopenharmony_ci drm_sched_job_cleanup(&job->base); 12462306a36Sopenharmony_ci job->ops->free(job); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int 12862306a36Sopenharmony_cisync_find_fence(struct nouveau_job *job, 12962306a36Sopenharmony_ci struct drm_nouveau_sync *sync, 13062306a36Sopenharmony_ci struct dma_fence **fence) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 13362306a36Sopenharmony_ci u64 point = 0; 13462306a36Sopenharmony_ci int ret; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && 13762306a36Sopenharmony_ci stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) 13862306a36Sopenharmony_ci return -EOPNOTSUPP; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) 14162306a36Sopenharmony_ci point = sync->timeline_value; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci ret = drm_syncobj_find_fence(job->file_priv, 14462306a36Sopenharmony_ci sync->handle, point, 14562306a36Sopenharmony_ci 0 /* flags */, fence); 14662306a36Sopenharmony_ci if (ret) 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int 15362306a36Sopenharmony_cinouveau_job_add_deps(struct nouveau_job *job) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct dma_fence *in_fence = NULL; 15662306a36Sopenharmony_ci int ret, i; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci for (i = 0; i < job->in_sync.count; i++) { 15962306a36Sopenharmony_ci struct drm_nouveau_sync *sync = &job->in_sync.data[i]; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci ret = sync_find_fence(job, sync, &in_fence); 16262306a36Sopenharmony_ci if (ret) { 16362306a36Sopenharmony_ci NV_PRINTK(warn, job->cli, 16462306a36Sopenharmony_ci "Failed to find syncobj (-> in): handle=%d\n", 16562306a36Sopenharmony_ci sync->handle); 16662306a36Sopenharmony_ci return ret; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ret = drm_sched_job_add_dependency(&job->base, in_fence); 17062306a36Sopenharmony_ci if (ret) 17162306a36Sopenharmony_ci return ret; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void 17862306a36Sopenharmony_cinouveau_job_fence_attach_cleanup(struct nouveau_job *job) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci int i; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci for (i = 0; i < job->out_sync.count; i++) { 18362306a36Sopenharmony_ci struct drm_syncobj *obj = job->out_sync.objs[i]; 18462306a36Sopenharmony_ci struct dma_fence_chain *chain = job->out_sync.chains[i]; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (obj) 18762306a36Sopenharmony_ci drm_syncobj_put(obj); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (chain) 19062306a36Sopenharmony_ci dma_fence_chain_free(chain); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int 19562306a36Sopenharmony_cinouveau_job_fence_attach_prepare(struct nouveau_job *job) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int i, ret; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci for (i = 0; i < job->out_sync.count; i++) { 20062306a36Sopenharmony_ci struct drm_nouveau_sync *sync = &job->out_sync.data[i]; 20162306a36Sopenharmony_ci struct drm_syncobj **pobj = &job->out_sync.objs[i]; 20262306a36Sopenharmony_ci struct dma_fence_chain **pchain = &job->out_sync.chains[i]; 20362306a36Sopenharmony_ci u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && 20662306a36Sopenharmony_ci stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 20762306a36Sopenharmony_ci ret = -EINVAL; 20862306a36Sopenharmony_ci goto err_sync_cleanup; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci *pobj = drm_syncobj_find(job->file_priv, sync->handle); 21262306a36Sopenharmony_ci if (!*pobj) { 21362306a36Sopenharmony_ci NV_PRINTK(warn, job->cli, 21462306a36Sopenharmony_ci "Failed to find syncobj (-> out): handle=%d\n", 21562306a36Sopenharmony_ci sync->handle); 21662306a36Sopenharmony_ci ret = -ENOENT; 21762306a36Sopenharmony_ci goto err_sync_cleanup; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 22162306a36Sopenharmony_ci *pchain = dma_fence_chain_alloc(); 22262306a36Sopenharmony_ci if (!*pchain) { 22362306a36Sopenharmony_ci ret = -ENOMEM; 22462306a36Sopenharmony_ci goto err_sync_cleanup; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cierr_sync_cleanup: 23262306a36Sopenharmony_ci nouveau_job_fence_attach_cleanup(job); 23362306a36Sopenharmony_ci return ret; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void 23762306a36Sopenharmony_cinouveau_job_fence_attach(struct nouveau_job *job) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct dma_fence *fence = job->done_fence; 24062306a36Sopenharmony_ci int i; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci for (i = 0; i < job->out_sync.count; i++) { 24362306a36Sopenharmony_ci struct drm_nouveau_sync *sync = &job->out_sync.data[i]; 24462306a36Sopenharmony_ci struct drm_syncobj **pobj = &job->out_sync.objs[i]; 24562306a36Sopenharmony_ci struct dma_fence_chain **pchain = &job->out_sync.chains[i]; 24662306a36Sopenharmony_ci u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 24962306a36Sopenharmony_ci drm_syncobj_add_point(*pobj, *pchain, fence, 25062306a36Sopenharmony_ci sync->timeline_value); 25162306a36Sopenharmony_ci } else { 25262306a36Sopenharmony_ci drm_syncobj_replace_fence(*pobj, fence); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci drm_syncobj_put(*pobj); 25662306a36Sopenharmony_ci *pobj = NULL; 25762306a36Sopenharmony_ci *pchain = NULL; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ciint 26262306a36Sopenharmony_cinouveau_job_submit(struct nouveau_job *job) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct nouveau_sched_entity *entity = to_nouveau_sched_entity(job->base.entity); 26562306a36Sopenharmony_ci struct dma_fence *done_fence = NULL; 26662306a36Sopenharmony_ci int ret; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci ret = nouveau_job_add_deps(job); 26962306a36Sopenharmony_ci if (ret) 27062306a36Sopenharmony_ci goto err; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ret = nouveau_job_fence_attach_prepare(job); 27362306a36Sopenharmony_ci if (ret) 27462306a36Sopenharmony_ci goto err; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Make sure the job appears on the sched_entity's queue in the same 27762306a36Sopenharmony_ci * order as it was submitted. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci mutex_lock(&entity->mutex); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Guarantee we won't fail after the submit() callback returned 28262306a36Sopenharmony_ci * successfully. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci if (job->ops->submit) { 28562306a36Sopenharmony_ci ret = job->ops->submit(job); 28662306a36Sopenharmony_ci if (ret) 28762306a36Sopenharmony_ci goto err_cleanup; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci drm_sched_job_arm(&job->base); 29162306a36Sopenharmony_ci job->done_fence = dma_fence_get(&job->base.s_fence->finished); 29262306a36Sopenharmony_ci if (job->sync) 29362306a36Sopenharmony_ci done_fence = dma_fence_get(job->done_fence); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* If a sched job depends on a dma-fence from a job from the same GPU 29662306a36Sopenharmony_ci * scheduler instance, but a different scheduler entity, the GPU 29762306a36Sopenharmony_ci * scheduler does only wait for the particular job to be scheduled, 29862306a36Sopenharmony_ci * rather than for the job to fully complete. This is due to the GPU 29962306a36Sopenharmony_ci * scheduler assuming that there is a scheduler instance per ring. 30062306a36Sopenharmony_ci * However, the current implementation, in order to avoid arbitrary 30162306a36Sopenharmony_ci * amounts of kthreads, has a single scheduler instance while scheduler 30262306a36Sopenharmony_ci * entities represent rings. 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * As a workaround, set the DRM_SCHED_FENCE_DONT_PIPELINE for all 30562306a36Sopenharmony_ci * out-fences in order to force the scheduler to wait for full job 30662306a36Sopenharmony_ci * completion for dependent jobs from different entities and same 30762306a36Sopenharmony_ci * scheduler instance. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * There is some work in progress [1] to address the issues of firmware 31062306a36Sopenharmony_ci * schedulers; once it is in-tree the scheduler topology in Nouveau 31162306a36Sopenharmony_ci * should be re-worked accordingly. 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * [1] https://lore.kernel.org/dri-devel/20230801205103.627779-1-matthew.brost@intel.com/ 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci set_bit(DRM_SCHED_FENCE_DONT_PIPELINE, &job->done_fence->flags); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (job->ops->armed_submit) 31862306a36Sopenharmony_ci job->ops->armed_submit(job); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci nouveau_job_fence_attach(job); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Set job state before pushing the job to the scheduler, 32362306a36Sopenharmony_ci * such that we do not overwrite the job state set in run(). 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci job->state = NOUVEAU_JOB_SUBMIT_SUCCESS; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci drm_sched_entity_push_job(&job->base); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci mutex_unlock(&entity->mutex); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (done_fence) { 33262306a36Sopenharmony_ci dma_fence_wait(done_fence, true); 33362306a36Sopenharmony_ci dma_fence_put(done_fence); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cierr_cleanup: 33962306a36Sopenharmony_ci mutex_unlock(&entity->mutex); 34062306a36Sopenharmony_ci nouveau_job_fence_attach_cleanup(job); 34162306a36Sopenharmony_cierr: 34262306a36Sopenharmony_ci job->state = NOUVEAU_JOB_SUBMIT_FAILED; 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cibool 34762306a36Sopenharmony_cinouveau_sched_entity_qwork(struct nouveau_sched_entity *entity, 34862306a36Sopenharmony_ci struct work_struct *work) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci return queue_work(entity->sched_wq, work); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic struct dma_fence * 35462306a36Sopenharmony_cinouveau_job_run(struct nouveau_job *job) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct dma_fence *fence; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci fence = job->ops->run(job); 35962306a36Sopenharmony_ci if (IS_ERR(fence)) 36062306a36Sopenharmony_ci job->state = NOUVEAU_JOB_RUN_FAILED; 36162306a36Sopenharmony_ci else 36262306a36Sopenharmony_ci job->state = NOUVEAU_JOB_RUN_SUCCESS; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return fence; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic struct dma_fence * 36862306a36Sopenharmony_cinouveau_sched_run_job(struct drm_sched_job *sched_job) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct nouveau_job *job = to_nouveau_job(sched_job); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return nouveau_job_run(job); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic enum drm_gpu_sched_stat 37662306a36Sopenharmony_cinouveau_sched_timedout_job(struct drm_sched_job *sched_job) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct drm_gpu_scheduler *sched = sched_job->sched; 37962306a36Sopenharmony_ci struct nouveau_job *job = to_nouveau_job(sched_job); 38062306a36Sopenharmony_ci enum drm_gpu_sched_stat stat = DRM_GPU_SCHED_STAT_NOMINAL; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci drm_sched_stop(sched, sched_job); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (job->ops->timeout) 38562306a36Sopenharmony_ci stat = job->ops->timeout(job); 38662306a36Sopenharmony_ci else 38762306a36Sopenharmony_ci NV_PRINTK(warn, job->cli, "Generic job timeout.\n"); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci drm_sched_start(sched, true); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return stat; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void 39562306a36Sopenharmony_cinouveau_sched_free_job(struct drm_sched_job *sched_job) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct nouveau_job *job = to_nouveau_job(sched_job); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci nouveau_job_fini(job); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciint nouveau_sched_entity_init(struct nouveau_sched_entity *entity, 40362306a36Sopenharmony_ci struct drm_gpu_scheduler *sched, 40462306a36Sopenharmony_ci struct workqueue_struct *sched_wq) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci mutex_init(&entity->mutex); 40762306a36Sopenharmony_ci spin_lock_init(&entity->job.list.lock); 40862306a36Sopenharmony_ci INIT_LIST_HEAD(&entity->job.list.head); 40962306a36Sopenharmony_ci init_waitqueue_head(&entity->job.wq); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci entity->sched_wq = sched_wq; 41262306a36Sopenharmony_ci return drm_sched_entity_init(&entity->base, 41362306a36Sopenharmony_ci DRM_SCHED_PRIORITY_NORMAL, 41462306a36Sopenharmony_ci &sched, 1, NULL); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_civoid 41862306a36Sopenharmony_cinouveau_sched_entity_fini(struct nouveau_sched_entity *entity) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci drm_sched_entity_destroy(&entity->base); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic const struct drm_sched_backend_ops nouveau_sched_ops = { 42462306a36Sopenharmony_ci .run_job = nouveau_sched_run_job, 42562306a36Sopenharmony_ci .timedout_job = nouveau_sched_timedout_job, 42662306a36Sopenharmony_ci .free_job = nouveau_sched_free_job, 42762306a36Sopenharmony_ci}; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciint nouveau_sched_init(struct nouveau_drm *drm) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct drm_gpu_scheduler *sched = &drm->sched; 43262306a36Sopenharmony_ci long job_hang_limit = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci drm->sched_wq = create_singlethread_workqueue("nouveau_sched_wq"); 43562306a36Sopenharmony_ci if (!drm->sched_wq) 43662306a36Sopenharmony_ci return -ENOMEM; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return drm_sched_init(sched, &nouveau_sched_ops, 43962306a36Sopenharmony_ci NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, 44062306a36Sopenharmony_ci NULL, NULL, "nouveau_sched", drm->dev->dev); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_civoid nouveau_sched_fini(struct nouveau_drm *drm) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci destroy_workqueue(drm->sched_wq); 44662306a36Sopenharmony_ci drm_sched_fini(&drm->sched); 44762306a36Sopenharmony_ci} 448