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