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 #define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 16b88baab8SDanilo Krummrich 175f03a507SDanilo Krummrich /* Starts at 0, since the DRM scheduler interprets those parameters as (initial) 185f03a507SDanilo Krummrich * index to the run-queue array. 195f03a507SDanilo Krummrich */ 205f03a507SDanilo Krummrich enum nouveau_sched_priority { 215f03a507SDanilo Krummrich NOUVEAU_SCHED_PRIORITY_SINGLE = DRM_SCHED_PRIORITY_MIN, 225f03a507SDanilo Krummrich NOUVEAU_SCHED_PRIORITY_COUNT, 235f03a507SDanilo Krummrich }; 245f03a507SDanilo Krummrich 25b88baab8SDanilo Krummrich int 26b88baab8SDanilo Krummrich nouveau_job_init(struct nouveau_job *job, 27b88baab8SDanilo Krummrich struct nouveau_job_args *args) 28b88baab8SDanilo Krummrich { 295f03a507SDanilo Krummrich struct nouveau_sched *sched = args->sched; 30b88baab8SDanilo Krummrich int ret; 31b88baab8SDanilo Krummrich 325f03a507SDanilo Krummrich INIT_LIST_HEAD(&job->entry); 335f03a507SDanilo Krummrich 34b88baab8SDanilo Krummrich job->file_priv = args->file_priv; 35b88baab8SDanilo Krummrich job->cli = nouveau_cli(args->file_priv); 365f03a507SDanilo Krummrich job->sched = sched; 37b88baab8SDanilo Krummrich 38b88baab8SDanilo Krummrich job->sync = args->sync; 39b88baab8SDanilo Krummrich job->resv_usage = args->resv_usage; 40b88baab8SDanilo Krummrich 41b88baab8SDanilo Krummrich job->ops = args->ops; 42b88baab8SDanilo Krummrich 43b88baab8SDanilo Krummrich job->in_sync.count = args->in_sync.count; 44b88baab8SDanilo Krummrich if (job->in_sync.count) { 45b88baab8SDanilo Krummrich if (job->sync) 46b88baab8SDanilo Krummrich return -EINVAL; 47b88baab8SDanilo Krummrich 48b88baab8SDanilo Krummrich job->in_sync.data = kmemdup(args->in_sync.s, 49b88baab8SDanilo Krummrich sizeof(*args->in_sync.s) * 50b88baab8SDanilo Krummrich args->in_sync.count, 51b88baab8SDanilo Krummrich GFP_KERNEL); 52b88baab8SDanilo Krummrich if (!job->in_sync.data) 53b88baab8SDanilo Krummrich return -ENOMEM; 54b88baab8SDanilo Krummrich } 55b88baab8SDanilo Krummrich 56b88baab8SDanilo Krummrich job->out_sync.count = args->out_sync.count; 57b88baab8SDanilo Krummrich if (job->out_sync.count) { 58b88baab8SDanilo Krummrich if (job->sync) { 59b88baab8SDanilo Krummrich ret = -EINVAL; 60b88baab8SDanilo Krummrich goto err_free_in_sync; 61b88baab8SDanilo Krummrich } 62b88baab8SDanilo Krummrich 63b88baab8SDanilo Krummrich job->out_sync.data = kmemdup(args->out_sync.s, 64b88baab8SDanilo Krummrich sizeof(*args->out_sync.s) * 65b88baab8SDanilo Krummrich args->out_sync.count, 66b88baab8SDanilo Krummrich GFP_KERNEL); 67b88baab8SDanilo Krummrich if (!job->out_sync.data) { 68b88baab8SDanilo Krummrich ret = -ENOMEM; 69b88baab8SDanilo Krummrich goto err_free_in_sync; 70b88baab8SDanilo Krummrich } 71b88baab8SDanilo Krummrich 72b88baab8SDanilo Krummrich job->out_sync.objs = kcalloc(job->out_sync.count, 73b88baab8SDanilo Krummrich sizeof(*job->out_sync.objs), 74b88baab8SDanilo Krummrich GFP_KERNEL); 75b88baab8SDanilo Krummrich if (!job->out_sync.objs) { 76b88baab8SDanilo Krummrich ret = -ENOMEM; 77b88baab8SDanilo Krummrich goto err_free_out_sync; 78b88baab8SDanilo Krummrich } 79b88baab8SDanilo Krummrich 80b88baab8SDanilo Krummrich job->out_sync.chains = kcalloc(job->out_sync.count, 81b88baab8SDanilo Krummrich sizeof(*job->out_sync.chains), 82b88baab8SDanilo Krummrich GFP_KERNEL); 83b88baab8SDanilo Krummrich if (!job->out_sync.chains) { 84b88baab8SDanilo Krummrich ret = -ENOMEM; 85b88baab8SDanilo Krummrich goto err_free_objs; 86b88baab8SDanilo Krummrich } 87b88baab8SDanilo Krummrich } 88b88baab8SDanilo Krummrich 89*46990918SDanilo Krummrich ret = drm_sched_job_init(&job->base, &sched->entity, 90*46990918SDanilo Krummrich args->credits, NULL); 91b88baab8SDanilo Krummrich if (ret) 92b88baab8SDanilo Krummrich goto err_free_chains; 93b88baab8SDanilo Krummrich 94b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_INITIALIZED; 95b88baab8SDanilo Krummrich 96b88baab8SDanilo Krummrich return 0; 97b88baab8SDanilo Krummrich 98b88baab8SDanilo Krummrich err_free_chains: 99b88baab8SDanilo Krummrich kfree(job->out_sync.chains); 100b88baab8SDanilo Krummrich err_free_objs: 101b88baab8SDanilo Krummrich kfree(job->out_sync.objs); 102b88baab8SDanilo Krummrich err_free_out_sync: 103b88baab8SDanilo Krummrich kfree(job->out_sync.data); 104b88baab8SDanilo Krummrich err_free_in_sync: 105b88baab8SDanilo Krummrich kfree(job->in_sync.data); 106b88baab8SDanilo Krummrich return ret; 107b88baab8SDanilo Krummrich } 108b88baab8SDanilo Krummrich 109b88baab8SDanilo Krummrich void 1105f03a507SDanilo Krummrich nouveau_job_fini(struct nouveau_job *job) 1115f03a507SDanilo Krummrich { 1125f03a507SDanilo Krummrich dma_fence_put(job->done_fence); 1135f03a507SDanilo Krummrich drm_sched_job_cleanup(&job->base); 1145f03a507SDanilo Krummrich 1155f03a507SDanilo Krummrich job->ops->free(job); 1165f03a507SDanilo Krummrich } 1175f03a507SDanilo Krummrich 1185f03a507SDanilo Krummrich void 1195f03a507SDanilo Krummrich nouveau_job_done(struct nouveau_job *job) 1205f03a507SDanilo Krummrich { 1215f03a507SDanilo Krummrich struct nouveau_sched *sched = job->sched; 1225f03a507SDanilo Krummrich 1235f03a507SDanilo Krummrich spin_lock(&sched->job.list.lock); 1245f03a507SDanilo Krummrich list_del(&job->entry); 1255f03a507SDanilo Krummrich spin_unlock(&sched->job.list.lock); 1265f03a507SDanilo Krummrich 1275f03a507SDanilo Krummrich wake_up(&sched->job.wq); 1285f03a507SDanilo Krummrich } 1295f03a507SDanilo Krummrich 1305f03a507SDanilo Krummrich void 131b88baab8SDanilo Krummrich nouveau_job_free(struct nouveau_job *job) 132b88baab8SDanilo Krummrich { 133b88baab8SDanilo Krummrich kfree(job->in_sync.data); 134b88baab8SDanilo Krummrich kfree(job->out_sync.data); 135b88baab8SDanilo Krummrich kfree(job->out_sync.objs); 136b88baab8SDanilo Krummrich kfree(job->out_sync.chains); 137b88baab8SDanilo Krummrich } 138b88baab8SDanilo Krummrich 139b88baab8SDanilo Krummrich static int 140b88baab8SDanilo Krummrich sync_find_fence(struct nouveau_job *job, 141b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync, 142b88baab8SDanilo Krummrich struct dma_fence **fence) 143b88baab8SDanilo Krummrich { 144b88baab8SDanilo Krummrich u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 145b88baab8SDanilo Krummrich u64 point = 0; 146b88baab8SDanilo Krummrich int ret; 147b88baab8SDanilo Krummrich 148b88baab8SDanilo Krummrich if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && 149b88baab8SDanilo Krummrich stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) 150b88baab8SDanilo Krummrich return -EOPNOTSUPP; 151b88baab8SDanilo Krummrich 152b88baab8SDanilo Krummrich if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) 153b88baab8SDanilo Krummrich point = sync->timeline_value; 154b88baab8SDanilo Krummrich 155b88baab8SDanilo Krummrich ret = drm_syncobj_find_fence(job->file_priv, 156b88baab8SDanilo Krummrich sync->handle, point, 157e05f3938SFaith Ekstrand 0 /* flags */, fence); 158b88baab8SDanilo Krummrich if (ret) 159b88baab8SDanilo Krummrich return ret; 160b88baab8SDanilo Krummrich 161b88baab8SDanilo Krummrich return 0; 162b88baab8SDanilo Krummrich } 163b88baab8SDanilo Krummrich 164b88baab8SDanilo Krummrich static int 165b88baab8SDanilo Krummrich nouveau_job_add_deps(struct nouveau_job *job) 166b88baab8SDanilo Krummrich { 167b88baab8SDanilo Krummrich struct dma_fence *in_fence = NULL; 168b88baab8SDanilo Krummrich int ret, i; 169b88baab8SDanilo Krummrich 170b88baab8SDanilo Krummrich for (i = 0; i < job->in_sync.count; i++) { 171b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync = &job->in_sync.data[i]; 172b88baab8SDanilo Krummrich 173b88baab8SDanilo Krummrich ret = sync_find_fence(job, sync, &in_fence); 174b88baab8SDanilo Krummrich if (ret) { 175b88baab8SDanilo Krummrich NV_PRINTK(warn, job->cli, 176b88baab8SDanilo Krummrich "Failed to find syncobj (-> in): handle=%d\n", 177b88baab8SDanilo Krummrich sync->handle); 178b88baab8SDanilo Krummrich return ret; 179b88baab8SDanilo Krummrich } 180b88baab8SDanilo Krummrich 181b88baab8SDanilo Krummrich ret = drm_sched_job_add_dependency(&job->base, in_fence); 182b88baab8SDanilo Krummrich if (ret) 183b88baab8SDanilo Krummrich return ret; 184b88baab8SDanilo Krummrich } 185b88baab8SDanilo Krummrich 186b88baab8SDanilo Krummrich return 0; 187b88baab8SDanilo Krummrich } 188b88baab8SDanilo Krummrich 189b88baab8SDanilo Krummrich static void 190b88baab8SDanilo Krummrich nouveau_job_fence_attach_cleanup(struct nouveau_job *job) 191b88baab8SDanilo Krummrich { 192b88baab8SDanilo Krummrich int i; 193b88baab8SDanilo Krummrich 194b88baab8SDanilo Krummrich for (i = 0; i < job->out_sync.count; i++) { 195b88baab8SDanilo Krummrich struct drm_syncobj *obj = job->out_sync.objs[i]; 196b88baab8SDanilo Krummrich struct dma_fence_chain *chain = job->out_sync.chains[i]; 197b88baab8SDanilo Krummrich 198b88baab8SDanilo Krummrich if (obj) 199b88baab8SDanilo Krummrich drm_syncobj_put(obj); 200b88baab8SDanilo Krummrich 201b88baab8SDanilo Krummrich if (chain) 202b88baab8SDanilo Krummrich dma_fence_chain_free(chain); 203b88baab8SDanilo Krummrich } 204b88baab8SDanilo Krummrich } 205b88baab8SDanilo Krummrich 206b88baab8SDanilo Krummrich static int 207b88baab8SDanilo Krummrich nouveau_job_fence_attach_prepare(struct nouveau_job *job) 208b88baab8SDanilo Krummrich { 209b88baab8SDanilo Krummrich int i, ret; 210b88baab8SDanilo Krummrich 211b88baab8SDanilo Krummrich for (i = 0; i < job->out_sync.count; i++) { 212b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync = &job->out_sync.data[i]; 213b88baab8SDanilo Krummrich struct drm_syncobj **pobj = &job->out_sync.objs[i]; 214b88baab8SDanilo Krummrich struct dma_fence_chain **pchain = &job->out_sync.chains[i]; 215b88baab8SDanilo Krummrich u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 216b88baab8SDanilo Krummrich 217b88baab8SDanilo Krummrich if (stype != DRM_NOUVEAU_SYNC_SYNCOBJ && 218b88baab8SDanilo Krummrich stype != DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 219b88baab8SDanilo Krummrich ret = -EINVAL; 220b88baab8SDanilo Krummrich goto err_sync_cleanup; 221b88baab8SDanilo Krummrich } 222b88baab8SDanilo Krummrich 223b88baab8SDanilo Krummrich *pobj = drm_syncobj_find(job->file_priv, sync->handle); 224b88baab8SDanilo Krummrich if (!*pobj) { 225b88baab8SDanilo Krummrich NV_PRINTK(warn, job->cli, 226b88baab8SDanilo Krummrich "Failed to find syncobj (-> out): handle=%d\n", 227b88baab8SDanilo Krummrich sync->handle); 228b88baab8SDanilo Krummrich ret = -ENOENT; 229b88baab8SDanilo Krummrich goto err_sync_cleanup; 230b88baab8SDanilo Krummrich } 231b88baab8SDanilo Krummrich 232b88baab8SDanilo Krummrich if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 233b88baab8SDanilo Krummrich *pchain = dma_fence_chain_alloc(); 234b88baab8SDanilo Krummrich if (!*pchain) { 235b88baab8SDanilo Krummrich ret = -ENOMEM; 236b88baab8SDanilo Krummrich goto err_sync_cleanup; 237b88baab8SDanilo Krummrich } 238b88baab8SDanilo Krummrich } 239b88baab8SDanilo Krummrich } 240b88baab8SDanilo Krummrich 241b88baab8SDanilo Krummrich return 0; 242b88baab8SDanilo Krummrich 243b88baab8SDanilo Krummrich err_sync_cleanup: 244b88baab8SDanilo Krummrich nouveau_job_fence_attach_cleanup(job); 245b88baab8SDanilo Krummrich return ret; 246b88baab8SDanilo Krummrich } 247b88baab8SDanilo Krummrich 248b88baab8SDanilo Krummrich static void 249b88baab8SDanilo Krummrich nouveau_job_fence_attach(struct nouveau_job *job) 250b88baab8SDanilo Krummrich { 251b88baab8SDanilo Krummrich struct dma_fence *fence = job->done_fence; 252b88baab8SDanilo Krummrich int i; 253b88baab8SDanilo Krummrich 254b88baab8SDanilo Krummrich for (i = 0; i < job->out_sync.count; i++) { 255b88baab8SDanilo Krummrich struct drm_nouveau_sync *sync = &job->out_sync.data[i]; 256b88baab8SDanilo Krummrich struct drm_syncobj **pobj = &job->out_sync.objs[i]; 257b88baab8SDanilo Krummrich struct dma_fence_chain **pchain = &job->out_sync.chains[i]; 258b88baab8SDanilo Krummrich u32 stype = sync->flags & DRM_NOUVEAU_SYNC_TYPE_MASK; 259b88baab8SDanilo Krummrich 260b88baab8SDanilo Krummrich if (stype == DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ) { 261b88baab8SDanilo Krummrich drm_syncobj_add_point(*pobj, *pchain, fence, 262b88baab8SDanilo Krummrich sync->timeline_value); 263b88baab8SDanilo Krummrich } else { 264b88baab8SDanilo Krummrich drm_syncobj_replace_fence(*pobj, fence); 265b88baab8SDanilo Krummrich } 266b88baab8SDanilo Krummrich 267b88baab8SDanilo Krummrich drm_syncobj_put(*pobj); 268b88baab8SDanilo Krummrich *pobj = NULL; 269b88baab8SDanilo Krummrich *pchain = NULL; 270b88baab8SDanilo Krummrich } 271b88baab8SDanilo Krummrich } 272b88baab8SDanilo Krummrich 273b88baab8SDanilo Krummrich int 274b88baab8SDanilo Krummrich nouveau_job_submit(struct nouveau_job *job) 275b88baab8SDanilo Krummrich { 2765f03a507SDanilo Krummrich struct nouveau_sched *sched = job->sched; 277b88baab8SDanilo Krummrich struct dma_fence *done_fence = NULL; 278014f831aSDanilo Krummrich struct drm_gpuvm_exec vm_exec = { 279014f831aSDanilo Krummrich .vm = &nouveau_cli_uvmm(job->cli)->base, 280014f831aSDanilo Krummrich .flags = DRM_EXEC_IGNORE_DUPLICATES, 281014f831aSDanilo Krummrich .num_fences = 1, 282014f831aSDanilo Krummrich }; 283b88baab8SDanilo Krummrich int ret; 284b88baab8SDanilo Krummrich 285b88baab8SDanilo Krummrich ret = nouveau_job_add_deps(job); 286b88baab8SDanilo Krummrich if (ret) 287b88baab8SDanilo Krummrich goto err; 288b88baab8SDanilo Krummrich 289b88baab8SDanilo Krummrich ret = nouveau_job_fence_attach_prepare(job); 290b88baab8SDanilo Krummrich if (ret) 291b88baab8SDanilo Krummrich goto err; 292b88baab8SDanilo Krummrich 293b88baab8SDanilo Krummrich /* Make sure the job appears on the sched_entity's queue in the same 294b88baab8SDanilo Krummrich * order as it was submitted. 295b88baab8SDanilo Krummrich */ 2965f03a507SDanilo Krummrich mutex_lock(&sched->mutex); 297b88baab8SDanilo Krummrich 298b88baab8SDanilo Krummrich /* Guarantee we won't fail after the submit() callback returned 299b88baab8SDanilo Krummrich * successfully. 300b88baab8SDanilo Krummrich */ 301b88baab8SDanilo Krummrich if (job->ops->submit) { 302014f831aSDanilo Krummrich ret = job->ops->submit(job, &vm_exec); 303b88baab8SDanilo Krummrich if (ret) 304b88baab8SDanilo Krummrich goto err_cleanup; 305b88baab8SDanilo Krummrich } 306b88baab8SDanilo Krummrich 3075f03a507SDanilo Krummrich /* Submit was successful; add the job to the schedulers job list. */ 3085f03a507SDanilo Krummrich spin_lock(&sched->job.list.lock); 3095f03a507SDanilo Krummrich list_add(&job->entry, &sched->job.list.head); 3105f03a507SDanilo Krummrich spin_unlock(&sched->job.list.lock); 3115f03a507SDanilo Krummrich 312b88baab8SDanilo Krummrich drm_sched_job_arm(&job->base); 313b88baab8SDanilo Krummrich job->done_fence = dma_fence_get(&job->base.s_fence->finished); 314b88baab8SDanilo Krummrich if (job->sync) 315b88baab8SDanilo Krummrich done_fence = dma_fence_get(job->done_fence); 316b88baab8SDanilo Krummrich 317b88baab8SDanilo Krummrich if (job->ops->armed_submit) 318014f831aSDanilo Krummrich job->ops->armed_submit(job, &vm_exec); 319b88baab8SDanilo Krummrich 320b88baab8SDanilo Krummrich nouveau_job_fence_attach(job); 321b88baab8SDanilo Krummrich 322b88baab8SDanilo Krummrich /* Set job state before pushing the job to the scheduler, 323b88baab8SDanilo Krummrich * such that we do not overwrite the job state set in run(). 324b88baab8SDanilo Krummrich */ 325b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_SUBMIT_SUCCESS; 326b88baab8SDanilo Krummrich 327b88baab8SDanilo Krummrich drm_sched_entity_push_job(&job->base); 328b88baab8SDanilo Krummrich 3295f03a507SDanilo Krummrich mutex_unlock(&sched->mutex); 330b88baab8SDanilo Krummrich 331b88baab8SDanilo Krummrich if (done_fence) { 332b88baab8SDanilo Krummrich dma_fence_wait(done_fence, true); 333b88baab8SDanilo Krummrich dma_fence_put(done_fence); 334b88baab8SDanilo Krummrich } 335b88baab8SDanilo Krummrich 336b88baab8SDanilo Krummrich return 0; 337b88baab8SDanilo Krummrich 338b88baab8SDanilo Krummrich err_cleanup: 3395f03a507SDanilo Krummrich mutex_unlock(&sched->mutex); 340b88baab8SDanilo Krummrich nouveau_job_fence_attach_cleanup(job); 341b88baab8SDanilo Krummrich err: 342b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_SUBMIT_FAILED; 343b88baab8SDanilo Krummrich return ret; 344b88baab8SDanilo Krummrich } 345b88baab8SDanilo Krummrich 346b88baab8SDanilo Krummrich static struct dma_fence * 347b88baab8SDanilo Krummrich nouveau_job_run(struct nouveau_job *job) 348b88baab8SDanilo Krummrich { 349b88baab8SDanilo Krummrich struct dma_fence *fence; 350b88baab8SDanilo Krummrich 351b88baab8SDanilo Krummrich fence = job->ops->run(job); 352b88baab8SDanilo Krummrich if (IS_ERR(fence)) 353b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_RUN_FAILED; 354b88baab8SDanilo Krummrich else 355b88baab8SDanilo Krummrich job->state = NOUVEAU_JOB_RUN_SUCCESS; 356b88baab8SDanilo Krummrich 357b88baab8SDanilo Krummrich return fence; 358b88baab8SDanilo Krummrich } 359b88baab8SDanilo Krummrich 360b88baab8SDanilo Krummrich static struct dma_fence * 361b88baab8SDanilo Krummrich nouveau_sched_run_job(struct drm_sched_job *sched_job) 362b88baab8SDanilo Krummrich { 363b88baab8SDanilo Krummrich struct nouveau_job *job = to_nouveau_job(sched_job); 364b88baab8SDanilo Krummrich 365b88baab8SDanilo Krummrich return nouveau_job_run(job); 366b88baab8SDanilo Krummrich } 367b88baab8SDanilo Krummrich 368b88baab8SDanilo Krummrich static enum drm_gpu_sched_stat 369b88baab8SDanilo Krummrich nouveau_sched_timedout_job(struct drm_sched_job *sched_job) 370b88baab8SDanilo Krummrich { 37131499b01SDanilo Krummrich struct drm_gpu_scheduler *sched = sched_job->sched; 372b88baab8SDanilo Krummrich struct nouveau_job *job = to_nouveau_job(sched_job); 37331499b01SDanilo Krummrich enum drm_gpu_sched_stat stat = DRM_GPU_SCHED_STAT_NOMINAL; 374b88baab8SDanilo Krummrich 37531499b01SDanilo Krummrich drm_sched_stop(sched, sched_job); 376b88baab8SDanilo Krummrich 377b88baab8SDanilo Krummrich if (job->ops->timeout) 37831499b01SDanilo Krummrich stat = job->ops->timeout(job); 37931499b01SDanilo Krummrich else 38031499b01SDanilo Krummrich NV_PRINTK(warn, job->cli, "Generic job timeout.\n"); 381b88baab8SDanilo Krummrich 38231499b01SDanilo Krummrich drm_sched_start(sched, true); 38331499b01SDanilo Krummrich 38431499b01SDanilo Krummrich return stat; 385b88baab8SDanilo Krummrich } 386b88baab8SDanilo Krummrich 387b88baab8SDanilo Krummrich static void 388b88baab8SDanilo Krummrich nouveau_sched_free_job(struct drm_sched_job *sched_job) 389b88baab8SDanilo Krummrich { 390b88baab8SDanilo Krummrich struct nouveau_job *job = to_nouveau_job(sched_job); 391b88baab8SDanilo Krummrich 392b88baab8SDanilo Krummrich nouveau_job_fini(job); 393b88baab8SDanilo Krummrich } 394b88baab8SDanilo Krummrich 395b88baab8SDanilo Krummrich static const struct drm_sched_backend_ops nouveau_sched_ops = { 396b88baab8SDanilo Krummrich .run_job = nouveau_sched_run_job, 397b88baab8SDanilo Krummrich .timedout_job = nouveau_sched_timedout_job, 398b88baab8SDanilo Krummrich .free_job = nouveau_sched_free_job, 399b88baab8SDanilo Krummrich }; 400b88baab8SDanilo Krummrich 4015f03a507SDanilo Krummrich int 4025f03a507SDanilo Krummrich nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, 403*46990918SDanilo Krummrich struct workqueue_struct *wq, u32 credit_limit) 404b88baab8SDanilo Krummrich { 4055f03a507SDanilo Krummrich struct drm_gpu_scheduler *drm_sched = &sched->base; 4065f03a507SDanilo Krummrich struct drm_sched_entity *entity = &sched->entity; 407b88baab8SDanilo Krummrich long job_hang_limit = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS); 4085f03a507SDanilo Krummrich int ret; 409b88baab8SDanilo Krummrich 4105f03a507SDanilo Krummrich if (!wq) { 4115f03a507SDanilo Krummrich wq = alloc_workqueue("nouveau_sched_wq_%d", 0, WQ_MAX_ACTIVE, 4125f03a507SDanilo Krummrich current->pid); 4135f03a507SDanilo Krummrich if (!wq) 414b88baab8SDanilo Krummrich return -ENOMEM; 415b88baab8SDanilo Krummrich 4165f03a507SDanilo Krummrich sched->wq = wq; 417b88baab8SDanilo Krummrich } 418b88baab8SDanilo Krummrich 4195f03a507SDanilo Krummrich ret = drm_sched_init(drm_sched, &nouveau_sched_ops, wq, 4205f03a507SDanilo Krummrich NOUVEAU_SCHED_PRIORITY_COUNT, 421*46990918SDanilo Krummrich credit_limit, 0, job_hang_limit, 4225f03a507SDanilo Krummrich NULL, NULL, "nouveau_sched", drm->dev->dev); 4235f03a507SDanilo Krummrich if (ret) 4245f03a507SDanilo Krummrich goto fail_wq; 4255f03a507SDanilo Krummrich 4265f03a507SDanilo Krummrich /* Using DRM_SCHED_PRIORITY_MIN, since that's what we're required to use 4275f03a507SDanilo Krummrich * when we want to have a single run-queue only. 4285f03a507SDanilo Krummrich * 4295f03a507SDanilo Krummrich * It's not documented, but one will find out when trying to use any 4305f03a507SDanilo Krummrich * other priority running into faults, because the scheduler uses the 4315f03a507SDanilo Krummrich * priority as array index. 4325f03a507SDanilo Krummrich * 4335f03a507SDanilo Krummrich * Can't use NOUVEAU_SCHED_PRIORITY_SINGLE either, because it's not 4345f03a507SDanilo Krummrich * matching the enum type used in drm_sched_entity_init(). 4355f03a507SDanilo Krummrich */ 4365f03a507SDanilo Krummrich ret = drm_sched_entity_init(entity, DRM_SCHED_PRIORITY_MIN, 4375f03a507SDanilo Krummrich &drm_sched, 1, NULL); 4385f03a507SDanilo Krummrich if (ret) 4395f03a507SDanilo Krummrich goto fail_sched; 4405f03a507SDanilo Krummrich 4415f03a507SDanilo Krummrich mutex_init(&sched->mutex); 4425f03a507SDanilo Krummrich spin_lock_init(&sched->job.list.lock); 4435f03a507SDanilo Krummrich INIT_LIST_HEAD(&sched->job.list.head); 4445f03a507SDanilo Krummrich init_waitqueue_head(&sched->job.wq); 4455f03a507SDanilo Krummrich 4465f03a507SDanilo Krummrich return 0; 4475f03a507SDanilo Krummrich 4485f03a507SDanilo Krummrich fail_sched: 4495f03a507SDanilo Krummrich drm_sched_fini(drm_sched); 4505f03a507SDanilo Krummrich fail_wq: 4515f03a507SDanilo Krummrich if (sched->wq) 4525f03a507SDanilo Krummrich destroy_workqueue(sched->wq); 4535f03a507SDanilo Krummrich return ret; 4545f03a507SDanilo Krummrich } 4555f03a507SDanilo Krummrich 4565f03a507SDanilo Krummrich void 4575f03a507SDanilo Krummrich nouveau_sched_fini(struct nouveau_sched *sched) 458b88baab8SDanilo Krummrich { 4595f03a507SDanilo Krummrich struct drm_gpu_scheduler *drm_sched = &sched->base; 4605f03a507SDanilo Krummrich struct drm_sched_entity *entity = &sched->entity; 4615f03a507SDanilo Krummrich 4625f03a507SDanilo Krummrich rmb(); /* for list_empty to work without lock */ 4635f03a507SDanilo Krummrich wait_event(sched->job.wq, list_empty(&sched->job.list.head)); 4645f03a507SDanilo Krummrich 4655f03a507SDanilo Krummrich drm_sched_entity_fini(entity); 4665f03a507SDanilo Krummrich drm_sched_fini(drm_sched); 4675f03a507SDanilo Krummrich 4685f03a507SDanilo Krummrich /* Destroy workqueue after scheduler tear down, otherwise it might still 4695f03a507SDanilo Krummrich * be in use. 4705f03a507SDanilo Krummrich */ 4715f03a507SDanilo Krummrich if (sched->wq) 4725f03a507SDanilo Krummrich destroy_workqueue(sched->wq); 473b88baab8SDanilo Krummrich } 474