132de57e9SJack Xiao /*
232de57e9SJack Xiao  * Copyright 2019 Advanced Micro Devices, Inc.
332de57e9SJack Xiao  *
432de57e9SJack Xiao  * Permission is hereby granted, free of charge, to any person obtaining a
532de57e9SJack Xiao  * copy of this software and associated documentation files (the "Software"),
632de57e9SJack Xiao  * to deal in the Software without restriction, including without limitation
732de57e9SJack Xiao  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
832de57e9SJack Xiao  * and/or sell copies of the Software, and to permit persons to whom the
932de57e9SJack Xiao  * Software is furnished to do so, subject to the following conditions:
1032de57e9SJack Xiao  *
1132de57e9SJack Xiao  * The above copyright notice and this permission notice shall be included in
1232de57e9SJack Xiao  * all copies or substantial portions of the Software.
1332de57e9SJack Xiao  *
1432de57e9SJack Xiao  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1532de57e9SJack Xiao  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1632de57e9SJack Xiao  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1732de57e9SJack Xiao  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1832de57e9SJack Xiao  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1932de57e9SJack Xiao  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2032de57e9SJack Xiao  * OTHER DEALINGS IN THE SOFTWARE.
2132de57e9SJack Xiao  *
2232de57e9SJack Xiao  */
2332de57e9SJack Xiao 
24cc42e76eSMario Limonciello #include <linux/firmware.h>
252acc73f8SChristian König #include <drm/drm_exec.h>
26cc42e76eSMario Limonciello 
2732de57e9SJack Xiao #include "amdgpu_mes.h"
2832de57e9SJack Xiao #include "amdgpu.h"
2932de57e9SJack Xiao #include "soc15_common.h"
3032de57e9SJack Xiao #include "amdgpu_mes_ctx.h"
3132de57e9SJack Xiao 
3232de57e9SJack Xiao #define AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS 1024
3332de57e9SJack Xiao #define AMDGPU_ONE_DOORBELL_SIZE 8
3432de57e9SJack Xiao 
amdgpu_mes_doorbell_process_slice(struct amdgpu_device * adev)35464913c0SMukul Joshi int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev)
3632de57e9SJack Xiao {
3732de57e9SJack Xiao 	return roundup(AMDGPU_ONE_DOORBELL_SIZE *
3832de57e9SJack Xiao 		       AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS,
3932de57e9SJack Xiao 		       PAGE_SIZE);
4032de57e9SJack Xiao }
4132de57e9SJack Xiao 
amdgpu_mes_kernel_doorbell_get(struct amdgpu_device * adev,int ip_type,uint64_t * doorbell_index)42e3cbb1f4SShashank Sharma static int amdgpu_mes_kernel_doorbell_get(struct amdgpu_device *adev,
4332de57e9SJack Xiao 					 int ip_type, uint64_t *doorbell_index)
4432de57e9SJack Xiao {
4532de57e9SJack Xiao 	unsigned int offset, found;
46e3cbb1f4SShashank Sharma 	struct amdgpu_mes *mes = &adev->mes;
4732de57e9SJack Xiao 
48e3cbb1f4SShashank Sharma 	if (ip_type == AMDGPU_RING_TYPE_SDMA)
4932de57e9SJack Xiao 		offset = adev->doorbell_index.sdma_engine[0];
50e3cbb1f4SShashank Sharma 	else
51e3cbb1f4SShashank Sharma 		offset = 0;
5232de57e9SJack Xiao 
53e3cbb1f4SShashank Sharma 	found = find_next_zero_bit(mes->doorbell_bitmap, mes->num_mes_dbs, offset);
54e3cbb1f4SShashank Sharma 	if (found >= mes->num_mes_dbs) {
5532de57e9SJack Xiao 		DRM_WARN("No doorbell available\n");
5632de57e9SJack Xiao 		return -ENOSPC;
5732de57e9SJack Xiao 	}
5832de57e9SJack Xiao 
59e3cbb1f4SShashank Sharma 	set_bit(found, mes->doorbell_bitmap);
6032de57e9SJack Xiao 
61e3cbb1f4SShashank Sharma 	/* Get the absolute doorbell index on BAR */
62e3cbb1f4SShashank Sharma 	*doorbell_index = mes->db_start_dw_offset + found * 2;
6332de57e9SJack Xiao 	return 0;
6432de57e9SJack Xiao }
6532de57e9SJack Xiao 
amdgpu_mes_kernel_doorbell_free(struct amdgpu_device * adev,uint32_t doorbell_index)66e3cbb1f4SShashank Sharma static void amdgpu_mes_kernel_doorbell_free(struct amdgpu_device *adev,
6732de57e9SJack Xiao 					   uint32_t doorbell_index)
6832de57e9SJack Xiao {
69e3cbb1f4SShashank Sharma 	unsigned int old, rel_index;
70e3cbb1f4SShashank Sharma 	struct amdgpu_mes *mes = &adev->mes;
7132de57e9SJack Xiao 
72e3cbb1f4SShashank Sharma 	/* Find the relative index of the doorbell in this object */
73e3cbb1f4SShashank Sharma 	rel_index = (doorbell_index - mes->db_start_dw_offset) / 2;
74e3cbb1f4SShashank Sharma 	old = test_and_clear_bit(rel_index, mes->doorbell_bitmap);
7532de57e9SJack Xiao 	WARN_ON(!old);
7632de57e9SJack Xiao }
7732de57e9SJack Xiao 
amdgpu_mes_doorbell_init(struct amdgpu_device * adev)7832de57e9SJack Xiao static int amdgpu_mes_doorbell_init(struct amdgpu_device *adev)
7932de57e9SJack Xiao {
800fe69062SLe Ma 	int i;
81e3cbb1f4SShashank Sharma 	struct amdgpu_mes *mes = &adev->mes;
8232de57e9SJack Xiao 
83e3cbb1f4SShashank Sharma 	/* Bitmap for dynamic allocation of kernel doorbells */
84e3cbb1f4SShashank Sharma 	mes->doorbell_bitmap = bitmap_zalloc(PAGE_SIZE / sizeof(u32), GFP_KERNEL);
85e3cbb1f4SShashank Sharma 	if (!mes->doorbell_bitmap) {
86e3cbb1f4SShashank Sharma 		DRM_ERROR("Failed to allocate MES doorbell bitmap\n");
87e3cbb1f4SShashank Sharma 		return -ENOMEM;
88e3cbb1f4SShashank Sharma 	}
890fe69062SLe Ma 
90e3cbb1f4SShashank Sharma 	mes->num_mes_dbs = PAGE_SIZE / AMDGPU_ONE_DOORBELL_SIZE;
91e3cbb1f4SShashank Sharma 	for (i = 0; i < AMDGPU_MES_PRIORITY_NUM_LEVELS; i++) {
92e3cbb1f4SShashank Sharma 		adev->mes.aggregated_doorbells[i] = mes->db_start_dw_offset + i * 2;
93e3cbb1f4SShashank Sharma 		set_bit(i, mes->doorbell_bitmap);
94e3cbb1f4SShashank Sharma 	}
9532de57e9SJack Xiao 
9632de57e9SJack Xiao 	return 0;
9732de57e9SJack Xiao }
98b04c1d64SJack Xiao 
amdgpu_mes_event_log_init(struct amdgpu_device * adev)99b2662d4cSshaoyunl static int amdgpu_mes_event_log_init(struct amdgpu_device *adev)
100b2662d4cSshaoyunl {
101b2662d4cSshaoyunl 	int r;
102b2662d4cSshaoyunl 
103e58acb76Sshaoyunl 	if (!amdgpu_mes_log_enable)
104e58acb76Sshaoyunl 		return 0;
105e58acb76Sshaoyunl 
106739d0f3eSMichael Chen 	r = amdgpu_bo_create_kernel(adev, adev->mes.event_log_size, PAGE_SIZE,
10792fd1714Sshaoyunl 				    AMDGPU_GEM_DOMAIN_VRAM,
108b2662d4cSshaoyunl 				    &adev->mes.event_log_gpu_obj,
109b2662d4cSshaoyunl 				    &adev->mes.event_log_gpu_addr,
110b2662d4cSshaoyunl 				    &adev->mes.event_log_cpu_addr);
111b2662d4cSshaoyunl 	if (r) {
112b2662d4cSshaoyunl 		dev_warn(adev->dev, "failed to create MES event log buffer (%d)", r);
113b2662d4cSshaoyunl 		return r;
114b2662d4cSshaoyunl 	}
115b2662d4cSshaoyunl 
116739d0f3eSMichael Chen 	memset(adev->mes.event_log_cpu_addr, 0, adev->mes.event_log_size);
117b2662d4cSshaoyunl 
118b2662d4cSshaoyunl 	return  0;
119b2662d4cSshaoyunl 
120b2662d4cSshaoyunl }
121b2662d4cSshaoyunl 
amdgpu_mes_doorbell_free(struct amdgpu_device * adev)122e3cbb1f4SShashank Sharma static void amdgpu_mes_doorbell_free(struct amdgpu_device *adev)
123e3cbb1f4SShashank Sharma {
124e3cbb1f4SShashank Sharma 	bitmap_free(adev->mes.doorbell_bitmap);
125e3cbb1f4SShashank Sharma }
126e3cbb1f4SShashank Sharma 
amdgpu_mes_init(struct amdgpu_device * adev)127b04c1d64SJack Xiao int amdgpu_mes_init(struct amdgpu_device *adev)
128b04c1d64SJack Xiao {
129b04c1d64SJack Xiao 	int i, r;
130b04c1d64SJack Xiao 
131b04c1d64SJack Xiao 	adev->mes.adev = adev;
132b04c1d64SJack Xiao 
133b04c1d64SJack Xiao 	idr_init(&adev->mes.pasid_idr);
134b04c1d64SJack Xiao 	idr_init(&adev->mes.gang_id_idr);
135b04c1d64SJack Xiao 	idr_init(&adev->mes.queue_id_idr);
136b04c1d64SJack Xiao 	ida_init(&adev->mes.doorbell_ida);
137b04c1d64SJack Xiao 	spin_lock_init(&adev->mes.queue_id_lock);
13818ee4ce6SJack Xiao 	mutex_init(&adev->mes.mutex_hidden);
139b04c1d64SJack Xiao 
140c7d43556SJack Xiao 	for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++)
141c7d43556SJack Xiao 		spin_lock_init(&adev->mes.ring_lock[i]);
142c7d43556SJack Xiao 
143b04c1d64SJack Xiao 	adev->mes.total_max_queue = AMDGPU_FENCE_MES_QUEUE_ID_MASK;
144b04c1d64SJack Xiao 	adev->mes.vmid_mask_mmhub = 0xffffff00;
145b04c1d64SJack Xiao 	adev->mes.vmid_mask_gfxhub = 0xffffff00;
146b04c1d64SJack Xiao 
147b04c1d64SJack Xiao 	for (i = 0; i < AMDGPU_MES_MAX_COMPUTE_PIPES; i++) {
148a52077b6SAlex Deucher 		if (i >= (adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_mec))
1495608ddf6SAlex Deucher 			break;
150b04c1d64SJack Xiao 		adev->mes.compute_hqd_mask[i] = 0xc;
151b04c1d64SJack Xiao 	}
152b04c1d64SJack Xiao 
153b04c1d64SJack Xiao 	for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++)
154b04c1d64SJack Xiao 		adev->mes.gfx_hqd_mask[i] = i ? 0 : 0xfffffffe;
155b04c1d64SJack Xiao 
15618ee4ce6SJack Xiao 	for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++) {
1575e93d0e3SAlex Deucher 		if (i >= adev->sdma.num_instances)
1585e93d0e3SAlex Deucher 			break;
15918ee4ce6SJack Xiao 		adev->mes.sdma_hqd_mask[i] = 0xfc;
16018ee4ce6SJack Xiao 	}
161b04c1d64SJack Xiao 
162ea5d6db1SJack Xiao 	for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) {
163ea5d6db1SJack Xiao 		r = amdgpu_device_wb_get(adev, &adev->mes.sch_ctx_offs[i]);
164b04c1d64SJack Xiao 		if (r) {
165b04c1d64SJack Xiao 			dev_err(adev->dev,
166ea5d6db1SJack Xiao 				"(%d) ring trail_fence_offs wb alloc failed\n",
167ea5d6db1SJack Xiao 				r);
168ea5d6db1SJack Xiao 			goto error;
169b04c1d64SJack Xiao 		}
170ea5d6db1SJack Xiao 		adev->mes.sch_ctx_gpu_addr[i] =
171ea5d6db1SJack Xiao 			adev->wb.gpu_addr + (adev->mes.sch_ctx_offs[i] * 4);
172ea5d6db1SJack Xiao 		adev->mes.sch_ctx_ptr[i] =
173ea5d6db1SJack Xiao 			(uint64_t *)&adev->wb.wb[adev->mes.sch_ctx_offs[i]];
174b04c1d64SJack Xiao 
175ea5d6db1SJack Xiao 		r = amdgpu_device_wb_get(adev,
176ea5d6db1SJack Xiao 				 &adev->mes.query_status_fence_offs[i]);
1770bf478f0SJack Xiao 		if (r) {
1780bf478f0SJack Xiao 			dev_err(adev->dev,
179ea5d6db1SJack Xiao 			      "(%d) query_status_fence_offs wb alloc failed\n",
180ea5d6db1SJack Xiao 			      r);
181ea5d6db1SJack Xiao 			goto error;
1820bf478f0SJack Xiao 		}
183ea5d6db1SJack Xiao 		adev->mes.query_status_fence_gpu_addr[i] = adev->wb.gpu_addr +
184ea5d6db1SJack Xiao 			(adev->mes.query_status_fence_offs[i] * 4);
185ea5d6db1SJack Xiao 		adev->mes.query_status_fence_ptr[i] =
186ea5d6db1SJack Xiao 			(uint64_t *)&adev->wb.wb[adev->mes.query_status_fence_offs[i]];
187ea5d6db1SJack Xiao 	}
1880bf478f0SJack Xiao 
189b04c1d64SJack Xiao 	r = amdgpu_mes_doorbell_init(adev);
190b04c1d64SJack Xiao 	if (r)
191b04c1d64SJack Xiao 		goto error;
192b04c1d64SJack Xiao 
193b2662d4cSshaoyunl 	r = amdgpu_mes_event_log_init(adev);
194b2662d4cSshaoyunl 	if (r)
195b2662d4cSshaoyunl 		goto error_doorbell;
196b2662d4cSshaoyunl 
197b04c1d64SJack Xiao 	return 0;
198b04c1d64SJack Xiao 
199b2662d4cSshaoyunl error_doorbell:
200b2662d4cSshaoyunl 	amdgpu_mes_doorbell_free(adev);
201b04c1d64SJack Xiao error:
202ea5d6db1SJack Xiao 	for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) {
203ea5d6db1SJack Xiao 		if (adev->mes.sch_ctx_ptr[i])
204ea5d6db1SJack Xiao 			amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs[i]);
205ea5d6db1SJack Xiao 		if (adev->mes.query_status_fence_ptr[i])
206ea5d6db1SJack Xiao 			amdgpu_device_wb_free(adev,
207ea5d6db1SJack Xiao 				      adev->mes.query_status_fence_offs[i]);
208ea5d6db1SJack Xiao 	}
209ea5d6db1SJack Xiao 
210b04c1d64SJack Xiao 	idr_destroy(&adev->mes.pasid_idr);
211b04c1d64SJack Xiao 	idr_destroy(&adev->mes.gang_id_idr);
212b04c1d64SJack Xiao 	idr_destroy(&adev->mes.queue_id_idr);
213b04c1d64SJack Xiao 	ida_destroy(&adev->mes.doorbell_ida);
21418ee4ce6SJack Xiao 	mutex_destroy(&adev->mes.mutex_hidden);
215b04c1d64SJack Xiao 	return r;
216b04c1d64SJack Xiao }
217b04c1d64SJack Xiao 
amdgpu_mes_fini(struct amdgpu_device * adev)218b04c1d64SJack Xiao void amdgpu_mes_fini(struct amdgpu_device *adev)
219b04c1d64SJack Xiao {
220ea5d6db1SJack Xiao 	int i;
221ea5d6db1SJack Xiao 
222b2662d4cSshaoyunl 	amdgpu_bo_free_kernel(&adev->mes.event_log_gpu_obj,
223b2662d4cSshaoyunl 			      &adev->mes.event_log_gpu_addr,
224b2662d4cSshaoyunl 			      &adev->mes.event_log_cpu_addr);
225b2662d4cSshaoyunl 
226ea5d6db1SJack Xiao 	for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) {
227ea5d6db1SJack Xiao 		if (adev->mes.sch_ctx_ptr[i])
228ea5d6db1SJack Xiao 			amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs[i]);
229ea5d6db1SJack Xiao 		if (adev->mes.query_status_fence_ptr[i])
230ea5d6db1SJack Xiao 			amdgpu_device_wb_free(adev,
231ea5d6db1SJack Xiao 				      adev->mes.query_status_fence_offs[i]);
232ea5d6db1SJack Xiao 	}
233ea5d6db1SJack Xiao 
234e3cbb1f4SShashank Sharma 	amdgpu_mes_doorbell_free(adev);
235b04c1d64SJack Xiao 
236b04c1d64SJack Xiao 	idr_destroy(&adev->mes.pasid_idr);
237b04c1d64SJack Xiao 	idr_destroy(&adev->mes.gang_id_idr);
238b04c1d64SJack Xiao 	idr_destroy(&adev->mes.queue_id_idr);
239b04c1d64SJack Xiao 	ida_destroy(&adev->mes.doorbell_ida);
24018ee4ce6SJack Xiao 	mutex_destroy(&adev->mes.mutex_hidden);
24118ee4ce6SJack Xiao }
24218ee4ce6SJack Xiao 
amdgpu_mes_queue_free_mqd(struct amdgpu_mes_queue * q)24318ee4ce6SJack Xiao static void amdgpu_mes_queue_free_mqd(struct amdgpu_mes_queue *q)
24418ee4ce6SJack Xiao {
24518ee4ce6SJack Xiao 	amdgpu_bo_free_kernel(&q->mqd_obj,
24618ee4ce6SJack Xiao 			      &q->mqd_gpu_addr,
24718ee4ce6SJack Xiao 			      &q->mqd_cpu_ptr);
248b04c1d64SJack Xiao }
24948dcd2b7SJack Xiao 
amdgpu_mes_create_process(struct amdgpu_device * adev,int pasid,struct amdgpu_vm * vm)25048dcd2b7SJack Xiao int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid,
25148dcd2b7SJack Xiao 			      struct amdgpu_vm *vm)
25248dcd2b7SJack Xiao {
25348dcd2b7SJack Xiao 	struct amdgpu_mes_process *process;
25448dcd2b7SJack Xiao 	int r;
25548dcd2b7SJack Xiao 
25648dcd2b7SJack Xiao 	/* allocate the mes process buffer */
25748dcd2b7SJack Xiao 	process = kzalloc(sizeof(struct amdgpu_mes_process), GFP_KERNEL);
25848dcd2b7SJack Xiao 	if (!process) {
25948dcd2b7SJack Xiao 		DRM_ERROR("no more memory to create mes process\n");
26048dcd2b7SJack Xiao 		return -ENOMEM;
26148dcd2b7SJack Xiao 	}
26248dcd2b7SJack Xiao 
26348dcd2b7SJack Xiao 	/* allocate the process context bo and map it */
26448dcd2b7SJack Xiao 	r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_PROC_CTX_SIZE, PAGE_SIZE,
26548dcd2b7SJack Xiao 				    AMDGPU_GEM_DOMAIN_GTT,
26648dcd2b7SJack Xiao 				    &process->proc_ctx_bo,
26748dcd2b7SJack Xiao 				    &process->proc_ctx_gpu_addr,
26848dcd2b7SJack Xiao 				    &process->proc_ctx_cpu_ptr);
26948dcd2b7SJack Xiao 	if (r) {
27048dcd2b7SJack Xiao 		DRM_ERROR("failed to allocate process context bo\n");
27118ee4ce6SJack Xiao 		goto clean_up_memory;
27248dcd2b7SJack Xiao 	}
27348dcd2b7SJack Xiao 	memset(process->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE);
27448dcd2b7SJack Xiao 
27518ee4ce6SJack Xiao 	/*
27618ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
27718ee4ce6SJack Xiao 	 * lock dependencies.
27818ee4ce6SJack Xiao 	 */
27918ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
28018ee4ce6SJack Xiao 
28118ee4ce6SJack Xiao 	/* add the mes process to idr list */
28218ee4ce6SJack Xiao 	r = idr_alloc(&adev->mes.pasid_idr, process, pasid, pasid + 1,
28318ee4ce6SJack Xiao 		      GFP_KERNEL);
28418ee4ce6SJack Xiao 	if (r < 0) {
28518ee4ce6SJack Xiao 		DRM_ERROR("failed to lock pasid=%d\n", pasid);
28618ee4ce6SJack Xiao 		goto clean_up_ctx;
28718ee4ce6SJack Xiao 	}
28818ee4ce6SJack Xiao 
28948dcd2b7SJack Xiao 	INIT_LIST_HEAD(&process->gang_list);
29048dcd2b7SJack Xiao 	process->vm = vm;
29148dcd2b7SJack Xiao 	process->pasid = pasid;
29248dcd2b7SJack Xiao 	process->process_quantum = adev->mes.default_process_quantum;
29348dcd2b7SJack Xiao 	process->pd_gpu_addr = amdgpu_bo_gpu_offset(vm->root.bo);
29448dcd2b7SJack Xiao 
29518ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
29648dcd2b7SJack Xiao 	return 0;
29748dcd2b7SJack Xiao 
29848dcd2b7SJack Xiao clean_up_ctx:
299664c3b03SShashank Sharma 	amdgpu_mes_unlock(&adev->mes);
30048dcd2b7SJack Xiao 	amdgpu_bo_free_kernel(&process->proc_ctx_bo,
30148dcd2b7SJack Xiao 			      &process->proc_ctx_gpu_addr,
30248dcd2b7SJack Xiao 			      &process->proc_ctx_cpu_ptr);
30348dcd2b7SJack Xiao clean_up_memory:
30448dcd2b7SJack Xiao 	kfree(process);
30548dcd2b7SJack Xiao 	return r;
30648dcd2b7SJack Xiao }
307063a38d6SJack Xiao 
amdgpu_mes_destroy_process(struct amdgpu_device * adev,int pasid)308063a38d6SJack Xiao void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid)
309063a38d6SJack Xiao {
310063a38d6SJack Xiao 	struct amdgpu_mes_process *process;
311063a38d6SJack Xiao 	struct amdgpu_mes_gang *gang, *tmp1;
312063a38d6SJack Xiao 	struct amdgpu_mes_queue *queue, *tmp2;
313063a38d6SJack Xiao 	struct mes_remove_queue_input queue_input;
314063a38d6SJack Xiao 	unsigned long flags;
315063a38d6SJack Xiao 	int r;
316063a38d6SJack Xiao 
31718ee4ce6SJack Xiao 	/*
31818ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
31918ee4ce6SJack Xiao 	 * lock dependencies.
32018ee4ce6SJack Xiao 	 */
32118ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
322063a38d6SJack Xiao 
323063a38d6SJack Xiao 	process = idr_find(&adev->mes.pasid_idr, pasid);
324063a38d6SJack Xiao 	if (!process) {
325063a38d6SJack Xiao 		DRM_WARN("pasid %d doesn't exist\n", pasid);
32618ee4ce6SJack Xiao 		amdgpu_mes_unlock(&adev->mes);
327063a38d6SJack Xiao 		return;
328063a38d6SJack Xiao 	}
329063a38d6SJack Xiao 
33018ee4ce6SJack Xiao 	/* Remove all queues from hardware */
331063a38d6SJack Xiao 	list_for_each_entry_safe(gang, tmp1, &process->gang_list, list) {
332063a38d6SJack Xiao 		list_for_each_entry_safe(queue, tmp2, &gang->queue_list, list) {
333063a38d6SJack Xiao 			spin_lock_irqsave(&adev->mes.queue_id_lock, flags);
334063a38d6SJack Xiao 			idr_remove(&adev->mes.queue_id_idr, queue->queue_id);
335063a38d6SJack Xiao 			spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
336063a38d6SJack Xiao 
337063a38d6SJack Xiao 			queue_input.doorbell_offset = queue->doorbell_off;
338063a38d6SJack Xiao 			queue_input.gang_context_addr = gang->gang_ctx_gpu_addr;
339063a38d6SJack Xiao 
340063a38d6SJack Xiao 			r = adev->mes.funcs->remove_hw_queue(&adev->mes,
341063a38d6SJack Xiao 							     &queue_input);
342063a38d6SJack Xiao 			if (r)
343063a38d6SJack Xiao 				DRM_WARN("failed to remove hardware queue\n");
344063a38d6SJack Xiao 		}
345063a38d6SJack Xiao 
346063a38d6SJack Xiao 		idr_remove(&adev->mes.gang_id_idr, gang->gang_id);
34718ee4ce6SJack Xiao 	}
34818ee4ce6SJack Xiao 
34918ee4ce6SJack Xiao 	idr_remove(&adev->mes.pasid_idr, pasid);
35018ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
35118ee4ce6SJack Xiao 
35218ee4ce6SJack Xiao 	/* free all memory allocated by the process */
35318ee4ce6SJack Xiao 	list_for_each_entry_safe(gang, tmp1, &process->gang_list, list) {
35418ee4ce6SJack Xiao 		/* free all queues in the gang */
35518ee4ce6SJack Xiao 		list_for_each_entry_safe(queue, tmp2, &gang->queue_list, list) {
35618ee4ce6SJack Xiao 			amdgpu_mes_queue_free_mqd(queue);
35718ee4ce6SJack Xiao 			list_del(&queue->list);
35818ee4ce6SJack Xiao 			kfree(queue);
35918ee4ce6SJack Xiao 		}
360063a38d6SJack Xiao 		amdgpu_bo_free_kernel(&gang->gang_ctx_bo,
361063a38d6SJack Xiao 				      &gang->gang_ctx_gpu_addr,
362063a38d6SJack Xiao 				      &gang->gang_ctx_cpu_ptr);
363063a38d6SJack Xiao 		list_del(&gang->list);
364063a38d6SJack Xiao 		kfree(gang);
36518ee4ce6SJack Xiao 
366063a38d6SJack Xiao 	}
367063a38d6SJack Xiao 	amdgpu_bo_free_kernel(&process->proc_ctx_bo,
368063a38d6SJack Xiao 			      &process->proc_ctx_gpu_addr,
369063a38d6SJack Xiao 			      &process->proc_ctx_cpu_ptr);
370063a38d6SJack Xiao 	kfree(process);
371063a38d6SJack Xiao }
3725d0f619fSJack Xiao 
amdgpu_mes_add_gang(struct amdgpu_device * adev,int pasid,struct amdgpu_mes_gang_properties * gprops,int * gang_id)3735d0f619fSJack Xiao int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid,
3745d0f619fSJack Xiao 			struct amdgpu_mes_gang_properties *gprops,
3755d0f619fSJack Xiao 			int *gang_id)
3765d0f619fSJack Xiao {
3775d0f619fSJack Xiao 	struct amdgpu_mes_process *process;
3785d0f619fSJack Xiao 	struct amdgpu_mes_gang *gang;
3795d0f619fSJack Xiao 	int r;
3805d0f619fSJack Xiao 
3815d0f619fSJack Xiao 	/* allocate the mes gang buffer */
3825d0f619fSJack Xiao 	gang = kzalloc(sizeof(struct amdgpu_mes_gang), GFP_KERNEL);
3835d0f619fSJack Xiao 	if (!gang) {
3845d0f619fSJack Xiao 		return -ENOMEM;
3855d0f619fSJack Xiao 	}
3865d0f619fSJack Xiao 
3875d0f619fSJack Xiao 	/* allocate the gang context bo and map it to cpu space */
3885d0f619fSJack Xiao 	r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_GANG_CTX_SIZE, PAGE_SIZE,
3895d0f619fSJack Xiao 				    AMDGPU_GEM_DOMAIN_GTT,
3905d0f619fSJack Xiao 				    &gang->gang_ctx_bo,
3915d0f619fSJack Xiao 				    &gang->gang_ctx_gpu_addr,
3925d0f619fSJack Xiao 				    &gang->gang_ctx_cpu_ptr);
3935d0f619fSJack Xiao 	if (r) {
3945d0f619fSJack Xiao 		DRM_ERROR("failed to allocate process context bo\n");
39518ee4ce6SJack Xiao 		goto clean_up_mem;
3965d0f619fSJack Xiao 	}
3975d0f619fSJack Xiao 	memset(gang->gang_ctx_cpu_ptr, 0, AMDGPU_MES_GANG_CTX_SIZE);
3985d0f619fSJack Xiao 
39918ee4ce6SJack Xiao 	/*
40018ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
40118ee4ce6SJack Xiao 	 * lock dependencies.
40218ee4ce6SJack Xiao 	 */
40318ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
40418ee4ce6SJack Xiao 
40518ee4ce6SJack Xiao 	process = idr_find(&adev->mes.pasid_idr, pasid);
40618ee4ce6SJack Xiao 	if (!process) {
40718ee4ce6SJack Xiao 		DRM_ERROR("pasid %d doesn't exist\n", pasid);
40818ee4ce6SJack Xiao 		r = -EINVAL;
40918ee4ce6SJack Xiao 		goto clean_up_ctx;
41018ee4ce6SJack Xiao 	}
41118ee4ce6SJack Xiao 
41218ee4ce6SJack Xiao 	/* add the mes gang to idr list */
41318ee4ce6SJack Xiao 	r = idr_alloc(&adev->mes.gang_id_idr, gang, 1, 0,
41418ee4ce6SJack Xiao 		      GFP_KERNEL);
41518ee4ce6SJack Xiao 	if (r < 0) {
41618ee4ce6SJack Xiao 		DRM_ERROR("failed to allocate idr for gang\n");
41718ee4ce6SJack Xiao 		goto clean_up_ctx;
41818ee4ce6SJack Xiao 	}
41918ee4ce6SJack Xiao 
42018ee4ce6SJack Xiao 	gang->gang_id = r;
42118ee4ce6SJack Xiao 	*gang_id = r;
42218ee4ce6SJack Xiao 
4235d0f619fSJack Xiao 	INIT_LIST_HEAD(&gang->queue_list);
4245d0f619fSJack Xiao 	gang->process = process;
4255d0f619fSJack Xiao 	gang->priority = gprops->priority;
4265d0f619fSJack Xiao 	gang->gang_quantum = gprops->gang_quantum ?
4275d0f619fSJack Xiao 		gprops->gang_quantum : adev->mes.default_gang_quantum;
4285d0f619fSJack Xiao 	gang->global_priority_level = gprops->global_priority_level;
4295d0f619fSJack Xiao 	gang->inprocess_gang_priority = gprops->inprocess_gang_priority;
4305d0f619fSJack Xiao 	list_add_tail(&gang->list, &process->gang_list);
4315d0f619fSJack Xiao 
43218ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
4335d0f619fSJack Xiao 	return 0;
4345d0f619fSJack Xiao 
43518ee4ce6SJack Xiao clean_up_ctx:
43618ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
43718ee4ce6SJack Xiao 	amdgpu_bo_free_kernel(&gang->gang_ctx_bo,
43818ee4ce6SJack Xiao 			      &gang->gang_ctx_gpu_addr,
43918ee4ce6SJack Xiao 			      &gang->gang_ctx_cpu_ptr);
44018ee4ce6SJack Xiao clean_up_mem:
4415d0f619fSJack Xiao 	kfree(gang);
4425d0f619fSJack Xiao 	return r;
4435d0f619fSJack Xiao }
444b0306e58SJack Xiao 
amdgpu_mes_remove_gang(struct amdgpu_device * adev,int gang_id)445b0306e58SJack Xiao int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id)
446b0306e58SJack Xiao {
447b0306e58SJack Xiao 	struct amdgpu_mes_gang *gang;
448b0306e58SJack Xiao 
44918ee4ce6SJack Xiao 	/*
45018ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
45118ee4ce6SJack Xiao 	 * lock dependencies.
45218ee4ce6SJack Xiao 	 */
45318ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
454b0306e58SJack Xiao 
455b0306e58SJack Xiao 	gang = idr_find(&adev->mes.gang_id_idr, gang_id);
456b0306e58SJack Xiao 	if (!gang) {
457b0306e58SJack Xiao 		DRM_ERROR("gang id %d doesn't exist\n", gang_id);
45818ee4ce6SJack Xiao 		amdgpu_mes_unlock(&adev->mes);
459b0306e58SJack Xiao 		return -EINVAL;
460b0306e58SJack Xiao 	}
461b0306e58SJack Xiao 
462b0306e58SJack Xiao 	if (!list_empty(&gang->queue_list)) {
463b0306e58SJack Xiao 		DRM_ERROR("queue list is not empty\n");
46418ee4ce6SJack Xiao 		amdgpu_mes_unlock(&adev->mes);
465b0306e58SJack Xiao 		return -EBUSY;
466b0306e58SJack Xiao 	}
467b0306e58SJack Xiao 
468b0306e58SJack Xiao 	idr_remove(&adev->mes.gang_id_idr, gang->gang_id);
46918ee4ce6SJack Xiao 	list_del(&gang->list);
47018ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
47118ee4ce6SJack Xiao 
472b0306e58SJack Xiao 	amdgpu_bo_free_kernel(&gang->gang_ctx_bo,
473b0306e58SJack Xiao 			      &gang->gang_ctx_gpu_addr,
474b0306e58SJack Xiao 			      &gang->gang_ctx_cpu_ptr);
47518ee4ce6SJack Xiao 
476b0306e58SJack Xiao 	kfree(gang);
477b0306e58SJack Xiao 
478b0306e58SJack Xiao 	return 0;
479b0306e58SJack Xiao }
480c8bb1057SJack Xiao 
amdgpu_mes_suspend(struct amdgpu_device * adev)481c8bb1057SJack Xiao int amdgpu_mes_suspend(struct amdgpu_device *adev)
482c8bb1057SJack Xiao {
483c8bb1057SJack Xiao 	struct mes_suspend_gang_input input;
484ccf8ef6bSMukul Joshi 	int r;
485ccf8ef6bSMukul Joshi 
486ccf8ef6bSMukul Joshi 	if (!amdgpu_mes_suspend_resume_all_supported(adev))
487ccf8ef6bSMukul Joshi 		return 0;
488ccf8ef6bSMukul Joshi 
489ccf8ef6bSMukul Joshi 	memset(&input, 0x0, sizeof(struct mes_suspend_gang_input));
490ccf8ef6bSMukul Joshi 	input.suspend_all_gangs = 1;
491c8bb1057SJack Xiao 
49218ee4ce6SJack Xiao 	/*
49318ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
49418ee4ce6SJack Xiao 	 * lock dependencies.
49518ee4ce6SJack Xiao 	 */
49618ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
497c8bb1057SJack Xiao 	r = adev->mes.funcs->suspend_gang(&adev->mes, &input);
49818ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
499ccf8ef6bSMukul Joshi 	if (r)
500ccf8ef6bSMukul Joshi 		DRM_ERROR("failed to suspend all gangs");
501ccf8ef6bSMukul Joshi 
502ccf8ef6bSMukul Joshi 	return r;
503c8bb1057SJack Xiao }
504ea756bd5SJack Xiao 
amdgpu_mes_resume(struct amdgpu_device * adev)505ea756bd5SJack Xiao int amdgpu_mes_resume(struct amdgpu_device *adev)
506ea756bd5SJack Xiao {
507ea756bd5SJack Xiao 	struct mes_resume_gang_input input;
508ccf8ef6bSMukul Joshi 	int r;
509ccf8ef6bSMukul Joshi 
510ccf8ef6bSMukul Joshi 	if (!amdgpu_mes_suspend_resume_all_supported(adev))
511ccf8ef6bSMukul Joshi 		return 0;
512ccf8ef6bSMukul Joshi 
513ccf8ef6bSMukul Joshi 	memset(&input, 0x0, sizeof(struct mes_resume_gang_input));
514ccf8ef6bSMukul Joshi 	input.resume_all_gangs = 1;
515ea756bd5SJack Xiao 
51618ee4ce6SJack Xiao 	/*
51718ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
51818ee4ce6SJack Xiao 	 * lock dependencies.
51918ee4ce6SJack Xiao 	 */
52018ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
521ea756bd5SJack Xiao 	r = adev->mes.funcs->resume_gang(&adev->mes, &input);
52218ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
523ccf8ef6bSMukul Joshi 	if (r)
524ccf8ef6bSMukul Joshi 		DRM_ERROR("failed to resume all gangs");
525ccf8ef6bSMukul Joshi 
526ccf8ef6bSMukul Joshi 	return r;
527ea756bd5SJack Xiao }
5285fa963d0SJack Xiao 
amdgpu_mes_queue_alloc_mqd(struct amdgpu_device * adev,struct amdgpu_mes_queue * q,struct amdgpu_mes_queue_properties * p)52918ee4ce6SJack Xiao static int amdgpu_mes_queue_alloc_mqd(struct amdgpu_device *adev,
5305fa963d0SJack Xiao 				     struct amdgpu_mes_queue *q,
5315fa963d0SJack Xiao 				     struct amdgpu_mes_queue_properties *p)
5325fa963d0SJack Xiao {
5335fa963d0SJack Xiao 	struct amdgpu_mqd *mqd_mgr = &adev->mqds[p->queue_type];
5345fa963d0SJack Xiao 	u32 mqd_size = mqd_mgr->mqd_size;
5355fa963d0SJack Xiao 	int r;
5365fa963d0SJack Xiao 
5375fa963d0SJack Xiao 	r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE,
5385fa963d0SJack Xiao 				    AMDGPU_GEM_DOMAIN_GTT,
5395fa963d0SJack Xiao 				    &q->mqd_obj,
5405fa963d0SJack Xiao 				    &q->mqd_gpu_addr, &q->mqd_cpu_ptr);
5415fa963d0SJack Xiao 	if (r) {
5425fa963d0SJack Xiao 		dev_warn(adev->dev, "failed to create queue mqd bo (%d)", r);
5435fa963d0SJack Xiao 		return r;
5445fa963d0SJack Xiao 	}
5455fa963d0SJack Xiao 	memset(q->mqd_cpu_ptr, 0, mqd_size);
5465fa963d0SJack Xiao 
54718ee4ce6SJack Xiao 	r = amdgpu_bo_reserve(q->mqd_obj, false);
54818ee4ce6SJack Xiao 	if (unlikely(r != 0))
54918ee4ce6SJack Xiao 		goto clean_up;
55018ee4ce6SJack Xiao 
55118ee4ce6SJack Xiao 	return 0;
55218ee4ce6SJack Xiao 
55318ee4ce6SJack Xiao clean_up:
55418ee4ce6SJack Xiao 	amdgpu_bo_free_kernel(&q->mqd_obj,
55518ee4ce6SJack Xiao 			      &q->mqd_gpu_addr,
55618ee4ce6SJack Xiao 			      &q->mqd_cpu_ptr);
55718ee4ce6SJack Xiao 	return r;
55818ee4ce6SJack Xiao }
55918ee4ce6SJack Xiao 
amdgpu_mes_queue_init_mqd(struct amdgpu_device * adev,struct amdgpu_mes_queue * q,struct amdgpu_mes_queue_properties * p)56018ee4ce6SJack Xiao static void amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev,
56118ee4ce6SJack Xiao 				     struct amdgpu_mes_queue *q,
56218ee4ce6SJack Xiao 				     struct amdgpu_mes_queue_properties *p)
56318ee4ce6SJack Xiao {
56418ee4ce6SJack Xiao 	struct amdgpu_mqd *mqd_mgr = &adev->mqds[p->queue_type];
56518ee4ce6SJack Xiao 	struct amdgpu_mqd_prop mqd_prop = {0};
56618ee4ce6SJack Xiao 
5675fa963d0SJack Xiao 	mqd_prop.mqd_gpu_addr = q->mqd_gpu_addr;
5685fa963d0SJack Xiao 	mqd_prop.hqd_base_gpu_addr = p->hqd_base_gpu_addr;
5695fa963d0SJack Xiao 	mqd_prop.rptr_gpu_addr = p->rptr_gpu_addr;
5705fa963d0SJack Xiao 	mqd_prop.wptr_gpu_addr = p->wptr_gpu_addr;
5715fa963d0SJack Xiao 	mqd_prop.queue_size = p->queue_size;
5725fa963d0SJack Xiao 	mqd_prop.use_doorbell = true;
5735fa963d0SJack Xiao 	mqd_prop.doorbell_index = p->doorbell_off;
5745fa963d0SJack Xiao 	mqd_prop.eop_gpu_addr = p->eop_gpu_addr;
5755fa963d0SJack Xiao 	mqd_prop.hqd_pipe_priority = p->hqd_pipe_priority;
5765fa963d0SJack Xiao 	mqd_prop.hqd_queue_priority = p->hqd_queue_priority;
5775fa963d0SJack Xiao 	mqd_prop.hqd_active = false;
5785fa963d0SJack Xiao 
57936e7ff5cSTim Huang 	if (p->queue_type == AMDGPU_RING_TYPE_GFX ||
58036e7ff5cSTim Huang 	    p->queue_type == AMDGPU_RING_TYPE_COMPUTE) {
58136e7ff5cSTim Huang 		mutex_lock(&adev->srbm_mutex);
58236e7ff5cSTim Huang 		amdgpu_gfx_select_me_pipe_q(adev, p->ring->me, p->ring->pipe, 0, 0, 0);
58336e7ff5cSTim Huang 	}
58436e7ff5cSTim Huang 
5855fa963d0SJack Xiao 	mqd_mgr->init_mqd(adev, q->mqd_cpu_ptr, &mqd_prop);
5865fa963d0SJack Xiao 
58736e7ff5cSTim Huang 	if (p->queue_type == AMDGPU_RING_TYPE_GFX ||
58836e7ff5cSTim Huang 	    p->queue_type == AMDGPU_RING_TYPE_COMPUTE) {
58936e7ff5cSTim Huang 		amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0, 0);
59036e7ff5cSTim Huang 		mutex_unlock(&adev->srbm_mutex);
59136e7ff5cSTim Huang 	}
59236e7ff5cSTim Huang 
5935fa963d0SJack Xiao 	amdgpu_bo_unreserve(q->mqd_obj);
5945fa963d0SJack Xiao }
595be5609deSJack Xiao 
amdgpu_mes_add_hw_queue(struct amdgpu_device * adev,int gang_id,struct amdgpu_mes_queue_properties * qprops,int * queue_id)596be5609deSJack Xiao int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id,
597be5609deSJack Xiao 			    struct amdgpu_mes_queue_properties *qprops,
598be5609deSJack Xiao 			    int *queue_id)
599be5609deSJack Xiao {
600be5609deSJack Xiao 	struct amdgpu_mes_queue *queue;
601be5609deSJack Xiao 	struct amdgpu_mes_gang *gang;
602be5609deSJack Xiao 	struct mes_add_queue_input queue_input;
603be5609deSJack Xiao 	unsigned long flags;
604be5609deSJack Xiao 	int r;
605be5609deSJack Xiao 
6067a1c5c67SJonathan Kim 	memset(&queue_input, 0, sizeof(struct mes_add_queue_input));
6077a1c5c67SJonathan Kim 
60818ee4ce6SJack Xiao 	/* allocate the mes queue buffer */
60918ee4ce6SJack Xiao 	queue = kzalloc(sizeof(struct amdgpu_mes_queue), GFP_KERNEL);
61018ee4ce6SJack Xiao 	if (!queue) {
61118ee4ce6SJack Xiao 		DRM_ERROR("Failed to allocate memory for queue\n");
61218ee4ce6SJack Xiao 		return -ENOMEM;
61318ee4ce6SJack Xiao 	}
61418ee4ce6SJack Xiao 
61518ee4ce6SJack Xiao 	/* Allocate the queue mqd */
61618ee4ce6SJack Xiao 	r = amdgpu_mes_queue_alloc_mqd(adev, queue, qprops);
61718ee4ce6SJack Xiao 	if (r)
61818ee4ce6SJack Xiao 		goto clean_up_memory;
61918ee4ce6SJack Xiao 
62018ee4ce6SJack Xiao 	/*
62118ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
62218ee4ce6SJack Xiao 	 * lock dependencies.
62318ee4ce6SJack Xiao 	 */
62418ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
625be5609deSJack Xiao 
626be5609deSJack Xiao 	gang = idr_find(&adev->mes.gang_id_idr, gang_id);
627be5609deSJack Xiao 	if (!gang) {
628be5609deSJack Xiao 		DRM_ERROR("gang id %d doesn't exist\n", gang_id);
62918ee4ce6SJack Xiao 		r = -EINVAL;
63018ee4ce6SJack Xiao 		goto clean_up_mqd;
631be5609deSJack Xiao 	}
632be5609deSJack Xiao 
633be5609deSJack Xiao 	/* add the mes gang to idr list */
634be5609deSJack Xiao 	spin_lock_irqsave(&adev->mes.queue_id_lock, flags);
635be5609deSJack Xiao 	r = idr_alloc(&adev->mes.queue_id_idr, queue, 1, 0,
636be5609deSJack Xiao 		      GFP_ATOMIC);
637be5609deSJack Xiao 	if (r < 0) {
638be5609deSJack Xiao 		spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
63918ee4ce6SJack Xiao 		goto clean_up_mqd;
640be5609deSJack Xiao 	}
641be5609deSJack Xiao 	spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
642be5609deSJack Xiao 	*queue_id = queue->queue_id = r;
643be5609deSJack Xiao 
644be5609deSJack Xiao 	/* allocate a doorbell index for the queue */
64597d5aa60SShashank Sharma 	r = amdgpu_mes_kernel_doorbell_get(adev,
646be5609deSJack Xiao 					  qprops->queue_type,
647be5609deSJack Xiao 					  &qprops->doorbell_off);
648be5609deSJack Xiao 	if (r)
649be5609deSJack Xiao 		goto clean_up_queue_id;
650be5609deSJack Xiao 
651be5609deSJack Xiao 	/* initialize the queue mqd */
65218ee4ce6SJack Xiao 	amdgpu_mes_queue_init_mqd(adev, queue, qprops);
653be5609deSJack Xiao 
654be5609deSJack Xiao 	/* add hw queue to mes */
655be5609deSJack Xiao 	queue_input.process_id = gang->process->pasid;
65618ee4ce6SJack Xiao 
65718ee4ce6SJack Xiao 	queue_input.page_table_base_addr =
65818ee4ce6SJack Xiao 		adev->vm_manager.vram_base_offset + gang->process->pd_gpu_addr -
65918ee4ce6SJack Xiao 		adev->gmc.vram_start;
66018ee4ce6SJack Xiao 
661be5609deSJack Xiao 	queue_input.process_va_start = 0;
662be5609deSJack Xiao 	queue_input.process_va_end =
663be5609deSJack Xiao 		(adev->vm_manager.max_pfn - 1) << AMDGPU_GPU_PAGE_SHIFT;
664be5609deSJack Xiao 	queue_input.process_quantum = gang->process->process_quantum;
665be5609deSJack Xiao 	queue_input.process_context_addr = gang->process->proc_ctx_gpu_addr;
666be5609deSJack Xiao 	queue_input.gang_quantum = gang->gang_quantum;
667be5609deSJack Xiao 	queue_input.gang_context_addr = gang->gang_ctx_gpu_addr;
668be5609deSJack Xiao 	queue_input.inprocess_gang_priority = gang->inprocess_gang_priority;
669be5609deSJack Xiao 	queue_input.gang_global_priority_level = gang->global_priority_level;
670be5609deSJack Xiao 	queue_input.doorbell_offset = qprops->doorbell_off;
671be5609deSJack Xiao 	queue_input.mqd_addr = queue->mqd_gpu_addr;
672be5609deSJack Xiao 	queue_input.wptr_addr = qprops->wptr_gpu_addr;
673fe4e9ff9SJack Xiao 	queue_input.wptr_mc_addr = qprops->wptr_mc_addr;
674be5609deSJack Xiao 	queue_input.queue_type = qprops->queue_type;
675be5609deSJack Xiao 	queue_input.paging = qprops->paging;
676a9579956SGraham Sider 	queue_input.is_kfd_process = 0;
677be5609deSJack Xiao 
678be5609deSJack Xiao 	r = adev->mes.funcs->add_hw_queue(&adev->mes, &queue_input);
679be5609deSJack Xiao 	if (r) {
680be5609deSJack Xiao 		DRM_ERROR("failed to add hardware queue to MES, doorbell=0x%llx\n",
681be5609deSJack Xiao 			  qprops->doorbell_off);
68218ee4ce6SJack Xiao 		goto clean_up_doorbell;
683be5609deSJack Xiao 	}
684be5609deSJack Xiao 
685be5609deSJack Xiao 	DRM_DEBUG("MES hw queue was added, pasid=%d, gang id=%d, "
686be5609deSJack Xiao 		  "queue type=%d, doorbell=0x%llx\n",
687be5609deSJack Xiao 		  gang->process->pasid, gang_id, qprops->queue_type,
688be5609deSJack Xiao 		  qprops->doorbell_off);
689be5609deSJack Xiao 
690be5609deSJack Xiao 	queue->ring = qprops->ring;
691be5609deSJack Xiao 	queue->doorbell_off = qprops->doorbell_off;
692be5609deSJack Xiao 	queue->wptr_gpu_addr = qprops->wptr_gpu_addr;
693be5609deSJack Xiao 	queue->queue_type = qprops->queue_type;
694be5609deSJack Xiao 	queue->paging = qprops->paging;
695be5609deSJack Xiao 	queue->gang = gang;
6962d7a1f71SLe Ma 	queue->ring->mqd_ptr = queue->mqd_cpu_ptr;
697be5609deSJack Xiao 	list_add_tail(&queue->list, &gang->queue_list);
698be5609deSJack Xiao 
69918ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
700be5609deSJack Xiao 	return 0;
701be5609deSJack Xiao 
702be5609deSJack Xiao clean_up_doorbell:
70397d5aa60SShashank Sharma 	amdgpu_mes_kernel_doorbell_free(adev, qprops->doorbell_off);
704be5609deSJack Xiao clean_up_queue_id:
705be5609deSJack Xiao 	spin_lock_irqsave(&adev->mes.queue_id_lock, flags);
706be5609deSJack Xiao 	idr_remove(&adev->mes.queue_id_idr, queue->queue_id);
707be5609deSJack Xiao 	spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
70818ee4ce6SJack Xiao clean_up_mqd:
70918ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
71018ee4ce6SJack Xiao 	amdgpu_mes_queue_free_mqd(queue);
711be5609deSJack Xiao clean_up_memory:
712be5609deSJack Xiao 	kfree(queue);
713be5609deSJack Xiao 	return r;
714be5609deSJack Xiao }
715bcc4e1e1SJack Xiao 
amdgpu_mes_remove_hw_queue(struct amdgpu_device * adev,int queue_id)716bcc4e1e1SJack Xiao int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id)
717bcc4e1e1SJack Xiao {
718bcc4e1e1SJack Xiao 	unsigned long flags;
719bcc4e1e1SJack Xiao 	struct amdgpu_mes_queue *queue;
720bcc4e1e1SJack Xiao 	struct amdgpu_mes_gang *gang;
721bcc4e1e1SJack Xiao 	struct mes_remove_queue_input queue_input;
722bcc4e1e1SJack Xiao 	int r;
723bcc4e1e1SJack Xiao 
72418ee4ce6SJack Xiao 	/*
72518ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
72618ee4ce6SJack Xiao 	 * lock dependencies.
72718ee4ce6SJack Xiao 	 */
72818ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
729bcc4e1e1SJack Xiao 
730bcc4e1e1SJack Xiao 	/* remove the mes gang from idr list */
731bcc4e1e1SJack Xiao 	spin_lock_irqsave(&adev->mes.queue_id_lock, flags);
732bcc4e1e1SJack Xiao 
733bcc4e1e1SJack Xiao 	queue = idr_find(&adev->mes.queue_id_idr, queue_id);
734bcc4e1e1SJack Xiao 	if (!queue) {
735bcc4e1e1SJack Xiao 		spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
73618ee4ce6SJack Xiao 		amdgpu_mes_unlock(&adev->mes);
737bcc4e1e1SJack Xiao 		DRM_ERROR("queue id %d doesn't exist\n", queue_id);
738bcc4e1e1SJack Xiao 		return -EINVAL;
739bcc4e1e1SJack Xiao 	}
740bcc4e1e1SJack Xiao 
741bcc4e1e1SJack Xiao 	idr_remove(&adev->mes.queue_id_idr, queue_id);
742bcc4e1e1SJack Xiao 	spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
743bcc4e1e1SJack Xiao 
744bcc4e1e1SJack Xiao 	DRM_DEBUG("try to remove queue, doorbell off = 0x%llx\n",
745bcc4e1e1SJack Xiao 		  queue->doorbell_off);
746bcc4e1e1SJack Xiao 
747bcc4e1e1SJack Xiao 	gang = queue->gang;
748bcc4e1e1SJack Xiao 	queue_input.doorbell_offset = queue->doorbell_off;
749bcc4e1e1SJack Xiao 	queue_input.gang_context_addr = gang->gang_ctx_gpu_addr;
750bcc4e1e1SJack Xiao 
751bcc4e1e1SJack Xiao 	r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);
752bcc4e1e1SJack Xiao 	if (r)
753bcc4e1e1SJack Xiao 		DRM_ERROR("failed to remove hardware queue, queue id = %d\n",
754bcc4e1e1SJack Xiao 			  queue_id);
755bcc4e1e1SJack Xiao 
756bcc4e1e1SJack Xiao 	list_del(&queue->list);
75797d5aa60SShashank Sharma 	amdgpu_mes_kernel_doorbell_free(adev, queue->doorbell_off);
75818ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
75918ee4ce6SJack Xiao 
76018ee4ce6SJack Xiao 	amdgpu_mes_queue_free_mqd(queue);
761bcc4e1e1SJack Xiao 	kfree(queue);
762bcc4e1e1SJack Xiao 	return 0;
763bcc4e1e1SJack Xiao }
7641a27aacbSJack Xiao 
amdgpu_mes_reset_hw_queue(struct amdgpu_device * adev,int queue_id)7655b7a59deSAlex Deucher int amdgpu_mes_reset_hw_queue(struct amdgpu_device *adev, int queue_id)
7665b7a59deSAlex Deucher {
7675b7a59deSAlex Deucher 	unsigned long flags;
7685b7a59deSAlex Deucher 	struct amdgpu_mes_queue *queue;
7695b7a59deSAlex Deucher 	struct amdgpu_mes_gang *gang;
7705b7a59deSAlex Deucher 	struct mes_reset_queue_input queue_input;
7715b7a59deSAlex Deucher 	int r;
7725b7a59deSAlex Deucher 
7735b7a59deSAlex Deucher 	/*
7745b7a59deSAlex Deucher 	 * Avoid taking any other locks under MES lock to avoid circular
7755b7a59deSAlex Deucher 	 * lock dependencies.
7765b7a59deSAlex Deucher 	 */
7775b7a59deSAlex Deucher 	amdgpu_mes_lock(&adev->mes);
7785b7a59deSAlex Deucher 
7795b7a59deSAlex Deucher 	/* remove the mes gang from idr list */
7805b7a59deSAlex Deucher 	spin_lock_irqsave(&adev->mes.queue_id_lock, flags);
7815b7a59deSAlex Deucher 
7825b7a59deSAlex Deucher 	queue = idr_find(&adev->mes.queue_id_idr, queue_id);
7835b7a59deSAlex Deucher 	if (!queue) {
7845b7a59deSAlex Deucher 		spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
7855b7a59deSAlex Deucher 		amdgpu_mes_unlock(&adev->mes);
7865b7a59deSAlex Deucher 		DRM_ERROR("queue id %d doesn't exist\n", queue_id);
7875b7a59deSAlex Deucher 		return -EINVAL;
7885b7a59deSAlex Deucher 	}
7895b7a59deSAlex Deucher 	spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags);
7905b7a59deSAlex Deucher 
7915b7a59deSAlex Deucher 	DRM_DEBUG("try to reset queue, doorbell off = 0x%llx\n",
7925b7a59deSAlex Deucher 		  queue->doorbell_off);
7935b7a59deSAlex Deucher 
7945b7a59deSAlex Deucher 	gang = queue->gang;
7955b7a59deSAlex Deucher 	queue_input.doorbell_offset = queue->doorbell_off;
7965b7a59deSAlex Deucher 	queue_input.gang_context_addr = gang->gang_ctx_gpu_addr;
7975b7a59deSAlex Deucher 
7985b7a59deSAlex Deucher 	r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
7995b7a59deSAlex Deucher 	if (r)
8005b7a59deSAlex Deucher 		DRM_ERROR("failed to reset hardware queue, queue id = %d\n",
8015b7a59deSAlex Deucher 			  queue_id);
8025b7a59deSAlex Deucher 
8035b7a59deSAlex Deucher 	amdgpu_mes_unlock(&adev->mes);
8045b7a59deSAlex Deucher 
8055b7a59deSAlex Deucher 	return 0;
8065b7a59deSAlex Deucher }
8075b7a59deSAlex Deucher 
amdgpu_mes_reset_hw_queue_mmio(struct amdgpu_device * adev,int queue_type,int me_id,int pipe_id,int queue_id,int vmid)80801b4ae38SJiadong Zhu int amdgpu_mes_reset_hw_queue_mmio(struct amdgpu_device *adev, int queue_type,
80901b4ae38SJiadong Zhu 				   int me_id, int pipe_id, int queue_id, int vmid)
81001b4ae38SJiadong Zhu {
81101b4ae38SJiadong Zhu 	struct mes_reset_queue_input queue_input;
81201b4ae38SJiadong Zhu 	int r;
81301b4ae38SJiadong Zhu 
814e8397d32SJesse Zhang 	queue_input.queue_type = queue_type;
81501b4ae38SJiadong Zhu 	queue_input.use_mmio = true;
81601b4ae38SJiadong Zhu 	queue_input.me_id = me_id;
81701b4ae38SJiadong Zhu 	queue_input.pipe_id = pipe_id;
81801b4ae38SJiadong Zhu 	queue_input.queue_id = queue_id;
81901b4ae38SJiadong Zhu 	queue_input.vmid = vmid;
82001b4ae38SJiadong Zhu 	r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
82101b4ae38SJiadong Zhu 	if (r)
82201b4ae38SJiadong Zhu 		DRM_ERROR("failed to reset hardware queue by mmio, queue id = %d\n",
82301b4ae38SJiadong Zhu 			  queue_id);
82401b4ae38SJiadong Zhu 	return r;
82501b4ae38SJiadong Zhu }
82601b4ae38SJiadong Zhu 
amdgpu_mes_map_legacy_queue(struct amdgpu_device * adev,struct amdgpu_ring * ring)827029c2b03SJack Xiao int amdgpu_mes_map_legacy_queue(struct amdgpu_device *adev,
828029c2b03SJack Xiao 				struct amdgpu_ring *ring)
829029c2b03SJack Xiao {
830029c2b03SJack Xiao 	struct mes_map_legacy_queue_input queue_input;
831029c2b03SJack Xiao 	int r;
832029c2b03SJack Xiao 
833029c2b03SJack Xiao 	memset(&queue_input, 0, sizeof(queue_input));
834029c2b03SJack Xiao 
835029c2b03SJack Xiao 	queue_input.queue_type = ring->funcs->type;
836029c2b03SJack Xiao 	queue_input.doorbell_offset = ring->doorbell_index;
837029c2b03SJack Xiao 	queue_input.pipe_id = ring->pipe;
838029c2b03SJack Xiao 	queue_input.queue_id = ring->queue;
839029c2b03SJack Xiao 	queue_input.mqd_addr = amdgpu_bo_gpu_offset(ring->mqd_obj);
840029c2b03SJack Xiao 	queue_input.wptr_addr = ring->wptr_gpu_addr;
841029c2b03SJack Xiao 
842029c2b03SJack Xiao 	r = adev->mes.funcs->map_legacy_queue(&adev->mes, &queue_input);
843029c2b03SJack Xiao 	if (r)
844029c2b03SJack Xiao 		DRM_ERROR("failed to map legacy queue\n");
845029c2b03SJack Xiao 
846029c2b03SJack Xiao 	return r;
847029c2b03SJack Xiao }
848029c2b03SJack Xiao 
amdgpu_mes_unmap_legacy_queue(struct amdgpu_device * adev,struct amdgpu_ring * ring,enum amdgpu_unmap_queues_action action,u64 gpu_addr,u64 seq)84918ee4ce6SJack Xiao int amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev,
85018ee4ce6SJack Xiao 				  struct amdgpu_ring *ring,
85118ee4ce6SJack Xiao 				  enum amdgpu_unmap_queues_action action,
85218ee4ce6SJack Xiao 				  u64 gpu_addr, u64 seq)
85318ee4ce6SJack Xiao {
85418ee4ce6SJack Xiao 	struct mes_unmap_legacy_queue_input queue_input;
85518ee4ce6SJack Xiao 	int r;
85618ee4ce6SJack Xiao 
85718ee4ce6SJack Xiao 	queue_input.action = action;
85818ee4ce6SJack Xiao 	queue_input.queue_type = ring->funcs->type;
85918ee4ce6SJack Xiao 	queue_input.doorbell_offset = ring->doorbell_index;
86018ee4ce6SJack Xiao 	queue_input.pipe_id = ring->pipe;
86118ee4ce6SJack Xiao 	queue_input.queue_id = ring->queue;
86218ee4ce6SJack Xiao 	queue_input.trail_fence_addr = gpu_addr;
86318ee4ce6SJack Xiao 	queue_input.trail_fence_data = seq;
86418ee4ce6SJack Xiao 
86518ee4ce6SJack Xiao 	r = adev->mes.funcs->unmap_legacy_queue(&adev->mes, &queue_input);
86618ee4ce6SJack Xiao 	if (r)
86718ee4ce6SJack Xiao 		DRM_ERROR("failed to unmap legacy queue\n");
86818ee4ce6SJack Xiao 
86918ee4ce6SJack Xiao 	return r;
87018ee4ce6SJack Xiao }
87118ee4ce6SJack Xiao 
amdgpu_mes_reset_legacy_queue(struct amdgpu_device * adev,struct amdgpu_ring * ring,unsigned int vmid,bool use_mmio)872c30fb344SAlex Deucher int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev,
873c30fb344SAlex Deucher 				  struct amdgpu_ring *ring,
8748b2429a1SJiadong Zhu 				  unsigned int vmid,
8758b2429a1SJiadong Zhu 				  bool use_mmio)
876c30fb344SAlex Deucher {
877c30fb344SAlex Deucher 	struct mes_reset_legacy_queue_input queue_input;
878c30fb344SAlex Deucher 	int r;
879c30fb344SAlex Deucher 
880c30fb344SAlex Deucher 	memset(&queue_input, 0, sizeof(queue_input));
881c30fb344SAlex Deucher 
882c30fb344SAlex Deucher 	queue_input.queue_type = ring->funcs->type;
883c30fb344SAlex Deucher 	queue_input.doorbell_offset = ring->doorbell_index;
88401b4ae38SJiadong Zhu 	queue_input.me_id = ring->me;
885c30fb344SAlex Deucher 	queue_input.pipe_id = ring->pipe;
886c30fb344SAlex Deucher 	queue_input.queue_id = ring->queue;
887ced65debSJiadong Zhu 	queue_input.mqd_addr = ring->mqd_obj ? amdgpu_bo_gpu_offset(ring->mqd_obj) : 0;
888c30fb344SAlex Deucher 	queue_input.wptr_addr = ring->wptr_gpu_addr;
889c30fb344SAlex Deucher 	queue_input.vmid = vmid;
89001b4ae38SJiadong Zhu 	queue_input.use_mmio = use_mmio;
891c30fb344SAlex Deucher 
892c30fb344SAlex Deucher 	r = adev->mes.funcs->reset_legacy_queue(&adev->mes, &queue_input);
893c30fb344SAlex Deucher 	if (r)
894c30fb344SAlex Deucher 		DRM_ERROR("failed to reset legacy queue\n");
895c30fb344SAlex Deucher 
896c30fb344SAlex Deucher 	return r;
897c30fb344SAlex Deucher }
898c30fb344SAlex Deucher 
amdgpu_mes_rreg(struct amdgpu_device * adev,uint32_t reg)899adc0e6abSJack Xiao uint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg)
900adc0e6abSJack Xiao {
901adc0e6abSJack Xiao 	struct mes_misc_op_input op_input;
902adc0e6abSJack Xiao 	int r, val = 0;
903f4a3246aSchongli2 	uint32_t addr_offset = 0;
904f4a3246aSchongli2 	uint64_t read_val_gpu_addr;
905f4a3246aSchongli2 	uint32_t *read_val_ptr;
906adc0e6abSJack Xiao 
907f4a3246aSchongli2 	if (amdgpu_device_wb_get(adev, &addr_offset)) {
908f4a3246aSchongli2 		DRM_ERROR("critical bug! too many mes readers\n");
909f4a3246aSchongli2 		goto error;
910f4a3246aSchongli2 	}
911f4a3246aSchongli2 	read_val_gpu_addr = adev->wb.gpu_addr + (addr_offset * 4);
912f4a3246aSchongli2 	read_val_ptr = (uint32_t *)&adev->wb.wb[addr_offset];
913adc0e6abSJack Xiao 	op_input.op = MES_MISC_OP_READ_REG;
914adc0e6abSJack Xiao 	op_input.read_reg.reg_offset = reg;
915f4a3246aSchongli2 	op_input.read_reg.buffer_addr = read_val_gpu_addr;
916adc0e6abSJack Xiao 
917adc0e6abSJack Xiao 	if (!adev->mes.funcs->misc_op) {
918adc0e6abSJack Xiao 		DRM_ERROR("mes rreg is not supported!\n");
919adc0e6abSJack Xiao 		goto error;
920adc0e6abSJack Xiao 	}
921adc0e6abSJack Xiao 
922adc0e6abSJack Xiao 	r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
923adc0e6abSJack Xiao 	if (r)
924adc0e6abSJack Xiao 		DRM_ERROR("failed to read reg (0x%x)\n", reg);
925adc0e6abSJack Xiao 	else
926f4a3246aSchongli2 		val = *(read_val_ptr);
927adc0e6abSJack Xiao 
928adc0e6abSJack Xiao error:
929f4a3246aSchongli2 	if (addr_offset)
930f4a3246aSchongli2 		amdgpu_device_wb_free(adev, addr_offset);
931adc0e6abSJack Xiao 	return val;
932adc0e6abSJack Xiao }
933adc0e6abSJack Xiao 
amdgpu_mes_wreg(struct amdgpu_device * adev,uint32_t reg,uint32_t val)934adc0e6abSJack Xiao int amdgpu_mes_wreg(struct amdgpu_device *adev,
935adc0e6abSJack Xiao 		    uint32_t reg, uint32_t val)
936adc0e6abSJack Xiao {
937adc0e6abSJack Xiao 	struct mes_misc_op_input op_input;
938adc0e6abSJack Xiao 	int r;
939adc0e6abSJack Xiao 
940adc0e6abSJack Xiao 	op_input.op = MES_MISC_OP_WRITE_REG;
941adc0e6abSJack Xiao 	op_input.write_reg.reg_offset = reg;
942adc0e6abSJack Xiao 	op_input.write_reg.reg_value = val;
943adc0e6abSJack Xiao 
944adc0e6abSJack Xiao 	if (!adev->mes.funcs->misc_op) {
945adc0e6abSJack Xiao 		DRM_ERROR("mes wreg is not supported!\n");
946adc0e6abSJack Xiao 		r = -EINVAL;
947adc0e6abSJack Xiao 		goto error;
948adc0e6abSJack Xiao 	}
949adc0e6abSJack Xiao 
950adc0e6abSJack Xiao 	r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
951adc0e6abSJack Xiao 	if (r)
952adc0e6abSJack Xiao 		DRM_ERROR("failed to write reg (0x%x)\n", reg);
953adc0e6abSJack Xiao 
954adc0e6abSJack Xiao error:
955adc0e6abSJack Xiao 	return r;
956adc0e6abSJack Xiao }
957adc0e6abSJack Xiao 
amdgpu_mes_reg_write_reg_wait(struct amdgpu_device * adev,uint32_t reg0,uint32_t reg1,uint32_t ref,uint32_t mask)958adc0e6abSJack Xiao int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev,
959adc0e6abSJack Xiao 				  uint32_t reg0, uint32_t reg1,
960adc0e6abSJack Xiao 				  uint32_t ref, uint32_t mask)
961adc0e6abSJack Xiao {
962adc0e6abSJack Xiao 	struct mes_misc_op_input op_input;
963adc0e6abSJack Xiao 	int r;
964adc0e6abSJack Xiao 
965adc0e6abSJack Xiao 	op_input.op = MES_MISC_OP_WRM_REG_WR_WAIT;
966adc0e6abSJack Xiao 	op_input.wrm_reg.reg0 = reg0;
967adc0e6abSJack Xiao 	op_input.wrm_reg.reg1 = reg1;
968adc0e6abSJack Xiao 	op_input.wrm_reg.ref = ref;
969adc0e6abSJack Xiao 	op_input.wrm_reg.mask = mask;
970adc0e6abSJack Xiao 
971adc0e6abSJack Xiao 	if (!adev->mes.funcs->misc_op) {
972adc0e6abSJack Xiao 		DRM_ERROR("mes reg_write_reg_wait is not supported!\n");
973adc0e6abSJack Xiao 		r = -EINVAL;
974adc0e6abSJack Xiao 		goto error;
975adc0e6abSJack Xiao 	}
976adc0e6abSJack Xiao 
977adc0e6abSJack Xiao 	r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
978adc0e6abSJack Xiao 	if (r)
979adc0e6abSJack Xiao 		DRM_ERROR("failed to reg_write_reg_wait\n");
980adc0e6abSJack Xiao 
981adc0e6abSJack Xiao error:
982adc0e6abSJack Xiao 	return r;
983adc0e6abSJack Xiao }
984adc0e6abSJack Xiao 
amdgpu_mes_reg_wait(struct amdgpu_device * adev,uint32_t reg,uint32_t val,uint32_t mask)985adc0e6abSJack Xiao int amdgpu_mes_reg_wait(struct amdgpu_device *adev, uint32_t reg,
986adc0e6abSJack Xiao 			uint32_t val, uint32_t mask)
987adc0e6abSJack Xiao {
988adc0e6abSJack Xiao 	struct mes_misc_op_input op_input;
989adc0e6abSJack Xiao 	int r;
990adc0e6abSJack Xiao 
991adc0e6abSJack Xiao 	op_input.op = MES_MISC_OP_WRM_REG_WAIT;
992adc0e6abSJack Xiao 	op_input.wrm_reg.reg0 = reg;
993adc0e6abSJack Xiao 	op_input.wrm_reg.ref = val;
994adc0e6abSJack Xiao 	op_input.wrm_reg.mask = mask;
995adc0e6abSJack Xiao 
996adc0e6abSJack Xiao 	if (!adev->mes.funcs->misc_op) {
997adc0e6abSJack Xiao 		DRM_ERROR("mes reg wait is not supported!\n");
998adc0e6abSJack Xiao 		r = -EINVAL;
999adc0e6abSJack Xiao 		goto error;
1000adc0e6abSJack Xiao 	}
1001adc0e6abSJack Xiao 
1002adc0e6abSJack Xiao 	r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
1003adc0e6abSJack Xiao 	if (r)
1004adc0e6abSJack Xiao 		DRM_ERROR("failed to reg_write_reg_wait\n");
1005adc0e6abSJack Xiao 
1006adc0e6abSJack Xiao error:
1007adc0e6abSJack Xiao 	return r;
1008adc0e6abSJack Xiao }
1009adc0e6abSJack Xiao 
amdgpu_mes_set_shader_debugger(struct amdgpu_device * adev,uint64_t process_context_addr,uint32_t spi_gdbg_per_vmid_cntl,const uint32_t * tcp_watch_cntl,uint32_t flags,bool trap_en)1010a9818854SJonathan Kim int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev,
1011a9818854SJonathan Kim 				uint64_t process_context_addr,
1012a9818854SJonathan Kim 				uint32_t spi_gdbg_per_vmid_cntl,
1013a9818854SJonathan Kim 				const uint32_t *tcp_watch_cntl,
101409d49e14SJonathan Kim 				uint32_t flags,
101509d49e14SJonathan Kim 				bool trap_en)
1016a9818854SJonathan Kim {
1017a9818854SJonathan Kim 	struct mes_misc_op_input op_input = {0};
1018a9818854SJonathan Kim 	int r;
1019a9818854SJonathan Kim 
1020a9818854SJonathan Kim 	if (!adev->mes.funcs->misc_op) {
1021a9818854SJonathan Kim 		DRM_ERROR("mes set shader debugger is not supported!\n");
1022a9818854SJonathan Kim 		return -EINVAL;
1023a9818854SJonathan Kim 	}
1024a9818854SJonathan Kim 
1025a9818854SJonathan Kim 	op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER;
1026a9818854SJonathan Kim 	op_input.set_shader_debugger.process_context_addr = process_context_addr;
1027a9818854SJonathan Kim 	op_input.set_shader_debugger.flags.u32all = flags;
1028bd33bb14SJonathan Kim 
1029bd33bb14SJonathan Kim 	/* use amdgpu mes_flush_shader_debugger instead */
1030bd33bb14SJonathan Kim 	if (op_input.set_shader_debugger.flags.process_ctx_flush)
1031bd33bb14SJonathan Kim 		return -EINVAL;
1032bd33bb14SJonathan Kim 
1033a9818854SJonathan Kim 	op_input.set_shader_debugger.spi_gdbg_per_vmid_cntl = spi_gdbg_per_vmid_cntl;
1034a9818854SJonathan Kim 	memcpy(op_input.set_shader_debugger.tcp_watch_cntl, tcp_watch_cntl,
1035a9818854SJonathan Kim 			sizeof(op_input.set_shader_debugger.tcp_watch_cntl));
1036a9818854SJonathan Kim 
103709d49e14SJonathan Kim 	if (((adev->mes.sched_version & AMDGPU_MES_API_VERSION_MASK) >>
103809d49e14SJonathan Kim 			AMDGPU_MES_API_VERSION_SHIFT) >= 14)
103909d49e14SJonathan Kim 		op_input.set_shader_debugger.trap_en = trap_en;
104009d49e14SJonathan Kim 
1041a9818854SJonathan Kim 	amdgpu_mes_lock(&adev->mes);
1042a9818854SJonathan Kim 
1043a9818854SJonathan Kim 	r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
1044a9818854SJonathan Kim 	if (r)
1045a9818854SJonathan Kim 		DRM_ERROR("failed to set_shader_debugger\n");
1046a9818854SJonathan Kim 
1047a9818854SJonathan Kim 	amdgpu_mes_unlock(&adev->mes);
1048a9818854SJonathan Kim 
1049a9818854SJonathan Kim 	return r;
1050a9818854SJonathan Kim }
1051a9818854SJonathan Kim 
amdgpu_mes_flush_shader_debugger(struct amdgpu_device * adev,uint64_t process_context_addr)1052bd33bb14SJonathan Kim int amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev,
1053bd33bb14SJonathan Kim 				     uint64_t process_context_addr)
1054bd33bb14SJonathan Kim {
1055bd33bb14SJonathan Kim 	struct mes_misc_op_input op_input = {0};
1056bd33bb14SJonathan Kim 	int r;
1057bd33bb14SJonathan Kim 
1058bd33bb14SJonathan Kim 	if (!adev->mes.funcs->misc_op) {
1059bd33bb14SJonathan Kim 		DRM_ERROR("mes flush shader debugger is not supported!\n");
1060bd33bb14SJonathan Kim 		return -EINVAL;
1061bd33bb14SJonathan Kim 	}
1062bd33bb14SJonathan Kim 
1063bd33bb14SJonathan Kim 	op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER;
1064bd33bb14SJonathan Kim 	op_input.set_shader_debugger.process_context_addr = process_context_addr;
1065bd33bb14SJonathan Kim 	op_input.set_shader_debugger.flags.process_ctx_flush = true;
1066bd33bb14SJonathan Kim 
1067bd33bb14SJonathan Kim 	amdgpu_mes_lock(&adev->mes);
1068bd33bb14SJonathan Kim 
1069bd33bb14SJonathan Kim 	r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
1070bd33bb14SJonathan Kim 	if (r)
1071bd33bb14SJonathan Kim 		DRM_ERROR("failed to set_shader_debugger\n");
1072bd33bb14SJonathan Kim 
1073bd33bb14SJonathan Kim 	amdgpu_mes_unlock(&adev->mes);
1074bd33bb14SJonathan Kim 
1075bd33bb14SJonathan Kim 	return r;
1076bd33bb14SJonathan Kim }
1077bd33bb14SJonathan Kim 
10781a27aacbSJack Xiao static void
amdgpu_mes_ring_to_queue_props(struct amdgpu_device * adev,struct amdgpu_ring * ring,struct amdgpu_mes_queue_properties * props)10791a27aacbSJack Xiao amdgpu_mes_ring_to_queue_props(struct amdgpu_device *adev,
10801a27aacbSJack Xiao 			       struct amdgpu_ring *ring,
10811a27aacbSJack Xiao 			       struct amdgpu_mes_queue_properties *props)
10821a27aacbSJack Xiao {
10831a27aacbSJack Xiao 	props->queue_type = ring->funcs->type;
10841a27aacbSJack Xiao 	props->hqd_base_gpu_addr = ring->gpu_addr;
10851a27aacbSJack Xiao 	props->rptr_gpu_addr = ring->rptr_gpu_addr;
10861a27aacbSJack Xiao 	props->wptr_gpu_addr = ring->wptr_gpu_addr;
1087fe4e9ff9SJack Xiao 	props->wptr_mc_addr =
1088fe4e9ff9SJack Xiao 		ring->mes_ctx->meta_data_mc_addr + ring->wptr_offs;
10891a27aacbSJack Xiao 	props->queue_size = ring->ring_size;
10901a27aacbSJack Xiao 	props->eop_gpu_addr = ring->eop_gpu_addr;
10911a27aacbSJack Xiao 	props->hqd_pipe_priority = AMDGPU_GFX_PIPE_PRIO_NORMAL;
10921a27aacbSJack Xiao 	props->hqd_queue_priority = AMDGPU_GFX_QUEUE_PRIORITY_MINIMUM;
10931a27aacbSJack Xiao 	props->paging = false;
10941a27aacbSJack Xiao 	props->ring = ring;
10951a27aacbSJack Xiao }
109611ec5b36SJack Xiao 
109711ec5b36SJack Xiao #define DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(_eng)			\
109811ec5b36SJack Xiao do {									\
109911ec5b36SJack Xiao        if (id_offs < AMDGPU_MES_CTX_MAX_OFFS)				\
110011ec5b36SJack Xiao 		return offsetof(struct amdgpu_mes_ctx_meta_data,	\
110111ec5b36SJack Xiao 				_eng[ring->idx].slots[id_offs]);        \
110211ec5b36SJack Xiao        else if (id_offs == AMDGPU_MES_CTX_RING_OFFS)			\
110311ec5b36SJack Xiao 		return offsetof(struct amdgpu_mes_ctx_meta_data,        \
110411ec5b36SJack Xiao 				_eng[ring->idx].ring);                  \
110511ec5b36SJack Xiao        else if (id_offs == AMDGPU_MES_CTX_IB_OFFS)			\
110611ec5b36SJack Xiao 		return offsetof(struct amdgpu_mes_ctx_meta_data,        \
110711ec5b36SJack Xiao 				_eng[ring->idx].ib);                    \
110811ec5b36SJack Xiao        else if (id_offs == AMDGPU_MES_CTX_PADDING_OFFS)			\
110911ec5b36SJack Xiao 		return offsetof(struct amdgpu_mes_ctx_meta_data,        \
111011ec5b36SJack Xiao 				_eng[ring->idx].padding);               \
111111ec5b36SJack Xiao } while(0)
111211ec5b36SJack Xiao 
amdgpu_mes_ctx_get_offs(struct amdgpu_ring * ring,unsigned int id_offs)111311ec5b36SJack Xiao int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs)
111411ec5b36SJack Xiao {
111511ec5b36SJack Xiao 	switch (ring->funcs->type) {
111611ec5b36SJack Xiao 	case AMDGPU_RING_TYPE_GFX:
111711ec5b36SJack Xiao 		DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(gfx);
111811ec5b36SJack Xiao 		break;
111911ec5b36SJack Xiao 	case AMDGPU_RING_TYPE_COMPUTE:
112011ec5b36SJack Xiao 		DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(compute);
112111ec5b36SJack Xiao 		break;
112211ec5b36SJack Xiao 	case AMDGPU_RING_TYPE_SDMA:
112311ec5b36SJack Xiao 		DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(sdma);
112411ec5b36SJack Xiao 		break;
112511ec5b36SJack Xiao 	default:
112611ec5b36SJack Xiao 		break;
112711ec5b36SJack Xiao 	}
112811ec5b36SJack Xiao 
112911ec5b36SJack Xiao 	WARN_ON(1);
113011ec5b36SJack Xiao 	return -EINVAL;
113111ec5b36SJack Xiao }
1132d0c423b6SJack Xiao 
amdgpu_mes_add_ring(struct amdgpu_device * adev,int gang_id,int queue_type,int idx,struct amdgpu_mes_ctx_data * ctx_data,struct amdgpu_ring ** out)1133d0c423b6SJack Xiao int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id,
1134d0c423b6SJack Xiao 			int queue_type, int idx,
1135d0c423b6SJack Xiao 			struct amdgpu_mes_ctx_data *ctx_data,
1136d0c423b6SJack Xiao 			struct amdgpu_ring **out)
1137d0c423b6SJack Xiao {
1138d0c423b6SJack Xiao 	struct amdgpu_ring *ring;
1139d0c423b6SJack Xiao 	struct amdgpu_mes_gang *gang;
1140d0c423b6SJack Xiao 	struct amdgpu_mes_queue_properties qprops = {0};
1141d0c423b6SJack Xiao 	int r, queue_id, pasid;
1142d0c423b6SJack Xiao 
114318ee4ce6SJack Xiao 	/*
114418ee4ce6SJack Xiao 	 * Avoid taking any other locks under MES lock to avoid circular
114518ee4ce6SJack Xiao 	 * lock dependencies.
114618ee4ce6SJack Xiao 	 */
114718ee4ce6SJack Xiao 	amdgpu_mes_lock(&adev->mes);
1148d0c423b6SJack Xiao 	gang = idr_find(&adev->mes.gang_id_idr, gang_id);
1149d0c423b6SJack Xiao 	if (!gang) {
1150d0c423b6SJack Xiao 		DRM_ERROR("gang id %d doesn't exist\n", gang_id);
115118ee4ce6SJack Xiao 		amdgpu_mes_unlock(&adev->mes);
1152d0c423b6SJack Xiao 		return -EINVAL;
1153d0c423b6SJack Xiao 	}
1154d0c423b6SJack Xiao 	pasid = gang->process->pasid;
1155d0c423b6SJack Xiao 
1156d0c423b6SJack Xiao 	ring = kzalloc(sizeof(struct amdgpu_ring), GFP_KERNEL);
1157d0c423b6SJack Xiao 	if (!ring) {
115818ee4ce6SJack Xiao 		amdgpu_mes_unlock(&adev->mes);
1159d0c423b6SJack Xiao 		return -ENOMEM;
1160d0c423b6SJack Xiao 	}
1161d0c423b6SJack Xiao 
1162d0c423b6SJack Xiao 	ring->ring_obj = NULL;
1163d0c423b6SJack Xiao 	ring->use_doorbell = true;
1164d0c423b6SJack Xiao 	ring->is_mes_queue = true;
1165d0c423b6SJack Xiao 	ring->mes_ctx = ctx_data;
1166d0c423b6SJack Xiao 	ring->idx = idx;
1167d0c423b6SJack Xiao 	ring->no_scheduler = true;
1168d0c423b6SJack Xiao 
1169d0c423b6SJack Xiao 	if (queue_type == AMDGPU_RING_TYPE_COMPUTE) {
1170d0c423b6SJack Xiao 		int offset = offsetof(struct amdgpu_mes_ctx_meta_data,
1171d0c423b6SJack Xiao 				      compute[ring->idx].mec_hpd);
1172d0c423b6SJack Xiao 		ring->eop_gpu_addr =
1173d0c423b6SJack Xiao 			amdgpu_mes_ctx_get_offs_gpu_addr(ring, offset);
1174d0c423b6SJack Xiao 	}
1175d0c423b6SJack Xiao 
1176d0c423b6SJack Xiao 	switch (queue_type) {
1177d0c423b6SJack Xiao 	case AMDGPU_RING_TYPE_GFX:
1178d0c423b6SJack Xiao 		ring->funcs = adev->gfx.gfx_ring[0].funcs;
117936e7ff5cSTim Huang 		ring->me = adev->gfx.gfx_ring[0].me;
118036e7ff5cSTim Huang 		ring->pipe = adev->gfx.gfx_ring[0].pipe;
1181d0c423b6SJack Xiao 		break;
1182d0c423b6SJack Xiao 	case AMDGPU_RING_TYPE_COMPUTE:
1183d0c423b6SJack Xiao 		ring->funcs = adev->gfx.compute_ring[0].funcs;
118436e7ff5cSTim Huang 		ring->me = adev->gfx.compute_ring[0].me;
118536e7ff5cSTim Huang 		ring->pipe = adev->gfx.compute_ring[0].pipe;
1186d0c423b6SJack Xiao 		break;
1187d0c423b6SJack Xiao 	case AMDGPU_RING_TYPE_SDMA:
1188d0c423b6SJack Xiao 		ring->funcs = adev->sdma.instance[0].ring.funcs;
1189d0c423b6SJack Xiao 		break;
1190d0c423b6SJack Xiao 	default:
1191d0c423b6SJack Xiao 		BUG();
1192d0c423b6SJack Xiao 	}
1193d0c423b6SJack Xiao 
1194d0c423b6SJack Xiao 	r = amdgpu_ring_init(adev, ring, 1024, NULL, 0,
1195d0c423b6SJack Xiao 			     AMDGPU_RING_PRIO_DEFAULT, NULL);
1196bfaf1883SSrinivasan Shanmugam 	if (r) {
1197bfaf1883SSrinivasan Shanmugam 		amdgpu_mes_unlock(&adev->mes);
1198d0c423b6SJack Xiao 		goto clean_up_memory;
1199bfaf1883SSrinivasan Shanmugam 	}
1200d0c423b6SJack Xiao 
1201d0c423b6SJack Xiao 	amdgpu_mes_ring_to_queue_props(adev, ring, &qprops);
1202d0c423b6SJack Xiao 
1203d0c423b6SJack Xiao 	dma_fence_wait(gang->process->vm->last_update, false);
1204d0c423b6SJack Xiao 	dma_fence_wait(ctx_data->meta_data_va->last_pt_update, false);
120518ee4ce6SJack Xiao 	amdgpu_mes_unlock(&adev->mes);
1206d0c423b6SJack Xiao 
1207d0c423b6SJack Xiao 	r = amdgpu_mes_add_hw_queue(adev, gang_id, &qprops, &queue_id);
1208d0c423b6SJack Xiao 	if (r)
1209d0c423b6SJack Xiao 		goto clean_up_ring;
1210d0c423b6SJack Xiao 
1211d0c423b6SJack Xiao 	ring->hw_queue_id = queue_id;
1212d0c423b6SJack Xiao 	ring->doorbell_index = qprops.doorbell_off;
1213d0c423b6SJack Xiao 
1214d0c423b6SJack Xiao 	if (queue_type == AMDGPU_RING_TYPE_GFX)
1215d0c423b6SJack Xiao 		sprintf(ring->name, "gfx_%d.%d.%d", pasid, gang_id, queue_id);
1216d0c423b6SJack Xiao 	else if (queue_type == AMDGPU_RING_TYPE_COMPUTE)
1217d0c423b6SJack Xiao 		sprintf(ring->name, "compute_%d.%d.%d", pasid, gang_id,
1218d0c423b6SJack Xiao 			queue_id);
1219d0c423b6SJack Xiao 	else if (queue_type == AMDGPU_RING_TYPE_SDMA)
1220d0c423b6SJack Xiao 		sprintf(ring->name, "sdma_%d.%d.%d", pasid, gang_id,
1221d0c423b6SJack Xiao 			queue_id);
1222d0c423b6SJack Xiao 	else
1223d0c423b6SJack Xiao 		BUG();
1224d0c423b6SJack Xiao 
1225d0c423b6SJack Xiao 	*out = ring;
1226d0c423b6SJack Xiao 	return 0;
1227d0c423b6SJack Xiao 
1228d0c423b6SJack Xiao clean_up_ring:
1229d0c423b6SJack Xiao 	amdgpu_ring_fini(ring);
1230d0c423b6SJack Xiao clean_up_memory:
1231d0c423b6SJack Xiao 	kfree(ring);
1232d0c423b6SJack Xiao 	return r;
1233d0c423b6SJack Xiao }
12349cc654c8SJack Xiao 
amdgpu_mes_remove_ring(struct amdgpu_device * adev,struct amdgpu_ring * ring)12359cc654c8SJack Xiao void amdgpu_mes_remove_ring(struct amdgpu_device *adev,
12369cc654c8SJack Xiao 			    struct amdgpu_ring *ring)
12379cc654c8SJack Xiao {
12389cc654c8SJack Xiao 	if (!ring)
12399cc654c8SJack Xiao 		return;
12409cc654c8SJack Xiao 
12419cc654c8SJack Xiao 	amdgpu_mes_remove_hw_queue(adev, ring->hw_queue_id);
1242*8fa7292fSThomas Gleixner 	timer_delete_sync(&ring->fence_drv.fallback_timer);
12439cc654c8SJack Xiao 	amdgpu_ring_fini(ring);
12449cc654c8SJack Xiao 	kfree(ring);
12459cc654c8SJack Xiao }
1246e3652b09SJack Xiao 
amdgpu_mes_get_aggregated_doorbell_index(struct amdgpu_device * adev,enum amdgpu_mes_priority_level prio)12472d7a1f71SLe Ma uint32_t amdgpu_mes_get_aggregated_doorbell_index(struct amdgpu_device *adev,
12482d7a1f71SLe Ma 						   enum amdgpu_mes_priority_level prio)
12492d7a1f71SLe Ma {
12502d7a1f71SLe Ma 	return adev->mes.aggregated_doorbells[prio];
12512d7a1f71SLe Ma }
12522d7a1f71SLe Ma 
amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device * adev,struct amdgpu_mes_ctx_data * ctx_data)1253e3652b09SJack Xiao int amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device *adev,
1254e3652b09SJack Xiao 				   struct amdgpu_mes_ctx_data *ctx_data)
1255e3652b09SJack Xiao {
1256e3652b09SJack Xiao 	int r;
1257e3652b09SJack Xiao 
1258e3652b09SJack Xiao 	r = amdgpu_bo_create_kernel(adev,
1259e3652b09SJack Xiao 			    sizeof(struct amdgpu_mes_ctx_meta_data),
1260e3652b09SJack Xiao 			    PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
1261fe4e9ff9SJack Xiao 			    &ctx_data->meta_data_obj,
1262fe4e9ff9SJack Xiao 			    &ctx_data->meta_data_mc_addr,
1263e3652b09SJack Xiao 			    &ctx_data->meta_data_ptr);
12640b9ff428SLee Jones 	if (r) {
12650b9ff428SLee Jones 		dev_warn(adev->dev, "(%d) create CTX bo failed\n", r);
12660b9ff428SLee Jones 		return r;
12670b9ff428SLee Jones 	}
12680b9ff428SLee Jones 
1269e3652b09SJack Xiao 	if (!ctx_data->meta_data_obj)
1270e3652b09SJack Xiao 		return -ENOMEM;
1271e3652b09SJack Xiao 
1272e3652b09SJack Xiao 	memset(ctx_data->meta_data_ptr, 0,
1273e3652b09SJack Xiao 	       sizeof(struct amdgpu_mes_ctx_meta_data));
1274e3652b09SJack Xiao 
1275e3652b09SJack Xiao 	return 0;
1276e3652b09SJack Xiao }
1277e3652b09SJack Xiao 
amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data * ctx_data)1278e3652b09SJack Xiao void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data)
1279e3652b09SJack Xiao {
1280e3652b09SJack Xiao 	if (ctx_data->meta_data_obj)
1281fe4e9ff9SJack Xiao 		amdgpu_bo_free_kernel(&ctx_data->meta_data_obj,
1282fe4e9ff9SJack Xiao 				      &ctx_data->meta_data_mc_addr,
1283fe4e9ff9SJack Xiao 				      &ctx_data->meta_data_ptr);
1284e3652b09SJack Xiao }
1285a22f760aSJack Xiao 
amdgpu_mes_ctx_map_meta_data(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct amdgpu_mes_ctx_data * ctx_data)12867c18b40eSJack Xiao int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev,
1287a22f760aSJack Xiao 				 struct amdgpu_vm *vm,
1288a22f760aSJack Xiao 				 struct amdgpu_mes_ctx_data *ctx_data)
1289a22f760aSJack Xiao {
12907c18b40eSJack Xiao 	struct amdgpu_bo_va *bo_va;
12917c18b40eSJack Xiao 	struct amdgpu_sync sync;
12922acc73f8SChristian König 	struct drm_exec exec;
1293a22f760aSJack Xiao 	int r;
1294a22f760aSJack Xiao 
12957c18b40eSJack Xiao 	amdgpu_sync_create(&sync);
1296a22f760aSJack Xiao 
129705d24935SRob Clark 	drm_exec_init(&exec, 0, 0);
12982acc73f8SChristian König 	drm_exec_until_all_locked(&exec) {
12992acc73f8SChristian König 		r = drm_exec_lock_obj(&exec,
13002acc73f8SChristian König 				      &ctx_data->meta_data_obj->tbo.base);
13012acc73f8SChristian König 		drm_exec_retry_on_contention(&exec);
13022acc73f8SChristian König 		if (unlikely(r))
13032acc73f8SChristian König 			goto error_fini_exec;
13047c18b40eSJack Xiao 
13052acc73f8SChristian König 		r = amdgpu_vm_lock_pd(vm, &exec, 0);
13062acc73f8SChristian König 		drm_exec_retry_on_contention(&exec);
13072acc73f8SChristian König 		if (unlikely(r))
13082acc73f8SChristian König 			goto error_fini_exec;
13097c18b40eSJack Xiao 	}
13107c18b40eSJack Xiao 
13117c18b40eSJack Xiao 	bo_va = amdgpu_vm_bo_add(adev, vm, ctx_data->meta_data_obj);
13127c18b40eSJack Xiao 	if (!bo_va) {
13137c18b40eSJack Xiao 		DRM_ERROR("failed to create bo_va for meta data BO\n");
13142acc73f8SChristian König 		r = -ENOMEM;
13152acc73f8SChristian König 		goto error_fini_exec;
13167c18b40eSJack Xiao 	}
13177c18b40eSJack Xiao 
13187c18b40eSJack Xiao 	r = amdgpu_vm_bo_map(adev, bo_va, ctx_data->meta_data_gpu_addr, 0,
13197c18b40eSJack Xiao 			     sizeof(struct amdgpu_mes_ctx_meta_data),
13207c18b40eSJack Xiao 			     AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
13217c18b40eSJack Xiao 			     AMDGPU_PTE_EXECUTABLE);
13227c18b40eSJack Xiao 
13237c18b40eSJack Xiao 	if (r) {
13247c18b40eSJack Xiao 		DRM_ERROR("failed to do bo_map on meta data, err=%d\n", r);
13252acc73f8SChristian König 		goto error_del_bo_va;
13267c18b40eSJack Xiao 	}
13277c18b40eSJack Xiao 
13287c18b40eSJack Xiao 	r = amdgpu_vm_bo_update(adev, bo_va, false);
13297c18b40eSJack Xiao 	if (r) {
13307c18b40eSJack Xiao 		DRM_ERROR("failed to do vm_bo_update on meta data\n");
13312acc73f8SChristian König 		goto error_del_bo_va;
13327c18b40eSJack Xiao 	}
133316590745SChristian König 	amdgpu_sync_fence(&sync, bo_va->last_pt_update, GFP_KERNEL);
1334a22f760aSJack Xiao 
1335a22f760aSJack Xiao 	r = amdgpu_vm_update_pdes(adev, vm, false);
13367c18b40eSJack Xiao 	if (r) {
13377c18b40eSJack Xiao 		DRM_ERROR("failed to update pdes on meta data\n");
13382acc73f8SChristian König 		goto error_del_bo_va;
13397c18b40eSJack Xiao 	}
134016590745SChristian König 	amdgpu_sync_fence(&sync, vm->last_update, GFP_KERNEL);
1341a22f760aSJack Xiao 
13427c18b40eSJack Xiao 	amdgpu_sync_wait(&sync, false);
13432acc73f8SChristian König 	drm_exec_fini(&exec);
1344a22f760aSJack Xiao 
13457c18b40eSJack Xiao 	amdgpu_sync_free(&sync);
13467c18b40eSJack Xiao 	ctx_data->meta_data_va = bo_va;
1347a22f760aSJack Xiao 	return 0;
1348a22f760aSJack Xiao 
13492acc73f8SChristian König error_del_bo_va:
13507c18b40eSJack Xiao 	amdgpu_vm_bo_del(adev, bo_va);
13512acc73f8SChristian König 
13522acc73f8SChristian König error_fini_exec:
13532acc73f8SChristian König 	drm_exec_fini(&exec);
13547c18b40eSJack Xiao 	amdgpu_sync_free(&sync);
1355a22f760aSJack Xiao 	return r;
1356a22f760aSJack Xiao }
1357f1d93c9cSJack Xiao 
amdgpu_mes_ctx_unmap_meta_data(struct amdgpu_device * adev,struct amdgpu_mes_ctx_data * ctx_data)1358737dad0bSJack Xiao int amdgpu_mes_ctx_unmap_meta_data(struct amdgpu_device *adev,
1359737dad0bSJack Xiao 				   struct amdgpu_mes_ctx_data *ctx_data)
1360737dad0bSJack Xiao {
1361737dad0bSJack Xiao 	struct amdgpu_bo_va *bo_va = ctx_data->meta_data_va;
1362737dad0bSJack Xiao 	struct amdgpu_bo *bo = ctx_data->meta_data_obj;
1363737dad0bSJack Xiao 	struct amdgpu_vm *vm = bo_va->base.vm;
13642acc73f8SChristian König 	struct dma_fence *fence;
13652acc73f8SChristian König 	struct drm_exec exec;
13662acc73f8SChristian König 	long r;
1367737dad0bSJack Xiao 
136805d24935SRob Clark 	drm_exec_init(&exec, 0, 0);
13692acc73f8SChristian König 	drm_exec_until_all_locked(&exec) {
13702acc73f8SChristian König 		r = drm_exec_lock_obj(&exec,
13712acc73f8SChristian König 				      &ctx_data->meta_data_obj->tbo.base);
13722acc73f8SChristian König 		drm_exec_retry_on_contention(&exec);
13732acc73f8SChristian König 		if (unlikely(r))
13742acc73f8SChristian König 			goto out_unlock;
1375737dad0bSJack Xiao 
13762acc73f8SChristian König 		r = amdgpu_vm_lock_pd(vm, &exec, 0);
13772acc73f8SChristian König 		drm_exec_retry_on_contention(&exec);
13782acc73f8SChristian König 		if (unlikely(r))
13792acc73f8SChristian König 			goto out_unlock;
1380737dad0bSJack Xiao 	}
1381737dad0bSJack Xiao 
1382737dad0bSJack Xiao 	amdgpu_vm_bo_del(adev, bo_va);
1383737dad0bSJack Xiao 	if (!amdgpu_vm_ready(vm))
1384737dad0bSJack Xiao 		goto out_unlock;
1385737dad0bSJack Xiao 
13862acc73f8SChristian König 	r = dma_resv_get_singleton(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
13872acc73f8SChristian König 				   &fence);
1388737dad0bSJack Xiao 	if (r)
1389737dad0bSJack Xiao 		goto out_unlock;
1390737dad0bSJack Xiao 	if (fence) {
1391737dad0bSJack Xiao 		amdgpu_bo_fence(bo, fence, true);
1392737dad0bSJack Xiao 		fence = NULL;
1393737dad0bSJack Xiao 	}
1394737dad0bSJack Xiao 
1395737dad0bSJack Xiao 	r = amdgpu_vm_clear_freed(adev, vm, &fence);
1396737dad0bSJack Xiao 	if (r || !fence)
1397737dad0bSJack Xiao 		goto out_unlock;
1398737dad0bSJack Xiao 
1399737dad0bSJack Xiao 	dma_fence_wait(fence, false);
1400737dad0bSJack Xiao 	amdgpu_bo_fence(bo, fence, true);
1401737dad0bSJack Xiao 	dma_fence_put(fence);
1402737dad0bSJack Xiao 
1403737dad0bSJack Xiao out_unlock:
1404737dad0bSJack Xiao 	if (unlikely(r < 0))
1405737dad0bSJack Xiao 		dev_err(adev->dev, "failed to clear page tables (%ld)\n", r);
14062acc73f8SChristian König 	drm_exec_fini(&exec);
1407737dad0bSJack Xiao 
1408737dad0bSJack Xiao 	return r;
1409737dad0bSJack Xiao }
1410737dad0bSJack Xiao 
amdgpu_mes_test_create_gang_and_queues(struct amdgpu_device * adev,int pasid,int * gang_id,int queue_type,int num_queue,struct amdgpu_ring ** added_rings,struct amdgpu_mes_ctx_data * ctx_data)1411f1d93c9cSJack Xiao static int amdgpu_mes_test_create_gang_and_queues(struct amdgpu_device *adev,
1412f1d93c9cSJack Xiao 					  int pasid, int *gang_id,
1413f1d93c9cSJack Xiao 					  int queue_type, int num_queue,
1414f1d93c9cSJack Xiao 					  struct amdgpu_ring **added_rings,
1415f1d93c9cSJack Xiao 					  struct amdgpu_mes_ctx_data *ctx_data)
1416f1d93c9cSJack Xiao {
1417f1d93c9cSJack Xiao 	struct amdgpu_ring *ring;
1418f1d93c9cSJack Xiao 	struct amdgpu_mes_gang_properties gprops = {0};
1419f1d93c9cSJack Xiao 	int r, j;
1420f1d93c9cSJack Xiao 
1421f1d93c9cSJack Xiao 	/* create a gang for the process */
1422f1d93c9cSJack Xiao 	gprops.priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
1423f1d93c9cSJack Xiao 	gprops.gang_quantum = adev->mes.default_gang_quantum;
1424f1d93c9cSJack Xiao 	gprops.inprocess_gang_priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
1425f1d93c9cSJack Xiao 	gprops.priority_level = AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
1426f1d93c9cSJack Xiao 	gprops.global_priority_level = AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
1427f1d93c9cSJack Xiao 
1428f1d93c9cSJack Xiao 	r = amdgpu_mes_add_gang(adev, pasid, &gprops, gang_id);
1429f1d93c9cSJack Xiao 	if (r) {
1430f1d93c9cSJack Xiao 		DRM_ERROR("failed to add gang\n");
1431f1d93c9cSJack Xiao 		return r;
1432f1d93c9cSJack Xiao 	}
1433f1d93c9cSJack Xiao 
1434f1d93c9cSJack Xiao 	/* create queues for the gang */
1435f1d93c9cSJack Xiao 	for (j = 0; j < num_queue; j++) {
1436f1d93c9cSJack Xiao 		r = amdgpu_mes_add_ring(adev, *gang_id, queue_type, j,
1437f1d93c9cSJack Xiao 					ctx_data, &ring);
1438f1d93c9cSJack Xiao 		if (r) {
1439f1d93c9cSJack Xiao 			DRM_ERROR("failed to add ring\n");
1440f1d93c9cSJack Xiao 			break;
1441f1d93c9cSJack Xiao 		}
1442f1d93c9cSJack Xiao 
1443f1d93c9cSJack Xiao 		DRM_INFO("ring %s was added\n", ring->name);
1444f1d93c9cSJack Xiao 		added_rings[j] = ring;
1445f1d93c9cSJack Xiao 	}
1446f1d93c9cSJack Xiao 
1447f1d93c9cSJack Xiao 	return 0;
1448f1d93c9cSJack Xiao }
1449cdb7476dSJack Xiao 
amdgpu_mes_test_queues(struct amdgpu_ring ** added_rings)1450cdb7476dSJack Xiao static int amdgpu_mes_test_queues(struct amdgpu_ring **added_rings)
1451cdb7476dSJack Xiao {
1452cdb7476dSJack Xiao 	struct amdgpu_ring *ring;
1453cdb7476dSJack Xiao 	int i, r;
1454cdb7476dSJack Xiao 
1455cdb7476dSJack Xiao 	for (i = 0; i < AMDGPU_MES_CTX_MAX_RINGS; i++) {
1456cdb7476dSJack Xiao 		ring = added_rings[i];
1457cdb7476dSJack Xiao 		if (!ring)
1458cdb7476dSJack Xiao 			continue;
1459cdb7476dSJack Xiao 
146093ab59acSGuchun Chen 		r = amdgpu_ring_test_helper(ring);
146193ab59acSGuchun Chen 		if (r)
1462cdb7476dSJack Xiao 			return r;
1463cdb7476dSJack Xiao 
1464cdb7476dSJack Xiao 		r = amdgpu_ring_test_ib(ring, 1000 * 10);
1465cdb7476dSJack Xiao 		if (r) {
1466cdb7476dSJack Xiao 			DRM_DEV_ERROR(ring->adev->dev,
1467cdb7476dSJack Xiao 				      "ring %s ib test failed (%d)\n",
1468cdb7476dSJack Xiao 				      ring->name, r);
1469cdb7476dSJack Xiao 			return r;
1470cdb7476dSJack Xiao 		} else
1471cdb7476dSJack Xiao 			DRM_INFO("ring %s ib test pass\n", ring->name);
1472cdb7476dSJack Xiao 	}
1473cdb7476dSJack Xiao 
1474cdb7476dSJack Xiao 	return 0;
1475cdb7476dSJack Xiao }
14766624d161SJack Xiao 
amdgpu_mes_self_test(struct amdgpu_device * adev)14776624d161SJack Xiao int amdgpu_mes_self_test(struct amdgpu_device *adev)
14786624d161SJack Xiao {
14796624d161SJack Xiao 	struct amdgpu_vm *vm = NULL;
14806624d161SJack Xiao 	struct amdgpu_mes_ctx_data ctx_data = {0};
14816624d161SJack Xiao 	struct amdgpu_ring *added_rings[AMDGPU_MES_CTX_MAX_RINGS] = { NULL };
14826624d161SJack Xiao 	int gang_ids[3] = {0};
14835ee33d90SJack Xiao 	int queue_types[][2] = { { AMDGPU_RING_TYPE_GFX, 1 },
14845ee33d90SJack Xiao 				 { AMDGPU_RING_TYPE_COMPUTE, 1 },
14855ee33d90SJack Xiao 				 { AMDGPU_RING_TYPE_SDMA, 1} };
14866624d161SJack Xiao 	int i, r, pasid, k = 0;
14876624d161SJack Xiao 
14886624d161SJack Xiao 	pasid = amdgpu_pasid_alloc(16);
14896624d161SJack Xiao 	if (pasid < 0) {
14906624d161SJack Xiao 		dev_warn(adev->dev, "No more PASIDs available!");
14916624d161SJack Xiao 		pasid = 0;
14926624d161SJack Xiao 	}
14936624d161SJack Xiao 
14946624d161SJack Xiao 	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
14956624d161SJack Xiao 	if (!vm) {
14966624d161SJack Xiao 		r = -ENOMEM;
14976624d161SJack Xiao 		goto error_pasid;
14986624d161SJack Xiao 	}
14996624d161SJack Xiao 
15005003ca63SGuchun Chen 	r = amdgpu_vm_init(adev, vm, -1);
15016624d161SJack Xiao 	if (r) {
15026624d161SJack Xiao 		DRM_ERROR("failed to initialize vm\n");
15036624d161SJack Xiao 		goto error_pasid;
15046624d161SJack Xiao 	}
15056624d161SJack Xiao 
15066624d161SJack Xiao 	r = amdgpu_mes_ctx_alloc_meta_data(adev, &ctx_data);
15076624d161SJack Xiao 	if (r) {
15086624d161SJack Xiao 		DRM_ERROR("failed to alloc ctx meta data\n");
1509c3c48339SJianglei Nie 		goto error_fini;
15106624d161SJack Xiao 	}
15116624d161SJack Xiao 
151200a11f97SArunpravin Paneer Selvam 	ctx_data.meta_data_gpu_addr = AMDGPU_VA_RESERVED_BOTTOM;
15137c18b40eSJack Xiao 	r = amdgpu_mes_ctx_map_meta_data(adev, vm, &ctx_data);
15146624d161SJack Xiao 	if (r) {
15156624d161SJack Xiao 		DRM_ERROR("failed to map ctx meta data\n");
15166624d161SJack Xiao 		goto error_vm;
15176624d161SJack Xiao 	}
15186624d161SJack Xiao 
15196624d161SJack Xiao 	r = amdgpu_mes_create_process(adev, pasid, vm);
15206624d161SJack Xiao 	if (r) {
15216624d161SJack Xiao 		DRM_ERROR("failed to create MES process\n");
15226624d161SJack Xiao 		goto error_vm;
15236624d161SJack Xiao 	}
15246624d161SJack Xiao 
15256624d161SJack Xiao 	for (i = 0; i < ARRAY_SIZE(queue_types); i++) {
152618ee4ce6SJack Xiao 		/* On GFX v10.3, fw hasn't supported to map sdma queue. */
15274e8303cfSLijo Lazar 		if (amdgpu_ip_version(adev, GC_HWIP, 0) >=
15284e8303cfSLijo Lazar 			    IP_VERSION(10, 3, 0) &&
15294e8303cfSLijo Lazar 		    amdgpu_ip_version(adev, GC_HWIP, 0) <
15304e8303cfSLijo Lazar 			    IP_VERSION(11, 0, 0) &&
153118ee4ce6SJack Xiao 		    queue_types[i][0] == AMDGPU_RING_TYPE_SDMA)
1532da1c0338SJack Xiao 			continue;
1533da1c0338SJack Xiao 
15346624d161SJack Xiao 		r = amdgpu_mes_test_create_gang_and_queues(adev, pasid,
15356624d161SJack Xiao 							   &gang_ids[i],
15366624d161SJack Xiao 							   queue_types[i][0],
15376624d161SJack Xiao 							   queue_types[i][1],
15386624d161SJack Xiao 							   &added_rings[k],
15396624d161SJack Xiao 							   &ctx_data);
15406624d161SJack Xiao 		if (r)
15416624d161SJack Xiao 			goto error_queues;
15426624d161SJack Xiao 
15436624d161SJack Xiao 		k += queue_types[i][1];
15446624d161SJack Xiao 	}
15456624d161SJack Xiao 
15466624d161SJack Xiao 	/* start ring test and ib test for MES queues */
15476624d161SJack Xiao 	amdgpu_mes_test_queues(added_rings);
15486624d161SJack Xiao 
15496624d161SJack Xiao error_queues:
15506624d161SJack Xiao 	/* remove all queues */
15516624d161SJack Xiao 	for (i = 0; i < ARRAY_SIZE(added_rings); i++) {
15526624d161SJack Xiao 		if (!added_rings[i])
15536624d161SJack Xiao 			continue;
15546624d161SJack Xiao 		amdgpu_mes_remove_ring(adev, added_rings[i]);
15556624d161SJack Xiao 	}
15566624d161SJack Xiao 
15576624d161SJack Xiao 	for (i = 0; i < ARRAY_SIZE(gang_ids); i++) {
15586624d161SJack Xiao 		if (!gang_ids[i])
15596624d161SJack Xiao 			continue;
15606624d161SJack Xiao 		amdgpu_mes_remove_gang(adev, gang_ids[i]);
15616624d161SJack Xiao 	}
15626624d161SJack Xiao 
15636624d161SJack Xiao 	amdgpu_mes_destroy_process(adev, pasid);
15646624d161SJack Xiao 
15656624d161SJack Xiao error_vm:
1566737dad0bSJack Xiao 	amdgpu_mes_ctx_unmap_meta_data(adev, &ctx_data);
1567c3c48339SJianglei Nie 
1568c3c48339SJianglei Nie error_fini:
15696624d161SJack Xiao 	amdgpu_vm_fini(adev, vm);
15706624d161SJack Xiao 
15716624d161SJack Xiao error_pasid:
15726624d161SJack Xiao 	if (pasid)
15736624d161SJack Xiao 		amdgpu_pasid_free(pasid);
15746624d161SJack Xiao 
15756624d161SJack Xiao 	amdgpu_mes_ctx_free_meta_data(&ctx_data);
15766624d161SJack Xiao 	kfree(vm);
15776624d161SJack Xiao 	return 0;
15786624d161SJack Xiao }
1579cc42e76eSMario Limonciello 
amdgpu_mes_init_microcode(struct amdgpu_device * adev,int pipe)1580cc42e76eSMario Limonciello int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe)
1581cc42e76eSMario Limonciello {
1582cc42e76eSMario Limonciello 	const struct mes_firmware_header_v1_0 *mes_hdr;
1583cc42e76eSMario Limonciello 	struct amdgpu_firmware_info *info;
1584cc42e76eSMario Limonciello 	char ucode_prefix[30];
158520fd1446SSrinivasan Shanmugam 	char fw_name[50];
158697998b89SJack Xiao 	bool need_retry = false;
1587e89bd361SAlex Deucher 	u32 *ucode_ptr;
1588cc42e76eSMario Limonciello 	int r;
1589cc42e76eSMario Limonciello 
159097998b89SJack Xiao 	amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix,
159197998b89SJack Xiao 				       sizeof(ucode_prefix));
1592e69c2dd7SJack Xiao 	if (adev->enable_uni_mes) {
159315ddc4e6SJack Xiao 		snprintf(fw_name, sizeof(fw_name),
159415ddc4e6SJack Xiao 			 "amdgpu/%s_uni_mes.bin", ucode_prefix);
159515ddc4e6SJack Xiao 	} else if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(11, 0, 0) &&
159669d4c44eSLikun Gao 	    amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(12, 0, 0)) {
159797998b89SJack Xiao 		snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin",
159897998b89SJack Xiao 			 ucode_prefix,
159997998b89SJack Xiao 			 pipe == AMDGPU_MES_SCHED_PIPE ? "_2" : "1");
160097998b89SJack Xiao 		need_retry = true;
160197998b89SJack Xiao 	} else {
1602cc42e76eSMario Limonciello 		snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin",
1603cc42e76eSMario Limonciello 			 ucode_prefix,
1604cc42e76eSMario Limonciello 			 pipe == AMDGPU_MES_SCHED_PIPE ? "" : "1");
160597998b89SJack Xiao 	}
160697998b89SJack Xiao 
1607ea5d4934SMario Limonciello 	r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], AMDGPU_UCODE_REQUIRED,
1608ea5d4934SMario Limonciello 				 "%s", fw_name);
160997998b89SJack Xiao 	if (r && need_retry && pipe == AMDGPU_MES_SCHED_PIPE) {
1610bf349b03SYang Wang 		dev_info(adev->dev, "try to fall back to %s_mes.bin\n", ucode_prefix);
161197998b89SJack Xiao 		r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe],
1612ea5d4934SMario Limonciello 					 AMDGPU_UCODE_REQUIRED,
1613bf349b03SYang Wang 					 "amdgpu/%s_mes.bin", ucode_prefix);
161497998b89SJack Xiao 	}
161597998b89SJack Xiao 
1616cc42e76eSMario Limonciello 	if (r)
1617cc42e76eSMario Limonciello 		goto out;
1618cc42e76eSMario Limonciello 
1619cc42e76eSMario Limonciello 	mes_hdr = (const struct mes_firmware_header_v1_0 *)
1620cc42e76eSMario Limonciello 		adev->mes.fw[pipe]->data;
1621cc42e76eSMario Limonciello 	adev->mes.uc_start_addr[pipe] =
1622cc42e76eSMario Limonciello 		le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) |
1623cc42e76eSMario Limonciello 		((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32);
1624cc42e76eSMario Limonciello 	adev->mes.data_start_addr[pipe] =
1625cc42e76eSMario Limonciello 		le32_to_cpu(mes_hdr->mes_data_start_addr_lo) |
1626cc42e76eSMario Limonciello 		((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32);
1627e89bd361SAlex Deucher 	ucode_ptr = (u32 *)(adev->mes.fw[pipe]->data +
1628e89bd361SAlex Deucher 			  sizeof(union amdgpu_firmware_header));
1629e89bd361SAlex Deucher 	adev->mes.fw_version[pipe] =
1630e89bd361SAlex Deucher 		le32_to_cpu(ucode_ptr[24]) & AMDGPU_MES_VERSION_MASK;
1631cc42e76eSMario Limonciello 
1632cc42e76eSMario Limonciello 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
1633cc42e76eSMario Limonciello 		int ucode, ucode_data;
1634cc42e76eSMario Limonciello 
1635cc42e76eSMario Limonciello 		if (pipe == AMDGPU_MES_SCHED_PIPE) {
1636cc42e76eSMario Limonciello 			ucode = AMDGPU_UCODE_ID_CP_MES;
1637cc42e76eSMario Limonciello 			ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA;
1638cc42e76eSMario Limonciello 		} else {
1639cc42e76eSMario Limonciello 			ucode = AMDGPU_UCODE_ID_CP_MES1;
1640cc42e76eSMario Limonciello 			ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA;
1641cc42e76eSMario Limonciello 		}
1642cc42e76eSMario Limonciello 
1643cc42e76eSMario Limonciello 		info = &adev->firmware.ucode[ucode];
1644cc42e76eSMario Limonciello 		info->ucode_id = ucode;
1645cc42e76eSMario Limonciello 		info->fw = adev->mes.fw[pipe];
1646cc42e76eSMario Limonciello 		adev->firmware.fw_size +=
1647cc42e76eSMario Limonciello 			ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes),
1648cc42e76eSMario Limonciello 			      PAGE_SIZE);
1649cc42e76eSMario Limonciello 
1650cc42e76eSMario Limonciello 		info = &adev->firmware.ucode[ucode_data];
1651cc42e76eSMario Limonciello 		info->ucode_id = ucode_data;
1652cc42e76eSMario Limonciello 		info->fw = adev->mes.fw[pipe];
1653cc42e76eSMario Limonciello 		adev->firmware.fw_size +=
1654cc42e76eSMario Limonciello 			ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes),
1655cc42e76eSMario Limonciello 			      PAGE_SIZE);
1656cc42e76eSMario Limonciello 	}
1657cc42e76eSMario Limonciello 
1658cc42e76eSMario Limonciello 	return 0;
1659cc42e76eSMario Limonciello out:
166011e0b006SMario Limonciello 	amdgpu_ucode_release(&adev->mes.fw[pipe]);
1661cc42e76eSMario Limonciello 	return r;
1662cc42e76eSMario Limonciello }
1663b2662d4cSshaoyunl 
amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device * adev)1664ccf8ef6bSMukul Joshi bool amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device *adev)
1665ccf8ef6bSMukul Joshi {
1666ccf8ef6bSMukul Joshi 	uint32_t mes_rev = adev->mes.sched_version & AMDGPU_MES_VERSION_MASK;
1667ccf8ef6bSMukul Joshi 	bool is_supported = false;
1668ccf8ef6bSMukul Joshi 
1669ccf8ef6bSMukul Joshi 	if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(11, 0, 0) &&
1670ccf8ef6bSMukul Joshi 	    amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(12, 0, 0) &&
1671ccf8ef6bSMukul Joshi 	    mes_rev >= 0x63)
1672ccf8ef6bSMukul Joshi 		is_supported = true;
1673ccf8ef6bSMukul Joshi 
1674ccf8ef6bSMukul Joshi 	return is_supported;
1675ccf8ef6bSMukul Joshi }
1676ccf8ef6bSMukul Joshi 
16778521e3c5SShaoyun Liu /* Fix me -- node_id is used to identify the correct MES instances in the future */
amdgpu_mes_set_enforce_isolation(struct amdgpu_device * adev,uint32_t node_id,bool enable)167827b79151SAlex Deucher static int amdgpu_mes_set_enforce_isolation(struct amdgpu_device *adev,
167927b79151SAlex Deucher 					    uint32_t node_id, bool enable)
16808521e3c5SShaoyun Liu {
16818521e3c5SShaoyun Liu 	struct mes_misc_op_input op_input = {0};
16828521e3c5SShaoyun Liu 	int r;
16838521e3c5SShaoyun Liu 
16848521e3c5SShaoyun Liu 	op_input.op = MES_MISC_OP_CHANGE_CONFIG;
16858521e3c5SShaoyun Liu 	op_input.change_config.option.limit_single_process = enable ? 1 : 0;
16868521e3c5SShaoyun Liu 
16878521e3c5SShaoyun Liu 	if (!adev->mes.funcs->misc_op) {
16888521e3c5SShaoyun Liu 		dev_err(adev->dev, "mes change config is not supported!\n");
16898521e3c5SShaoyun Liu 		r = -EINVAL;
16908521e3c5SShaoyun Liu 		goto error;
16918521e3c5SShaoyun Liu 	}
16928521e3c5SShaoyun Liu 
16938521e3c5SShaoyun Liu 	r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
16948521e3c5SShaoyun Liu 	if (r)
16958521e3c5SShaoyun Liu 		dev_err(adev->dev, "failed to change_config.\n");
16968521e3c5SShaoyun Liu 
16978521e3c5SShaoyun Liu error:
16988521e3c5SShaoyun Liu 	return r;
16998521e3c5SShaoyun Liu }
17008521e3c5SShaoyun Liu 
amdgpu_mes_update_enforce_isolation(struct amdgpu_device * adev)170127b79151SAlex Deucher int amdgpu_mes_update_enforce_isolation(struct amdgpu_device *adev)
170227b79151SAlex Deucher {
170327b79151SAlex Deucher 	int i, r = 0;
170427b79151SAlex Deucher 
170527b79151SAlex Deucher 	if (adev->enable_mes && adev->gfx.enable_cleaner_shader) {
170627b79151SAlex Deucher 		mutex_lock(&adev->enforce_isolation_mutex);
170727b79151SAlex Deucher 		for (i = 0; i < (adev->xcp_mgr ? adev->xcp_mgr->num_xcps : 1); i++) {
170827b79151SAlex Deucher 			if (adev->enforce_isolation[i])
170927b79151SAlex Deucher 				r |= amdgpu_mes_set_enforce_isolation(adev, i, true);
171027b79151SAlex Deucher 			else
171127b79151SAlex Deucher 				r |= amdgpu_mes_set_enforce_isolation(adev, i, false);
171227b79151SAlex Deucher 		}
171327b79151SAlex Deucher 		mutex_unlock(&adev->enforce_isolation_mutex);
171427b79151SAlex Deucher 	}
171527b79151SAlex Deucher 	return r;
171627b79151SAlex Deucher }
171727b79151SAlex Deucher 
1718b2662d4cSshaoyunl #if defined(CONFIG_DEBUG_FS)
1719b2662d4cSshaoyunl 
amdgpu_debugfs_mes_event_log_show(struct seq_file * m,void * unused)1720b2662d4cSshaoyunl static int amdgpu_debugfs_mes_event_log_show(struct seq_file *m, void *unused)
1721b2662d4cSshaoyunl {
1722b2662d4cSshaoyunl 	struct amdgpu_device *adev = m->private;
1723b2662d4cSshaoyunl 	uint32_t *mem = (uint32_t *)(adev->mes.event_log_cpu_addr);
1724b2662d4cSshaoyunl 
1725b2662d4cSshaoyunl 	seq_hex_dump(m, "", DUMP_PREFIX_OFFSET, 32, 4,
1726739d0f3eSMichael Chen 		     mem, adev->mes.event_log_size, false);
1727b2662d4cSshaoyunl 
1728b2662d4cSshaoyunl 	return 0;
1729b2662d4cSshaoyunl }
1730b2662d4cSshaoyunl 
1731b2662d4cSshaoyunl DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_mes_event_log);
1732b2662d4cSshaoyunl 
1733b2662d4cSshaoyunl #endif
1734b2662d4cSshaoyunl 
amdgpu_debugfs_mes_event_log_init(struct amdgpu_device * adev)1735b2662d4cSshaoyunl void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev)
1736b2662d4cSshaoyunl {
1737b2662d4cSshaoyunl 
1738b2662d4cSshaoyunl #if defined(CONFIG_DEBUG_FS)
1739b2662d4cSshaoyunl 	struct drm_minor *minor = adev_to_drm(adev)->primary;
1740b2662d4cSshaoyunl 	struct dentry *root = minor->debugfs_root;
1741e58acb76Sshaoyunl 	if (adev->enable_mes && amdgpu_mes_log_enable)
1742b2662d4cSshaoyunl 		debugfs_create_file("amdgpu_mes_event_log", 0444, root,
1743b2662d4cSshaoyunl 				    adev, &amdgpu_debugfs_mes_event_log_fops);
1744b2662d4cSshaoyunl 
1745b2662d4cSshaoyunl #endif
1746b2662d4cSshaoyunl }
1747