1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013 Red Hat
4  * Author: Rob Clark <robdclark@gmail.com>
5  */
6 
7 #include <linux/file.h>
8 #include <linux/sync_file.h>
9 #include <linux/uaccess.h>
10 
11 #include <drm/drm_drv.h>
12 #include <drm/drm_file.h>
13 #include <drm/drm_syncobj.h>
14 
15 #include "msm_drv.h"
16 #include "msm_gpu.h"
17 #include "msm_gem.h"
18 #include "msm_gpu_trace.h"
19 
20 /*
21  * Cmdstream submission:
22  */
23 
24 static struct msm_gem_submit *submit_create(struct drm_device *dev,
25 		struct msm_gpu *gpu,
26 		struct msm_gpu_submitqueue *queue, uint32_t nr_bos,
27 		uint32_t nr_cmds)
28 {
29 	struct msm_gem_submit *submit;
30 	uint64_t sz;
31 	int ret;
32 
33 	sz = struct_size(submit, bos, nr_bos) +
34 			((u64)nr_cmds * sizeof(submit->cmd[0]));
35 
36 	if (sz > SIZE_MAX)
37 		return ERR_PTR(-ENOMEM);
38 
39 	submit = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
40 	if (!submit)
41 		return ERR_PTR(-ENOMEM);
42 
43 	ret = drm_sched_job_init(&submit->base, queue->entity, queue);
44 	if (ret) {
45 		kfree(submit);
46 		return ERR_PTR(ret);
47 	}
48 
49 	kref_init(&submit->ref);
50 	submit->dev = dev;
51 	submit->aspace = queue->ctx->aspace;
52 	submit->gpu = gpu;
53 	submit->cmd = (void *)&submit->bos[nr_bos];
54 	submit->queue = queue;
55 	submit->ring = gpu->rb[queue->ring_nr];
56 	submit->fault_dumped = false;
57 
58 	INIT_LIST_HEAD(&submit->node);
59 
60 	return submit;
61 }
62 
63 void __msm_gem_submit_destroy(struct kref *kref)
64 {
65 	struct msm_gem_submit *submit =
66 			container_of(kref, struct msm_gem_submit, ref);
67 	unsigned i;
68 
69 	if (submit->fence_id) {
70 		mutex_lock(&submit->queue->lock);
71 		idr_remove(&submit->queue->fence_idr, submit->fence_id);
72 		mutex_unlock(&submit->queue->lock);
73 	}
74 
75 	dma_fence_put(submit->user_fence);
76 	dma_fence_put(submit->hw_fence);
77 
78 	put_pid(submit->pid);
79 	msm_submitqueue_put(submit->queue);
80 
81 	for (i = 0; i < submit->nr_cmds; i++)
82 		kfree(submit->cmd[i].relocs);
83 
84 	kfree(submit);
85 }
86 
87 static int submit_lookup_objects(struct msm_gem_submit *submit,
88 		struct drm_msm_gem_submit *args, struct drm_file *file)
89 {
90 	unsigned i;
91 	int ret = 0;
92 
93 	for (i = 0; i < args->nr_bos; i++) {
94 		struct drm_msm_gem_submit_bo submit_bo;
95 		void __user *userptr =
96 			u64_to_user_ptr(args->bos + (i * sizeof(submit_bo)));
97 
98 		/* make sure we don't have garbage flags, in case we hit
99 		 * error path before flags is initialized:
100 		 */
101 		submit->bos[i].flags = 0;
102 
103 		if (copy_from_user(&submit_bo, userptr, sizeof(submit_bo))) {
104 			ret = -EFAULT;
105 			i = 0;
106 			goto out;
107 		}
108 
109 /* at least one of READ and/or WRITE flags should be set: */
110 #define MANDATORY_FLAGS (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE)
111 
112 		if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
113 			!(submit_bo.flags & MANDATORY_FLAGS)) {
114 			DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
115 			ret = -EINVAL;
116 			i = 0;
117 			goto out;
118 		}
119 
120 		submit->bos[i].handle = submit_bo.handle;
121 		submit->bos[i].flags = submit_bo.flags;
122 		/* in validate_objects() we figure out if this is true: */
123 		submit->bos[i].iova  = submit_bo.presumed;
124 	}
125 
126 	spin_lock(&file->table_lock);
127 
128 	for (i = 0; i < args->nr_bos; i++) {
129 		struct drm_gem_object *obj;
130 
131 		/* normally use drm_gem_object_lookup(), but for bulk lookup
132 		 * all under single table_lock just hit object_idr directly:
133 		 */
134 		obj = idr_find(&file->object_idr, submit->bos[i].handle);
135 		if (!obj) {
136 			DRM_ERROR("invalid handle %u at index %u\n", submit->bos[i].handle, i);
137 			ret = -EINVAL;
138 			goto out_unlock;
139 		}
140 
141 		drm_gem_object_get(obj);
142 
143 		submit->bos[i].obj = to_msm_bo(obj);
144 	}
145 
146 out_unlock:
147 	spin_unlock(&file->table_lock);
148 
149 out:
150 	submit->nr_bos = i;
151 
152 	return ret;
153 }
154 
155 static int submit_lookup_cmds(struct msm_gem_submit *submit,
156 		struct drm_msm_gem_submit *args, struct drm_file *file)
157 {
158 	unsigned i;
159 	size_t sz;
160 	int ret = 0;
161 
162 	for (i = 0; i < args->nr_cmds; i++) {
163 		struct drm_msm_gem_submit_cmd submit_cmd;
164 		void __user *userptr =
165 			u64_to_user_ptr(args->cmds + (i * sizeof(submit_cmd)));
166 
167 		ret = copy_from_user(&submit_cmd, userptr, sizeof(submit_cmd));
168 		if (ret) {
169 			ret = -EFAULT;
170 			goto out;
171 		}
172 
173 		/* validate input from userspace: */
174 		switch (submit_cmd.type) {
175 		case MSM_SUBMIT_CMD_BUF:
176 		case MSM_SUBMIT_CMD_IB_TARGET_BUF:
177 		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
178 			break;
179 		default:
180 			DRM_ERROR("invalid type: %08x\n", submit_cmd.type);
181 			return -EINVAL;
182 		}
183 
184 		if (submit_cmd.size % 4) {
185 			DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
186 					submit_cmd.size);
187 			ret = -EINVAL;
188 			goto out;
189 		}
190 
191 		submit->cmd[i].type = submit_cmd.type;
192 		submit->cmd[i].size = submit_cmd.size / 4;
193 		submit->cmd[i].offset = submit_cmd.submit_offset / 4;
194 		submit->cmd[i].idx  = submit_cmd.submit_idx;
195 		submit->cmd[i].nr_relocs = submit_cmd.nr_relocs;
196 
197 		userptr = u64_to_user_ptr(submit_cmd.relocs);
198 
199 		sz = array_size(submit_cmd.nr_relocs,
200 				sizeof(struct drm_msm_gem_submit_reloc));
201 		/* check for overflow: */
202 		if (sz == SIZE_MAX) {
203 			ret = -ENOMEM;
204 			goto out;
205 		}
206 		submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL);
207 		ret = copy_from_user(submit->cmd[i].relocs, userptr, sz);
208 		if (ret) {
209 			ret = -EFAULT;
210 			goto out;
211 		}
212 	}
213 
214 out:
215 	return ret;
216 }
217 
218 /* Unwind bo state, according to cleanup_flags.  In the success case, only
219  * the lock is dropped at the end of the submit (and active/pin ref is dropped
220  * later when the submit is retired).
221  */
222 static void submit_cleanup_bo(struct msm_gem_submit *submit, int i,
223 		unsigned cleanup_flags)
224 {
225 	struct drm_gem_object *obj = &submit->bos[i].obj->base;
226 	unsigned flags = submit->bos[i].flags & cleanup_flags;
227 
228 	/*
229 	 * Clear flags bit before dropping lock, so that the msm_job_run()
230 	 * path isn't racing with submit_cleanup() (ie. the read/modify/
231 	 * write is protected by the obj lock in all paths)
232 	 */
233 	submit->bos[i].flags &= ~cleanup_flags;
234 
235 	if (flags & BO_VMA_PINNED)
236 		msm_gem_unpin_vma(submit->bos[i].vma);
237 
238 	if (flags & BO_OBJ_PINNED)
239 		msm_gem_unpin_locked(obj);
240 
241 	if (flags & BO_ACTIVE)
242 		msm_gem_active_put(obj);
243 
244 	if (flags & BO_LOCKED)
245 		dma_resv_unlock(obj->resv);
246 }
247 
248 static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i)
249 {
250 	unsigned cleanup_flags = BO_VMA_PINNED | BO_OBJ_PINNED |
251 				 BO_ACTIVE | BO_LOCKED;
252 	submit_cleanup_bo(submit, i, cleanup_flags);
253 
254 	if (!(submit->bos[i].flags & BO_VALID))
255 		submit->bos[i].iova = 0;
256 }
257 
258 /* This is where we make sure all the bo's are reserved and pin'd: */
259 static int submit_lock_objects(struct msm_gem_submit *submit)
260 {
261 	int contended, slow_locked = -1, i, ret = 0;
262 
263 retry:
264 	for (i = 0; i < submit->nr_bos; i++) {
265 		struct msm_gem_object *msm_obj = submit->bos[i].obj;
266 
267 		if (slow_locked == i)
268 			slow_locked = -1;
269 
270 		contended = i;
271 
272 		if (!(submit->bos[i].flags & BO_LOCKED)) {
273 			ret = dma_resv_lock_interruptible(msm_obj->base.resv,
274 							  &submit->ticket);
275 			if (ret)
276 				goto fail;
277 			submit->bos[i].flags |= BO_LOCKED;
278 		}
279 	}
280 
281 	ww_acquire_done(&submit->ticket);
282 
283 	return 0;
284 
285 fail:
286 	if (ret == -EALREADY) {
287 		DRM_ERROR("handle %u at index %u already on submit list\n",
288 				submit->bos[i].handle, i);
289 		ret = -EINVAL;
290 	}
291 
292 	for (; i >= 0; i--)
293 		submit_unlock_unpin_bo(submit, i);
294 
295 	if (slow_locked > 0)
296 		submit_unlock_unpin_bo(submit, slow_locked);
297 
298 	if (ret == -EDEADLK) {
299 		struct msm_gem_object *msm_obj = submit->bos[contended].obj;
300 		/* we lost out in a seqno race, lock and retry.. */
301 		ret = dma_resv_lock_slow_interruptible(msm_obj->base.resv,
302 						       &submit->ticket);
303 		if (!ret) {
304 			submit->bos[contended].flags |= BO_LOCKED;
305 			slow_locked = contended;
306 			goto retry;
307 		}
308 
309 		/* Not expecting -EALREADY here, if the bo was already
310 		 * locked, we should have gotten -EALREADY already from
311 		 * the dma_resv_lock_interruptable() call.
312 		 */
313 		WARN_ON_ONCE(ret == -EALREADY);
314 	}
315 
316 	return ret;
317 }
318 
319 static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
320 {
321 	int i, ret = 0;
322 
323 	for (i = 0; i < submit->nr_bos; i++) {
324 		struct drm_gem_object *obj = &submit->bos[i].obj->base;
325 		bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE;
326 
327 		/* NOTE: _reserve_shared() must happen before
328 		 * _add_shared_fence(), which makes this a slightly
329 		 * strange place to call it.  OTOH this is a
330 		 * convenient can-fail point to hook it in.
331 		 */
332 		ret = dma_resv_reserve_fences(obj->resv, 1);
333 		if (ret)
334 			return ret;
335 
336 		/* exclusive fences must be ordered */
337 		if (no_implicit && !write)
338 			continue;
339 
340 		ret = drm_sched_job_add_implicit_dependencies(&submit->base,
341 							      obj,
342 							      write);
343 		if (ret)
344 			break;
345 	}
346 
347 	return ret;
348 }
349 
350 static int submit_pin_objects(struct msm_gem_submit *submit)
351 {
352 	int i, ret = 0;
353 
354 	submit->valid = true;
355 
356 	/*
357 	 * Increment active_count first, so if under memory pressure, we
358 	 * don't inadvertently evict a bo needed by the submit in order
359 	 * to pin an earlier bo in the same submit.
360 	 */
361 	for (i = 0; i < submit->nr_bos; i++) {
362 		struct drm_gem_object *obj = &submit->bos[i].obj->base;
363 
364 		msm_gem_active_get(obj, submit->gpu);
365 		submit->bos[i].flags |= BO_ACTIVE;
366 	}
367 
368 	for (i = 0; i < submit->nr_bos; i++) {
369 		struct drm_gem_object *obj = &submit->bos[i].obj->base;
370 		struct msm_gem_vma *vma;
371 
372 		/* if locking succeeded, pin bo: */
373 		vma = msm_gem_get_vma_locked(obj, submit->aspace);
374 		if (IS_ERR(vma)) {
375 			ret = PTR_ERR(vma);
376 			break;
377 		}
378 
379 		ret = msm_gem_pin_vma_locked(obj, vma);
380 		if (ret)
381 			break;
382 
383 		submit->bos[i].flags |= BO_OBJ_PINNED | BO_VMA_PINNED;
384 		submit->bos[i].vma = vma;
385 
386 		if (vma->iova == submit->bos[i].iova) {
387 			submit->bos[i].flags |= BO_VALID;
388 		} else {
389 			submit->bos[i].iova = vma->iova;
390 			/* iova changed, so address in cmdstream is not valid: */
391 			submit->bos[i].flags &= ~BO_VALID;
392 			submit->valid = false;
393 		}
394 	}
395 
396 	return ret;
397 }
398 
399 static void submit_attach_object_fences(struct msm_gem_submit *submit)
400 {
401 	int i;
402 
403 	for (i = 0; i < submit->nr_bos; i++) {
404 		struct drm_gem_object *obj = &submit->bos[i].obj->base;
405 
406 		if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
407 			dma_resv_add_fence(obj->resv, submit->user_fence,
408 					   DMA_RESV_USAGE_WRITE);
409 		else if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
410 			dma_resv_add_fence(obj->resv, submit->user_fence,
411 					   DMA_RESV_USAGE_READ);
412 	}
413 }
414 
415 static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
416 		struct msm_gem_object **obj, uint64_t *iova, bool *valid)
417 {
418 	if (idx >= submit->nr_bos) {
419 		DRM_ERROR("invalid buffer index: %u (out of %u)\n",
420 				idx, submit->nr_bos);
421 		return -EINVAL;
422 	}
423 
424 	if (obj)
425 		*obj = submit->bos[idx].obj;
426 	if (iova)
427 		*iova = submit->bos[idx].iova;
428 	if (valid)
429 		*valid = !!(submit->bos[idx].flags & BO_VALID);
430 
431 	return 0;
432 }
433 
434 /* process the reloc's and patch up the cmdstream as needed: */
435 static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *obj,
436 		uint32_t offset, uint32_t nr_relocs, struct drm_msm_gem_submit_reloc *relocs)
437 {
438 	uint32_t i, last_offset = 0;
439 	uint32_t *ptr;
440 	int ret = 0;
441 
442 	if (!nr_relocs)
443 		return 0;
444 
445 	if (offset % 4) {
446 		DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
447 		return -EINVAL;
448 	}
449 
450 	/* For now, just map the entire thing.  Eventually we probably
451 	 * to do it page-by-page, w/ kmap() if not vmap()d..
452 	 */
453 	ptr = msm_gem_get_vaddr_locked(&obj->base);
454 
455 	if (IS_ERR(ptr)) {
456 		ret = PTR_ERR(ptr);
457 		DBG("failed to map: %d", ret);
458 		return ret;
459 	}
460 
461 	for (i = 0; i < nr_relocs; i++) {
462 		struct drm_msm_gem_submit_reloc submit_reloc = relocs[i];
463 		uint32_t off;
464 		uint64_t iova;
465 		bool valid;
466 
467 		if (submit_reloc.submit_offset % 4) {
468 			DRM_ERROR("non-aligned reloc offset: %u\n",
469 					submit_reloc.submit_offset);
470 			ret = -EINVAL;
471 			goto out;
472 		}
473 
474 		/* offset in dwords: */
475 		off = submit_reloc.submit_offset / 4;
476 
477 		if ((off >= (obj->base.size / 4)) ||
478 				(off < last_offset)) {
479 			DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
480 			ret = -EINVAL;
481 			goto out;
482 		}
483 
484 		ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid);
485 		if (ret)
486 			goto out;
487 
488 		if (valid)
489 			continue;
490 
491 		iova += submit_reloc.reloc_offset;
492 
493 		if (submit_reloc.shift < 0)
494 			iova >>= -submit_reloc.shift;
495 		else
496 			iova <<= submit_reloc.shift;
497 
498 		ptr[off] = iova | submit_reloc.or;
499 
500 		last_offset = off;
501 	}
502 
503 out:
504 	msm_gem_put_vaddr_locked(&obj->base);
505 
506 	return ret;
507 }
508 
509 /* Cleanup submit at end of ioctl.  In the error case, this also drops
510  * references, unpins, and drops active refcnt.  In the non-error case,
511  * this is done when the submit is retired.
512  */
513 static void submit_cleanup(struct msm_gem_submit *submit, bool error)
514 {
515 	unsigned cleanup_flags = BO_LOCKED;
516 	unsigned i;
517 
518 	if (error)
519 		cleanup_flags |= BO_VMA_PINNED | BO_OBJ_PINNED | BO_ACTIVE;
520 
521 	for (i = 0; i < submit->nr_bos; i++) {
522 		struct msm_gem_object *msm_obj = submit->bos[i].obj;
523 		submit_cleanup_bo(submit, i, cleanup_flags);
524 		if (error)
525 			drm_gem_object_put(&msm_obj->base);
526 	}
527 }
528 
529 void msm_submit_retire(struct msm_gem_submit *submit)
530 {
531 	int i;
532 
533 	for (i = 0; i < submit->nr_bos; i++) {
534 		struct drm_gem_object *obj = &submit->bos[i].obj->base;
535 
536 		msm_gem_lock(obj);
537 		/* Note, VMA already fence-unpinned before submit: */
538 		submit_cleanup_bo(submit, i, BO_OBJ_PINNED | BO_ACTIVE);
539 		msm_gem_unlock(obj);
540 		drm_gem_object_put(obj);
541 	}
542 }
543 
544 struct msm_submit_post_dep {
545 	struct drm_syncobj *syncobj;
546 	uint64_t point;
547 	struct dma_fence_chain *chain;
548 };
549 
550 static struct drm_syncobj **msm_parse_deps(struct msm_gem_submit *submit,
551                                            struct drm_file *file,
552                                            uint64_t in_syncobjs_addr,
553                                            uint32_t nr_in_syncobjs,
554                                            size_t syncobj_stride,
555                                            struct msm_ringbuffer *ring)
556 {
557 	struct drm_syncobj **syncobjs = NULL;
558 	struct drm_msm_gem_submit_syncobj syncobj_desc = {0};
559 	int ret = 0;
560 	uint32_t i, j;
561 
562 	syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs),
563 	                   GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
564 	if (!syncobjs)
565 		return ERR_PTR(-ENOMEM);
566 
567 	for (i = 0; i < nr_in_syncobjs; ++i) {
568 		uint64_t address = in_syncobjs_addr + i * syncobj_stride;
569 		struct dma_fence *fence;
570 
571 		if (copy_from_user(&syncobj_desc,
572 			           u64_to_user_ptr(address),
573 			           min(syncobj_stride, sizeof(syncobj_desc)))) {
574 			ret = -EFAULT;
575 			break;
576 		}
577 
578 		if (syncobj_desc.point &&
579 		    !drm_core_check_feature(submit->dev, DRIVER_SYNCOBJ_TIMELINE)) {
580 			ret = -EOPNOTSUPP;
581 			break;
582 		}
583 
584 		if (syncobj_desc.flags & ~MSM_SUBMIT_SYNCOBJ_FLAGS) {
585 			ret = -EINVAL;
586 			break;
587 		}
588 
589 		ret = drm_syncobj_find_fence(file, syncobj_desc.handle,
590 		                             syncobj_desc.point, 0, &fence);
591 		if (ret)
592 			break;
593 
594 		ret = drm_sched_job_add_dependency(&submit->base, fence);
595 		if (ret)
596 			break;
597 
598 		if (syncobj_desc.flags & MSM_SUBMIT_SYNCOBJ_RESET) {
599 			syncobjs[i] =
600 				drm_syncobj_find(file, syncobj_desc.handle);
601 			if (!syncobjs[i]) {
602 				ret = -EINVAL;
603 				break;
604 			}
605 		}
606 	}
607 
608 	if (ret) {
609 		for (j = 0; j <= i; ++j) {
610 			if (syncobjs[j])
611 				drm_syncobj_put(syncobjs[j]);
612 		}
613 		kfree(syncobjs);
614 		return ERR_PTR(ret);
615 	}
616 	return syncobjs;
617 }
618 
619 static void msm_reset_syncobjs(struct drm_syncobj **syncobjs,
620                                uint32_t nr_syncobjs)
621 {
622 	uint32_t i;
623 
624 	for (i = 0; syncobjs && i < nr_syncobjs; ++i) {
625 		if (syncobjs[i])
626 			drm_syncobj_replace_fence(syncobjs[i], NULL);
627 	}
628 }
629 
630 static struct msm_submit_post_dep *msm_parse_post_deps(struct drm_device *dev,
631                                                        struct drm_file *file,
632                                                        uint64_t syncobjs_addr,
633                                                        uint32_t nr_syncobjs,
634                                                        size_t syncobj_stride)
635 {
636 	struct msm_submit_post_dep *post_deps;
637 	struct drm_msm_gem_submit_syncobj syncobj_desc = {0};
638 	int ret = 0;
639 	uint32_t i, j;
640 
641 	post_deps = kmalloc_array(nr_syncobjs, sizeof(*post_deps),
642 	                          GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
643 	if (!post_deps)
644 		return ERR_PTR(-ENOMEM);
645 
646 	for (i = 0; i < nr_syncobjs; ++i) {
647 		uint64_t address = syncobjs_addr + i * syncobj_stride;
648 
649 		if (copy_from_user(&syncobj_desc,
650 			           u64_to_user_ptr(address),
651 			           min(syncobj_stride, sizeof(syncobj_desc)))) {
652 			ret = -EFAULT;
653 			break;
654 		}
655 
656 		post_deps[i].point = syncobj_desc.point;
657 		post_deps[i].chain = NULL;
658 
659 		if (syncobj_desc.flags) {
660 			ret = -EINVAL;
661 			break;
662 		}
663 
664 		if (syncobj_desc.point) {
665 			if (!drm_core_check_feature(dev,
666 			                            DRIVER_SYNCOBJ_TIMELINE)) {
667 				ret = -EOPNOTSUPP;
668 				break;
669 			}
670 
671 			post_deps[i].chain = dma_fence_chain_alloc();
672 			if (!post_deps[i].chain) {
673 				ret = -ENOMEM;
674 				break;
675 			}
676 		}
677 
678 		post_deps[i].syncobj =
679 			drm_syncobj_find(file, syncobj_desc.handle);
680 		if (!post_deps[i].syncobj) {
681 			ret = -EINVAL;
682 			break;
683 		}
684 	}
685 
686 	if (ret) {
687 		for (j = 0; j <= i; ++j) {
688 			dma_fence_chain_free(post_deps[j].chain);
689 			if (post_deps[j].syncobj)
690 				drm_syncobj_put(post_deps[j].syncobj);
691 		}
692 
693 		kfree(post_deps);
694 		return ERR_PTR(ret);
695 	}
696 
697 	return post_deps;
698 }
699 
700 static void msm_process_post_deps(struct msm_submit_post_dep *post_deps,
701                                   uint32_t count, struct dma_fence *fence)
702 {
703 	uint32_t i;
704 
705 	for (i = 0; post_deps && i < count; ++i) {
706 		if (post_deps[i].chain) {
707 			drm_syncobj_add_point(post_deps[i].syncobj,
708 			                      post_deps[i].chain,
709 			                      fence, post_deps[i].point);
710 			post_deps[i].chain = NULL;
711 		} else {
712 			drm_syncobj_replace_fence(post_deps[i].syncobj,
713 			                          fence);
714 		}
715 	}
716 }
717 
718 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
719 		struct drm_file *file)
720 {
721 	static atomic_t ident = ATOMIC_INIT(0);
722 	struct msm_drm_private *priv = dev->dev_private;
723 	struct drm_msm_gem_submit *args = data;
724 	struct msm_file_private *ctx = file->driver_priv;
725 	struct msm_gem_submit *submit = NULL;
726 	struct msm_gpu *gpu = priv->gpu;
727 	struct msm_gpu_submitqueue *queue;
728 	struct msm_ringbuffer *ring;
729 	struct msm_submit_post_dep *post_deps = NULL;
730 	struct drm_syncobj **syncobjs_to_reset = NULL;
731 	int out_fence_fd = -1;
732 	struct pid *pid = get_pid(task_pid(current));
733 	bool has_ww_ticket = false;
734 	unsigned i;
735 	int ret, submitid;
736 
737 	if (!gpu)
738 		return -ENXIO;
739 
740 	if (args->pad)
741 		return -EINVAL;
742 
743 	if (unlikely(!ctx->aspace) && !capable(CAP_SYS_RAWIO)) {
744 		DRM_ERROR_RATELIMITED("IOMMU support or CAP_SYS_RAWIO required!\n");
745 		return -EPERM;
746 	}
747 
748 	/* for now, we just have 3d pipe.. eventually this would need to
749 	 * be more clever to dispatch to appropriate gpu module:
750 	 */
751 	if (MSM_PIPE_ID(args->flags) != MSM_PIPE_3D0)
752 		return -EINVAL;
753 
754 	if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS)
755 		return -EINVAL;
756 
757 	if (args->flags & MSM_SUBMIT_SUDO) {
758 		if (!IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) ||
759 		    !capable(CAP_SYS_RAWIO))
760 			return -EINVAL;
761 	}
762 
763 	queue = msm_submitqueue_get(ctx, args->queueid);
764 	if (!queue)
765 		return -ENOENT;
766 
767 	/* Get a unique identifier for the submission for logging purposes */
768 	submitid = atomic_inc_return(&ident) - 1;
769 
770 	ring = gpu->rb[queue->ring_nr];
771 	trace_msm_gpu_submit(pid_nr(pid), ring->id, submitid,
772 		args->nr_bos, args->nr_cmds);
773 
774 	ret = mutex_lock_interruptible(&queue->lock);
775 	if (ret)
776 		goto out_post_unlock;
777 
778 	if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
779 		out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
780 		if (out_fence_fd < 0) {
781 			ret = out_fence_fd;
782 			goto out_unlock;
783 		}
784 	}
785 
786 	submit = submit_create(dev, gpu, queue, args->nr_bos,
787 		args->nr_cmds);
788 	if (IS_ERR(submit)) {
789 		ret = PTR_ERR(submit);
790 		submit = NULL;
791 		goto out_unlock;
792 	}
793 
794 	submit->pid = pid;
795 	submit->ident = submitid;
796 
797 	if (args->flags & MSM_SUBMIT_SUDO)
798 		submit->in_rb = true;
799 
800 	if (args->flags & MSM_SUBMIT_FENCE_FD_IN) {
801 		struct dma_fence *in_fence;
802 
803 		in_fence = sync_file_get_fence(args->fence_fd);
804 
805 		if (!in_fence) {
806 			ret = -EINVAL;
807 			goto out_unlock;
808 		}
809 
810 		ret = drm_sched_job_add_dependency(&submit->base, in_fence);
811 		if (ret)
812 			goto out_unlock;
813 	}
814 
815 	if (args->flags & MSM_SUBMIT_SYNCOBJ_IN) {
816 		syncobjs_to_reset = msm_parse_deps(submit, file,
817 		                                   args->in_syncobjs,
818 		                                   args->nr_in_syncobjs,
819 		                                   args->syncobj_stride, ring);
820 		if (IS_ERR(syncobjs_to_reset)) {
821 			ret = PTR_ERR(syncobjs_to_reset);
822 			goto out_unlock;
823 		}
824 	}
825 
826 	if (args->flags & MSM_SUBMIT_SYNCOBJ_OUT) {
827 		post_deps = msm_parse_post_deps(dev, file,
828 		                                args->out_syncobjs,
829 		                                args->nr_out_syncobjs,
830 		                                args->syncobj_stride);
831 		if (IS_ERR(post_deps)) {
832 			ret = PTR_ERR(post_deps);
833 			goto out_unlock;
834 		}
835 	}
836 
837 	ret = submit_lookup_objects(submit, args, file);
838 	if (ret)
839 		goto out;
840 
841 	ret = submit_lookup_cmds(submit, args, file);
842 	if (ret)
843 		goto out;
844 
845 	/* copy_*_user while holding a ww ticket upsets lockdep */
846 	ww_acquire_init(&submit->ticket, &reservation_ww_class);
847 	has_ww_ticket = true;
848 	ret = submit_lock_objects(submit);
849 	if (ret)
850 		goto out;
851 
852 	ret = submit_fence_sync(submit, !!(args->flags & MSM_SUBMIT_NO_IMPLICIT));
853 	if (ret)
854 		goto out;
855 
856 	ret = submit_pin_objects(submit);
857 	if (ret)
858 		goto out;
859 
860 	for (i = 0; i < args->nr_cmds; i++) {
861 		struct msm_gem_object *msm_obj;
862 		uint64_t iova;
863 
864 		ret = submit_bo(submit, submit->cmd[i].idx,
865 				&msm_obj, &iova, NULL);
866 		if (ret)
867 			goto out;
868 
869 		if (!submit->cmd[i].size ||
870 			((submit->cmd[i].size + submit->cmd[i].offset) >
871 				msm_obj->base.size / 4)) {
872 			DRM_ERROR("invalid cmdstream size: %u\n", submit->cmd[i].size * 4);
873 			ret = -EINVAL;
874 			goto out;
875 		}
876 
877 		submit->cmd[i].iova = iova + (submit->cmd[i].offset * 4);
878 
879 		if (submit->valid)
880 			continue;
881 
882 		ret = submit_reloc(submit, msm_obj, submit->cmd[i].offset * 4,
883 				submit->cmd[i].nr_relocs, submit->cmd[i].relocs);
884 		if (ret)
885 			goto out;
886 	}
887 
888 	submit->nr_cmds = i;
889 
890 	/*
891 	 * If using userspace provided seqno fence, validate that the id
892 	 * is available before arming sched job.  Since access to fence_idr
893 	 * is serialized on the queue lock, the slot should be still avail
894 	 * after the job is armed
895 	 */
896 	if ((args->flags & MSM_SUBMIT_FENCE_SN_IN) &&
897 			idr_find(&queue->fence_idr, args->fence)) {
898 		ret = -EINVAL;
899 		goto out;
900 	}
901 
902 	drm_sched_job_arm(&submit->base);
903 
904 	submit->user_fence = dma_fence_get(&submit->base.s_fence->finished);
905 
906 	if (args->flags & MSM_SUBMIT_FENCE_SN_IN) {
907 		/*
908 		 * Userspace has assigned the seqno fence that it wants
909 		 * us to use.  It is an error to pick a fence sequence
910 		 * number that is not available.
911 		 */
912 		submit->fence_id = args->fence;
913 		ret = idr_alloc_u32(&queue->fence_idr, submit->user_fence,
914 				    &submit->fence_id, submit->fence_id,
915 				    GFP_KERNEL);
916 		/*
917 		 * We've already validated that the fence_id slot is valid,
918 		 * so if idr_alloc_u32 failed, it is a kernel bug
919 		 */
920 		WARN_ON(ret);
921 	} else {
922 		/*
923 		 * Allocate an id which can be used by WAIT_FENCE ioctl to map
924 		 * back to the underlying fence.
925 		 */
926 		submit->fence_id = idr_alloc_cyclic(&queue->fence_idr,
927 						    submit->user_fence, 1,
928 						    INT_MAX, GFP_KERNEL);
929 	}
930 	if (submit->fence_id < 0) {
931 		ret = submit->fence_id;
932 		submit->fence_id = 0;
933 	}
934 
935 	if (ret == 0 && args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
936 		struct sync_file *sync_file = sync_file_create(submit->user_fence);
937 		if (!sync_file) {
938 			ret = -ENOMEM;
939 		} else {
940 			fd_install(out_fence_fd, sync_file->file);
941 			args->fence_fd = out_fence_fd;
942 		}
943 	}
944 
945 	submit_attach_object_fences(submit);
946 
947 	/* The scheduler owns a ref now: */
948 	msm_gem_submit_get(submit);
949 
950 	drm_sched_entity_push_job(&submit->base);
951 
952 	args->fence = submit->fence_id;
953 	queue->last_fence = submit->fence_id;
954 
955 	msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs);
956 	msm_process_post_deps(post_deps, args->nr_out_syncobjs,
957 	                      submit->user_fence);
958 
959 
960 out:
961 	submit_cleanup(submit, !!ret);
962 	if (has_ww_ticket)
963 		ww_acquire_fini(&submit->ticket);
964 out_unlock:
965 	if (ret && (out_fence_fd >= 0))
966 		put_unused_fd(out_fence_fd);
967 	mutex_unlock(&queue->lock);
968 	if (submit)
969 		msm_gem_submit_put(submit);
970 out_post_unlock:
971 	if (!IS_ERR_OR_NULL(post_deps)) {
972 		for (i = 0; i < args->nr_out_syncobjs; ++i) {
973 			kfree(post_deps[i].chain);
974 			drm_syncobj_put(post_deps[i].syncobj);
975 		}
976 		kfree(post_deps);
977 	}
978 
979 	if (!IS_ERR_OR_NULL(syncobjs_to_reset)) {
980 		for (i = 0; i < args->nr_in_syncobjs; ++i) {
981 			if (syncobjs_to_reset[i])
982 				drm_syncobj_put(syncobjs_to_reset[i]);
983 		}
984 		kfree(syncobjs_to_reset);
985 	}
986 
987 	return ret;
988 }
989