xref: /linux/drivers/gpu/drm/nouveau/nouveau_sched.c (revision 014f831abcb82738e57c0b00db66dfef0798ed67)
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