1b88baab8SDanilo Krummrich // SPDX-License-Identifier: MIT 2b88baab8SDanilo Krummrich 3b88baab8SDanilo Krummrich #include <linux/slab.h> 4b88baab8SDanilo Krummrich #include <drm/gpu_scheduler.h> 5b88baab8SDanilo Krummrich #include <drm/drm_syncobj.h> 6b88baab8SDanilo Krummrich 7b88baab8SDanilo Krummrich #include "nouveau_drv.h" 8b88baab8SDanilo Krummrich #include "nouveau_gem.h" 9b88baab8SDanilo Krummrich #include "nouveau_mem.h" 10b88baab8SDanilo Krummrich #include "nouveau_dma.h" 11b88baab8SDanilo Krummrich #include "nouveau_exec.h" 12b88baab8SDanilo Krummrich #include "nouveau_abi16.h" 13b88baab8SDanilo Krummrich #include "nouveau_sched.h" 14b88baab8SDanilo Krummrich 15b88baab8SDanilo Krummrich /* FIXME 16b88baab8SDanilo Krummrich * 17b88baab8SDanilo Krummrich * We want to make sure that jobs currently executing can't be deferred by 18b88baab8SDanilo Krummrich * other jobs competing for the hardware. Otherwise we might end up with job 19b88baab8SDanilo Krummrich * timeouts just because of too many clients submitting too many jobs. We don't 20b88baab8SDanilo Krummrich * want jobs to time out because of system load, but because of the job being 21b88baab8SDanilo Krummrich * too bulky. 22b88baab8SDanilo Krummrich * 23b88baab8SDanilo Krummrich * For now allow for up to 16 concurrent jobs in flight until we know how many 24b88baab8SDanilo Krummrich * rings the hardware can process in parallel. 25b88baab8SDanilo Krummrich */ 26b88baab8SDanilo Krummrich #define NOUVEAU_SCHED_HW_SUBMISSIONS 16 27b88baab8SDanilo Krummrich #define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 28b88baab8SDanilo Krummrich 29b88baab8SDanilo Krummrich int 30b88baab8SDanilo Krummrich nouveau_job_init(struct nouveau_job *job, 31b88baab8SDanilo Krummrich struct nouveau_job_args *args) 32b88baab8SDanilo Krummrich { 33b88baab8SDanilo Krummrich struct nouveau_sched_entity *entity = args->sched_entity; 34b88baab8SDanilo Krummrich int ret; 35b88baab8SDanilo Krummrich 36b88baab8SDanilo Krummrich job->file_priv = args->file_priv; 37b88baab8SDanilo Krummrich job->cli = nouveau_cli(args->file_priv); 38b88baab8SDanilo Krummrich job->entity = entity; 39b88baab8SDanilo Krummrich 40b88baab8SDanilo Krummrich job->sync = args->sync; 41b88baab8SDanilo Krummrich job->resv_usage = args->resv_usage; 42b88baab8SDanilo Krummrich 43b88baab8SDanilo Krummrich job->ops = args->ops; 44b88baab8SDanilo Krummrich 45b88baab8SDanilo Krummrich job->in_sync.count = args->in_sync.count; 46b88baab8SDanilo Krummrich if (job->in_sync.count) { 47b88baab8SDanilo Krummrich if (job->sync) 48b88baab8SDanilo Krummrich return -EINVAL; 49b88baab8SDanilo Krummrich 50b88baab8SDanilo Krummrich job->in_sync.data = kmemdup(args->in_sync.s, 51b88baab8SDanilo Krummrich sizeof(*args->in_sync.s) * 52b88baab8SDanilo Krummrich args->in_sync.count, 53b88baab8SDanilo Krummrich GFP_KERNEL); 54b88baab8SDanilo Krummrich if (!job->in_sync.data) 55b88baab8SDanilo Krummrich return -ENOMEM; 56b88baab8SDanilo Krummrich } 57b88baab8SDanilo Krummrich 58b88baab8SDanilo Krummrich job->out_sync.count = args->out_sync.count; 59b88baab8SDanilo Krummrich if (job->out_sync.count) { 60b88baab8SDanilo Krummrich if (job->sync) { 61b88baab8SDanilo Krummrich ret = -EINVAL; 62b88baab8SDanilo Krummrich goto err_free_in_sync; 63b88baab8SDanilo Krummrich } 64b88baab8SDanilo Krummrich 65b88baab8SDanilo Krummrich job->out_sync.data = kmemdup(args->out_sync.s, 66b88baab8SDanilo Krummrich sizeof(*args->out_sync.s) * 67b88baab8SDanilo Krummrich args->out_sync.count, 68b88baab8SDanilo Krummrich GFP_KERNEL); 69b88baab8SDanilo Krummrich if (!job->out_sync.data) { 70b88baab8SDanilo Krummrich ret = -ENOMEM; 71b88baab8SDanilo Krummrich goto err_free_in_sync; 72b88baab8SDanilo Krummrich } 73b88baab8SDanilo Krummrich 74b88baab8SDanilo Krummrich job->out_sync.objs = kcalloc(job->out_sync.count, 75b88baab8SDanilo Krummrich sizeof(*job->out_sync.objs), 76b88baab8SDanilo Krummrich GFP_KERNEL); 77b88baab8SDanilo Krummrich if (!job->out_sync.objs) { 78b88baab8SDanilo Krummrich ret = -ENOMEM; 79b88baab8SDanilo Krummrich goto err_free_out_sync; 80b88baab8SDanilo Krummrich } 81b88baab8SDanilo Krummrich 82b88baab8SDanilo Krummrich job->out_sync.chains = kcalloc(job->out_sync.count, 83b88baab8SDanilo Krummrich sizeof(*job->out_sync.chains), 84b88baab8SDanilo Krummrich GFP_KERNEL); 85b88baab8SDanilo Krummrich if (!job->out_sync.chains) { 86b88baab8SDanilo Krummrich ret = -ENOMEM; 87b88baab8SDanilo Krummrich goto err_free_objs; 88b88baab8SDanilo Krummrich } 89b88baab8SDanilo Krummrich 90b88baab8SDanilo Krummrich } 91b88baab8SDanilo Krummrich 92a78422e9SDanilo Krummrich ret = drm_sched_job_init(&job->base, &entity->base, 1, NULL); 93b88baab8SDanilo Krummrich if (ret) 94b88baab8SDanilo Krummrich goto err_free_chains; 95b88baab8SDanilo Krummrich 96b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_INITIALIZED; 97b88baab8SDanilo Krummrich 98b88baab8SDanilo Krummrich return 0; 99b88baab8SDanilo Krummrich 100b88baab8SDanilo Krummrich err_free_chains: 101b88baab8SDanilo Krummrich kfree(job->out_sync.chains); 102b88baab8SDanilo Krummrich err_free_objs: 103b88baab8SDanilo Krummrich kfree(job->out_sync.objs); 104b88baab8SDanilo Krummrich err_free_out_sync: 105b88baab8SDanilo Krummrich kfree(job->out_sync.data); 106b88baab8SDanilo Krummrich err_free_in_sync: 107b88baab8SDanilo Krummrich kfree(job->in_sync.data); 108b88baab8SDanilo Krummrich return ret; 109b88baab8SDanilo Krummrich } 110b88baab8SDanilo Krummrich 111b88baab8SDanilo Krummrich void 112b88baab8SDanilo Krummrich nouveau_job_free(struct nouveau_job *job) 113b88baab8SDanilo Krummrich { 114b88baab8SDanilo Krummrich kfree(job->in_sync.data); 115b88baab8SDanilo Krummrich kfree(job->out_sync.data); 116b88baab8SDanilo Krummrich kfree(job->out_sync.objs); 117b88baab8SDanilo Krummrich kfree(job->out_sync.chains); 118b88baab8SDanilo Krummrich } 119b88baab8SDanilo Krummrich 120b88baab8SDanilo Krummrich void nouveau_job_fini(struct nouveau_job *job) 121b88baab8SDanilo Krummrich { 122b88baab8SDanilo Krummrich dma_fence_put(job->done_fence); 123b88baab8SDanilo Krummrich drm_sched_job_cleanup(&job->base); 124b88baab8SDanilo Krummrich job->ops->free(job); 125b88baab8SDanilo Krummrich } 126b88baab8SDanilo Krummrich 127b88baab8SDanilo Krummrich static int 128b88baab8SDanilo Krummrich sync_find_fence(struct nouveau_job *job, 129b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync, 130b88baab8SDanilo Krummrich struct dma_fence **fence) 131b88baab8SDanilo Krummrich { 132b88baab8SDanilo Krummrich u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 133b88baab8SDanilo Krummrich u64 point = 0; 134b88baab8SDanilo Krummrich int ret; 135b88baab8SDanilo Krummrich 136b88baab8SDanilo Krummrich if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && 137b88baab8SDanilo Krummrich stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) 138b88baab8SDanilo Krummrich return -EOPNOTSUPP; 139b88baab8SDanilo Krummrich 140b88baab8SDanilo Krummrich if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) 141b88baab8SDanilo Krummrich point = sync->timeline_value; 142b88baab8SDanilo Krummrich 143b88baab8SDanilo Krummrich ret = drm_syncobj_find_fence(job->file_priv, 144b88baab8SDanilo Krummrich sync->handle, point, 145e05f3938SFaith Ekstrand 0 /* flags */, fence); 146b88baab8SDanilo Krummrich if (ret) 147b88baab8SDanilo Krummrich return ret; 148b88baab8SDanilo Krummrich 149b88baab8SDanilo Krummrich return 0; 150b88baab8SDanilo Krummrich } 151b88baab8SDanilo Krummrich 152b88baab8SDanilo Krummrich static int 153b88baab8SDanilo Krummrich nouveau_job_add_deps(struct nouveau_job *job) 154b88baab8SDanilo Krummrich { 155b88baab8SDanilo Krummrich struct dma_fence *in_fence = NULL; 156b88baab8SDanilo Krummrich int ret, i; 157b88baab8SDanilo Krummrich 158b88baab8SDanilo Krummrich for (i = 0; i < job->in_sync.count; i++) { 159b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync = &job->in_sync.data[i]; 160b88baab8SDanilo Krummrich 161b88baab8SDanilo Krummrich ret = sync_find_fence(job, sync, &in_fence); 162b88baab8SDanilo Krummrich if (ret) { 163b88baab8SDanilo Krummrich NV_PRINTK(warn, job->cli, 164b88baab8SDanilo Krummrich "Failed to find syncobj (-> in): handle=%d\n", 165b88baab8SDanilo Krummrich sync->handle); 166b88baab8SDanilo Krummrich return ret; 167b88baab8SDanilo Krummrich } 168b88baab8SDanilo Krummrich 169b88baab8SDanilo Krummrich ret = drm_sched_job_add_dependency(&job->base, in_fence); 170b88baab8SDanilo Krummrich if (ret) 171b88baab8SDanilo Krummrich return ret; 172b88baab8SDanilo Krummrich } 173b88baab8SDanilo Krummrich 174b88baab8SDanilo Krummrich return 0; 175b88baab8SDanilo Krummrich } 176b88baab8SDanilo Krummrich 177b88baab8SDanilo Krummrich static void 178b88baab8SDanilo Krummrich nouveau_job_fence_attach_cleanup(struct nouveau_job *job) 179b88baab8SDanilo Krummrich { 180b88baab8SDanilo Krummrich int i; 181b88baab8SDanilo Krummrich 182b88baab8SDanilo Krummrich for (i = 0; i < job->out_sync.count; i++) { 183b88baab8SDanilo Krummrich struct drm_syncobj *obj = job->out_sync.objs[i]; 184b88baab8SDanilo Krummrich struct dma_fence_chain *chain = job->out_sync.chains[i]; 185b88baab8SDanilo Krummrich 186b88baab8SDanilo Krummrich if (obj) 187b88baab8SDanilo Krummrich drm_syncobj_put(obj); 188b88baab8SDanilo Krummrich 189b88baab8SDanilo Krummrich if (chain) 190b88baab8SDanilo Krummrich dma_fence_chain_free(chain); 191b88baab8SDanilo Krummrich } 192b88baab8SDanilo Krummrich } 193b88baab8SDanilo Krummrich 194b88baab8SDanilo Krummrich static int 195b88baab8SDanilo Krummrich nouveau_job_fence_attach_prepare(struct nouveau_job *job) 196b88baab8SDanilo Krummrich { 197b88baab8SDanilo Krummrich int i, ret; 198b88baab8SDanilo Krummrich 199b88baab8SDanilo Krummrich for (i = 0; i < job->out_sync.count; i++) { 200b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync = &job->out_sync.data[i]; 201b88baab8SDanilo Krummrich struct drm_syncobj **pobj = &job->out_sync.objs[i]; 202b88baab8SDanilo Krummrich struct dma_fence_chain **pchain = &job->out_sync.chains[i]; 203b88baab8SDanilo Krummrich u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 204b88baab8SDanilo Krummrich 205b88baab8SDanilo Krummrich if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && 206b88baab8SDanilo Krummrich stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 207b88baab8SDanilo Krummrich ret = -EINVAL; 208b88baab8SDanilo Krummrich goto err_sync_cleanup; 209b88baab8SDanilo Krummrich } 210b88baab8SDanilo Krummrich 211b88baab8SDanilo Krummrich *pobj = drm_syncobj_find(job->file_priv, sync->handle); 212b88baab8SDanilo Krummrich if (!*pobj) { 213b88baab8SDanilo Krummrich NV_PRINTK(warn, job->cli, 214b88baab8SDanilo Krummrich "Failed to find syncobj (-> out): handle=%d\n", 215b88baab8SDanilo Krummrich sync->handle); 216b88baab8SDanilo Krummrich ret = -ENOENT; 217b88baab8SDanilo Krummrich goto err_sync_cleanup; 218b88baab8SDanilo Krummrich } 219b88baab8SDanilo Krummrich 220b88baab8SDanilo Krummrich if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 221b88baab8SDanilo Krummrich *pchain = dma_fence_chain_alloc(); 222b88baab8SDanilo Krummrich if (!*pchain) { 223b88baab8SDanilo Krummrich ret = -ENOMEM; 224b88baab8SDanilo Krummrich goto err_sync_cleanup; 225b88baab8SDanilo Krummrich } 226b88baab8SDanilo Krummrich } 227b88baab8SDanilo Krummrich } 228b88baab8SDanilo Krummrich 229b88baab8SDanilo Krummrich return 0; 230b88baab8SDanilo Krummrich 231b88baab8SDanilo Krummrich err_sync_cleanup: 232b88baab8SDanilo Krummrich nouveau_job_fence_attach_cleanup(job); 233b88baab8SDanilo Krummrich return ret; 234b88baab8SDanilo Krummrich } 235b88baab8SDanilo Krummrich 236b88baab8SDanilo Krummrich static void 237b88baab8SDanilo Krummrich nouveau_job_fence_attach(struct nouveau_job *job) 238b88baab8SDanilo Krummrich { 239b88baab8SDanilo Krummrich struct dma_fence *fence = job->done_fence; 240b88baab8SDanilo Krummrich int i; 241b88baab8SDanilo Krummrich 242b88baab8SDanilo Krummrich for (i = 0; i < job->out_sync.count; i++) { 243b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync = &job->out_sync.data[i]; 244b88baab8SDanilo Krummrich struct drm_syncobj **pobj = &job->out_sync.objs[i]; 245b88baab8SDanilo Krummrich struct dma_fence_chain **pchain = &job->out_sync.chains[i]; 246b88baab8SDanilo Krummrich u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 247b88baab8SDanilo Krummrich 248b88baab8SDanilo Krummrich if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 249b88baab8SDanilo Krummrich drm_syncobj_add_point(*pobj, *pchain, fence, 250b88baab8SDanilo Krummrich sync->timeline_value); 251b88baab8SDanilo Krummrich } else { 252b88baab8SDanilo Krummrich drm_syncobj_replace_fence(*pobj, fence); 253b88baab8SDanilo Krummrich } 254b88baab8SDanilo Krummrich 255b88baab8SDanilo Krummrich drm_syncobj_put(*pobj); 256b88baab8SDanilo Krummrich *pobj = NULL; 257b88baab8SDanilo Krummrich *pchain = NULL; 258b88baab8SDanilo Krummrich } 259b88baab8SDanilo Krummrich } 260b88baab8SDanilo Krummrich 261b88baab8SDanilo Krummrich int 262b88baab8SDanilo Krummrich nouveau_job_submit(struct nouveau_job *job) 263b88baab8SDanilo Krummrich { 264b88baab8SDanilo Krummrich struct nouveau_sched_entity *entity = to_nouveau_sched_entity(job->base.entity); 265b88baab8SDanilo Krummrich struct dma_fence *done_fence = NULL; 266*014f831aSDanilo Krummrich struct drm_gpuvm_exec vm_exec = { 267*014f831aSDanilo Krummrich .vm = &nouveau_cli_uvmm(job->cli)->base, 268*014f831aSDanilo Krummrich .flags = DRM_EXEC_IGNORE_DUPLICATES, 269*014f831aSDanilo Krummrich .num_fences = 1, 270*014f831aSDanilo Krummrich }; 271b88baab8SDanilo Krummrich int ret; 272b88baab8SDanilo Krummrich 273b88baab8SDanilo Krummrich ret = nouveau_job_add_deps(job); 274b88baab8SDanilo Krummrich if (ret) 275b88baab8SDanilo Krummrich goto err; 276b88baab8SDanilo Krummrich 277b88baab8SDanilo Krummrich ret = nouveau_job_fence_attach_prepare(job); 278b88baab8SDanilo Krummrich if (ret) 279b88baab8SDanilo Krummrich goto err; 280b88baab8SDanilo Krummrich 281b88baab8SDanilo Krummrich /* Make sure the job appears on the sched_entity's queue in the same 282b88baab8SDanilo Krummrich * order as it was submitted. 283b88baab8SDanilo Krummrich */ 284b88baab8SDanilo Krummrich mutex_lock(&entity->mutex); 285b88baab8SDanilo Krummrich 286b88baab8SDanilo Krummrich /* Guarantee we won't fail after the submit() callback returned 287b88baab8SDanilo Krummrich * successfully. 288b88baab8SDanilo Krummrich */ 289b88baab8SDanilo Krummrich if (job->ops->submit) { 290*014f831aSDanilo Krummrich ret = job->ops->submit(job, &vm_exec); 291b88baab8SDanilo Krummrich if (ret) 292b88baab8SDanilo Krummrich goto err_cleanup; 293b88baab8SDanilo Krummrich } 294b88baab8SDanilo Krummrich 295b88baab8SDanilo Krummrich drm_sched_job_arm(&job->base); 296b88baab8SDanilo Krummrich job->done_fence = dma_fence_get(&job->base.s_fence->finished); 297b88baab8SDanilo Krummrich if (job->sync) 298b88baab8SDanilo Krummrich done_fence = dma_fence_get(job->done_fence); 299b88baab8SDanilo Krummrich 3007baf6055SDanilo Krummrich /* If a sched job depends on a dma-fence from a job from the same GPU 3017baf6055SDanilo Krummrich * scheduler instance, but a different scheduler entity, the GPU 3027baf6055SDanilo Krummrich * scheduler does only wait for the particular job to be scheduled, 3037baf6055SDanilo Krummrich * rather than for the job to fully complete. This is due to the GPU 3047baf6055SDanilo Krummrich * scheduler assuming that there is a scheduler instance per ring. 3057baf6055SDanilo Krummrich * However, the current implementation, in order to avoid arbitrary 3067baf6055SDanilo Krummrich * amounts of kthreads, has a single scheduler instance while scheduler 3077baf6055SDanilo Krummrich * entities represent rings. 3087baf6055SDanilo Krummrich * 3097baf6055SDanilo Krummrich * As a workaround, set the DRM_SCHED_FENCE_DONT_PIPELINE for all 3107baf6055SDanilo Krummrich * out-fences in order to force the scheduler to wait for full job 3117baf6055SDanilo Krummrich * completion for dependent jobs from different entities and same 3127baf6055SDanilo Krummrich * scheduler instance. 3137baf6055SDanilo Krummrich * 3147baf6055SDanilo Krummrich * There is some work in progress [1] to address the issues of firmware 3157baf6055SDanilo Krummrich * schedulers; once it is in-tree the scheduler topology in Nouveau 3167baf6055SDanilo Krummrich * should be re-worked accordingly. 3177baf6055SDanilo Krummrich * 3187baf6055SDanilo Krummrich * [1] https://lore.kernel.org/dri-devel/20230801205103.627779-1-matthew.brost@intel.com/ 3197baf6055SDanilo Krummrich */ 3207baf6055SDanilo Krummrich set_bit(DRM_SCHED_FENCE_DONT_PIPELINE, &job->done_fence->flags); 3217baf6055SDanilo Krummrich 322b88baab8SDanilo Krummrich if (job->ops->armed_submit) 323*014f831aSDanilo Krummrich job->ops->armed_submit(job, &vm_exec); 324b88baab8SDanilo Krummrich 325b88baab8SDanilo Krummrich nouveau_job_fence_attach(job); 326b88baab8SDanilo Krummrich 327b88baab8SDanilo Krummrich /* Set job state before pushing the job to the scheduler, 328b88baab8SDanilo Krummrich * such that we do not overwrite the job state set in run(). 329b88baab8SDanilo Krummrich */ 330b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_SUBMIT_SUCCESS; 331b88baab8SDanilo Krummrich 332b88baab8SDanilo Krummrich drm_sched_entity_push_job(&job->base); 333b88baab8SDanilo Krummrich 334b88baab8SDanilo Krummrich mutex_unlock(&entity->mutex); 335b88baab8SDanilo Krummrich 336b88baab8SDanilo Krummrich if (done_fence) { 337b88baab8SDanilo Krummrich dma_fence_wait(done_fence, true); 338b88baab8SDanilo Krummrich dma_fence_put(done_fence); 339b88baab8SDanilo Krummrich } 340b88baab8SDanilo Krummrich 341b88baab8SDanilo Krummrich return 0; 342b88baab8SDanilo Krummrich 343b88baab8SDanilo Krummrich err_cleanup: 344b88baab8SDanilo Krummrich mutex_unlock(&entity->mutex); 345b88baab8SDanilo Krummrich nouveau_job_fence_attach_cleanup(job); 346b88baab8SDanilo Krummrich err: 347b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_SUBMIT_FAILED; 348b88baab8SDanilo Krummrich return ret; 349b88baab8SDanilo Krummrich } 350b88baab8SDanilo Krummrich 351b88baab8SDanilo Krummrich bool 352b88baab8SDanilo Krummrich nouveau_sched_entity_qwork(struct nouveau_sched_entity *entity, 353b88baab8SDanilo Krummrich struct work_struct *work) 354b88baab8SDanilo Krummrich { 355b88baab8SDanilo Krummrich return queue_work(entity->sched_wq, work); 356b88baab8SDanilo Krummrich } 357b88baab8SDanilo Krummrich 358b88baab8SDanilo Krummrich static struct dma_fence * 359b88baab8SDanilo Krummrich nouveau_job_run(struct nouveau_job *job) 360b88baab8SDanilo Krummrich { 361b88baab8SDanilo Krummrich struct dma_fence *fence; 362b88baab8SDanilo Krummrich 363b88baab8SDanilo Krummrich fence = job->ops->run(job); 364b88baab8SDanilo Krummrich if (IS_ERR(fence)) 365b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_RUN_FAILED; 366b88baab8SDanilo Krummrich else 367b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_RUN_SUCCESS; 368b88baab8SDanilo Krummrich 369b88baab8SDanilo Krummrich return fence; 370b88baab8SDanilo Krummrich } 371b88baab8SDanilo Krummrich 372b88baab8SDanilo Krummrich static struct dma_fence * 373b88baab8SDanilo Krummrich nouveau_sched_run_job(struct drm_sched_job *sched_job) 374b88baab8SDanilo Krummrich { 375b88baab8SDanilo Krummrich struct nouveau_job *job = to_nouveau_job(sched_job); 376b88baab8SDanilo Krummrich 377b88baab8SDanilo Krummrich return nouveau_job_run(job); 378b88baab8SDanilo Krummrich } 379b88baab8SDanilo Krummrich 380b88baab8SDanilo Krummrich static enum drm_gpu_sched_stat 381b88baab8SDanilo Krummrich nouveau_sched_timedout_job(struct drm_sched_job *sched_job) 382b88baab8SDanilo Krummrich { 38331499b01SDanilo Krummrich struct drm_gpu_scheduler *sched = sched_job->sched; 384b88baab8SDanilo Krummrich struct nouveau_job *job = to_nouveau_job(sched_job); 38531499b01SDanilo Krummrich enum drm_gpu_sched_stat stat = DRM_GPU_SCHED_STAT_NOMINAL; 386b88baab8SDanilo Krummrich 38731499b01SDanilo Krummrich drm_sched_stop(sched, sched_job); 388b88baab8SDanilo Krummrich 389b88baab8SDanilo Krummrich if (job->ops->timeout) 39031499b01SDanilo Krummrich stat = job->ops->timeout(job); 39131499b01SDanilo Krummrich else 39231499b01SDanilo Krummrich NV_PRINTK(warn, job->cli, "Generic job timeout.\n"); 393b88baab8SDanilo Krummrich 39431499b01SDanilo Krummrich drm_sched_start(sched, true); 39531499b01SDanilo Krummrich 39631499b01SDanilo Krummrich return stat; 397b88baab8SDanilo Krummrich } 398b88baab8SDanilo Krummrich 399b88baab8SDanilo Krummrich static void 400b88baab8SDanilo Krummrich nouveau_sched_free_job(struct drm_sched_job *sched_job) 401b88baab8SDanilo Krummrich { 402b88baab8SDanilo Krummrich struct nouveau_job *job = to_nouveau_job(sched_job); 403b88baab8SDanilo Krummrich 404b88baab8SDanilo Krummrich nouveau_job_fini(job); 405b88baab8SDanilo Krummrich } 406b88baab8SDanilo Krummrich 407b88baab8SDanilo Krummrich int nouveau_sched_entity_init(struct nouveau_sched_entity *entity, 408b88baab8SDanilo Krummrich struct drm_gpu_scheduler *sched, 409b88baab8SDanilo Krummrich struct workqueue_struct *sched_wq) 410b88baab8SDanilo Krummrich { 411b88baab8SDanilo Krummrich mutex_init(&entity->mutex); 412b88baab8SDanilo Krummrich spin_lock_init(&entity->job.list.lock); 413b88baab8SDanilo Krummrich INIT_LIST_HEAD(&entity->job.list.head); 414b88baab8SDanilo Krummrich init_waitqueue_head(&entity->job.wq); 415b88baab8SDanilo Krummrich 416b88baab8SDanilo Krummrich entity->sched_wq = sched_wq; 417b88baab8SDanilo Krummrich return drm_sched_entity_init(&entity->base, 418b88baab8SDanilo Krummrich DRM_SCHED_PRIORITY_NORMAL, 419b88baab8SDanilo Krummrich &sched, 1, NULL); 420b88baab8SDanilo Krummrich } 421b88baab8SDanilo Krummrich 422b88baab8SDanilo Krummrich void 423b88baab8SDanilo Krummrich nouveau_sched_entity_fini(struct nouveau_sched_entity *entity) 424b88baab8SDanilo Krummrich { 425b88baab8SDanilo Krummrich drm_sched_entity_destroy(&entity->base); 426b88baab8SDanilo Krummrich } 427b88baab8SDanilo Krummrich 428b88baab8SDanilo Krummrich static const struct drm_sched_backend_ops nouveau_sched_ops = { 429b88baab8SDanilo Krummrich .run_job = nouveau_sched_run_job, 430b88baab8SDanilo Krummrich .timedout_job = nouveau_sched_timedout_job, 431b88baab8SDanilo Krummrich .free_job = nouveau_sched_free_job, 432b88baab8SDanilo Krummrich }; 433b88baab8SDanilo Krummrich 434b88baab8SDanilo Krummrich int nouveau_sched_init(struct nouveau_drm *drm) 435b88baab8SDanilo Krummrich { 436b88baab8SDanilo Krummrich struct drm_gpu_scheduler *sched = &drm->sched; 437b88baab8SDanilo Krummrich long job_hang_limit = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS); 438b88baab8SDanilo Krummrich 439b88baab8SDanilo Krummrich drm->sched_wq = create_singlethread_workqueue("nouveau_sched_wq"); 440b88baab8SDanilo Krummrich if (!drm->sched_wq) 441b88baab8SDanilo Krummrich return -ENOMEM; 442b88baab8SDanilo Krummrich 443a6149f03SMatthew Brost return drm_sched_init(sched, &nouveau_sched_ops, NULL, 44456e44960SLuben Tuikov DRM_SCHED_PRIORITY_COUNT, 445b88baab8SDanilo Krummrich NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, 446b88baab8SDanilo Krummrich NULL, NULL, "nouveau_sched", drm->dev->dev); 447b88baab8SDanilo Krummrich } 448b88baab8SDanilo Krummrich 449b88baab8SDanilo Krummrich void nouveau_sched_fini(struct nouveau_drm *drm) 450b88baab8SDanilo Krummrich { 451b88baab8SDanilo Krummrich destroy_workqueue(drm->sched_wq); 452b88baab8SDanilo Krummrich drm_sched_fini(&drm->sched); 453b88baab8SDanilo Krummrich } 454