xref: /linux/drivers/accel/ivpu/ivpu_job.c (revision 37aeccf5f839c155e8c9100937a01059b24e61b5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2020-2024 Intel Corporation
4  */
5 
6 #include <drm/drm_file.h>
7 
8 #include <linux/bitfield.h>
9 #include <linux/highmem.h>
10 #include <linux/pci.h>
11 #include <linux/module.h>
12 #include <uapi/drm/ivpu_accel.h>
13 
14 #include "ivpu_drv.h"
15 #include "ivpu_fw.h"
16 #include "ivpu_hw.h"
17 #include "ivpu_ipc.h"
18 #include "ivpu_job.h"
19 #include "ivpu_jsm_msg.h"
20 #include "ivpu_pm.h"
21 #include "ivpu_trace.h"
22 #include "vpu_boot_api.h"
23 
24 #define CMD_BUF_IDX	     0
25 #define JOB_MAX_BUFFER_COUNT 65535
26 
27 static void ivpu_cmdq_ring_db(struct ivpu_device *vdev, struct ivpu_cmdq *cmdq)
28 {
29 	ivpu_hw_db_set(vdev, cmdq->db_id);
30 }
31 
32 static int ivpu_preemption_buffers_create(struct ivpu_device *vdev,
33 					  struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
34 {
35 	u64 primary_size = ALIGN(vdev->fw->primary_preempt_buf_size, PAGE_SIZE);
36 	u64 secondary_size = ALIGN(vdev->fw->secondary_preempt_buf_size, PAGE_SIZE);
37 
38 	if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW)
39 		return 0;
40 
41 	cmdq->primary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &vdev->hw->ranges.user,
42 						   primary_size, DRM_IVPU_BO_WC);
43 	if (!cmdq->primary_preempt_buf) {
44 		ivpu_err(vdev, "Failed to create primary preemption buffer\n");
45 		return -ENOMEM;
46 	}
47 
48 	cmdq->secondary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &vdev->hw->ranges.shave,
49 						     secondary_size, DRM_IVPU_BO_WC);
50 	if (!cmdq->secondary_preempt_buf) {
51 		ivpu_err(vdev, "Failed to create secondary preemption buffer\n");
52 		goto err_free_primary;
53 	}
54 
55 	return 0;
56 
57 err_free_primary:
58 	ivpu_bo_free(cmdq->primary_preempt_buf);
59 	cmdq->primary_preempt_buf = NULL;
60 	return -ENOMEM;
61 }
62 
63 static void ivpu_preemption_buffers_free(struct ivpu_device *vdev,
64 					 struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
65 {
66 	if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW)
67 		return;
68 
69 	if (cmdq->primary_preempt_buf)
70 		ivpu_bo_free(cmdq->primary_preempt_buf);
71 	if (cmdq->secondary_preempt_buf)
72 		ivpu_bo_free(cmdq->secondary_preempt_buf);
73 }
74 
75 static int ivpu_id_alloc(struct xarray *xa, u32 *id, void *entry, struct xa_limit *limit,
76 			 const struct xa_limit default_limit)
77 {
78 	int ret;
79 
80 	ret = __xa_alloc(xa, id, entry, *limit, GFP_KERNEL);
81 	if (ret) {
82 		limit->min = default_limit.min;
83 		ret = __xa_alloc(xa, id, entry, *limit, GFP_KERNEL);
84 		if (ret)
85 			return ret;
86 	}
87 
88 	limit->min = *id + 1;
89 	if (limit->min > limit->max)
90 		limit->min = default_limit.min;
91 
92 	return ret;
93 }
94 
95 static struct ivpu_cmdq *ivpu_cmdq_alloc(struct ivpu_file_priv *file_priv)
96 {
97 	struct ivpu_device *vdev = file_priv->vdev;
98 	struct ivpu_cmdq *cmdq;
99 	int ret;
100 
101 	cmdq = kzalloc(sizeof(*cmdq), GFP_KERNEL);
102 	if (!cmdq)
103 		return NULL;
104 
105 	xa_lock(&vdev->db_xa); /* lock here to protect db_limit */
106 	ret = ivpu_id_alloc(&vdev->db_xa, &cmdq->db_id, NULL, &vdev->db_limit,
107 			    vdev->default_db_limit);
108 	xa_unlock(&vdev->db_xa);
109 	if (ret) {
110 		ivpu_err(vdev, "Failed to allocate doorbell id: %d\n", ret);
111 		goto err_free_cmdq;
112 	}
113 
114 	cmdq->mem = ivpu_bo_create_global(vdev, SZ_4K, DRM_IVPU_BO_WC | DRM_IVPU_BO_MAPPABLE);
115 	if (!cmdq->mem)
116 		goto err_erase_xa;
117 
118 	ret = ivpu_preemption_buffers_create(vdev, file_priv, cmdq);
119 	if (ret)
120 		ivpu_warn(vdev, "Failed to allocate preemption buffers, preemption limited\n");
121 
122 	return cmdq;
123 
124 err_erase_xa:
125 	xa_erase(&vdev->db_xa, cmdq->db_id);
126 err_free_cmdq:
127 	kfree(cmdq);
128 	return NULL;
129 }
130 
131 static void ivpu_cmdq_free(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
132 {
133 	if (!cmdq)
134 		return;
135 
136 	ivpu_preemption_buffers_free(file_priv->vdev, file_priv, cmdq);
137 	ivpu_bo_free(cmdq->mem);
138 	xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
139 	kfree(cmdq);
140 }
141 
142 static int ivpu_hws_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u16 engine,
143 			      u8 priority)
144 {
145 	struct ivpu_device *vdev = file_priv->vdev;
146 	int ret;
147 
148 	ret = ivpu_jsm_hws_create_cmdq(vdev, file_priv->ctx.id, file_priv->ctx.id, cmdq->db_id,
149 				       task_pid_nr(current), engine,
150 				       cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem));
151 	if (ret)
152 		return ret;
153 
154 	ret = ivpu_jsm_hws_set_context_sched_properties(vdev, file_priv->ctx.id, cmdq->db_id,
155 							priority);
156 	if (ret)
157 		return ret;
158 
159 	return 0;
160 }
161 
162 static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
163 {
164 	struct ivpu_device *vdev = file_priv->vdev;
165 	int ret;
166 
167 	if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
168 		ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, cmdq->db_id, cmdq->db_id,
169 					       cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem));
170 	else
171 		ret = ivpu_jsm_register_db(vdev, file_priv->ctx.id, cmdq->db_id,
172 					   cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem));
173 
174 	if (!ret)
175 		ivpu_dbg(vdev, JOB, "DB %d registered to ctx %d\n", cmdq->db_id, file_priv->ctx.id);
176 
177 	return ret;
178 }
179 
180 static int
181 ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u16 engine, u8 priority)
182 {
183 	struct ivpu_device *vdev = file_priv->vdev;
184 	struct vpu_job_queue_header *jobq_header;
185 	int ret;
186 
187 	lockdep_assert_held(&file_priv->lock);
188 
189 	if (cmdq->db_registered)
190 		return 0;
191 
192 	cmdq->entry_count = (u32)((ivpu_bo_size(cmdq->mem) - sizeof(struct vpu_job_queue_header)) /
193 				  sizeof(struct vpu_job_queue_entry));
194 
195 	cmdq->jobq = (struct vpu_job_queue *)ivpu_bo_vaddr(cmdq->mem);
196 	jobq_header = &cmdq->jobq->header;
197 	jobq_header->engine_idx = engine;
198 	jobq_header->head = 0;
199 	jobq_header->tail = 0;
200 	if (ivpu_test_mode & IVPU_TEST_MODE_TURBO) {
201 		ivpu_dbg(vdev, JOB, "Turbo mode enabled");
202 		jobq_header->flags = VPU_JOB_QUEUE_FLAGS_TURBO_MODE;
203 	}
204 
205 	wmb(); /* Flush WC buffer for jobq->header */
206 
207 	if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
208 		ret = ivpu_hws_cmdq_init(file_priv, cmdq, engine, priority);
209 		if (ret)
210 			return ret;
211 	}
212 
213 	ret = ivpu_register_db(file_priv, cmdq);
214 	if (ret)
215 		return ret;
216 
217 	cmdq->db_registered = true;
218 
219 	return 0;
220 }
221 
222 static int ivpu_cmdq_fini(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
223 {
224 	struct ivpu_device *vdev = file_priv->vdev;
225 	int ret;
226 
227 	lockdep_assert_held(&file_priv->lock);
228 
229 	if (!cmdq->db_registered)
230 		return 0;
231 
232 	cmdq->db_registered = false;
233 
234 	if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
235 		ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->db_id);
236 		if (!ret)
237 			ivpu_dbg(vdev, JOB, "Command queue %d destroyed\n", cmdq->db_id);
238 	}
239 
240 	ret = ivpu_jsm_unregister_db(vdev, cmdq->db_id);
241 	if (!ret)
242 		ivpu_dbg(vdev, JOB, "DB %d unregistered\n", cmdq->db_id);
243 
244 	return 0;
245 }
246 
247 static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u16 engine,
248 					   u8 priority)
249 {
250 	int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority);
251 	struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx];
252 	int ret;
253 
254 	lockdep_assert_held(&file_priv->lock);
255 
256 	if (!cmdq) {
257 		cmdq = ivpu_cmdq_alloc(file_priv);
258 		if (!cmdq)
259 			return NULL;
260 		file_priv->cmdq[cmdq_idx] = cmdq;
261 	}
262 
263 	ret = ivpu_cmdq_init(file_priv, cmdq, engine, priority);
264 	if (ret)
265 		return NULL;
266 
267 	return cmdq;
268 }
269 
270 static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engine, u8 priority)
271 {
272 	int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority);
273 	struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx];
274 
275 	lockdep_assert_held(&file_priv->lock);
276 
277 	if (cmdq) {
278 		file_priv->cmdq[cmdq_idx] = NULL;
279 		ivpu_cmdq_fini(file_priv, cmdq);
280 		ivpu_cmdq_free(file_priv, cmdq);
281 	}
282 }
283 
284 void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv)
285 {
286 	u16 engine;
287 	u8 priority;
288 
289 	lockdep_assert_held(&file_priv->lock);
290 
291 	for (engine = 0; engine < IVPU_NUM_ENGINES; engine++)
292 		for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++)
293 			ivpu_cmdq_release_locked(file_priv, engine, priority);
294 }
295 
296 /*
297  * Mark the doorbell as unregistered
298  * This function needs to be called when the VPU hardware is restarted
299  * and FW loses job queue state. The next time job queue is used it
300  * will be registered again.
301  */
302 static void ivpu_cmdq_reset(struct ivpu_file_priv *file_priv)
303 {
304 	u16 engine;
305 	u8 priority;
306 
307 	mutex_lock(&file_priv->lock);
308 
309 	for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) {
310 		for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) {
311 			int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority);
312 			struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx];
313 
314 			if (cmdq)
315 				cmdq->db_registered = false;
316 		}
317 	}
318 
319 	mutex_unlock(&file_priv->lock);
320 }
321 
322 void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev)
323 {
324 	struct ivpu_file_priv *file_priv;
325 	unsigned long ctx_id;
326 
327 	mutex_lock(&vdev->context_list_lock);
328 
329 	xa_for_each(&vdev->context_xa, ctx_id, file_priv)
330 		ivpu_cmdq_reset(file_priv);
331 
332 	mutex_unlock(&vdev->context_list_lock);
333 }
334 
335 static void ivpu_cmdq_fini_all(struct ivpu_file_priv *file_priv)
336 {
337 	u16 engine;
338 	u8 priority;
339 
340 	for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) {
341 		for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) {
342 			int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority);
343 
344 			if (file_priv->cmdq[cmdq_idx])
345 				ivpu_cmdq_fini(file_priv, file_priv->cmdq[cmdq_idx]);
346 		}
347 	}
348 }
349 
350 void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv)
351 {
352 	struct ivpu_device *vdev = file_priv->vdev;
353 
354 	lockdep_assert_held(&file_priv->lock);
355 
356 	ivpu_cmdq_fini_all(file_priv);
357 
358 	if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_OS)
359 		ivpu_jsm_context_release(vdev, file_priv->ctx.id);
360 }
361 
362 static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job)
363 {
364 	struct ivpu_device *vdev = job->vdev;
365 	struct vpu_job_queue_header *header = &cmdq->jobq->header;
366 	struct vpu_job_queue_entry *entry;
367 	u32 tail = READ_ONCE(header->tail);
368 	u32 next_entry = (tail + 1) % cmdq->entry_count;
369 
370 	/* Check if there is space left in job queue */
371 	if (next_entry == header->head) {
372 		ivpu_dbg(vdev, JOB, "Job queue full: ctx %d engine %d db %d head %d tail %d\n",
373 			 job->file_priv->ctx.id, job->engine_idx, cmdq->db_id, header->head, tail);
374 		return -EBUSY;
375 	}
376 
377 	entry = &cmdq->jobq->slot[tail].job;
378 	entry->batch_buf_addr = job->cmd_buf_vpu_addr;
379 	entry->job_id = job->job_id;
380 	entry->flags = 0;
381 	if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION))
382 		entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK;
383 
384 	if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW &&
385 	    (unlikely(!(ivpu_test_mode & IVPU_TEST_MODE_PREEMPTION_DISABLE)))) {
386 		if (cmdq->primary_preempt_buf) {
387 			entry->primary_preempt_buf_addr = cmdq->primary_preempt_buf->vpu_addr;
388 			entry->primary_preempt_buf_size = ivpu_bo_size(cmdq->primary_preempt_buf);
389 		}
390 
391 		if (cmdq->secondary_preempt_buf) {
392 			entry->secondary_preempt_buf_addr = cmdq->secondary_preempt_buf->vpu_addr;
393 			entry->secondary_preempt_buf_size =
394 				ivpu_bo_size(cmdq->secondary_preempt_buf);
395 		}
396 	}
397 
398 	wmb(); /* Ensure that tail is updated after filling entry */
399 	header->tail = next_entry;
400 	wmb(); /* Flush WC buffer for jobq header */
401 
402 	return 0;
403 }
404 
405 struct ivpu_fence {
406 	struct dma_fence base;
407 	spinlock_t lock; /* protects base */
408 	struct ivpu_device *vdev;
409 };
410 
411 static inline struct ivpu_fence *to_vpu_fence(struct dma_fence *fence)
412 {
413 	return container_of(fence, struct ivpu_fence, base);
414 }
415 
416 static const char *ivpu_fence_get_driver_name(struct dma_fence *fence)
417 {
418 	return DRIVER_NAME;
419 }
420 
421 static const char *ivpu_fence_get_timeline_name(struct dma_fence *fence)
422 {
423 	struct ivpu_fence *ivpu_fence = to_vpu_fence(fence);
424 
425 	return dev_name(ivpu_fence->vdev->drm.dev);
426 }
427 
428 static const struct dma_fence_ops ivpu_fence_ops = {
429 	.get_driver_name = ivpu_fence_get_driver_name,
430 	.get_timeline_name = ivpu_fence_get_timeline_name,
431 };
432 
433 static struct dma_fence *ivpu_fence_create(struct ivpu_device *vdev)
434 {
435 	struct ivpu_fence *fence;
436 
437 	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
438 	if (!fence)
439 		return NULL;
440 
441 	fence->vdev = vdev;
442 	spin_lock_init(&fence->lock);
443 	dma_fence_init(&fence->base, &ivpu_fence_ops, &fence->lock, dma_fence_context_alloc(1), 1);
444 
445 	return &fence->base;
446 }
447 
448 static void ivpu_job_destroy(struct ivpu_job *job)
449 {
450 	struct ivpu_device *vdev = job->vdev;
451 	u32 i;
452 
453 	ivpu_dbg(vdev, JOB, "Job destroyed: id %3u ctx %2d engine %d",
454 		 job->job_id, job->file_priv->ctx.id, job->engine_idx);
455 
456 	for (i = 0; i < job->bo_count; i++)
457 		if (job->bos[i])
458 			drm_gem_object_put(&job->bos[i]->base.base);
459 
460 	dma_fence_put(job->done_fence);
461 	ivpu_file_priv_put(&job->file_priv);
462 	kfree(job);
463 }
464 
465 static struct ivpu_job *
466 ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
467 {
468 	struct ivpu_device *vdev = file_priv->vdev;
469 	struct ivpu_job *job;
470 
471 	job = kzalloc(struct_size(job, bos, bo_count), GFP_KERNEL);
472 	if (!job)
473 		return NULL;
474 
475 	job->vdev = vdev;
476 	job->engine_idx = engine_idx;
477 	job->bo_count = bo_count;
478 	job->done_fence = ivpu_fence_create(vdev);
479 	if (!job->done_fence) {
480 		ivpu_warn_ratelimited(vdev, "Failed to create a fence\n");
481 		goto err_free_job;
482 	}
483 
484 	job->file_priv = ivpu_file_priv_get(file_priv);
485 
486 	trace_job("create", job);
487 	ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx);
488 	return job;
489 
490 err_free_job:
491 	kfree(job);
492 	return NULL;
493 }
494 
495 static struct ivpu_job *ivpu_job_remove_from_submitted_jobs(struct ivpu_device *vdev, u32 job_id)
496 {
497 	struct ivpu_job *job;
498 
499 	xa_lock(&vdev->submitted_jobs_xa);
500 	job = __xa_erase(&vdev->submitted_jobs_xa, job_id);
501 
502 	if (xa_empty(&vdev->submitted_jobs_xa) && job) {
503 		vdev->busy_time = ktime_add(ktime_sub(ktime_get(), vdev->busy_start_ts),
504 					    vdev->busy_time);
505 	}
506 
507 	xa_unlock(&vdev->submitted_jobs_xa);
508 
509 	return job;
510 }
511 
512 static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job_status)
513 {
514 	struct ivpu_job *job;
515 
516 	job = ivpu_job_remove_from_submitted_jobs(vdev, job_id);
517 	if (!job)
518 		return -ENOENT;
519 
520 	if (job->file_priv->has_mmu_faults)
521 		job_status = DRM_IVPU_JOB_STATUS_ABORTED;
522 
523 	job->bos[CMD_BUF_IDX]->job_status = job_status;
524 	dma_fence_signal(job->done_fence);
525 
526 	trace_job("done", job);
527 	ivpu_dbg(vdev, JOB, "Job complete:  id %3u ctx %2d engine %d status 0x%x\n",
528 		 job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status);
529 
530 	ivpu_job_destroy(job);
531 	ivpu_stop_job_timeout_detection(vdev);
532 
533 	ivpu_rpm_put(vdev);
534 	return 0;
535 }
536 
537 void ivpu_jobs_abort_all(struct ivpu_device *vdev)
538 {
539 	struct ivpu_job *job;
540 	unsigned long id;
541 
542 	xa_for_each(&vdev->submitted_jobs_xa, id, job)
543 		ivpu_job_signal_and_destroy(vdev, id, DRM_IVPU_JOB_STATUS_ABORTED);
544 }
545 
546 static int ivpu_job_submit(struct ivpu_job *job, u8 priority)
547 {
548 	struct ivpu_file_priv *file_priv = job->file_priv;
549 	struct ivpu_device *vdev = job->vdev;
550 	struct ivpu_cmdq *cmdq;
551 	bool is_first_job;
552 	int ret;
553 
554 	ret = ivpu_rpm_get(vdev);
555 	if (ret < 0)
556 		return ret;
557 
558 	mutex_lock(&file_priv->lock);
559 
560 	cmdq = ivpu_cmdq_acquire(file_priv, job->engine_idx, priority);
561 	if (!cmdq) {
562 		ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx %d engine %d prio %d\n",
563 				      file_priv->ctx.id, job->engine_idx, priority);
564 		ret = -EINVAL;
565 		goto err_unlock_file_priv;
566 	}
567 
568 	xa_lock(&vdev->submitted_jobs_xa);
569 	is_first_job = xa_empty(&vdev->submitted_jobs_xa);
570 	ret = ivpu_id_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, &file_priv->job_limit,
571 			    file_priv->default_job_limit);
572 	if (ret) {
573 		ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n",
574 			 file_priv->ctx.id);
575 		ret = -EBUSY;
576 		goto err_unlock_submitted_jobs_xa;
577 	}
578 
579 	ret = ivpu_cmdq_push_job(cmdq, job);
580 	if (ret)
581 		goto err_erase_xa;
582 
583 	ivpu_start_job_timeout_detection(vdev);
584 
585 	if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) {
586 		cmdq->jobq->header.head = cmdq->jobq->header.tail;
587 		wmb(); /* Flush WC buffer for jobq header */
588 	} else {
589 		ivpu_cmdq_ring_db(vdev, cmdq);
590 		if (is_first_job)
591 			vdev->busy_start_ts = ktime_get();
592 	}
593 
594 	trace_job("submit", job);
595 	ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d prio %d addr 0x%llx next %d\n",
596 		 job->job_id, file_priv->ctx.id, job->engine_idx, priority,
597 		 job->cmd_buf_vpu_addr, cmdq->jobq->header.tail);
598 
599 	xa_unlock(&vdev->submitted_jobs_xa);
600 
601 	mutex_unlock(&file_priv->lock);
602 
603 	if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW))
604 		ivpu_job_signal_and_destroy(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS);
605 
606 	return 0;
607 
608 err_erase_xa:
609 	__xa_erase(&vdev->submitted_jobs_xa, job->job_id);
610 err_unlock_submitted_jobs_xa:
611 	xa_unlock(&vdev->submitted_jobs_xa);
612 err_unlock_file_priv:
613 	mutex_unlock(&file_priv->lock);
614 	ivpu_rpm_put(vdev);
615 	return ret;
616 }
617 
618 static int
619 ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 *buf_handles,
620 				u32 buf_count, u32 commands_offset)
621 {
622 	struct ivpu_file_priv *file_priv = file->driver_priv;
623 	struct ivpu_device *vdev = file_priv->vdev;
624 	struct ww_acquire_ctx acquire_ctx;
625 	enum dma_resv_usage usage;
626 	struct ivpu_bo *bo;
627 	int ret;
628 	u32 i;
629 
630 	for (i = 0; i < buf_count; i++) {
631 		struct drm_gem_object *obj = drm_gem_object_lookup(file, buf_handles[i]);
632 
633 		if (!obj)
634 			return -ENOENT;
635 
636 		job->bos[i] = to_ivpu_bo(obj);
637 
638 		ret = ivpu_bo_pin(job->bos[i]);
639 		if (ret)
640 			return ret;
641 	}
642 
643 	bo = job->bos[CMD_BUF_IDX];
644 	if (!dma_resv_test_signaled(bo->base.base.resv, DMA_RESV_USAGE_READ)) {
645 		ivpu_warn(vdev, "Buffer is already in use\n");
646 		return -EBUSY;
647 	}
648 
649 	if (commands_offset >= ivpu_bo_size(bo)) {
650 		ivpu_warn(vdev, "Invalid command buffer offset %u\n", commands_offset);
651 		return -EINVAL;
652 	}
653 
654 	job->cmd_buf_vpu_addr = bo->vpu_addr + commands_offset;
655 
656 	ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, buf_count,
657 					&acquire_ctx);
658 	if (ret) {
659 		ivpu_warn(vdev, "Failed to lock reservations: %d\n", ret);
660 		return ret;
661 	}
662 
663 	for (i = 0; i < buf_count; i++) {
664 		ret = dma_resv_reserve_fences(job->bos[i]->base.base.resv, 1);
665 		if (ret) {
666 			ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret);
667 			goto unlock_reservations;
668 		}
669 	}
670 
671 	for (i = 0; i < buf_count; i++) {
672 		usage = (i == CMD_BUF_IDX) ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_BOOKKEEP;
673 		dma_resv_add_fence(job->bos[i]->base.base.resv, job->done_fence, usage);
674 	}
675 
676 unlock_reservations:
677 	drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, buf_count, &acquire_ctx);
678 
679 	wmb(); /* Flush write combining buffers */
680 
681 	return ret;
682 }
683 
684 static inline u8 ivpu_job_to_hws_priority(struct ivpu_file_priv *file_priv, u8 priority)
685 {
686 	if (priority == DRM_IVPU_JOB_PRIORITY_DEFAULT)
687 		return DRM_IVPU_JOB_PRIORITY_NORMAL;
688 
689 	return priority - 1;
690 }
691 
692 int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
693 {
694 	struct ivpu_file_priv *file_priv = file->driver_priv;
695 	struct ivpu_device *vdev = file_priv->vdev;
696 	struct drm_ivpu_submit *params = data;
697 	struct ivpu_job *job;
698 	u32 *buf_handles;
699 	int idx, ret;
700 	u8 priority;
701 
702 	if (params->engine > DRM_IVPU_ENGINE_COPY)
703 		return -EINVAL;
704 
705 	if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
706 		return -EINVAL;
707 
708 	if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT)
709 		return -EINVAL;
710 
711 	if (!IS_ALIGNED(params->commands_offset, 8))
712 		return -EINVAL;
713 
714 	if (!file_priv->ctx.id)
715 		return -EINVAL;
716 
717 	if (file_priv->has_mmu_faults)
718 		return -EBADFD;
719 
720 	buf_handles = kcalloc(params->buffer_count, sizeof(u32), GFP_KERNEL);
721 	if (!buf_handles)
722 		return -ENOMEM;
723 
724 	ret = copy_from_user(buf_handles,
725 			     (void __user *)params->buffers_ptr,
726 			     params->buffer_count * sizeof(u32));
727 	if (ret) {
728 		ret = -EFAULT;
729 		goto err_free_handles;
730 	}
731 
732 	if (!drm_dev_enter(&vdev->drm, &idx)) {
733 		ret = -ENODEV;
734 		goto err_free_handles;
735 	}
736 
737 	ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n",
738 		 file_priv->ctx.id, params->buffer_count);
739 
740 	job = ivpu_job_create(file_priv, params->engine, params->buffer_count);
741 	if (!job) {
742 		ivpu_err(vdev, "Failed to create job\n");
743 		ret = -ENOMEM;
744 		goto err_exit_dev;
745 	}
746 
747 	ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count,
748 					      params->commands_offset);
749 	if (ret) {
750 		ivpu_err(vdev, "Failed to prepare job: %d\n", ret);
751 		goto err_destroy_job;
752 	}
753 
754 	priority = ivpu_job_to_hws_priority(file_priv, params->priority);
755 
756 	down_read(&vdev->pm->reset_lock);
757 	ret = ivpu_job_submit(job, priority);
758 	up_read(&vdev->pm->reset_lock);
759 	if (ret)
760 		goto err_signal_fence;
761 
762 	drm_dev_exit(idx);
763 	kfree(buf_handles);
764 	return ret;
765 
766 err_signal_fence:
767 	dma_fence_signal(job->done_fence);
768 err_destroy_job:
769 	ivpu_job_destroy(job);
770 err_exit_dev:
771 	drm_dev_exit(idx);
772 err_free_handles:
773 	kfree(buf_handles);
774 	return ret;
775 }
776 
777 static void
778 ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr,
779 		       struct vpu_jsm_msg *jsm_msg)
780 {
781 	struct vpu_ipc_msg_payload_job_done *payload;
782 	int ret;
783 
784 	if (!jsm_msg) {
785 		ivpu_err(vdev, "IPC message has no JSM payload\n");
786 		return;
787 	}
788 
789 	if (jsm_msg->result != VPU_JSM_STATUS_SUCCESS) {
790 		ivpu_err(vdev, "Invalid JSM message result: %d\n", jsm_msg->result);
791 		return;
792 	}
793 
794 	payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload;
795 	ret = ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status);
796 	if (!ret && !xa_empty(&vdev->submitted_jobs_xa))
797 		ivpu_start_job_timeout_detection(vdev);
798 }
799 
800 void ivpu_job_done_consumer_init(struct ivpu_device *vdev)
801 {
802 	ivpu_ipc_consumer_add(vdev, &vdev->job_done_consumer,
803 			      VPU_IPC_CHAN_JOB_RET, ivpu_job_done_callback);
804 }
805 
806 void ivpu_job_done_consumer_fini(struct ivpu_device *vdev)
807 {
808 	ivpu_ipc_consumer_del(vdev, &vdev->job_done_consumer);
809 }
810