xref: /linux/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c (revision b08494a8f7416e5f09907318c5460ad6f6e2a548)
142a66677SAlex Deucher // SPDX-License-Identifier: MIT
242a66677SAlex Deucher /*
342a66677SAlex Deucher  * Copyright 2023 Advanced Micro Devices, Inc.
442a66677SAlex Deucher  *
542a66677SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
642a66677SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
742a66677SAlex Deucher  * to deal in the Software without restriction, including without limitation
842a66677SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
942a66677SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
1042a66677SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
1142a66677SAlex Deucher  *
1242a66677SAlex Deucher  * The above copyright notice and this permission notice shall be included in
1342a66677SAlex Deucher  * all copies or substantial portions of the Software.
1442a66677SAlex Deucher  *
1542a66677SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1642a66677SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1742a66677SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1842a66677SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1942a66677SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2042a66677SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2142a66677SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
2242a66677SAlex Deucher  *
2342a66677SAlex Deucher  */
2442a66677SAlex Deucher 
2542a66677SAlex Deucher #include <drm/drm_auth.h>
2642a66677SAlex Deucher #include <drm/drm_exec.h>
2742a66677SAlex Deucher #include <linux/pm_runtime.h>
2842a66677SAlex Deucher 
2942a66677SAlex Deucher #include "amdgpu.h"
3042a66677SAlex Deucher #include "amdgpu_vm.h"
3142a66677SAlex Deucher #include "amdgpu_userq.h"
3242a66677SAlex Deucher #include "amdgpu_userq_fence.h"
3342a66677SAlex Deucher 
3442a66677SAlex Deucher u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev)
3542a66677SAlex Deucher {
3642a66677SAlex Deucher 	int i;
3742a66677SAlex Deucher 	u32 userq_ip_mask = 0;
3842a66677SAlex Deucher 
3942a66677SAlex Deucher 	for (i = 0; i < AMDGPU_HW_IP_NUM; i++) {
4042a66677SAlex Deucher 		if (adev->userq_funcs[i])
4142a66677SAlex Deucher 			userq_ip_mask |= (1 << i);
4242a66677SAlex Deucher 	}
4342a66677SAlex Deucher 
4442a66677SAlex Deucher 	return userq_ip_mask;
4542a66677SAlex Deucher }
4642a66677SAlex Deucher 
4742a66677SAlex Deucher static int
4842a66677SAlex Deucher amdgpu_userq_unmap_helper(struct amdgpu_userq_mgr *uq_mgr,
4942a66677SAlex Deucher 			  struct amdgpu_usermode_queue *queue)
5042a66677SAlex Deucher {
5142a66677SAlex Deucher 	struct amdgpu_device *adev = uq_mgr->adev;
5242a66677SAlex Deucher 	const struct amdgpu_userq_funcs *userq_funcs =
5342a66677SAlex Deucher 		adev->userq_funcs[queue->queue_type];
5442a66677SAlex Deucher 	int r = 0;
5542a66677SAlex Deucher 
5642a66677SAlex Deucher 	if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
5742a66677SAlex Deucher 		r = userq_funcs->unmap(uq_mgr, queue);
5842a66677SAlex Deucher 		if (r)
5942a66677SAlex Deucher 			queue->state = AMDGPU_USERQ_STATE_HUNG;
6042a66677SAlex Deucher 		else
6142a66677SAlex Deucher 			queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
6242a66677SAlex Deucher 	}
6342a66677SAlex Deucher 	return r;
6442a66677SAlex Deucher }
6542a66677SAlex Deucher 
6642a66677SAlex Deucher static int
6742a66677SAlex Deucher amdgpu_userq_map_helper(struct amdgpu_userq_mgr *uq_mgr,
6842a66677SAlex Deucher 			struct amdgpu_usermode_queue *queue)
6942a66677SAlex Deucher {
7042a66677SAlex Deucher 	struct amdgpu_device *adev = uq_mgr->adev;
7142a66677SAlex Deucher 	const struct amdgpu_userq_funcs *userq_funcs =
7242a66677SAlex Deucher 		adev->userq_funcs[queue->queue_type];
7342a66677SAlex Deucher 	int r = 0;
7442a66677SAlex Deucher 
7542a66677SAlex Deucher 	if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
7642a66677SAlex Deucher 		r = userq_funcs->map(uq_mgr, queue);
7742a66677SAlex Deucher 		if (r) {
7842a66677SAlex Deucher 			queue->state = AMDGPU_USERQ_STATE_HUNG;
7942a66677SAlex Deucher 		} else {
8042a66677SAlex Deucher 			queue->state = AMDGPU_USERQ_STATE_MAPPED;
8142a66677SAlex Deucher 		}
8242a66677SAlex Deucher 	}
8342a66677SAlex Deucher 	return r;
8442a66677SAlex Deucher }
8542a66677SAlex Deucher 
8642a66677SAlex Deucher static void
8742a66677SAlex Deucher amdgpu_userq_wait_for_last_fence(struct amdgpu_userq_mgr *uq_mgr,
8842a66677SAlex Deucher 				 struct amdgpu_usermode_queue *queue)
8942a66677SAlex Deucher {
9042a66677SAlex Deucher 	struct dma_fence *f = queue->last_fence;
9142a66677SAlex Deucher 	int ret;
9242a66677SAlex Deucher 
9342a66677SAlex Deucher 	if (f && !dma_fence_is_signaled(f)) {
9442a66677SAlex Deucher 		ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100));
9542a66677SAlex Deucher 		if (ret <= 0)
968c97cdb1SSunil Khatri 			drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n",
97127e612bSSunil Khatri 				     f->context, f->seqno);
9842a66677SAlex Deucher 	}
9942a66677SAlex Deucher }
10042a66677SAlex Deucher 
10142a66677SAlex Deucher static void
10242a66677SAlex Deucher amdgpu_userq_cleanup(struct amdgpu_userq_mgr *uq_mgr,
10342a66677SAlex Deucher 		     struct amdgpu_usermode_queue *queue,
10442a66677SAlex Deucher 		     int queue_id)
10542a66677SAlex Deucher {
10642a66677SAlex Deucher 	struct amdgpu_device *adev = uq_mgr->adev;
10742a66677SAlex Deucher 	const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
10842a66677SAlex Deucher 
10942a66677SAlex Deucher 	uq_funcs->mqd_destroy(uq_mgr, queue);
11042a66677SAlex Deucher 	amdgpu_userq_fence_driver_free(queue);
11142a66677SAlex Deucher 	idr_remove(&uq_mgr->userq_idr, queue_id);
11242a66677SAlex Deucher 	kfree(queue);
11342a66677SAlex Deucher }
11442a66677SAlex Deucher 
11542a66677SAlex Deucher int
11642a66677SAlex Deucher amdgpu_userq_active(struct amdgpu_userq_mgr *uq_mgr)
11742a66677SAlex Deucher {
11842a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
11942a66677SAlex Deucher 	int queue_id;
12042a66677SAlex Deucher 	int ret = 0;
12142a66677SAlex Deucher 
12242a66677SAlex Deucher 	mutex_lock(&uq_mgr->userq_mutex);
12342a66677SAlex Deucher 	/* Resume all the queues for this process */
12442a66677SAlex Deucher 	idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id)
12542a66677SAlex Deucher 		ret += queue->state == AMDGPU_USERQ_STATE_MAPPED;
12642a66677SAlex Deucher 
12742a66677SAlex Deucher 	mutex_unlock(&uq_mgr->userq_mutex);
12842a66677SAlex Deucher 	return ret;
12942a66677SAlex Deucher }
13042a66677SAlex Deucher 
13142a66677SAlex Deucher static struct amdgpu_usermode_queue *
13242a66677SAlex Deucher amdgpu_userq_find(struct amdgpu_userq_mgr *uq_mgr, int qid)
13342a66677SAlex Deucher {
13442a66677SAlex Deucher 	return idr_find(&uq_mgr->userq_idr, qid);
13542a66677SAlex Deucher }
13642a66677SAlex Deucher 
13742a66677SAlex Deucher void
13842a66677SAlex Deucher amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr,
13942a66677SAlex Deucher 			     struct amdgpu_eviction_fence_mgr *evf_mgr)
14042a66677SAlex Deucher {
14142a66677SAlex Deucher 	struct amdgpu_eviction_fence *ev_fence;
14242a66677SAlex Deucher 
14342a66677SAlex Deucher retry:
14442a66677SAlex Deucher 	/* Flush any pending resume work to create ev_fence */
14542a66677SAlex Deucher 	flush_delayed_work(&uq_mgr->resume_work);
14642a66677SAlex Deucher 
14742a66677SAlex Deucher 	mutex_lock(&uq_mgr->userq_mutex);
14842a66677SAlex Deucher 	spin_lock(&evf_mgr->ev_fence_lock);
14942a66677SAlex Deucher 	ev_fence = evf_mgr->ev_fence;
15042a66677SAlex Deucher 	spin_unlock(&evf_mgr->ev_fence_lock);
15142a66677SAlex Deucher 	if (!ev_fence || dma_fence_is_signaled(&ev_fence->base)) {
15242a66677SAlex Deucher 		mutex_unlock(&uq_mgr->userq_mutex);
15342a66677SAlex Deucher 		/*
15442a66677SAlex Deucher 		 * Looks like there was no pending resume work,
15542a66677SAlex Deucher 		 * add one now to create a valid eviction fence
15642a66677SAlex Deucher 		 */
15742a66677SAlex Deucher 		schedule_delayed_work(&uq_mgr->resume_work, 0);
15842a66677SAlex Deucher 		goto retry;
15942a66677SAlex Deucher 	}
16042a66677SAlex Deucher }
16142a66677SAlex Deucher 
16242a66677SAlex Deucher int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
16342a66677SAlex Deucher 			       struct amdgpu_userq_obj *userq_obj,
16442a66677SAlex Deucher 			       int size)
16542a66677SAlex Deucher {
16642a66677SAlex Deucher 	struct amdgpu_device *adev = uq_mgr->adev;
16742a66677SAlex Deucher 	struct amdgpu_bo_param bp;
16842a66677SAlex Deucher 	int r;
16942a66677SAlex Deucher 
17042a66677SAlex Deucher 	memset(&bp, 0, sizeof(bp));
17142a66677SAlex Deucher 	bp.byte_align = PAGE_SIZE;
17242a66677SAlex Deucher 	bp.domain = AMDGPU_GEM_DOMAIN_GTT;
17342a66677SAlex Deucher 	bp.flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
17442a66677SAlex Deucher 		   AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
17542a66677SAlex Deucher 	bp.type = ttm_bo_type_kernel;
17642a66677SAlex Deucher 	bp.size = size;
17742a66677SAlex Deucher 	bp.resv = NULL;
17842a66677SAlex Deucher 	bp.bo_ptr_size = sizeof(struct amdgpu_bo);
17942a66677SAlex Deucher 
18042a66677SAlex Deucher 	r = amdgpu_bo_create(adev, &bp, &userq_obj->obj);
18142a66677SAlex Deucher 	if (r) {
182c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to allocate BO for userqueue (%d)", r);
18342a66677SAlex Deucher 		return r;
18442a66677SAlex Deucher 	}
18542a66677SAlex Deucher 
18642a66677SAlex Deucher 	r = amdgpu_bo_reserve(userq_obj->obj, true);
18742a66677SAlex Deucher 	if (r) {
188c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to reserve BO to map (%d)", r);
18942a66677SAlex Deucher 		goto free_obj;
19042a66677SAlex Deucher 	}
19142a66677SAlex Deucher 
19242a66677SAlex Deucher 	r = amdgpu_ttm_alloc_gart(&(userq_obj->obj)->tbo);
19342a66677SAlex Deucher 	if (r) {
194c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to alloc GART for userqueue object (%d)", r);
19542a66677SAlex Deucher 		goto unresv;
19642a66677SAlex Deucher 	}
19742a66677SAlex Deucher 
19842a66677SAlex Deucher 	r = amdgpu_bo_kmap(userq_obj->obj, &userq_obj->cpu_ptr);
19942a66677SAlex Deucher 	if (r) {
200c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to map BO for userqueue (%d)", r);
20142a66677SAlex Deucher 		goto unresv;
20242a66677SAlex Deucher 	}
20342a66677SAlex Deucher 
20442a66677SAlex Deucher 	userq_obj->gpu_addr = amdgpu_bo_gpu_offset(userq_obj->obj);
20542a66677SAlex Deucher 	amdgpu_bo_unreserve(userq_obj->obj);
20642a66677SAlex Deucher 	memset(userq_obj->cpu_ptr, 0, size);
20742a66677SAlex Deucher 	return 0;
20842a66677SAlex Deucher 
20942a66677SAlex Deucher unresv:
21042a66677SAlex Deucher 	amdgpu_bo_unreserve(userq_obj->obj);
21142a66677SAlex Deucher 
21242a66677SAlex Deucher free_obj:
21342a66677SAlex Deucher 	amdgpu_bo_unref(&userq_obj->obj);
21442a66677SAlex Deucher 	return r;
21542a66677SAlex Deucher }
21642a66677SAlex Deucher 
21742a66677SAlex Deucher void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
21842a66677SAlex Deucher 				 struct amdgpu_userq_obj *userq_obj)
21942a66677SAlex Deucher {
22042a66677SAlex Deucher 	amdgpu_bo_kunmap(userq_obj->obj);
22142a66677SAlex Deucher 	amdgpu_bo_unref(&userq_obj->obj);
22242a66677SAlex Deucher }
22342a66677SAlex Deucher 
22442a66677SAlex Deucher uint64_t
22542a66677SAlex Deucher amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
22642a66677SAlex Deucher 				struct amdgpu_db_info *db_info,
22742a66677SAlex Deucher 				struct drm_file *filp)
22842a66677SAlex Deucher {
22942a66677SAlex Deucher 	uint64_t index;
23042a66677SAlex Deucher 	struct drm_gem_object *gobj;
23142a66677SAlex Deucher 	struct amdgpu_userq_obj *db_obj = db_info->db_obj;
23242a66677SAlex Deucher 	int r, db_size;
23342a66677SAlex Deucher 
23442a66677SAlex Deucher 	gobj = drm_gem_object_lookup(filp, db_info->doorbell_handle);
23542a66677SAlex Deucher 	if (gobj == NULL) {
236c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Can't find GEM object for doorbell\n");
23742a66677SAlex Deucher 		return -EINVAL;
23842a66677SAlex Deucher 	}
23942a66677SAlex Deucher 
24042a66677SAlex Deucher 	db_obj->obj = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
24142a66677SAlex Deucher 	drm_gem_object_put(gobj);
24242a66677SAlex Deucher 
243bc5bab82SArunpravin Paneer Selvam 	r = amdgpu_bo_reserve(db_obj->obj, true);
24442a66677SAlex Deucher 	if (r) {
245c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "[Usermode queues] Failed to pin doorbell object\n");
24642a66677SAlex Deucher 		goto unref_bo;
24742a66677SAlex Deucher 	}
24842a66677SAlex Deucher 
249bc5bab82SArunpravin Paneer Selvam 	/* Pin the BO before generating the index, unpin in queue destroy */
250bc5bab82SArunpravin Paneer Selvam 	r = amdgpu_bo_pin(db_obj->obj, AMDGPU_GEM_DOMAIN_DOORBELL);
25142a66677SAlex Deucher 	if (r) {
252c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "[Usermode queues] Failed to pin doorbell object\n");
253bc5bab82SArunpravin Paneer Selvam 		goto unresv_bo;
25442a66677SAlex Deucher 	}
25542a66677SAlex Deucher 
25642a66677SAlex Deucher 	switch (db_info->queue_type) {
25742a66677SAlex Deucher 	case AMDGPU_HW_IP_GFX:
25842a66677SAlex Deucher 	case AMDGPU_HW_IP_COMPUTE:
25942a66677SAlex Deucher 	case AMDGPU_HW_IP_DMA:
26042a66677SAlex Deucher 		db_size = sizeof(u64);
26142a66677SAlex Deucher 		break;
26242a66677SAlex Deucher 
26342a66677SAlex Deucher 	case AMDGPU_HW_IP_VCN_ENC:
26442a66677SAlex Deucher 		db_size = sizeof(u32);
26542a66677SAlex Deucher 		db_info->doorbell_offset += AMDGPU_NAVI10_DOORBELL64_VCN0_1 << 1;
26642a66677SAlex Deucher 		break;
26742a66677SAlex Deucher 
26842a66677SAlex Deucher 	case AMDGPU_HW_IP_VPE:
26942a66677SAlex Deucher 		db_size = sizeof(u32);
27042a66677SAlex Deucher 		db_info->doorbell_offset += AMDGPU_NAVI10_DOORBELL64_VPE << 1;
27142a66677SAlex Deucher 		break;
27242a66677SAlex Deucher 
27342a66677SAlex Deucher 	default:
274c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "[Usermode queues] IP %d not support\n",
275c46a3762SSunil Khatri 			     db_info->queue_type);
27642a66677SAlex Deucher 		r = -EINVAL;
27742a66677SAlex Deucher 		goto unpin_bo;
27842a66677SAlex Deucher 	}
27942a66677SAlex Deucher 
28042a66677SAlex Deucher 	index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
28142a66677SAlex Deucher 					     db_info->doorbell_offset, db_size);
28271353c1aSSunil Khatri 	drm_dbg_driver(adev_to_drm(uq_mgr->adev),
28371353c1aSSunil Khatri 		       "[Usermode queues] doorbell index=%lld\n", index);
28442a66677SAlex Deucher 	amdgpu_bo_unreserve(db_obj->obj);
28542a66677SAlex Deucher 	return index;
28642a66677SAlex Deucher 
28742a66677SAlex Deucher unpin_bo:
28842a66677SAlex Deucher 	amdgpu_bo_unpin(db_obj->obj);
289bc5bab82SArunpravin Paneer Selvam unresv_bo:
290bc5bab82SArunpravin Paneer Selvam 	amdgpu_bo_unreserve(db_obj->obj);
29142a66677SAlex Deucher unref_bo:
29242a66677SAlex Deucher 	amdgpu_bo_unref(&db_obj->obj);
29342a66677SAlex Deucher 	return r;
29442a66677SAlex Deucher }
29542a66677SAlex Deucher 
29642a66677SAlex Deucher static int
29742a66677SAlex Deucher amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
29842a66677SAlex Deucher {
29942a66677SAlex Deucher 	struct amdgpu_fpriv *fpriv = filp->driver_priv;
30042a66677SAlex Deucher 	struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
30142a66677SAlex Deucher 	struct amdgpu_device *adev = uq_mgr->adev;
30242a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
30342a66677SAlex Deucher 	int r = 0;
30442a66677SAlex Deucher 
305f10eb185SArvind Yadav 	cancel_delayed_work_sync(&uq_mgr->resume_work);
30642a66677SAlex Deucher 	mutex_lock(&uq_mgr->userq_mutex);
30742a66677SAlex Deucher 
30842a66677SAlex Deucher 	queue = amdgpu_userq_find(uq_mgr, queue_id);
30942a66677SAlex Deucher 	if (!queue) {
31071353c1aSSunil Khatri 		drm_dbg_driver(adev_to_drm(uq_mgr->adev), "Invalid queue id to destroy\n");
31142a66677SAlex Deucher 		mutex_unlock(&uq_mgr->userq_mutex);
31242a66677SAlex Deucher 		return -EINVAL;
31342a66677SAlex Deucher 	}
31442a66677SAlex Deucher 	amdgpu_userq_wait_for_last_fence(uq_mgr, queue);
315bc5bab82SArunpravin Paneer Selvam 	r = amdgpu_bo_reserve(queue->db_obj.obj, true);
316bc5bab82SArunpravin Paneer Selvam 	if (!r) {
31742a66677SAlex Deucher 		amdgpu_bo_unpin(queue->db_obj.obj);
318bc5bab82SArunpravin Paneer Selvam 		amdgpu_bo_unreserve(queue->db_obj.obj);
319bc5bab82SArunpravin Paneer Selvam 	}
32042a66677SAlex Deucher 	amdgpu_bo_unref(&queue->db_obj.obj);
321bc5bab82SArunpravin Paneer Selvam 	r = amdgpu_userq_unmap_helper(uq_mgr, queue);
32242a66677SAlex Deucher 	amdgpu_userq_cleanup(uq_mgr, queue, queue_id);
32342a66677SAlex Deucher 	mutex_unlock(&uq_mgr->userq_mutex);
32442a66677SAlex Deucher 
32542a66677SAlex Deucher 	pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
32642a66677SAlex Deucher 	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
32742a66677SAlex Deucher 
32842a66677SAlex Deucher 	return r;
32942a66677SAlex Deucher }
33042a66677SAlex Deucher 
33142a66677SAlex Deucher static int amdgpu_userq_priority_permit(struct drm_file *filp,
33242a66677SAlex Deucher 					int priority)
33342a66677SAlex Deucher {
33442a66677SAlex Deucher 	if (priority < AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_HIGH)
33542a66677SAlex Deucher 		return 0;
33642a66677SAlex Deucher 
33742a66677SAlex Deucher 	if (capable(CAP_SYS_NICE))
33842a66677SAlex Deucher 		return 0;
33942a66677SAlex Deucher 
34042a66677SAlex Deucher 	if (drm_is_current_master(filp))
34142a66677SAlex Deucher 		return 0;
34242a66677SAlex Deucher 
34342a66677SAlex Deucher 	return -EACCES;
34442a66677SAlex Deucher }
34542a66677SAlex Deucher 
34642a66677SAlex Deucher static int
34742a66677SAlex Deucher amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
34842a66677SAlex Deucher {
34942a66677SAlex Deucher 	struct amdgpu_fpriv *fpriv = filp->driver_priv;
35042a66677SAlex Deucher 	struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
35142a66677SAlex Deucher 	struct amdgpu_device *adev = uq_mgr->adev;
35242a66677SAlex Deucher 	const struct amdgpu_userq_funcs *uq_funcs;
35342a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
35442a66677SAlex Deucher 	struct amdgpu_db_info db_info;
35542a66677SAlex Deucher 	bool skip_map_queue;
35642a66677SAlex Deucher 	uint64_t index;
35742a66677SAlex Deucher 	int qid, r = 0;
35842a66677SAlex Deucher 	int priority =
35942a66677SAlex Deucher 		(args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK) >>
36042a66677SAlex Deucher 		AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT;
36142a66677SAlex Deucher 
36242a66677SAlex Deucher 	/* Usermode queues are only supported for GFX IP as of now */
36342a66677SAlex Deucher 	if (args->in.ip_type != AMDGPU_HW_IP_GFX &&
36442a66677SAlex Deucher 	    args->in.ip_type != AMDGPU_HW_IP_DMA &&
36542a66677SAlex Deucher 	    args->in.ip_type != AMDGPU_HW_IP_COMPUTE) {
366c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Usermode queue doesn't support IP type %u\n",
367c46a3762SSunil Khatri 			     args->in.ip_type);
36842a66677SAlex Deucher 		return -EINVAL;
36942a66677SAlex Deucher 	}
37042a66677SAlex Deucher 
37142a66677SAlex Deucher 	r = amdgpu_userq_priority_permit(filp, priority);
37242a66677SAlex Deucher 	if (r)
37342a66677SAlex Deucher 		return r;
37442a66677SAlex Deucher 
37542a66677SAlex Deucher 	if ((args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_SECURE) &&
37642a66677SAlex Deucher 	    (args->in.ip_type != AMDGPU_HW_IP_GFX) &&
37742a66677SAlex Deucher 	    (args->in.ip_type != AMDGPU_HW_IP_COMPUTE) &&
37842a66677SAlex Deucher 	    !amdgpu_is_tmz(adev)) {
379c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Secure only supported on GFX/Compute queues\n");
38042a66677SAlex Deucher 		return -EINVAL;
38142a66677SAlex Deucher 	}
38242a66677SAlex Deucher 
38342a66677SAlex Deucher 	r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
38442a66677SAlex Deucher 	if (r < 0) {
385c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "pm_runtime_get_sync() failed for userqueue create\n");
38642a66677SAlex Deucher 		pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
38742a66677SAlex Deucher 		return r;
38842a66677SAlex Deucher 	}
38942a66677SAlex Deucher 
39042a66677SAlex Deucher 	/*
39142a66677SAlex Deucher 	 * There could be a situation that we are creating a new queue while
39242a66677SAlex Deucher 	 * the other queues under this UQ_mgr are suspended. So if there is any
39342a66677SAlex Deucher 	 * resume work pending, wait for it to get done.
39442a66677SAlex Deucher 	 *
39542a66677SAlex Deucher 	 * This will also make sure we have a valid eviction fence ready to be used.
39642a66677SAlex Deucher 	 */
397*96a86dcbSJesse.Zhang 	mutex_lock(&adev->userq_mutex);
39842a66677SAlex Deucher 	amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr);
39942a66677SAlex Deucher 
40042a66677SAlex Deucher 	uq_funcs = adev->userq_funcs[args->in.ip_type];
40142a66677SAlex Deucher 	if (!uq_funcs) {
402c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Usermode queue is not supported for this IP (%u)\n",
403c46a3762SSunil Khatri 			     args->in.ip_type);
40442a66677SAlex Deucher 		r = -EINVAL;
40542a66677SAlex Deucher 		goto unlock;
40642a66677SAlex Deucher 	}
40742a66677SAlex Deucher 
40842a66677SAlex Deucher 	queue = kzalloc(sizeof(struct amdgpu_usermode_queue), GFP_KERNEL);
40942a66677SAlex Deucher 	if (!queue) {
410c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to allocate memory for queue\n");
41142a66677SAlex Deucher 		r = -ENOMEM;
41242a66677SAlex Deucher 		goto unlock;
41342a66677SAlex Deucher 	}
41442a66677SAlex Deucher 	queue->doorbell_handle = args->in.doorbell_handle;
41542a66677SAlex Deucher 	queue->queue_type = args->in.ip_type;
41642a66677SAlex Deucher 	queue->vm = &fpriv->vm;
41742a66677SAlex Deucher 	queue->priority = priority;
41842a66677SAlex Deucher 
41942a66677SAlex Deucher 	db_info.queue_type = queue->queue_type;
42042a66677SAlex Deucher 	db_info.doorbell_handle = queue->doorbell_handle;
42142a66677SAlex Deucher 	db_info.db_obj = &queue->db_obj;
42242a66677SAlex Deucher 	db_info.doorbell_offset = args->in.doorbell_offset;
42342a66677SAlex Deucher 
42442a66677SAlex Deucher 	/* Convert relative doorbell offset into absolute doorbell index */
42542a66677SAlex Deucher 	index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp);
42642a66677SAlex Deucher 	if (index == (uint64_t)-EINVAL) {
427c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n");
42842a66677SAlex Deucher 		kfree(queue);
42942a66677SAlex Deucher 		goto unlock;
43042a66677SAlex Deucher 	}
43142a66677SAlex Deucher 
43242a66677SAlex Deucher 	queue->doorbell_index = index;
43342a66677SAlex Deucher 	xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
43442a66677SAlex Deucher 	r = amdgpu_userq_fence_driver_alloc(adev, queue);
43542a66677SAlex Deucher 	if (r) {
436c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n");
43742a66677SAlex Deucher 		goto unlock;
43842a66677SAlex Deucher 	}
43942a66677SAlex Deucher 
44042a66677SAlex Deucher 	r = uq_funcs->mqd_create(uq_mgr, &args->in, queue);
44142a66677SAlex Deucher 	if (r) {
442c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to create Queue\n");
44342a66677SAlex Deucher 		amdgpu_userq_fence_driver_free(queue);
44442a66677SAlex Deucher 		kfree(queue);
44542a66677SAlex Deucher 		goto unlock;
44642a66677SAlex Deucher 	}
44742a66677SAlex Deucher 
44842a66677SAlex Deucher 
44942a66677SAlex Deucher 	qid = idr_alloc(&uq_mgr->userq_idr, queue, 1, AMDGPU_MAX_USERQ_COUNT, GFP_KERNEL);
45042a66677SAlex Deucher 	if (qid < 0) {
451c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to allocate a queue id\n");
45242a66677SAlex Deucher 		amdgpu_userq_fence_driver_free(queue);
45342a66677SAlex Deucher 		uq_funcs->mqd_destroy(uq_mgr, queue);
45442a66677SAlex Deucher 		kfree(queue);
45542a66677SAlex Deucher 		r = -ENOMEM;
45642a66677SAlex Deucher 		goto unlock;
45742a66677SAlex Deucher 	}
45842a66677SAlex Deucher 
45942a66677SAlex Deucher 	/* don't map the queue if scheduling is halted */
46042a66677SAlex Deucher 	if (adev->userq_halt_for_enforce_isolation &&
46142a66677SAlex Deucher 	    ((queue->queue_type == AMDGPU_HW_IP_GFX) ||
46242a66677SAlex Deucher 	     (queue->queue_type == AMDGPU_HW_IP_COMPUTE)))
46342a66677SAlex Deucher 		skip_map_queue = true;
46442a66677SAlex Deucher 	else
46542a66677SAlex Deucher 		skip_map_queue = false;
46642a66677SAlex Deucher 	if (!skip_map_queue) {
46742a66677SAlex Deucher 		r = amdgpu_userq_map_helper(uq_mgr, queue);
46842a66677SAlex Deucher 		if (r) {
469c46a3762SSunil Khatri 			drm_file_err(uq_mgr->file, "Failed to map Queue\n");
47042a66677SAlex Deucher 			idr_remove(&uq_mgr->userq_idr, qid);
47142a66677SAlex Deucher 			amdgpu_userq_fence_driver_free(queue);
47242a66677SAlex Deucher 			uq_funcs->mqd_destroy(uq_mgr, queue);
47342a66677SAlex Deucher 			kfree(queue);
47442a66677SAlex Deucher 			goto unlock;
47542a66677SAlex Deucher 		}
47642a66677SAlex Deucher 	}
47742a66677SAlex Deucher 
47842a66677SAlex Deucher 
47942a66677SAlex Deucher 	args->out.queue_id = qid;
48042a66677SAlex Deucher 
48142a66677SAlex Deucher unlock:
48242a66677SAlex Deucher 	mutex_unlock(&uq_mgr->userq_mutex);
483*96a86dcbSJesse.Zhang 	mutex_unlock(&adev->userq_mutex);
48442a66677SAlex Deucher 
48542a66677SAlex Deucher 	return r;
48642a66677SAlex Deucher }
48742a66677SAlex Deucher 
48842a66677SAlex Deucher int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
48942a66677SAlex Deucher 		       struct drm_file *filp)
49042a66677SAlex Deucher {
49142a66677SAlex Deucher 	union drm_amdgpu_userq *args = data;
49242a66677SAlex Deucher 	int r;
49342a66677SAlex Deucher 
49442a66677SAlex Deucher 	switch (args->in.op) {
49542a66677SAlex Deucher 	case AMDGPU_USERQ_OP_CREATE:
49642a66677SAlex Deucher 		if (args->in.flags & ~(AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK |
49742a66677SAlex Deucher 				       AMDGPU_USERQ_CREATE_FLAGS_QUEUE_SECURE))
49842a66677SAlex Deucher 			return -EINVAL;
49942a66677SAlex Deucher 		r = amdgpu_userq_create(filp, args);
50042a66677SAlex Deucher 		if (r)
501c46a3762SSunil Khatri 			drm_file_err(filp, "Failed to create usermode queue\n");
50242a66677SAlex Deucher 		break;
50342a66677SAlex Deucher 
50442a66677SAlex Deucher 	case AMDGPU_USERQ_OP_FREE:
50542a66677SAlex Deucher 		if (args->in.ip_type ||
50642a66677SAlex Deucher 		    args->in.doorbell_handle ||
50742a66677SAlex Deucher 		    args->in.doorbell_offset ||
50842a66677SAlex Deucher 		    args->in.flags ||
50942a66677SAlex Deucher 		    args->in.queue_va ||
51042a66677SAlex Deucher 		    args->in.queue_size ||
51142a66677SAlex Deucher 		    args->in.rptr_va ||
51242a66677SAlex Deucher 		    args->in.wptr_va ||
51342a66677SAlex Deucher 		    args->in.wptr_va ||
51442a66677SAlex Deucher 		    args->in.mqd ||
51542a66677SAlex Deucher 		    args->in.mqd_size)
51642a66677SAlex Deucher 			return -EINVAL;
51742a66677SAlex Deucher 		r = amdgpu_userq_destroy(filp, args->in.queue_id);
51842a66677SAlex Deucher 		if (r)
519c46a3762SSunil Khatri 			drm_file_err(filp, "Failed to destroy usermode queue\n");
52042a66677SAlex Deucher 		break;
52142a66677SAlex Deucher 
52242a66677SAlex Deucher 	default:
52371353c1aSSunil Khatri 		drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op);
52442a66677SAlex Deucher 		return -EINVAL;
52542a66677SAlex Deucher 	}
52642a66677SAlex Deucher 
52742a66677SAlex Deucher 	return r;
52842a66677SAlex Deucher }
52942a66677SAlex Deucher 
53042a66677SAlex Deucher static int
53142a66677SAlex Deucher amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
53242a66677SAlex Deucher {
53342a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
53442a66677SAlex Deucher 	int queue_id;
53542a66677SAlex Deucher 	int ret = 0, r;
53642a66677SAlex Deucher 
53742a66677SAlex Deucher 	/* Resume all the queues for this process */
53842a66677SAlex Deucher 	idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id) {
53942a66677SAlex Deucher 		r = amdgpu_userq_map_helper(uq_mgr, queue);
54042a66677SAlex Deucher 		if (r)
54142a66677SAlex Deucher 			ret = r;
54242a66677SAlex Deucher 	}
54342a66677SAlex Deucher 
54442a66677SAlex Deucher 	if (ret)
545c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to map all the queues\n");
54642a66677SAlex Deucher 	return ret;
54742a66677SAlex Deucher }
54842a66677SAlex Deucher 
54942a66677SAlex Deucher static int
55042a66677SAlex Deucher amdgpu_userq_validate_vm_bo(void *_unused, struct amdgpu_bo *bo)
55142a66677SAlex Deucher {
55242a66677SAlex Deucher 	struct ttm_operation_ctx ctx = { false, false };
55342a66677SAlex Deucher 	int ret;
55442a66677SAlex Deucher 
55542a66677SAlex Deucher 	amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
55642a66677SAlex Deucher 
55742a66677SAlex Deucher 	ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
55842a66677SAlex Deucher 	if (ret)
55942a66677SAlex Deucher 		DRM_ERROR("Fail to validate\n");
56042a66677SAlex Deucher 
56142a66677SAlex Deucher 	return ret;
56242a66677SAlex Deucher }
56342a66677SAlex Deucher 
56442a66677SAlex Deucher static int
56542a66677SAlex Deucher amdgpu_userq_validate_bos(struct amdgpu_userq_mgr *uq_mgr)
56642a66677SAlex Deucher {
56742a66677SAlex Deucher 	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
56842a66677SAlex Deucher 	struct amdgpu_vm *vm = &fpriv->vm;
56942a66677SAlex Deucher 	struct amdgpu_device *adev = uq_mgr->adev;
57042a66677SAlex Deucher 	struct amdgpu_bo_va *bo_va;
57142a66677SAlex Deucher 	struct ww_acquire_ctx *ticket;
57242a66677SAlex Deucher 	struct drm_exec exec;
57342a66677SAlex Deucher 	struct amdgpu_bo *bo;
57442a66677SAlex Deucher 	struct dma_resv *resv;
57542a66677SAlex Deucher 	bool clear, unlock;
57642a66677SAlex Deucher 	int ret = 0;
57742a66677SAlex Deucher 
57842a66677SAlex Deucher 	drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0);
57942a66677SAlex Deucher 	drm_exec_until_all_locked(&exec) {
58042a66677SAlex Deucher 		ret = amdgpu_vm_lock_pd(vm, &exec, 2);
58142a66677SAlex Deucher 		drm_exec_retry_on_contention(&exec);
58242a66677SAlex Deucher 		if (unlikely(ret)) {
583c46a3762SSunil Khatri 			drm_file_err(uq_mgr->file, "Failed to lock PD\n");
58442a66677SAlex Deucher 			goto unlock_all;
58542a66677SAlex Deucher 		}
58642a66677SAlex Deucher 
58742a66677SAlex Deucher 		/* Lock the done list */
58842a66677SAlex Deucher 		list_for_each_entry(bo_va, &vm->done, base.vm_status) {
58942a66677SAlex Deucher 			bo = bo_va->base.bo;
59042a66677SAlex Deucher 			if (!bo)
59142a66677SAlex Deucher 				continue;
59242a66677SAlex Deucher 
59342a66677SAlex Deucher 			ret = drm_exec_lock_obj(&exec, &bo->tbo.base);
59442a66677SAlex Deucher 			drm_exec_retry_on_contention(&exec);
59542a66677SAlex Deucher 			if (unlikely(ret))
59642a66677SAlex Deucher 				goto unlock_all;
59742a66677SAlex Deucher 		}
59842a66677SAlex Deucher 	}
59942a66677SAlex Deucher 
60042a66677SAlex Deucher 	spin_lock(&vm->status_lock);
60142a66677SAlex Deucher 	while (!list_empty(&vm->moved)) {
60242a66677SAlex Deucher 		bo_va = list_first_entry(&vm->moved, struct amdgpu_bo_va,
60342a66677SAlex Deucher 					 base.vm_status);
60442a66677SAlex Deucher 		spin_unlock(&vm->status_lock);
60542a66677SAlex Deucher 
60642a66677SAlex Deucher 		/* Per VM BOs never need to bo cleared in the page tables */
60742a66677SAlex Deucher 		ret = amdgpu_vm_bo_update(adev, bo_va, false);
60842a66677SAlex Deucher 		if (ret)
60942a66677SAlex Deucher 			goto unlock_all;
61042a66677SAlex Deucher 		spin_lock(&vm->status_lock);
61142a66677SAlex Deucher 	}
61242a66677SAlex Deucher 
61342a66677SAlex Deucher 	ticket = &exec.ticket;
61442a66677SAlex Deucher 	while (!list_empty(&vm->invalidated)) {
61542a66677SAlex Deucher 		bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
61642a66677SAlex Deucher 					 base.vm_status);
61742a66677SAlex Deucher 		resv = bo_va->base.bo->tbo.base.resv;
61842a66677SAlex Deucher 		spin_unlock(&vm->status_lock);
61942a66677SAlex Deucher 
62042a66677SAlex Deucher 		bo = bo_va->base.bo;
62142a66677SAlex Deucher 		ret = amdgpu_userq_validate_vm_bo(NULL, bo);
62242a66677SAlex Deucher 		if (ret) {
623c46a3762SSunil Khatri 			drm_file_err(uq_mgr->file, "Failed to validate BO\n");
62442a66677SAlex Deucher 			goto unlock_all;
62542a66677SAlex Deucher 		}
62642a66677SAlex Deucher 
62742a66677SAlex Deucher 		/* Try to reserve the BO to avoid clearing its ptes */
62842a66677SAlex Deucher 		if (!adev->debug_vm && dma_resv_trylock(resv)) {
62942a66677SAlex Deucher 			clear = false;
63042a66677SAlex Deucher 			unlock = true;
63142a66677SAlex Deucher 		/* The caller is already holding the reservation lock */
63297c39b4dSDan Carpenter 		} else if (dma_resv_locking_ctx(resv) == ticket) {
63342a66677SAlex Deucher 			clear = false;
63442a66677SAlex Deucher 			unlock = false;
63542a66677SAlex Deucher 		/* Somebody else is using the BO right now */
63642a66677SAlex Deucher 		} else {
63742a66677SAlex Deucher 			clear = true;
63842a66677SAlex Deucher 			unlock = false;
63942a66677SAlex Deucher 		}
64042a66677SAlex Deucher 
64142a66677SAlex Deucher 		ret = amdgpu_vm_bo_update(adev, bo_va, clear);
64242a66677SAlex Deucher 
64342a66677SAlex Deucher 		if (unlock)
64442a66677SAlex Deucher 			dma_resv_unlock(resv);
64542a66677SAlex Deucher 		if (ret)
64642a66677SAlex Deucher 			goto unlock_all;
64742a66677SAlex Deucher 
64842a66677SAlex Deucher 		spin_lock(&vm->status_lock);
64942a66677SAlex Deucher 	}
65042a66677SAlex Deucher 	spin_unlock(&vm->status_lock);
65142a66677SAlex Deucher 
65242a66677SAlex Deucher 	ret = amdgpu_eviction_fence_replace_fence(&fpriv->evf_mgr, &exec);
65342a66677SAlex Deucher 	if (ret)
654c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n");
65542a66677SAlex Deucher 
65642a66677SAlex Deucher unlock_all:
65742a66677SAlex Deucher 	drm_exec_fini(&exec);
65842a66677SAlex Deucher 	return ret;
65942a66677SAlex Deucher }
66042a66677SAlex Deucher 
66142a66677SAlex Deucher static void amdgpu_userq_restore_worker(struct work_struct *work)
66242a66677SAlex Deucher {
66342a66677SAlex Deucher 	struct amdgpu_userq_mgr *uq_mgr = work_to_uq_mgr(work, resume_work.work);
66442a66677SAlex Deucher 	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
66542a66677SAlex Deucher 	int ret;
66642a66677SAlex Deucher 
66742a66677SAlex Deucher 	flush_work(&fpriv->evf_mgr.suspend_work.work);
66842a66677SAlex Deucher 
66942a66677SAlex Deucher 	mutex_lock(&uq_mgr->userq_mutex);
67042a66677SAlex Deucher 
67142a66677SAlex Deucher 	ret = amdgpu_userq_validate_bos(uq_mgr);
67242a66677SAlex Deucher 	if (ret) {
673c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to validate BOs to restore\n");
67442a66677SAlex Deucher 		goto unlock;
67542a66677SAlex Deucher 	}
67642a66677SAlex Deucher 
67742a66677SAlex Deucher 	ret = amdgpu_userq_restore_all(uq_mgr);
67842a66677SAlex Deucher 	if (ret) {
679c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to restore all queues\n");
68042a66677SAlex Deucher 		goto unlock;
68142a66677SAlex Deucher 	}
68242a66677SAlex Deucher 
68342a66677SAlex Deucher unlock:
68442a66677SAlex Deucher 	mutex_unlock(&uq_mgr->userq_mutex);
68542a66677SAlex Deucher }
68642a66677SAlex Deucher 
68742a66677SAlex Deucher static int
68842a66677SAlex Deucher amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
68942a66677SAlex Deucher {
69042a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
69142a66677SAlex Deucher 	int queue_id;
69242a66677SAlex Deucher 	int ret = 0, r;
69342a66677SAlex Deucher 
69442a66677SAlex Deucher 	/* Try to unmap all the queues in this process ctx */
69542a66677SAlex Deucher 	idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id) {
69642a66677SAlex Deucher 		r = amdgpu_userq_unmap_helper(uq_mgr, queue);
69742a66677SAlex Deucher 		if (r)
69842a66677SAlex Deucher 			ret = r;
69942a66677SAlex Deucher 	}
70042a66677SAlex Deucher 
70142a66677SAlex Deucher 	if (ret)
702c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Couldn't unmap all the queues\n");
70342a66677SAlex Deucher 	return ret;
70442a66677SAlex Deucher }
70542a66677SAlex Deucher 
70642a66677SAlex Deucher static int
70742a66677SAlex Deucher amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
70842a66677SAlex Deucher {
70942a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
71042a66677SAlex Deucher 	int queue_id, ret;
71142a66677SAlex Deucher 
71242a66677SAlex Deucher 	idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id) {
71342a66677SAlex Deucher 		struct dma_fence *f = queue->last_fence;
71442a66677SAlex Deucher 
71542a66677SAlex Deucher 		if (!f || dma_fence_is_signaled(f))
71642a66677SAlex Deucher 			continue;
71742a66677SAlex Deucher 		ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100));
71842a66677SAlex Deucher 		if (ret <= 0) {
7198c97cdb1SSunil Khatri 			drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n",
72042a66677SAlex Deucher 				     f->context, f->seqno);
72142a66677SAlex Deucher 			return -ETIMEDOUT;
72242a66677SAlex Deucher 		}
72342a66677SAlex Deucher 	}
72442a66677SAlex Deucher 
72542a66677SAlex Deucher 	return 0;
72642a66677SAlex Deucher }
72742a66677SAlex Deucher 
72842a66677SAlex Deucher void
72942a66677SAlex Deucher amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr,
73042a66677SAlex Deucher 		   struct amdgpu_eviction_fence *ev_fence)
73142a66677SAlex Deucher {
73242a66677SAlex Deucher 	int ret;
73342a66677SAlex Deucher 	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
73442a66677SAlex Deucher 	struct amdgpu_eviction_fence_mgr *evf_mgr = &fpriv->evf_mgr;
73542a66677SAlex Deucher 
73642a66677SAlex Deucher 	/* Wait for any pending userqueue fence work to finish */
73742a66677SAlex Deucher 	ret = amdgpu_userq_wait_for_signal(uq_mgr);
73842a66677SAlex Deucher 	if (ret) {
739c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Not evicting userqueue, timeout waiting for work\n");
74042a66677SAlex Deucher 		return;
74142a66677SAlex Deucher 	}
74242a66677SAlex Deucher 
74342a66677SAlex Deucher 	ret = amdgpu_userq_evict_all(uq_mgr);
74442a66677SAlex Deucher 	if (ret) {
745c46a3762SSunil Khatri 		drm_file_err(uq_mgr->file, "Failed to evict userqueue\n");
74642a66677SAlex Deucher 		return;
74742a66677SAlex Deucher 	}
74842a66677SAlex Deucher 
74942a66677SAlex Deucher 	/* Signal current eviction fence */
75042a66677SAlex Deucher 	amdgpu_eviction_fence_signal(evf_mgr, ev_fence);
75142a66677SAlex Deucher 
75242a66677SAlex Deucher 	if (evf_mgr->fd_closing) {
753f10eb185SArvind Yadav 		cancel_delayed_work_sync(&uq_mgr->resume_work);
75442a66677SAlex Deucher 		return;
75542a66677SAlex Deucher 	}
75642a66677SAlex Deucher 
75742a66677SAlex Deucher 	/* Schedule a resume work */
75842a66677SAlex Deucher 	schedule_delayed_work(&uq_mgr->resume_work, 0);
75942a66677SAlex Deucher }
76042a66677SAlex Deucher 
76130ff7580SSunil Khatri int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv,
76230ff7580SSunil Khatri 			  struct amdgpu_device *adev)
76342a66677SAlex Deucher {
76442a66677SAlex Deucher 	mutex_init(&userq_mgr->userq_mutex);
76542a66677SAlex Deucher 	idr_init_base(&userq_mgr->userq_idr, 1);
76642a66677SAlex Deucher 	userq_mgr->adev = adev;
76730ff7580SSunil Khatri 	userq_mgr->file = file_priv;
76842a66677SAlex Deucher 
76942a66677SAlex Deucher 	mutex_lock(&adev->userq_mutex);
77042a66677SAlex Deucher 	list_add(&userq_mgr->list, &adev->userq_mgr_list);
77142a66677SAlex Deucher 	mutex_unlock(&adev->userq_mutex);
77242a66677SAlex Deucher 
77342a66677SAlex Deucher 	INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker);
77442a66677SAlex Deucher 	return 0;
77542a66677SAlex Deucher }
77642a66677SAlex Deucher 
77742a66677SAlex Deucher void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
77842a66677SAlex Deucher {
77942a66677SAlex Deucher 	struct amdgpu_device *adev = userq_mgr->adev;
78042a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
78142a66677SAlex Deucher 	struct amdgpu_userq_mgr *uqm, *tmp;
78242a66677SAlex Deucher 	uint32_t queue_id;
78342a66677SAlex Deucher 
784f10eb185SArvind Yadav 	cancel_delayed_work_sync(&userq_mgr->resume_work);
78542a66677SAlex Deucher 
786648a0dc0SJesse.Zhang 	mutex_lock(&adev->userq_mutex);
78742a66677SAlex Deucher 	mutex_lock(&userq_mgr->userq_mutex);
78842a66677SAlex Deucher 	idr_for_each_entry(&userq_mgr->userq_idr, queue, queue_id) {
78942a66677SAlex Deucher 		amdgpu_userq_wait_for_last_fence(userq_mgr, queue);
79042a66677SAlex Deucher 		amdgpu_userq_unmap_helper(userq_mgr, queue);
79142a66677SAlex Deucher 		amdgpu_userq_cleanup(userq_mgr, queue, queue_id);
79242a66677SAlex Deucher 	}
793648a0dc0SJesse.Zhang 
79442a66677SAlex Deucher 	list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) {
79542a66677SAlex Deucher 		if (uqm == userq_mgr) {
79642a66677SAlex Deucher 			list_del(&uqm->list);
79742a66677SAlex Deucher 			break;
79842a66677SAlex Deucher 		}
79942a66677SAlex Deucher 	}
80042a66677SAlex Deucher 	idr_destroy(&userq_mgr->userq_idr);
80142a66677SAlex Deucher 	mutex_unlock(&userq_mgr->userq_mutex);
802648a0dc0SJesse.Zhang 	mutex_unlock(&adev->userq_mutex);
80342a66677SAlex Deucher 	mutex_destroy(&userq_mgr->userq_mutex);
80442a66677SAlex Deucher }
80542a66677SAlex Deucher 
80642a66677SAlex Deucher int amdgpu_userq_suspend(struct amdgpu_device *adev)
80742a66677SAlex Deucher {
80842a66677SAlex Deucher 	u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
80942a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
81042a66677SAlex Deucher 	struct amdgpu_userq_mgr *uqm, *tmp;
81142a66677SAlex Deucher 	int queue_id;
81242a66677SAlex Deucher 	int ret = 0, r;
81342a66677SAlex Deucher 
81442a66677SAlex Deucher 	if (!ip_mask)
81542a66677SAlex Deucher 		return 0;
81642a66677SAlex Deucher 
81742a66677SAlex Deucher 	mutex_lock(&adev->userq_mutex);
81842a66677SAlex Deucher 	list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) {
81942a66677SAlex Deucher 		cancel_delayed_work_sync(&uqm->resume_work);
820c5e02d65SAlex Deucher 		mutex_lock(&uqm->userq_mutex);
82142a66677SAlex Deucher 		idr_for_each_entry(&uqm->userq_idr, queue, queue_id) {
82242a66677SAlex Deucher 			r = amdgpu_userq_unmap_helper(uqm, queue);
82342a66677SAlex Deucher 			if (r)
82442a66677SAlex Deucher 				ret = r;
82542a66677SAlex Deucher 		}
826c5e02d65SAlex Deucher 		mutex_unlock(&uqm->userq_mutex);
82742a66677SAlex Deucher 	}
82842a66677SAlex Deucher 	mutex_unlock(&adev->userq_mutex);
82942a66677SAlex Deucher 	return ret;
83042a66677SAlex Deucher }
83142a66677SAlex Deucher 
83242a66677SAlex Deucher int amdgpu_userq_resume(struct amdgpu_device *adev)
83342a66677SAlex Deucher {
83442a66677SAlex Deucher 	u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
83542a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
83642a66677SAlex Deucher 	struct amdgpu_userq_mgr *uqm, *tmp;
83742a66677SAlex Deucher 	int queue_id;
83842a66677SAlex Deucher 	int ret = 0, r;
83942a66677SAlex Deucher 
84042a66677SAlex Deucher 	if (!ip_mask)
84142a66677SAlex Deucher 		return 0;
84242a66677SAlex Deucher 
84342a66677SAlex Deucher 	mutex_lock(&adev->userq_mutex);
84442a66677SAlex Deucher 	list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) {
845c5e02d65SAlex Deucher 		mutex_lock(&uqm->userq_mutex);
84642a66677SAlex Deucher 		idr_for_each_entry(&uqm->userq_idr, queue, queue_id) {
84742a66677SAlex Deucher 			r = amdgpu_userq_map_helper(uqm, queue);
84842a66677SAlex Deucher 			if (r)
84942a66677SAlex Deucher 				ret = r;
85042a66677SAlex Deucher 		}
851c5e02d65SAlex Deucher 		mutex_unlock(&uqm->userq_mutex);
85242a66677SAlex Deucher 	}
85342a66677SAlex Deucher 	mutex_unlock(&adev->userq_mutex);
85442a66677SAlex Deucher 	return ret;
85542a66677SAlex Deucher }
85642a66677SAlex Deucher 
85742a66677SAlex Deucher int amdgpu_userq_stop_sched_for_enforce_isolation(struct amdgpu_device *adev,
85842a66677SAlex Deucher 						  u32 idx)
85942a66677SAlex Deucher {
86042a66677SAlex Deucher 	u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
86142a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
86242a66677SAlex Deucher 	struct amdgpu_userq_mgr *uqm, *tmp;
86342a66677SAlex Deucher 	int queue_id;
86442a66677SAlex Deucher 	int ret = 0, r;
86542a66677SAlex Deucher 
86642a66677SAlex Deucher 	/* only need to stop gfx/compute */
86742a66677SAlex Deucher 	if (!(ip_mask & ((1 << AMDGPU_HW_IP_GFX) | (1 << AMDGPU_HW_IP_COMPUTE))))
86842a66677SAlex Deucher 		return 0;
86942a66677SAlex Deucher 
87042a66677SAlex Deucher 	mutex_lock(&adev->userq_mutex);
87142a66677SAlex Deucher 	if (adev->userq_halt_for_enforce_isolation)
87242a66677SAlex Deucher 		dev_warn(adev->dev, "userq scheduling already stopped!\n");
87342a66677SAlex Deucher 	adev->userq_halt_for_enforce_isolation = true;
87442a66677SAlex Deucher 	list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) {
87542a66677SAlex Deucher 		cancel_delayed_work_sync(&uqm->resume_work);
876482d4853SAlex Deucher 		mutex_lock(&uqm->userq_mutex);
87742a66677SAlex Deucher 		idr_for_each_entry(&uqm->userq_idr, queue, queue_id) {
87842a66677SAlex Deucher 			if (((queue->queue_type == AMDGPU_HW_IP_GFX) ||
87942a66677SAlex Deucher 			     (queue->queue_type == AMDGPU_HW_IP_COMPUTE)) &&
88042a66677SAlex Deucher 			    (queue->xcp_id == idx)) {
88142a66677SAlex Deucher 				r = amdgpu_userq_unmap_helper(uqm, queue);
88242a66677SAlex Deucher 				if (r)
88342a66677SAlex Deucher 					ret = r;
88442a66677SAlex Deucher 			}
88542a66677SAlex Deucher 		}
886482d4853SAlex Deucher 		mutex_unlock(&uqm->userq_mutex);
88742a66677SAlex Deucher 	}
88842a66677SAlex Deucher 	mutex_unlock(&adev->userq_mutex);
88942a66677SAlex Deucher 	return ret;
89042a66677SAlex Deucher }
89142a66677SAlex Deucher 
89242a66677SAlex Deucher int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev,
89342a66677SAlex Deucher 						   u32 idx)
89442a66677SAlex Deucher {
89542a66677SAlex Deucher 	u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
89642a66677SAlex Deucher 	struct amdgpu_usermode_queue *queue;
89742a66677SAlex Deucher 	struct amdgpu_userq_mgr *uqm, *tmp;
89842a66677SAlex Deucher 	int queue_id;
89942a66677SAlex Deucher 	int ret = 0, r;
90042a66677SAlex Deucher 
90142a66677SAlex Deucher 	/* only need to stop gfx/compute */
90242a66677SAlex Deucher 	if (!(ip_mask & ((1 << AMDGPU_HW_IP_GFX) | (1 << AMDGPU_HW_IP_COMPUTE))))
90342a66677SAlex Deucher 		return 0;
90442a66677SAlex Deucher 
90542a66677SAlex Deucher 	mutex_lock(&adev->userq_mutex);
90642a66677SAlex Deucher 	if (!adev->userq_halt_for_enforce_isolation)
90742a66677SAlex Deucher 		dev_warn(adev->dev, "userq scheduling already started!\n");
90842a66677SAlex Deucher 	adev->userq_halt_for_enforce_isolation = false;
90942a66677SAlex Deucher 	list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) {
910482d4853SAlex Deucher 		mutex_lock(&uqm->userq_mutex);
91142a66677SAlex Deucher 		idr_for_each_entry(&uqm->userq_idr, queue, queue_id) {
91242a66677SAlex Deucher 			if (((queue->queue_type == AMDGPU_HW_IP_GFX) ||
91342a66677SAlex Deucher 			     (queue->queue_type == AMDGPU_HW_IP_COMPUTE)) &&
91442a66677SAlex Deucher 			    (queue->xcp_id == idx)) {
91542a66677SAlex Deucher 				r = amdgpu_userq_map_helper(uqm, queue);
91642a66677SAlex Deucher 				if (r)
91742a66677SAlex Deucher 					ret = r;
91842a66677SAlex Deucher 			}
91942a66677SAlex Deucher 		}
920482d4853SAlex Deucher 		mutex_unlock(&uqm->userq_mutex);
92142a66677SAlex Deucher 	}
92242a66677SAlex Deucher 	mutex_unlock(&adev->userq_mutex);
92342a66677SAlex Deucher 	return ret;
92442a66677SAlex Deucher }
925