xref: /linux/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c (revision e332935a540eb76dd656663ca908eb0544d96757)
197ff1946SArunpravin Paneer Selvam // SPDX-License-Identifier: MIT
297ff1946SArunpravin Paneer Selvam /*
397ff1946SArunpravin Paneer Selvam  * Copyright 2023 Advanced Micro Devices, Inc.
497ff1946SArunpravin Paneer Selvam  *
597ff1946SArunpravin Paneer Selvam  * Permission is hereby granted, free of charge, to any person obtaining a
697ff1946SArunpravin Paneer Selvam  * copy of this software and associated documentation files (the "Software"),
797ff1946SArunpravin Paneer Selvam  * to deal in the Software without restriction, including without limitation
897ff1946SArunpravin Paneer Selvam  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
997ff1946SArunpravin Paneer Selvam  * and/or sell copies of the Software, and to permit persons to whom the
1097ff1946SArunpravin Paneer Selvam  * Software is furnished to do so, subject to the following conditions:
1197ff1946SArunpravin Paneer Selvam  *
1297ff1946SArunpravin Paneer Selvam  * The above copyright notice and this permission notice shall be included in
1397ff1946SArunpravin Paneer Selvam  * all copies or substantial portions of the Software.
1497ff1946SArunpravin Paneer Selvam  *
1597ff1946SArunpravin Paneer Selvam  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1697ff1946SArunpravin Paneer Selvam  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1797ff1946SArunpravin Paneer Selvam  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1897ff1946SArunpravin Paneer Selvam  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1997ff1946SArunpravin Paneer Selvam  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2097ff1946SArunpravin Paneer Selvam  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2197ff1946SArunpravin Paneer Selvam  * OTHER DEALINGS IN THE SOFTWARE.
2297ff1946SArunpravin Paneer Selvam  *
2397ff1946SArunpravin Paneer Selvam  */
2497ff1946SArunpravin Paneer Selvam 
2597ff1946SArunpravin Paneer Selvam #include <linux/kref.h>
2697ff1946SArunpravin Paneer Selvam #include <linux/slab.h>
2715e30a6eSArunpravin Paneer Selvam #include <linux/dma-fence-unwrap.h>
2897ff1946SArunpravin Paneer Selvam 
29a292fdecSArunpravin Paneer Selvam #include <drm/drm_exec.h>
3097ff1946SArunpravin Paneer Selvam #include <drm/drm_syncobj.h>
3197ff1946SArunpravin Paneer Selvam 
3297ff1946SArunpravin Paneer Selvam #include "amdgpu.h"
3397ff1946SArunpravin Paneer Selvam #include "amdgpu_userq_fence.h"
3497ff1946SArunpravin Paneer Selvam 
3597ff1946SArunpravin Paneer Selvam static const struct dma_fence_ops amdgpu_userq_fence_ops;
3697ff1946SArunpravin Paneer Selvam static struct kmem_cache *amdgpu_userq_fence_slab;
3797ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_slab_init(void)3897ff1946SArunpravin Paneer Selvam int amdgpu_userq_fence_slab_init(void)
3997ff1946SArunpravin Paneer Selvam {
4097ff1946SArunpravin Paneer Selvam 	amdgpu_userq_fence_slab = kmem_cache_create("amdgpu_userq_fence",
4197ff1946SArunpravin Paneer Selvam 						    sizeof(struct amdgpu_userq_fence),
4297ff1946SArunpravin Paneer Selvam 						    0,
4397ff1946SArunpravin Paneer Selvam 						    SLAB_HWCACHE_ALIGN,
4497ff1946SArunpravin Paneer Selvam 						    NULL);
4597ff1946SArunpravin Paneer Selvam 	if (!amdgpu_userq_fence_slab)
4697ff1946SArunpravin Paneer Selvam 		return -ENOMEM;
4797ff1946SArunpravin Paneer Selvam 
4897ff1946SArunpravin Paneer Selvam 	return 0;
4997ff1946SArunpravin Paneer Selvam }
5097ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_slab_fini(void)5197ff1946SArunpravin Paneer Selvam void amdgpu_userq_fence_slab_fini(void)
5297ff1946SArunpravin Paneer Selvam {
5397ff1946SArunpravin Paneer Selvam 	rcu_barrier();
5497ff1946SArunpravin Paneer Selvam 	kmem_cache_destroy(amdgpu_userq_fence_slab);
5597ff1946SArunpravin Paneer Selvam }
5697ff1946SArunpravin Paneer Selvam 
to_amdgpu_userq_fence(struct dma_fence * f)5797ff1946SArunpravin Paneer Selvam static inline struct amdgpu_userq_fence *to_amdgpu_userq_fence(struct dma_fence *f)
5897ff1946SArunpravin Paneer Selvam {
5997ff1946SArunpravin Paneer Selvam 	if (!f || f->ops != &amdgpu_userq_fence_ops)
6097ff1946SArunpravin Paneer Selvam 		return NULL;
6197ff1946SArunpravin Paneer Selvam 
6297ff1946SArunpravin Paneer Selvam 	return container_of(f, struct amdgpu_userq_fence, base);
6397ff1946SArunpravin Paneer Selvam }
6497ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_read(struct amdgpu_userq_fence_driver * fence_drv)6597ff1946SArunpravin Paneer Selvam static u64 amdgpu_userq_fence_read(struct amdgpu_userq_fence_driver *fence_drv)
6697ff1946SArunpravin Paneer Selvam {
6797ff1946SArunpravin Paneer Selvam 	return le64_to_cpu(*fence_drv->cpu_addr);
6897ff1946SArunpravin Paneer Selvam }
6997ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_driver_alloc(struct amdgpu_device * adev,struct amdgpu_usermode_queue * userq)7097ff1946SArunpravin Paneer Selvam int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev,
7197ff1946SArunpravin Paneer Selvam 				    struct amdgpu_usermode_queue *userq)
7297ff1946SArunpravin Paneer Selvam {
7397ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence_driver *fence_drv;
7489498437SArunpravin Paneer Selvam 	unsigned long flags;
7597ff1946SArunpravin Paneer Selvam 	int r;
7697ff1946SArunpravin Paneer Selvam 
7797ff1946SArunpravin Paneer Selvam 	fence_drv = kzalloc(sizeof(*fence_drv), GFP_KERNEL);
780e023c32SDan Carpenter 	if (!fence_drv)
790e023c32SDan Carpenter 		return -ENOMEM;
8097ff1946SArunpravin Paneer Selvam 
8197ff1946SArunpravin Paneer Selvam 	/* Acquire seq64 memory */
82f7cb6a28SArunpravin Paneer Selvam 	r = amdgpu_seq64_alloc(adev, &fence_drv->va, &fence_drv->gpu_addr,
8397ff1946SArunpravin Paneer Selvam 			       &fence_drv->cpu_addr);
848ff7c78bSDan Carpenter 	if (r)
858ff7c78bSDan Carpenter 		goto free_fence_drv;
8697ff1946SArunpravin Paneer Selvam 
8797ff1946SArunpravin Paneer Selvam 	memset(fence_drv->cpu_addr, 0, sizeof(u64));
8897ff1946SArunpravin Paneer Selvam 
8997ff1946SArunpravin Paneer Selvam 	kref_init(&fence_drv->refcount);
9097ff1946SArunpravin Paneer Selvam 	INIT_LIST_HEAD(&fence_drv->fences);
9197ff1946SArunpravin Paneer Selvam 	spin_lock_init(&fence_drv->fence_list_lock);
9297ff1946SArunpravin Paneer Selvam 
9397ff1946SArunpravin Paneer Selvam 	fence_drv->adev = adev;
9497ff1946SArunpravin Paneer Selvam 	fence_drv->context = dma_fence_context_alloc(1);
9597ff1946SArunpravin Paneer Selvam 	get_task_comm(fence_drv->timeline_name, current);
9697ff1946SArunpravin Paneer Selvam 
9789498437SArunpravin Paneer Selvam 	xa_lock_irqsave(&adev->userq_xa, flags);
98fbea3d31SArunpravin Paneer Selvam 	r = xa_err(__xa_store(&adev->userq_xa, userq->doorbell_index,
99fbea3d31SArunpravin Paneer Selvam 			      fence_drv, GFP_KERNEL));
10089498437SArunpravin Paneer Selvam 	xa_unlock_irqrestore(&adev->userq_xa, flags);
101fbea3d31SArunpravin Paneer Selvam 	if (r)
102fbea3d31SArunpravin Paneer Selvam 		goto free_seq64;
10389498437SArunpravin Paneer Selvam 
10497ff1946SArunpravin Paneer Selvam 	userq->fence_drv = fence_drv;
10597ff1946SArunpravin Paneer Selvam 
10697ff1946SArunpravin Paneer Selvam 	return 0;
107e7cf21fbSArunpravin Paneer Selvam 
108e7cf21fbSArunpravin Paneer Selvam free_seq64:
109f7cb6a28SArunpravin Paneer Selvam 	amdgpu_seq64_free(adev, fence_drv->va);
110e7cf21fbSArunpravin Paneer Selvam free_fence_drv:
111e7cf21fbSArunpravin Paneer Selvam 	kfree(fence_drv);
112e7cf21fbSArunpravin Paneer Selvam 
113e7cf21fbSArunpravin Paneer Selvam 	return r;
11497ff1946SArunpravin Paneer Selvam }
11597ff1946SArunpravin Paneer Selvam 
amdgpu_userq_walk_and_drop_fence_drv(struct xarray * xa)116edc762a5SAlex Deucher static void amdgpu_userq_walk_and_drop_fence_drv(struct xarray *xa)
117edc762a5SAlex Deucher {
118edc762a5SAlex Deucher 	struct amdgpu_userq_fence_driver *fence_drv;
119edc762a5SAlex Deucher 	unsigned long index;
120edc762a5SAlex Deucher 
121edc762a5SAlex Deucher 	if (xa_empty(xa))
122edc762a5SAlex Deucher 		return;
123edc762a5SAlex Deucher 
124edc762a5SAlex Deucher 	xa_lock(xa);
125edc762a5SAlex Deucher 	xa_for_each(xa, index, fence_drv) {
126edc762a5SAlex Deucher 		__xa_erase(xa, index);
127edc762a5SAlex Deucher 		amdgpu_userq_fence_driver_put(fence_drv);
128edc762a5SAlex Deucher 	}
129edc762a5SAlex Deucher 
130edc762a5SAlex Deucher 	xa_unlock(xa);
131edc762a5SAlex Deucher }
132edc762a5SAlex Deucher 
133edc762a5SAlex Deucher void
amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue * userq)134edc762a5SAlex Deucher amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq)
135edc762a5SAlex Deucher {
136edc762a5SAlex Deucher 	amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa);
137edc762a5SAlex Deucher 	xa_destroy(&userq->fence_drv_xa);
138edc762a5SAlex Deucher 	/* Drop the fence_drv reference held by user queue */
139edc762a5SAlex Deucher 	amdgpu_userq_fence_driver_put(userq->fence_drv);
140edc762a5SAlex Deucher }
141edc762a5SAlex Deucher 
amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver * fence_drv)14297ff1946SArunpravin Paneer Selvam void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv)
14397ff1946SArunpravin Paneer Selvam {
14497ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence *userq_fence, *tmp;
14597ff1946SArunpravin Paneer Selvam 	struct dma_fence *fence;
14697ff1946SArunpravin Paneer Selvam 	u64 rptr;
147a292fdecSArunpravin Paneer Selvam 	int i;
14897ff1946SArunpravin Paneer Selvam 
14997ff1946SArunpravin Paneer Selvam 	if (!fence_drv)
15097ff1946SArunpravin Paneer Selvam 		return;
15197ff1946SArunpravin Paneer Selvam 
15297ff1946SArunpravin Paneer Selvam 	rptr = amdgpu_userq_fence_read(fence_drv);
15397ff1946SArunpravin Paneer Selvam 
15497ff1946SArunpravin Paneer Selvam 	spin_lock(&fence_drv->fence_list_lock);
15597ff1946SArunpravin Paneer Selvam 	list_for_each_entry_safe(userq_fence, tmp, &fence_drv->fences, link) {
15697ff1946SArunpravin Paneer Selvam 		fence = &userq_fence->base;
15797ff1946SArunpravin Paneer Selvam 
158a292fdecSArunpravin Paneer Selvam 		if (rptr < fence->seqno)
15997ff1946SArunpravin Paneer Selvam 			break;
160a292fdecSArunpravin Paneer Selvam 
161a292fdecSArunpravin Paneer Selvam 		dma_fence_signal(fence);
162a292fdecSArunpravin Paneer Selvam 
163a292fdecSArunpravin Paneer Selvam 		for (i = 0; i < userq_fence->fence_drv_array_count; i++)
164a292fdecSArunpravin Paneer Selvam 			amdgpu_userq_fence_driver_put(userq_fence->fence_drv_array[i]);
165a292fdecSArunpravin Paneer Selvam 
166a292fdecSArunpravin Paneer Selvam 		list_del(&userq_fence->link);
167a292fdecSArunpravin Paneer Selvam 		dma_fence_put(fence);
16897ff1946SArunpravin Paneer Selvam 	}
16997ff1946SArunpravin Paneer Selvam 	spin_unlock(&fence_drv->fence_list_lock);
17097ff1946SArunpravin Paneer Selvam }
17197ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_driver_destroy(struct kref * ref)17297ff1946SArunpravin Paneer Selvam void amdgpu_userq_fence_driver_destroy(struct kref *ref)
17397ff1946SArunpravin Paneer Selvam {
17497ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence_driver *fence_drv = container_of(ref,
17597ff1946SArunpravin Paneer Selvam 					 struct amdgpu_userq_fence_driver,
17697ff1946SArunpravin Paneer Selvam 					 refcount);
177a292fdecSArunpravin Paneer Selvam 	struct amdgpu_userq_fence_driver *xa_fence_drv;
17897ff1946SArunpravin Paneer Selvam 	struct amdgpu_device *adev = fence_drv->adev;
17997ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence *fence, *tmp;
180a292fdecSArunpravin Paneer Selvam 	struct xarray *xa = &adev->userq_xa;
181e7cf21fbSArunpravin Paneer Selvam 	unsigned long index, flags;
18297ff1946SArunpravin Paneer Selvam 	struct dma_fence *f;
18397ff1946SArunpravin Paneer Selvam 
184218caca4SArunpravin Paneer Selvam 	spin_lock_irqsave(&fence_drv->fence_list_lock, flags);
18597ff1946SArunpravin Paneer Selvam 	list_for_each_entry_safe(fence, tmp, &fence_drv->fences, link) {
18697ff1946SArunpravin Paneer Selvam 		f = &fence->base;
18797ff1946SArunpravin Paneer Selvam 
18897ff1946SArunpravin Paneer Selvam 		if (!dma_fence_is_signaled(f)) {
18997ff1946SArunpravin Paneer Selvam 			dma_fence_set_error(f, -ECANCELED);
19097ff1946SArunpravin Paneer Selvam 			dma_fence_signal(f);
19197ff1946SArunpravin Paneer Selvam 		}
19297ff1946SArunpravin Paneer Selvam 
19397ff1946SArunpravin Paneer Selvam 		list_del(&fence->link);
19497ff1946SArunpravin Paneer Selvam 		dma_fence_put(f);
19597ff1946SArunpravin Paneer Selvam 	}
196218caca4SArunpravin Paneer Selvam 	spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags);
19797ff1946SArunpravin Paneer Selvam 
198e7cf21fbSArunpravin Paneer Selvam 	xa_lock_irqsave(xa, flags);
199a292fdecSArunpravin Paneer Selvam 	xa_for_each(xa, index, xa_fence_drv)
200a292fdecSArunpravin Paneer Selvam 		if (xa_fence_drv == fence_drv)
201a292fdecSArunpravin Paneer Selvam 			__xa_erase(xa, index);
202e7cf21fbSArunpravin Paneer Selvam 	xa_unlock_irqrestore(xa, flags);
203a292fdecSArunpravin Paneer Selvam 
20497ff1946SArunpravin Paneer Selvam 	/* Free seq64 memory */
205f7cb6a28SArunpravin Paneer Selvam 	amdgpu_seq64_free(adev, fence_drv->va);
20697ff1946SArunpravin Paneer Selvam 	kfree(fence_drv);
20797ff1946SArunpravin Paneer Selvam }
20897ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_driver_get(struct amdgpu_userq_fence_driver * fence_drv)20997ff1946SArunpravin Paneer Selvam void amdgpu_userq_fence_driver_get(struct amdgpu_userq_fence_driver *fence_drv)
21097ff1946SArunpravin Paneer Selvam {
21197ff1946SArunpravin Paneer Selvam 	kref_get(&fence_drv->refcount);
21297ff1946SArunpravin Paneer Selvam }
21397ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver * fence_drv)21497ff1946SArunpravin Paneer Selvam void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv)
21597ff1946SArunpravin Paneer Selvam {
21697ff1946SArunpravin Paneer Selvam 	kref_put(&fence_drv->refcount, amdgpu_userq_fence_driver_destroy);
21797ff1946SArunpravin Paneer Selvam }
21897ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_alloc(struct amdgpu_userq_fence ** userq_fence)219f15d4e92SArvind Yadav static int amdgpu_userq_fence_alloc(struct amdgpu_userq_fence **userq_fence)
220f15d4e92SArvind Yadav {
221f15d4e92SArvind Yadav 	*userq_fence = kmem_cache_alloc(amdgpu_userq_fence_slab, GFP_ATOMIC);
222f15d4e92SArvind Yadav 	return *userq_fence ? 0 : -ENOMEM;
223f15d4e92SArvind Yadav }
224f15d4e92SArvind Yadav 
amdgpu_userq_fence_create(struct amdgpu_usermode_queue * userq,struct amdgpu_userq_fence * userq_fence,u64 seq,struct dma_fence ** f)225f15d4e92SArvind Yadav static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq,
226f15d4e92SArvind Yadav 				     struct amdgpu_userq_fence *userq_fence,
22797ff1946SArunpravin Paneer Selvam 				     u64 seq, struct dma_fence **f)
22897ff1946SArunpravin Paneer Selvam {
22997ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence_driver *fence_drv;
23097ff1946SArunpravin Paneer Selvam 	struct dma_fence *fence;
2312e65ea1aSArunpravin Paneer Selvam 	unsigned long flags;
23297ff1946SArunpravin Paneer Selvam 
23397ff1946SArunpravin Paneer Selvam 	fence_drv = userq->fence_drv;
23497ff1946SArunpravin Paneer Selvam 	if (!fence_drv)
23597ff1946SArunpravin Paneer Selvam 		return -EINVAL;
23697ff1946SArunpravin Paneer Selvam 
23797ff1946SArunpravin Paneer Selvam 	spin_lock_init(&userq_fence->lock);
23897ff1946SArunpravin Paneer Selvam 	INIT_LIST_HEAD(&userq_fence->link);
23997ff1946SArunpravin Paneer Selvam 	fence = &userq_fence->base;
24097ff1946SArunpravin Paneer Selvam 	userq_fence->fence_drv = fence_drv;
24197ff1946SArunpravin Paneer Selvam 
24297ff1946SArunpravin Paneer Selvam 	dma_fence_init(fence, &amdgpu_userq_fence_ops, &userq_fence->lock,
24397ff1946SArunpravin Paneer Selvam 		       fence_drv->context, seq);
24497ff1946SArunpravin Paneer Selvam 
24597ff1946SArunpravin Paneer Selvam 	amdgpu_userq_fence_driver_get(fence_drv);
24697ff1946SArunpravin Paneer Selvam 	dma_fence_get(fence);
24797ff1946SArunpravin Paneer Selvam 
248e7cf21fbSArunpravin Paneer Selvam 	if (!xa_empty(&userq->fence_drv_xa)) {
249a292fdecSArunpravin Paneer Selvam 		struct amdgpu_userq_fence_driver *stored_fence_drv;
250a292fdecSArunpravin Paneer Selvam 		unsigned long index, count = 0;
251a292fdecSArunpravin Paneer Selvam 		int i = 0;
252a292fdecSArunpravin Paneer Selvam 
253239a310bSArunpravin Paneer Selvam 		xa_lock(&userq->fence_drv_xa);
254e7cf21fbSArunpravin Paneer Selvam 		xa_for_each(&userq->fence_drv_xa, index, stored_fence_drv)
255a292fdecSArunpravin Paneer Selvam 			count++;
256a292fdecSArunpravin Paneer Selvam 
257a292fdecSArunpravin Paneer Selvam 		userq_fence->fence_drv_array =
258a292fdecSArunpravin Paneer Selvam 			kvmalloc_array(count,
259a292fdecSArunpravin Paneer Selvam 				       sizeof(struct amdgpu_userq_fence_driver *),
260239a310bSArunpravin Paneer Selvam 				       GFP_ATOMIC);
261a292fdecSArunpravin Paneer Selvam 
262a292fdecSArunpravin Paneer Selvam 		if (userq_fence->fence_drv_array) {
263e7cf21fbSArunpravin Paneer Selvam 			xa_for_each(&userq->fence_drv_xa, index, stored_fence_drv) {
264a292fdecSArunpravin Paneer Selvam 				userq_fence->fence_drv_array[i] = stored_fence_drv;
265239a310bSArunpravin Paneer Selvam 				__xa_erase(&userq->fence_drv_xa, index);
266a292fdecSArunpravin Paneer Selvam 				i++;
267a292fdecSArunpravin Paneer Selvam 			}
268a292fdecSArunpravin Paneer Selvam 		}
269a292fdecSArunpravin Paneer Selvam 
270a292fdecSArunpravin Paneer Selvam 		userq_fence->fence_drv_array_count = i;
271239a310bSArunpravin Paneer Selvam 		xa_unlock(&userq->fence_drv_xa);
272a292fdecSArunpravin Paneer Selvam 	} else {
273a292fdecSArunpravin Paneer Selvam 		userq_fence->fence_drv_array = NULL;
274a292fdecSArunpravin Paneer Selvam 		userq_fence->fence_drv_array_count = 0;
275a292fdecSArunpravin Paneer Selvam 	}
276a292fdecSArunpravin Paneer Selvam 
27797ff1946SArunpravin Paneer Selvam 	/* Check if hardware has already processed the job */
2782e65ea1aSArunpravin Paneer Selvam 	spin_lock_irqsave(&fence_drv->fence_list_lock, flags);
2792e65ea1aSArunpravin Paneer Selvam 	if (!dma_fence_is_signaled_locked(fence))
28097ff1946SArunpravin Paneer Selvam 		list_add_tail(&userq_fence->link, &fence_drv->fences);
28197ff1946SArunpravin Paneer Selvam 	else
28297ff1946SArunpravin Paneer Selvam 		dma_fence_put(fence);
28397ff1946SArunpravin Paneer Selvam 
2842e65ea1aSArunpravin Paneer Selvam 	spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags);
28597ff1946SArunpravin Paneer Selvam 
28697ff1946SArunpravin Paneer Selvam 	*f = fence;
28797ff1946SArunpravin Paneer Selvam 
28897ff1946SArunpravin Paneer Selvam 	return 0;
28997ff1946SArunpravin Paneer Selvam }
29097ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_get_driver_name(struct dma_fence * f)29197ff1946SArunpravin Paneer Selvam static const char *amdgpu_userq_fence_get_driver_name(struct dma_fence *f)
29297ff1946SArunpravin Paneer Selvam {
29342a66677SAlex Deucher 	return "amdgpu_userq_fence";
29497ff1946SArunpravin Paneer Selvam }
29597ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_get_timeline_name(struct dma_fence * f)29697ff1946SArunpravin Paneer Selvam static const char *amdgpu_userq_fence_get_timeline_name(struct dma_fence *f)
29797ff1946SArunpravin Paneer Selvam {
29897ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence *fence = to_amdgpu_userq_fence(f);
29997ff1946SArunpravin Paneer Selvam 
30097ff1946SArunpravin Paneer Selvam 	return fence->fence_drv->timeline_name;
30197ff1946SArunpravin Paneer Selvam }
30297ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_signaled(struct dma_fence * f)30397ff1946SArunpravin Paneer Selvam static bool amdgpu_userq_fence_signaled(struct dma_fence *f)
30497ff1946SArunpravin Paneer Selvam {
30597ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence *fence = to_amdgpu_userq_fence(f);
30697ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence_driver *fence_drv = fence->fence_drv;
30797ff1946SArunpravin Paneer Selvam 	u64 rptr, wptr;
30897ff1946SArunpravin Paneer Selvam 
30997ff1946SArunpravin Paneer Selvam 	rptr = amdgpu_userq_fence_read(fence_drv);
31097ff1946SArunpravin Paneer Selvam 	wptr = fence->base.seqno;
31197ff1946SArunpravin Paneer Selvam 
31297ff1946SArunpravin Paneer Selvam 	if (rptr >= wptr)
31397ff1946SArunpravin Paneer Selvam 		return true;
31497ff1946SArunpravin Paneer Selvam 
31597ff1946SArunpravin Paneer Selvam 	return false;
31697ff1946SArunpravin Paneer Selvam }
31797ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_free(struct rcu_head * rcu)31897ff1946SArunpravin Paneer Selvam static void amdgpu_userq_fence_free(struct rcu_head *rcu)
31997ff1946SArunpravin Paneer Selvam {
32097ff1946SArunpravin Paneer Selvam 	struct dma_fence *fence = container_of(rcu, struct dma_fence, rcu);
32197ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence *userq_fence = to_amdgpu_userq_fence(fence);
32297ff1946SArunpravin Paneer Selvam 	struct amdgpu_userq_fence_driver *fence_drv = userq_fence->fence_drv;
32397ff1946SArunpravin Paneer Selvam 
32497ff1946SArunpravin Paneer Selvam 	/* Release the fence driver reference */
32597ff1946SArunpravin Paneer Selvam 	amdgpu_userq_fence_driver_put(fence_drv);
326a292fdecSArunpravin Paneer Selvam 
327a292fdecSArunpravin Paneer Selvam 	kvfree(userq_fence->fence_drv_array);
32897ff1946SArunpravin Paneer Selvam 	kmem_cache_free(amdgpu_userq_fence_slab, userq_fence);
32997ff1946SArunpravin Paneer Selvam }
33097ff1946SArunpravin Paneer Selvam 
amdgpu_userq_fence_release(struct dma_fence * f)33197ff1946SArunpravin Paneer Selvam static void amdgpu_userq_fence_release(struct dma_fence *f)
33297ff1946SArunpravin Paneer Selvam {
33397ff1946SArunpravin Paneer Selvam 	call_rcu(&f->rcu, amdgpu_userq_fence_free);
33497ff1946SArunpravin Paneer Selvam }
33597ff1946SArunpravin Paneer Selvam 
33697ff1946SArunpravin Paneer Selvam static const struct dma_fence_ops amdgpu_userq_fence_ops = {
33797ff1946SArunpravin Paneer Selvam 	.use_64bit_seqno = true,
33897ff1946SArunpravin Paneer Selvam 	.get_driver_name = amdgpu_userq_fence_get_driver_name,
33997ff1946SArunpravin Paneer Selvam 	.get_timeline_name = amdgpu_userq_fence_get_timeline_name,
34097ff1946SArunpravin Paneer Selvam 	.signaled = amdgpu_userq_fence_signaled,
34197ff1946SArunpravin Paneer Selvam 	.release = amdgpu_userq_fence_release,
34297ff1946SArunpravin Paneer Selvam };
343a292fdecSArunpravin Paneer Selvam 
344a292fdecSArunpravin Paneer Selvam /**
345a292fdecSArunpravin Paneer Selvam  * amdgpu_userq_fence_read_wptr - Read the userq wptr value
346a292fdecSArunpravin Paneer Selvam  *
347a292fdecSArunpravin Paneer Selvam  * @queue: user mode queue structure pointer
348a292fdecSArunpravin Paneer Selvam  * @wptr: write pointer value
349a292fdecSArunpravin Paneer Selvam  *
350a292fdecSArunpravin Paneer Selvam  * Read the wptr value from userq's MQD. The userq signal IOCTL
351a292fdecSArunpravin Paneer Selvam  * creates a dma_fence for the shared buffers that expects the
352a292fdecSArunpravin Paneer Selvam  * RPTR value written to seq64 memory >= WPTR.
353a292fdecSArunpravin Paneer Selvam  *
354a292fdecSArunpravin Paneer Selvam  * Returns wptr value on success, error on failure.
355a292fdecSArunpravin Paneer Selvam  */
amdgpu_userq_fence_read_wptr(struct amdgpu_usermode_queue * queue,u64 * wptr)356d8675102SArunpravin Paneer Selvam static int amdgpu_userq_fence_read_wptr(struct amdgpu_usermode_queue *queue,
357a292fdecSArunpravin Paneer Selvam 					u64 *wptr)
358a292fdecSArunpravin Paneer Selvam {
359a292fdecSArunpravin Paneer Selvam 	struct amdgpu_bo_va_mapping *mapping;
360a292fdecSArunpravin Paneer Selvam 	struct amdgpu_bo *bo;
361a292fdecSArunpravin Paneer Selvam 	u64 addr, *ptr;
362a292fdecSArunpravin Paneer Selvam 	int r;
363a292fdecSArunpravin Paneer Selvam 
364d8675102SArunpravin Paneer Selvam 	r = amdgpu_bo_reserve(queue->vm->root.bo, false);
365d8675102SArunpravin Paneer Selvam 	if (r)
366d8675102SArunpravin Paneer Selvam 		return r;
367d8675102SArunpravin Paneer Selvam 
368a292fdecSArunpravin Paneer Selvam 	addr = queue->userq_prop->wptr_gpu_addr;
369a292fdecSArunpravin Paneer Selvam 	addr &= AMDGPU_GMC_HOLE_MASK;
370a292fdecSArunpravin Paneer Selvam 
371d8675102SArunpravin Paneer Selvam 	mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, addr >> PAGE_SHIFT);
372d8675102SArunpravin Paneer Selvam 	if (!mapping) {
373d6c6d5ecSDan Carpenter 		amdgpu_bo_unreserve(queue->vm->root.bo);
374d8675102SArunpravin Paneer Selvam 		DRM_ERROR("Failed to lookup amdgpu_bo_va_mapping\n");
375a292fdecSArunpravin Paneer Selvam 		return -EINVAL;
376d8675102SArunpravin Paneer Selvam 	}
377a292fdecSArunpravin Paneer Selvam 
378d8675102SArunpravin Paneer Selvam 	bo = amdgpu_bo_ref(mapping->bo_va->base.bo);
379d8675102SArunpravin Paneer Selvam 	amdgpu_bo_unreserve(queue->vm->root.bo);
380a292fdecSArunpravin Paneer Selvam 	r = amdgpu_bo_reserve(bo, true);
381a292fdecSArunpravin Paneer Selvam 	if (r) {
382a292fdecSArunpravin Paneer Selvam 		DRM_ERROR("Failed to reserve userqueue wptr bo");
383a292fdecSArunpravin Paneer Selvam 		return r;
384a292fdecSArunpravin Paneer Selvam 	}
385a292fdecSArunpravin Paneer Selvam 
386a292fdecSArunpravin Paneer Selvam 	r = amdgpu_bo_kmap(bo, (void **)&ptr);
387a292fdecSArunpravin Paneer Selvam 	if (r) {
388a292fdecSArunpravin Paneer Selvam 		DRM_ERROR("Failed mapping the userqueue wptr bo");
389a292fdecSArunpravin Paneer Selvam 		goto map_error;
390a292fdecSArunpravin Paneer Selvam 	}
391a292fdecSArunpravin Paneer Selvam 
392a292fdecSArunpravin Paneer Selvam 	*wptr = le64_to_cpu(*ptr);
393a292fdecSArunpravin Paneer Selvam 
394a292fdecSArunpravin Paneer Selvam 	amdgpu_bo_kunmap(bo);
395a292fdecSArunpravin Paneer Selvam 	amdgpu_bo_unreserve(bo);
396d8675102SArunpravin Paneer Selvam 	amdgpu_bo_unref(&bo);
397a292fdecSArunpravin Paneer Selvam 
398a292fdecSArunpravin Paneer Selvam 	return 0;
399a292fdecSArunpravin Paneer Selvam 
400a292fdecSArunpravin Paneer Selvam map_error:
401a292fdecSArunpravin Paneer Selvam 	amdgpu_bo_unreserve(bo);
402d8675102SArunpravin Paneer Selvam 	amdgpu_bo_unref(&bo);
403d8675102SArunpravin Paneer Selvam 
404a292fdecSArunpravin Paneer Selvam 	return r;
405a292fdecSArunpravin Paneer Selvam }
406a292fdecSArunpravin Paneer Selvam 
amdgpu_userq_fence_cleanup(struct dma_fence * fence)407f15d4e92SArvind Yadav static void amdgpu_userq_fence_cleanup(struct dma_fence *fence)
408f15d4e92SArvind Yadav {
409f15d4e92SArvind Yadav 	dma_fence_put(fence);
410f15d4e92SArvind Yadav }
411f15d4e92SArvind Yadav 
amdgpu_userq_signal_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)412a292fdecSArunpravin Paneer Selvam int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
413a292fdecSArunpravin Paneer Selvam 			      struct drm_file *filp)
414a292fdecSArunpravin Paneer Selvam {
415a292fdecSArunpravin Paneer Selvam 	struct amdgpu_fpriv *fpriv = filp->driver_priv;
416a292fdecSArunpravin Paneer Selvam 	struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr;
417a292fdecSArunpravin Paneer Selvam 	struct drm_amdgpu_userq_signal *args = data;
418cb4a73f4SArunpravin Paneer Selvam 	struct drm_gem_object **gobj_write = NULL;
419cb4a73f4SArunpravin Paneer Selvam 	struct drm_gem_object **gobj_read = NULL;
420a292fdecSArunpravin Paneer Selvam 	struct amdgpu_usermode_queue *queue;
421f15d4e92SArvind Yadav 	struct amdgpu_userq_fence *userq_fence;
422a292fdecSArunpravin Paneer Selvam 	struct drm_syncobj **syncobj = NULL;
423cb4a73f4SArunpravin Paneer Selvam 	u32 *bo_handles_write, num_write_bo_handles;
424a292fdecSArunpravin Paneer Selvam 	u32 *syncobj_handles, num_syncobj_handles;
425cb4a73f4SArunpravin Paneer Selvam 	u32 *bo_handles_read, num_read_bo_handles;
426cb4a73f4SArunpravin Paneer Selvam 	int r, i, entry, rentry, wentry;
427a292fdecSArunpravin Paneer Selvam 	struct dma_fence *fence;
428a292fdecSArunpravin Paneer Selvam 	struct drm_exec exec;
429a292fdecSArunpravin Paneer Selvam 	u64 wptr;
430a292fdecSArunpravin Paneer Selvam 
431a292fdecSArunpravin Paneer Selvam 	num_syncobj_handles = args->num_syncobj_handles;
4322761bb9aSArunpravin Paneer Selvam 	syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles),
433*98a46a40SDan Carpenter 				      size_mul(sizeof(u32), num_syncobj_handles));
434a292fdecSArunpravin Paneer Selvam 	if (IS_ERR(syncobj_handles))
435a292fdecSArunpravin Paneer Selvam 		return PTR_ERR(syncobj_handles);
436a292fdecSArunpravin Paneer Selvam 
437a292fdecSArunpravin Paneer Selvam 	/* Array of pointers to the looked up syncobjs */
438a292fdecSArunpravin Paneer Selvam 	syncobj = kmalloc_array(num_syncobj_handles, sizeof(*syncobj), GFP_KERNEL);
439a292fdecSArunpravin Paneer Selvam 	if (!syncobj) {
440a292fdecSArunpravin Paneer Selvam 		r = -ENOMEM;
441a292fdecSArunpravin Paneer Selvam 		goto free_syncobj_handles;
442a292fdecSArunpravin Paneer Selvam 	}
443a292fdecSArunpravin Paneer Selvam 
444a292fdecSArunpravin Paneer Selvam 	for (entry = 0; entry < num_syncobj_handles; entry++) {
445a292fdecSArunpravin Paneer Selvam 		syncobj[entry] = drm_syncobj_find(filp, syncobj_handles[entry]);
446a292fdecSArunpravin Paneer Selvam 		if (!syncobj[entry]) {
447a292fdecSArunpravin Paneer Selvam 			r = -ENOENT;
448a292fdecSArunpravin Paneer Selvam 			goto free_syncobj;
449a292fdecSArunpravin Paneer Selvam 		}
450a292fdecSArunpravin Paneer Selvam 	}
451a292fdecSArunpravin Paneer Selvam 
4522761bb9aSArunpravin Paneer Selvam 	num_read_bo_handles = args->num_bo_read_handles;
453cb4a73f4SArunpravin Paneer Selvam 	bo_handles_read = memdup_user(u64_to_user_ptr(args->bo_read_handles),
454cb4a73f4SArunpravin Paneer Selvam 				      sizeof(u32) * num_read_bo_handles);
455cb4a73f4SArunpravin Paneer Selvam 	if (IS_ERR(bo_handles_read)) {
456cb4a73f4SArunpravin Paneer Selvam 		r = PTR_ERR(bo_handles_read);
457a292fdecSArunpravin Paneer Selvam 		goto free_syncobj;
458cb4a73f4SArunpravin Paneer Selvam 	}
459a292fdecSArunpravin Paneer Selvam 
460cb4a73f4SArunpravin Paneer Selvam 	/* Array of pointers to the GEM read objects */
461cb4a73f4SArunpravin Paneer Selvam 	gobj_read = kmalloc_array(num_read_bo_handles, sizeof(*gobj_read), GFP_KERNEL);
462cb4a73f4SArunpravin Paneer Selvam 	if (!gobj_read) {
463a292fdecSArunpravin Paneer Selvam 		r = -ENOMEM;
464cb4a73f4SArunpravin Paneer Selvam 		goto free_bo_handles_read;
465a292fdecSArunpravin Paneer Selvam 	}
466a292fdecSArunpravin Paneer Selvam 
467cb4a73f4SArunpravin Paneer Selvam 	for (rentry = 0; rentry < num_read_bo_handles; rentry++) {
468cb4a73f4SArunpravin Paneer Selvam 		gobj_read[rentry] = drm_gem_object_lookup(filp, bo_handles_read[rentry]);
469cb4a73f4SArunpravin Paneer Selvam 		if (!gobj_read[rentry]) {
470a292fdecSArunpravin Paneer Selvam 			r = -ENOENT;
471cb4a73f4SArunpravin Paneer Selvam 			goto put_gobj_read;
472a292fdecSArunpravin Paneer Selvam 		}
473a292fdecSArunpravin Paneer Selvam 	}
474a292fdecSArunpravin Paneer Selvam 
4752761bb9aSArunpravin Paneer Selvam 	num_write_bo_handles = args->num_bo_write_handles;
476cb4a73f4SArunpravin Paneer Selvam 	bo_handles_write = memdup_user(u64_to_user_ptr(args->bo_write_handles),
477cb4a73f4SArunpravin Paneer Selvam 				       sizeof(u32) * num_write_bo_handles);
478cb4a73f4SArunpravin Paneer Selvam 	if (IS_ERR(bo_handles_write)) {
479cb4a73f4SArunpravin Paneer Selvam 		r = PTR_ERR(bo_handles_write);
480cb4a73f4SArunpravin Paneer Selvam 		goto put_gobj_read;
481cb4a73f4SArunpravin Paneer Selvam 	}
482cb4a73f4SArunpravin Paneer Selvam 
483cb4a73f4SArunpravin Paneer Selvam 	/* Array of pointers to the GEM write objects */
484cb4a73f4SArunpravin Paneer Selvam 	gobj_write = kmalloc_array(num_write_bo_handles, sizeof(*gobj_write), GFP_KERNEL);
485cb4a73f4SArunpravin Paneer Selvam 	if (!gobj_write) {
486cb4a73f4SArunpravin Paneer Selvam 		r = -ENOMEM;
487cb4a73f4SArunpravin Paneer Selvam 		goto free_bo_handles_write;
488cb4a73f4SArunpravin Paneer Selvam 	}
489cb4a73f4SArunpravin Paneer Selvam 
490cb4a73f4SArunpravin Paneer Selvam 	for (wentry = 0; wentry < num_write_bo_handles; wentry++) {
491cb4a73f4SArunpravin Paneer Selvam 		gobj_write[wentry] = drm_gem_object_lookup(filp, bo_handles_write[wentry]);
492cb4a73f4SArunpravin Paneer Selvam 		if (!gobj_write[wentry]) {
493cb4a73f4SArunpravin Paneer Selvam 			r = -ENOENT;
494cb4a73f4SArunpravin Paneer Selvam 			goto put_gobj_write;
495cb4a73f4SArunpravin Paneer Selvam 		}
496cb4a73f4SArunpravin Paneer Selvam 	}
497cb4a73f4SArunpravin Paneer Selvam 
498b0328087SShashank Sharma 	/* Retrieve the user queue */
499b0328087SShashank Sharma 	queue = idr_find(&userq_mgr->userq_idr, args->queue_id);
500b0328087SShashank Sharma 	if (!queue) {
501b0328087SShashank Sharma 		r = -ENOENT;
502a242a3e4SShashank Sharma 		goto put_gobj_write;
503b0328087SShashank Sharma 	}
504b0328087SShashank Sharma 
505f15d4e92SArvind Yadav 	r = amdgpu_userq_fence_read_wptr(queue, &wptr);
506f15d4e92SArvind Yadav 	if (r)
507f15d4e92SArvind Yadav 		goto put_gobj_write;
508f15d4e92SArvind Yadav 
509f15d4e92SArvind Yadav 	r = amdgpu_userq_fence_alloc(&userq_fence);
510f15d4e92SArvind Yadav 	if (r)
511f15d4e92SArvind Yadav 		goto put_gobj_write;
512f15d4e92SArvind Yadav 
513f15d4e92SArvind Yadav 	/* We are here means UQ is active, make sure the eviction fence is valid */
51442a66677SAlex Deucher 	amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr);
515f15d4e92SArvind Yadav 
516f15d4e92SArvind Yadav 	/* Create a new fence */
517f15d4e92SArvind Yadav 	r = amdgpu_userq_fence_create(queue, userq_fence, wptr, &fence);
518f15d4e92SArvind Yadav 	if (r) {
519f15d4e92SArvind Yadav 		mutex_unlock(&userq_mgr->userq_mutex);
520f15d4e92SArvind Yadav 		kmem_cache_free(amdgpu_userq_fence_slab, userq_fence);
521f15d4e92SArvind Yadav 		goto put_gobj_write;
522f15d4e92SArvind Yadav 	}
523f15d4e92SArvind Yadav 
524f15d4e92SArvind Yadav 	dma_fence_put(queue->last_fence);
525f15d4e92SArvind Yadav 	queue->last_fence = dma_fence_get(fence);
526f15d4e92SArvind Yadav 	mutex_unlock(&userq_mgr->userq_mutex);
527f15d4e92SArvind Yadav 
528cb4a73f4SArunpravin Paneer Selvam 	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
529cb4a73f4SArunpravin Paneer Selvam 		      (num_read_bo_handles + num_write_bo_handles));
530e7cf21fbSArunpravin Paneer Selvam 
531e7cf21fbSArunpravin Paneer Selvam 	/* Lock all BOs with retry handling */
532a292fdecSArunpravin Paneer Selvam 	drm_exec_until_all_locked(&exec) {
533cb4a73f4SArunpravin Paneer Selvam 		r = drm_exec_prepare_array(&exec, gobj_read, num_read_bo_handles, 1);
534cb4a73f4SArunpravin Paneer Selvam 		drm_exec_retry_on_contention(&exec);
535f15d4e92SArvind Yadav 		if (r) {
536f15d4e92SArvind Yadav 			amdgpu_userq_fence_cleanup(fence);
537a292fdecSArunpravin Paneer Selvam 			goto exec_fini;
538a292fdecSArunpravin Paneer Selvam 		}
539a292fdecSArunpravin Paneer Selvam 
540f15d4e92SArvind Yadav 		r = drm_exec_prepare_array(&exec, gobj_write, num_write_bo_handles, 1);
541f15d4e92SArvind Yadav 		drm_exec_retry_on_contention(&exec);
542f15d4e92SArvind Yadav 		if (r) {
543f15d4e92SArvind Yadav 			amdgpu_userq_fence_cleanup(fence);
544a292fdecSArunpravin Paneer Selvam 			goto exec_fini;
545f15d4e92SArvind Yadav 		}
546f15d4e92SArvind Yadav 	}
547a292fdecSArunpravin Paneer Selvam 
548cb4a73f4SArunpravin Paneer Selvam 	for (i = 0; i < num_read_bo_handles; i++) {
549cb4a73f4SArunpravin Paneer Selvam 		if (!gobj_read || !gobj_read[i]->resv)
550cb4a73f4SArunpravin Paneer Selvam 			continue;
551cb4a73f4SArunpravin Paneer Selvam 
552cb4a73f4SArunpravin Paneer Selvam 		dma_resv_add_fence(gobj_read[i]->resv, fence,
553cb4a73f4SArunpravin Paneer Selvam 				   DMA_RESV_USAGE_READ);
554cb4a73f4SArunpravin Paneer Selvam 	}
555cb4a73f4SArunpravin Paneer Selvam 
556cb4a73f4SArunpravin Paneer Selvam 	for (i = 0; i < num_write_bo_handles; i++) {
557cb4a73f4SArunpravin Paneer Selvam 		if (!gobj_write || !gobj_write[i]->resv)
558cb4a73f4SArunpravin Paneer Selvam 			continue;
559cb4a73f4SArunpravin Paneer Selvam 
560cb4a73f4SArunpravin Paneer Selvam 		dma_resv_add_fence(gobj_write[i]->resv, fence,
561cb4a73f4SArunpravin Paneer Selvam 				   DMA_RESV_USAGE_WRITE);
562cb4a73f4SArunpravin Paneer Selvam 	}
563a292fdecSArunpravin Paneer Selvam 
564a292fdecSArunpravin Paneer Selvam 	/* Add the created fence to syncobj/BO's */
565a292fdecSArunpravin Paneer Selvam 	for (i = 0; i < num_syncobj_handles; i++)
566a292fdecSArunpravin Paneer Selvam 		drm_syncobj_replace_fence(syncobj[i], fence);
567a292fdecSArunpravin Paneer Selvam 
568a292fdecSArunpravin Paneer Selvam 	/* drop the reference acquired in fence creation function */
569a292fdecSArunpravin Paneer Selvam 	dma_fence_put(fence);
570a292fdecSArunpravin Paneer Selvam 
571a292fdecSArunpravin Paneer Selvam exec_fini:
572a292fdecSArunpravin Paneer Selvam 	drm_exec_fini(&exec);
573cb4a73f4SArunpravin Paneer Selvam put_gobj_write:
574cb4a73f4SArunpravin Paneer Selvam 	while (wentry-- > 0)
575cb4a73f4SArunpravin Paneer Selvam 		drm_gem_object_put(gobj_write[wentry]);
576cb4a73f4SArunpravin Paneer Selvam 	kfree(gobj_write);
577cb4a73f4SArunpravin Paneer Selvam free_bo_handles_write:
578cb4a73f4SArunpravin Paneer Selvam 	kfree(bo_handles_write);
579cb4a73f4SArunpravin Paneer Selvam put_gobj_read:
580cb4a73f4SArunpravin Paneer Selvam 	while (rentry-- > 0)
581cb4a73f4SArunpravin Paneer Selvam 		drm_gem_object_put(gobj_read[rentry]);
582cb4a73f4SArunpravin Paneer Selvam 	kfree(gobj_read);
583cb4a73f4SArunpravin Paneer Selvam free_bo_handles_read:
584cb4a73f4SArunpravin Paneer Selvam 	kfree(bo_handles_read);
585a292fdecSArunpravin Paneer Selvam free_syncobj:
586a292fdecSArunpravin Paneer Selvam 	while (entry-- > 0)
587a292fdecSArunpravin Paneer Selvam 		if (syncobj[entry])
588a292fdecSArunpravin Paneer Selvam 			drm_syncobj_put(syncobj[entry]);
589a292fdecSArunpravin Paneer Selvam 	kfree(syncobj);
590a292fdecSArunpravin Paneer Selvam free_syncobj_handles:
591a292fdecSArunpravin Paneer Selvam 	kfree(syncobj_handles);
592a292fdecSArunpravin Paneer Selvam 
593a292fdecSArunpravin Paneer Selvam 	return r;
594a292fdecSArunpravin Paneer Selvam }
595a292fdecSArunpravin Paneer Selvam 
amdgpu_userq_wait_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)596a292fdecSArunpravin Paneer Selvam int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
597a292fdecSArunpravin Paneer Selvam 			    struct drm_file *filp)
598a292fdecSArunpravin Paneer Selvam {
599cb4a73f4SArunpravin Paneer Selvam 	u32 *syncobj_handles, *timeline_points, *timeline_handles, *bo_handles_read, *bo_handles_write;
6002761bb9aSArunpravin Paneer Selvam 	u32 num_syncobj, num_read_bo_handles, num_write_bo_handles;
601a292fdecSArunpravin Paneer Selvam 	struct drm_amdgpu_userq_fence_info *fence_info = NULL;
602a292fdecSArunpravin Paneer Selvam 	struct drm_amdgpu_userq_wait *wait_info = data;
6034b274063SArunpravin Paneer Selvam 	struct amdgpu_fpriv *fpriv = filp->driver_priv;
6044b274063SArunpravin Paneer Selvam 	struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr;
6054b274063SArunpravin Paneer Selvam 	struct amdgpu_usermode_queue *waitq;
606cb4a73f4SArunpravin Paneer Selvam 	struct drm_gem_object **gobj_write;
607cb4a73f4SArunpravin Paneer Selvam 	struct drm_gem_object **gobj_read;
608a292fdecSArunpravin Paneer Selvam 	struct dma_fence **fences = NULL;
6092761bb9aSArunpravin Paneer Selvam 	u16 num_points, num_fences = 0;
610cb4a73f4SArunpravin Paneer Selvam 	int r, i, rentry, wentry, cnt;
611a292fdecSArunpravin Paneer Selvam 	struct drm_exec exec;
612a292fdecSArunpravin Paneer Selvam 
6132761bb9aSArunpravin Paneer Selvam 	num_read_bo_handles = wait_info->num_bo_read_handles;
614cb4a73f4SArunpravin Paneer Selvam 	bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles),
615*98a46a40SDan Carpenter 				      size_mul(sizeof(u32), num_read_bo_handles));
616cb4a73f4SArunpravin Paneer Selvam 	if (IS_ERR(bo_handles_read))
617cb4a73f4SArunpravin Paneer Selvam 		return PTR_ERR(bo_handles_read);
618cb4a73f4SArunpravin Paneer Selvam 
6192761bb9aSArunpravin Paneer Selvam 	num_write_bo_handles = wait_info->num_bo_write_handles;
620cb4a73f4SArunpravin Paneer Selvam 	bo_handles_write = memdup_user(u64_to_user_ptr(wait_info->bo_write_handles),
621*98a46a40SDan Carpenter 				       size_mul(sizeof(u32), num_write_bo_handles));
622cb4a73f4SArunpravin Paneer Selvam 	if (IS_ERR(bo_handles_write)) {
623cb4a73f4SArunpravin Paneer Selvam 		r = PTR_ERR(bo_handles_write);
624cb4a73f4SArunpravin Paneer Selvam 		goto free_bo_handles_read;
625cb4a73f4SArunpravin Paneer Selvam 	}
626a292fdecSArunpravin Paneer Selvam 
627a292fdecSArunpravin Paneer Selvam 	num_syncobj = wait_info->num_syncobj_handles;
6282761bb9aSArunpravin Paneer Selvam 	syncobj_handles = memdup_user(u64_to_user_ptr(wait_info->syncobj_handles),
629*98a46a40SDan Carpenter 				      size_mul(sizeof(u32), num_syncobj));
630a292fdecSArunpravin Paneer Selvam 	if (IS_ERR(syncobj_handles)) {
631a292fdecSArunpravin Paneer Selvam 		r = PTR_ERR(syncobj_handles);
632cb4a73f4SArunpravin Paneer Selvam 		goto free_bo_handles_write;
633a292fdecSArunpravin Paneer Selvam 	}
634a292fdecSArunpravin Paneer Selvam 
6352761bb9aSArunpravin Paneer Selvam 	num_points = wait_info->num_syncobj_timeline_handles;
63615e30a6eSArunpravin Paneer Selvam 	timeline_handles = memdup_user(u64_to_user_ptr(wait_info->syncobj_timeline_handles),
63715e30a6eSArunpravin Paneer Selvam 				       sizeof(u32) * num_points);
63815e30a6eSArunpravin Paneer Selvam 	if (IS_ERR(timeline_handles)) {
63915e30a6eSArunpravin Paneer Selvam 		r = PTR_ERR(timeline_handles);
64015e30a6eSArunpravin Paneer Selvam 		goto free_syncobj_handles;
64115e30a6eSArunpravin Paneer Selvam 	}
64215e30a6eSArunpravin Paneer Selvam 
64315e30a6eSArunpravin Paneer Selvam 	timeline_points = memdup_user(u64_to_user_ptr(wait_info->syncobj_timeline_points),
64415e30a6eSArunpravin Paneer Selvam 				      sizeof(u32) * num_points);
64515e30a6eSArunpravin Paneer Selvam 	if (IS_ERR(timeline_points)) {
64615e30a6eSArunpravin Paneer Selvam 		r = PTR_ERR(timeline_points);
64715e30a6eSArunpravin Paneer Selvam 		goto free_timeline_handles;
64815e30a6eSArunpravin Paneer Selvam 	}
64915e30a6eSArunpravin Paneer Selvam 
650cb4a73f4SArunpravin Paneer Selvam 	gobj_read = kmalloc_array(num_read_bo_handles, sizeof(*gobj_read), GFP_KERNEL);
651cb4a73f4SArunpravin Paneer Selvam 	if (!gobj_read) {
652a292fdecSArunpravin Paneer Selvam 		r = -ENOMEM;
65315e30a6eSArunpravin Paneer Selvam 		goto free_timeline_points;
654a292fdecSArunpravin Paneer Selvam 	}
655a292fdecSArunpravin Paneer Selvam 
656cb4a73f4SArunpravin Paneer Selvam 	for (rentry = 0; rentry < num_read_bo_handles; rentry++) {
657cb4a73f4SArunpravin Paneer Selvam 		gobj_read[rentry] = drm_gem_object_lookup(filp, bo_handles_read[rentry]);
658cb4a73f4SArunpravin Paneer Selvam 		if (!gobj_read[rentry]) {
659a292fdecSArunpravin Paneer Selvam 			r = -ENOENT;
660cb4a73f4SArunpravin Paneer Selvam 			goto put_gobj_read;
661a292fdecSArunpravin Paneer Selvam 		}
662a292fdecSArunpravin Paneer Selvam 	}
663a292fdecSArunpravin Paneer Selvam 
664cb4a73f4SArunpravin Paneer Selvam 	gobj_write = kmalloc_array(num_write_bo_handles, sizeof(*gobj_write), GFP_KERNEL);
665cb4a73f4SArunpravin Paneer Selvam 	if (!gobj_write) {
666cb4a73f4SArunpravin Paneer Selvam 		r = -ENOMEM;
667cb4a73f4SArunpravin Paneer Selvam 		goto put_gobj_read;
668cb4a73f4SArunpravin Paneer Selvam 	}
669cb4a73f4SArunpravin Paneer Selvam 
670cb4a73f4SArunpravin Paneer Selvam 	for (wentry = 0; wentry < num_write_bo_handles; wentry++) {
671cb4a73f4SArunpravin Paneer Selvam 		gobj_write[wentry] = drm_gem_object_lookup(filp, bo_handles_write[wentry]);
672cb4a73f4SArunpravin Paneer Selvam 		if (!gobj_write[wentry]) {
673cb4a73f4SArunpravin Paneer Selvam 			r = -ENOENT;
674cb4a73f4SArunpravin Paneer Selvam 			goto put_gobj_write;
675cb4a73f4SArunpravin Paneer Selvam 		}
676cb4a73f4SArunpravin Paneer Selvam 	}
677cb4a73f4SArunpravin Paneer Selvam 
678cb4a73f4SArunpravin Paneer Selvam 	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
679cb4a73f4SArunpravin Paneer Selvam 		      (num_read_bo_handles + num_write_bo_handles));
680e7cf21fbSArunpravin Paneer Selvam 
681e7cf21fbSArunpravin Paneer Selvam 	/* Lock all BOs with retry handling */
682a292fdecSArunpravin Paneer Selvam 	drm_exec_until_all_locked(&exec) {
683cb4a73f4SArunpravin Paneer Selvam 		r = drm_exec_prepare_array(&exec, gobj_read, num_read_bo_handles, 1);
684a292fdecSArunpravin Paneer Selvam 		drm_exec_retry_on_contention(&exec);
685a292fdecSArunpravin Paneer Selvam 		if (r) {
686a292fdecSArunpravin Paneer Selvam 			drm_exec_fini(&exec);
687cb4a73f4SArunpravin Paneer Selvam 			goto put_gobj_write;
688cb4a73f4SArunpravin Paneer Selvam 		}
689cb4a73f4SArunpravin Paneer Selvam 
690cb4a73f4SArunpravin Paneer Selvam 		r = drm_exec_prepare_array(&exec, gobj_write, num_write_bo_handles, 1);
691cb4a73f4SArunpravin Paneer Selvam 		drm_exec_retry_on_contention(&exec);
692cb4a73f4SArunpravin Paneer Selvam 		if (r) {
693cb4a73f4SArunpravin Paneer Selvam 			drm_exec_fini(&exec);
694cb4a73f4SArunpravin Paneer Selvam 			goto put_gobj_write;
695a292fdecSArunpravin Paneer Selvam 		}
696a292fdecSArunpravin Paneer Selvam 	}
697a292fdecSArunpravin Paneer Selvam 
698a292fdecSArunpravin Paneer Selvam 	if (!wait_info->num_fences) {
69915e30a6eSArunpravin Paneer Selvam 		if (num_points) {
70015e30a6eSArunpravin Paneer Selvam 			struct dma_fence_unwrap iter;
70115e30a6eSArunpravin Paneer Selvam 			struct dma_fence *fence;
70215e30a6eSArunpravin Paneer Selvam 			struct dma_fence *f;
70315e30a6eSArunpravin Paneer Selvam 
70415e30a6eSArunpravin Paneer Selvam 			for (i = 0; i < num_points; i++) {
70515e30a6eSArunpravin Paneer Selvam 				r = drm_syncobj_find_fence(filp, timeline_handles[i],
70615e30a6eSArunpravin Paneer Selvam 							   timeline_points[i],
70715e30a6eSArunpravin Paneer Selvam 							   DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
70815e30a6eSArunpravin Paneer Selvam 							   &fence);
70915e30a6eSArunpravin Paneer Selvam 				if (r)
71015e30a6eSArunpravin Paneer Selvam 					goto exec_fini;
71115e30a6eSArunpravin Paneer Selvam 
71215e30a6eSArunpravin Paneer Selvam 				dma_fence_unwrap_for_each(f, &iter, fence)
71315e30a6eSArunpravin Paneer Selvam 					num_fences++;
71415e30a6eSArunpravin Paneer Selvam 
71515e30a6eSArunpravin Paneer Selvam 				dma_fence_put(fence);
71615e30a6eSArunpravin Paneer Selvam 			}
71715e30a6eSArunpravin Paneer Selvam 		}
71815e30a6eSArunpravin Paneer Selvam 
719a292fdecSArunpravin Paneer Selvam 		/* Count syncobj's fence */
720a292fdecSArunpravin Paneer Selvam 		for (i = 0; i < num_syncobj; i++) {
721a292fdecSArunpravin Paneer Selvam 			struct dma_fence *fence;
722a292fdecSArunpravin Paneer Selvam 
723a292fdecSArunpravin Paneer Selvam 			r = drm_syncobj_find_fence(filp, syncobj_handles[i],
72415e30a6eSArunpravin Paneer Selvam 						   0,
72515e30a6eSArunpravin Paneer Selvam 						   DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
72615e30a6eSArunpravin Paneer Selvam 						   &fence);
727a292fdecSArunpravin Paneer Selvam 			if (r)
728a292fdecSArunpravin Paneer Selvam 				goto exec_fini;
729a292fdecSArunpravin Paneer Selvam 
730a292fdecSArunpravin Paneer Selvam 			num_fences++;
731a292fdecSArunpravin Paneer Selvam 			dma_fence_put(fence);
732a292fdecSArunpravin Paneer Selvam 		}
733a292fdecSArunpravin Paneer Selvam 
734a292fdecSArunpravin Paneer Selvam 		/* Count GEM objects fence */
735cb4a73f4SArunpravin Paneer Selvam 		for (i = 0; i < num_read_bo_handles; i++) {
736a292fdecSArunpravin Paneer Selvam 			struct dma_resv_iter resv_cursor;
737a292fdecSArunpravin Paneer Selvam 			struct dma_fence *fence;
738a292fdecSArunpravin Paneer Selvam 
739cb4a73f4SArunpravin Paneer Selvam 			dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv,
740cb4a73f4SArunpravin Paneer Selvam 						DMA_RESV_USAGE_READ, fence)
741cb4a73f4SArunpravin Paneer Selvam 				num_fences++;
742cb4a73f4SArunpravin Paneer Selvam 		}
743cb4a73f4SArunpravin Paneer Selvam 
744cb4a73f4SArunpravin Paneer Selvam 		for (i = 0; i < num_write_bo_handles; i++) {
745cb4a73f4SArunpravin Paneer Selvam 			struct dma_resv_iter resv_cursor;
746cb4a73f4SArunpravin Paneer Selvam 			struct dma_fence *fence;
747cb4a73f4SArunpravin Paneer Selvam 
748cb4a73f4SArunpravin Paneer Selvam 			dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv,
749cb4a73f4SArunpravin Paneer Selvam 						DMA_RESV_USAGE_WRITE, fence)
750a292fdecSArunpravin Paneer Selvam 				num_fences++;
751a292fdecSArunpravin Paneer Selvam 		}
752a292fdecSArunpravin Paneer Selvam 
753a292fdecSArunpravin Paneer Selvam 		/*
754a292fdecSArunpravin Paneer Selvam 		 * Passing num_fences = 0 means that userspace doesn't want to
755a292fdecSArunpravin Paneer Selvam 		 * retrieve userq_fence_info. If num_fences = 0 we skip filling
756a292fdecSArunpravin Paneer Selvam 		 * userq_fence_info and return the actual number of fences on
757a292fdecSArunpravin Paneer Selvam 		 * args->num_fences.
758a292fdecSArunpravin Paneer Selvam 		 */
759a292fdecSArunpravin Paneer Selvam 		wait_info->num_fences = num_fences;
760a292fdecSArunpravin Paneer Selvam 	} else {
761a292fdecSArunpravin Paneer Selvam 		/* Array of fence info */
762a292fdecSArunpravin Paneer Selvam 		fence_info = kmalloc_array(wait_info->num_fences, sizeof(*fence_info), GFP_KERNEL);
763a292fdecSArunpravin Paneer Selvam 		if (!fence_info) {
764a292fdecSArunpravin Paneer Selvam 			r = -ENOMEM;
765a292fdecSArunpravin Paneer Selvam 			goto exec_fini;
766a292fdecSArunpravin Paneer Selvam 		}
767a292fdecSArunpravin Paneer Selvam 
768a292fdecSArunpravin Paneer Selvam 		/* Array of fences */
769a292fdecSArunpravin Paneer Selvam 		fences = kmalloc_array(wait_info->num_fences, sizeof(*fences), GFP_KERNEL);
770a292fdecSArunpravin Paneer Selvam 		if (!fences) {
771a292fdecSArunpravin Paneer Selvam 			r = -ENOMEM;
772a292fdecSArunpravin Paneer Selvam 			goto free_fence_info;
773a292fdecSArunpravin Paneer Selvam 		}
774a292fdecSArunpravin Paneer Selvam 
775cb4a73f4SArunpravin Paneer Selvam 		/* Retrieve GEM read objects fence */
776cb4a73f4SArunpravin Paneer Selvam 		for (i = 0; i < num_read_bo_handles; i++) {
777a292fdecSArunpravin Paneer Selvam 			struct dma_resv_iter resv_cursor;
778a292fdecSArunpravin Paneer Selvam 			struct dma_fence *fence;
779a292fdecSArunpravin Paneer Selvam 
780cb4a73f4SArunpravin Paneer Selvam 			dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv,
781cb4a73f4SArunpravin Paneer Selvam 						DMA_RESV_USAGE_READ, fence) {
782cb4a73f4SArunpravin Paneer Selvam 				if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
783cb4a73f4SArunpravin Paneer Selvam 					r = -EINVAL;
784cb4a73f4SArunpravin Paneer Selvam 					goto free_fences;
785cb4a73f4SArunpravin Paneer Selvam 				}
786cb4a73f4SArunpravin Paneer Selvam 
787cb4a73f4SArunpravin Paneer Selvam 				fences[num_fences++] = fence;
788cb4a73f4SArunpravin Paneer Selvam 				dma_fence_get(fence);
789cb4a73f4SArunpravin Paneer Selvam 			}
790cb4a73f4SArunpravin Paneer Selvam 		}
791cb4a73f4SArunpravin Paneer Selvam 
792cb4a73f4SArunpravin Paneer Selvam 		/* Retrieve GEM write objects fence */
793cb4a73f4SArunpravin Paneer Selvam 		for (i = 0; i < num_write_bo_handles; i++) {
794cb4a73f4SArunpravin Paneer Selvam 			struct dma_resv_iter resv_cursor;
795cb4a73f4SArunpravin Paneer Selvam 			struct dma_fence *fence;
796cb4a73f4SArunpravin Paneer Selvam 
797cb4a73f4SArunpravin Paneer Selvam 			dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv,
798cb4a73f4SArunpravin Paneer Selvam 						DMA_RESV_USAGE_WRITE, fence) {
799a292fdecSArunpravin Paneer Selvam 				if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
800a292fdecSArunpravin Paneer Selvam 					r = -EINVAL;
801a292fdecSArunpravin Paneer Selvam 					goto free_fences;
802a292fdecSArunpravin Paneer Selvam 				}
803a292fdecSArunpravin Paneer Selvam 
804a292fdecSArunpravin Paneer Selvam 				fences[num_fences++] = fence;
805a292fdecSArunpravin Paneer Selvam 				dma_fence_get(fence);
806a292fdecSArunpravin Paneer Selvam 			}
807a292fdecSArunpravin Paneer Selvam 		}
808a292fdecSArunpravin Paneer Selvam 
80915e30a6eSArunpravin Paneer Selvam 		if (num_points) {
81015e30a6eSArunpravin Paneer Selvam 			struct dma_fence_unwrap iter;
81115e30a6eSArunpravin Paneer Selvam 			struct dma_fence *fence;
81215e30a6eSArunpravin Paneer Selvam 			struct dma_fence *f;
81315e30a6eSArunpravin Paneer Selvam 
81415e30a6eSArunpravin Paneer Selvam 			for (i = 0; i < num_points; i++) {
81515e30a6eSArunpravin Paneer Selvam 				r = drm_syncobj_find_fence(filp, timeline_handles[i],
81615e30a6eSArunpravin Paneer Selvam 							   timeline_points[i],
81715e30a6eSArunpravin Paneer Selvam 							   DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
81815e30a6eSArunpravin Paneer Selvam 							   &fence);
81915e30a6eSArunpravin Paneer Selvam 				if (r)
82015e30a6eSArunpravin Paneer Selvam 					goto free_fences;
82115e30a6eSArunpravin Paneer Selvam 
82215e30a6eSArunpravin Paneer Selvam 				dma_fence_unwrap_for_each(f, &iter, fence) {
82315e30a6eSArunpravin Paneer Selvam 					if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
82415e30a6eSArunpravin Paneer Selvam 						r = -EINVAL;
82515e30a6eSArunpravin Paneer Selvam 						goto free_fences;
82615e30a6eSArunpravin Paneer Selvam 					}
82715e30a6eSArunpravin Paneer Selvam 
82815e30a6eSArunpravin Paneer Selvam 					dma_fence_get(f);
82915e30a6eSArunpravin Paneer Selvam 					fences[num_fences++] = f;
83015e30a6eSArunpravin Paneer Selvam 				}
83115e30a6eSArunpravin Paneer Selvam 
83215e30a6eSArunpravin Paneer Selvam 				dma_fence_put(fence);
83315e30a6eSArunpravin Paneer Selvam 			}
83415e30a6eSArunpravin Paneer Selvam 		}
83515e30a6eSArunpravin Paneer Selvam 
836a292fdecSArunpravin Paneer Selvam 		/* Retrieve syncobj's fence */
837a292fdecSArunpravin Paneer Selvam 		for (i = 0; i < num_syncobj; i++) {
838a292fdecSArunpravin Paneer Selvam 			struct dma_fence *fence;
839a292fdecSArunpravin Paneer Selvam 
840a292fdecSArunpravin Paneer Selvam 			r = drm_syncobj_find_fence(filp, syncobj_handles[i],
84115e30a6eSArunpravin Paneer Selvam 						   0,
84215e30a6eSArunpravin Paneer Selvam 						   DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
84315e30a6eSArunpravin Paneer Selvam 						   &fence);
844a292fdecSArunpravin Paneer Selvam 			if (r)
845a292fdecSArunpravin Paneer Selvam 				goto free_fences;
846a292fdecSArunpravin Paneer Selvam 
847a292fdecSArunpravin Paneer Selvam 			if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
848a292fdecSArunpravin Paneer Selvam 				r = -EINVAL;
849a292fdecSArunpravin Paneer Selvam 				goto free_fences;
850a292fdecSArunpravin Paneer Selvam 			}
851a292fdecSArunpravin Paneer Selvam 
852a292fdecSArunpravin Paneer Selvam 			fences[num_fences++] = fence;
853a292fdecSArunpravin Paneer Selvam 		}
854a292fdecSArunpravin Paneer Selvam 
8553e50b1d6SArvind Yadav 		/*
8563e50b1d6SArvind Yadav 		 * Keep only the latest fences to reduce the number of values
8573e50b1d6SArvind Yadav 		 * given back to userspace.
8583e50b1d6SArvind Yadav 		 */
8593e50b1d6SArvind Yadav 		num_fences = dma_fence_dedup_array(fences, num_fences);
8603e50b1d6SArvind Yadav 
8614b274063SArunpravin Paneer Selvam 		waitq = idr_find(&userq_mgr->userq_idr, wait_info->waitq_id);
862010503a3SArvind Yadav 		if (!waitq) {
863010503a3SArvind Yadav 			r = -EINVAL;
8644b274063SArunpravin Paneer Selvam 			goto free_fences;
865010503a3SArvind Yadav 		}
8664b274063SArunpravin Paneer Selvam 
867c9e20cb0SArunpravin Paneer Selvam 		for (i = 0, cnt = 0; i < num_fences; i++) {
868a292fdecSArunpravin Paneer Selvam 			struct amdgpu_userq_fence_driver *fence_drv;
869a292fdecSArunpravin Paneer Selvam 			struct amdgpu_userq_fence *userq_fence;
870a292fdecSArunpravin Paneer Selvam 			u32 index;
871a292fdecSArunpravin Paneer Selvam 
872a292fdecSArunpravin Paneer Selvam 			userq_fence = to_amdgpu_userq_fence(fences[i]);
873a292fdecSArunpravin Paneer Selvam 			if (!userq_fence) {
874a292fdecSArunpravin Paneer Selvam 				/*
875a292fdecSArunpravin Paneer Selvam 				 * Just waiting on other driver fences should
876a292fdecSArunpravin Paneer Selvam 				 * be good for now
877a292fdecSArunpravin Paneer Selvam 				 */
87815e30a6eSArunpravin Paneer Selvam 				r = dma_fence_wait(fences[i], true);
87915e30a6eSArunpravin Paneer Selvam 				if (r) {
880a292fdecSArunpravin Paneer Selvam 					dma_fence_put(fences[i]);
88115e30a6eSArunpravin Paneer Selvam 					goto free_fences;
88215e30a6eSArunpravin Paneer Selvam 				}
883a292fdecSArunpravin Paneer Selvam 
88415e30a6eSArunpravin Paneer Selvam 				dma_fence_put(fences[i]);
885a292fdecSArunpravin Paneer Selvam 				continue;
886a292fdecSArunpravin Paneer Selvam 			}
887a292fdecSArunpravin Paneer Selvam 
888a292fdecSArunpravin Paneer Selvam 			fence_drv = userq_fence->fence_drv;
889a292fdecSArunpravin Paneer Selvam 			/*
890a292fdecSArunpravin Paneer Selvam 			 * We need to make sure the user queue release their reference
891a292fdecSArunpravin Paneer Selvam 			 * to the fence drivers at some point before queue destruction.
892a292fdecSArunpravin Paneer Selvam 			 * Otherwise, we would gather those references until we don't
893a292fdecSArunpravin Paneer Selvam 			 * have any more space left and crash.
894a292fdecSArunpravin Paneer Selvam 			 */
8954b274063SArunpravin Paneer Selvam 			r = xa_alloc(&waitq->fence_drv_xa, &index, fence_drv,
896a292fdecSArunpravin Paneer Selvam 				     xa_limit_32b, GFP_KERNEL);
897a292fdecSArunpravin Paneer Selvam 			if (r)
898a292fdecSArunpravin Paneer Selvam 				goto free_fences;
899a292fdecSArunpravin Paneer Selvam 
900a292fdecSArunpravin Paneer Selvam 			amdgpu_userq_fence_driver_get(fence_drv);
901a292fdecSArunpravin Paneer Selvam 
902a292fdecSArunpravin Paneer Selvam 			/* Store drm syncobj's gpu va address and value */
903f7cb6a28SArunpravin Paneer Selvam 			fence_info[cnt].va = fence_drv->va;
904a292fdecSArunpravin Paneer Selvam 			fence_info[cnt].value = fences[i]->seqno;
905a292fdecSArunpravin Paneer Selvam 
906a292fdecSArunpravin Paneer Selvam 			dma_fence_put(fences[i]);
907a292fdecSArunpravin Paneer Selvam 			/* Increment the actual userq fence count */
908a292fdecSArunpravin Paneer Selvam 			cnt++;
909a292fdecSArunpravin Paneer Selvam 		}
910a292fdecSArunpravin Paneer Selvam 
911a292fdecSArunpravin Paneer Selvam 		wait_info->num_fences = cnt;
912a292fdecSArunpravin Paneer Selvam 		/* Copy userq fence info to user space */
9132761bb9aSArunpravin Paneer Selvam 		if (copy_to_user(u64_to_user_ptr(wait_info->out_fences),
914a292fdecSArunpravin Paneer Selvam 				 fence_info, wait_info->num_fences * sizeof(*fence_info))) {
915a292fdecSArunpravin Paneer Selvam 			r = -EFAULT;
916a292fdecSArunpravin Paneer Selvam 			goto free_fences;
917a292fdecSArunpravin Paneer Selvam 		}
918a292fdecSArunpravin Paneer Selvam 
919a292fdecSArunpravin Paneer Selvam 		kfree(fences);
920a292fdecSArunpravin Paneer Selvam 		kfree(fence_info);
921a292fdecSArunpravin Paneer Selvam 	}
922a292fdecSArunpravin Paneer Selvam 
923a292fdecSArunpravin Paneer Selvam 	drm_exec_fini(&exec);
924cb4a73f4SArunpravin Paneer Selvam 	for (i = 0; i < num_read_bo_handles; i++)
925cb4a73f4SArunpravin Paneer Selvam 		drm_gem_object_put(gobj_read[i]);
926cb4a73f4SArunpravin Paneer Selvam 	kfree(gobj_read);
927cb4a73f4SArunpravin Paneer Selvam 
928cb4a73f4SArunpravin Paneer Selvam 	for (i = 0; i < num_write_bo_handles; i++)
929cb4a73f4SArunpravin Paneer Selvam 		drm_gem_object_put(gobj_write[i]);
930cb4a73f4SArunpravin Paneer Selvam 	kfree(gobj_write);
931a292fdecSArunpravin Paneer Selvam 
93215e30a6eSArunpravin Paneer Selvam 	kfree(timeline_points);
93315e30a6eSArunpravin Paneer Selvam 	kfree(timeline_handles);
934a292fdecSArunpravin Paneer Selvam 	kfree(syncobj_handles);
935cb4a73f4SArunpravin Paneer Selvam 	kfree(bo_handles_write);
936cb4a73f4SArunpravin Paneer Selvam 	kfree(bo_handles_read);
937a292fdecSArunpravin Paneer Selvam 
938a292fdecSArunpravin Paneer Selvam 	return 0;
939a292fdecSArunpravin Paneer Selvam 
940a292fdecSArunpravin Paneer Selvam free_fences:
941a292fdecSArunpravin Paneer Selvam 	while (num_fences-- > 0)
942a292fdecSArunpravin Paneer Selvam 		dma_fence_put(fences[num_fences]);
943a292fdecSArunpravin Paneer Selvam 	kfree(fences);
944a292fdecSArunpravin Paneer Selvam free_fence_info:
945a292fdecSArunpravin Paneer Selvam 	kfree(fence_info);
946a292fdecSArunpravin Paneer Selvam exec_fini:
947a292fdecSArunpravin Paneer Selvam 	drm_exec_fini(&exec);
948cb4a73f4SArunpravin Paneer Selvam put_gobj_write:
949cb4a73f4SArunpravin Paneer Selvam 	while (wentry-- > 0)
950cb4a73f4SArunpravin Paneer Selvam 		drm_gem_object_put(gobj_write[wentry]);
951cb4a73f4SArunpravin Paneer Selvam 	kfree(gobj_write);
952cb4a73f4SArunpravin Paneer Selvam put_gobj_read:
953cb4a73f4SArunpravin Paneer Selvam 	while (rentry-- > 0)
954cb4a73f4SArunpravin Paneer Selvam 		drm_gem_object_put(gobj_read[rentry]);
955cb4a73f4SArunpravin Paneer Selvam 	kfree(gobj_read);
95615e30a6eSArunpravin Paneer Selvam free_timeline_points:
95715e30a6eSArunpravin Paneer Selvam 	kfree(timeline_points);
95815e30a6eSArunpravin Paneer Selvam free_timeline_handles:
95915e30a6eSArunpravin Paneer Selvam 	kfree(timeline_handles);
960a292fdecSArunpravin Paneer Selvam free_syncobj_handles:
961a292fdecSArunpravin Paneer Selvam 	kfree(syncobj_handles);
962cb4a73f4SArunpravin Paneer Selvam free_bo_handles_write:
963cb4a73f4SArunpravin Paneer Selvam 	kfree(bo_handles_write);
964cb4a73f4SArunpravin Paneer Selvam free_bo_handles_read:
965cb4a73f4SArunpravin Paneer Selvam 	kfree(bo_handles_read);
966a292fdecSArunpravin Paneer Selvam 
967a292fdecSArunpravin Paneer Selvam 	return r;
968a292fdecSArunpravin Paneer Selvam }
969