xref: /linux/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c (revision 994aeacbb3c039b4f3e02e76e6d39407920e76c6)
1d87f36a0SRajneesh Bhardwaj // SPDX-License-Identifier: GPL-2.0 OR MIT
264c7f8cfSBen Goz /*
3d87f36a0SRajneesh Bhardwaj  * Copyright 2014-2022 Advanced Micro Devices, Inc.
464c7f8cfSBen Goz  *
564c7f8cfSBen Goz  * Permission is hereby granted, free of charge, to any person obtaining a
664c7f8cfSBen Goz  * copy of this software and associated documentation files (the "Software"),
764c7f8cfSBen Goz  * to deal in the Software without restriction, including without limitation
864c7f8cfSBen Goz  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
964c7f8cfSBen Goz  * and/or sell copies of the Software, and to permit persons to whom the
1064c7f8cfSBen Goz  * Software is furnished to do so, subject to the following conditions:
1164c7f8cfSBen Goz  *
1264c7f8cfSBen Goz  * The above copyright notice and this permission notice shall be included in
1364c7f8cfSBen Goz  * all copies or substantial portions of the Software.
1464c7f8cfSBen Goz  *
1564c7f8cfSBen Goz  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1664c7f8cfSBen Goz  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1764c7f8cfSBen Goz  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1864c7f8cfSBen Goz  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1964c7f8cfSBen Goz  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2064c7f8cfSBen Goz  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2164c7f8cfSBen Goz  * OTHER DEALINGS IN THE SOFTWARE.
2264c7f8cfSBen Goz  *
2364c7f8cfSBen Goz  */
2464c7f8cfSBen Goz 
2526103436SFelix Kuehling #include <linux/ratelimit.h>
2626103436SFelix Kuehling #include <linux/printk.h>
2764c7f8cfSBen Goz #include <linux/slab.h>
2864c7f8cfSBen Goz #include <linux/list.h>
2964c7f8cfSBen Goz #include <linux/types.h>
3064c7f8cfSBen Goz #include <linux/bitops.h>
3199331a51SOded Gabbay #include <linux/sched.h>
3264c7f8cfSBen Goz #include "kfd_priv.h"
3364c7f8cfSBen Goz #include "kfd_device_queue_manager.h"
3464c7f8cfSBen Goz #include "kfd_mqd_manager.h"
3564c7f8cfSBen Goz #include "cik_regs.h"
3664c7f8cfSBen Goz #include "kfd_kernel_queue.h"
375b87245fSAmber Lin #include "amdgpu_amdkfd.h"
381802b042SYunxiang Li #include "amdgpu_reset.h"
39f2a1fbddSAlex Deucher #include "mes_v11_api_def.h"
400de4ec9aSJonathan Kim #include "kfd_debug.h"
4164c7f8cfSBen Goz 
4264c7f8cfSBen Goz /* Size of the per-pipe EOP queue */
4364c7f8cfSBen Goz #define CIK_HPD_EOP_BYTES_LOG2 11
4464c7f8cfSBen Goz #define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
4564c7f8cfSBen Goz 
4664c7f8cfSBen Goz static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,
47c7b6bac9SFenghua Yu 				  u32 pasid, unsigned int vmid);
4864c7f8cfSBen Goz 
49c4744e24SYong Zhao static int execute_queues_cpsch(struct device_queue_manager *dqm,
50c4744e24SYong Zhao 				enum kfd_unmap_queues_filter filter,
517cee6a68SJonathan Kim 				uint32_t filter_param,
527cee6a68SJonathan Kim 				uint32_t grace_period);
537da2bcf8SYong Zhao static int unmap_queues_cpsch(struct device_queue_manager *dqm,
544465f466SYong Zhao 				enum kfd_unmap_queues_filter filter,
557cee6a68SJonathan Kim 				uint32_t filter_param,
567cee6a68SJonathan Kim 				uint32_t grace_period,
577cee6a68SJonathan Kim 				bool reset);
5864c7f8cfSBen Goz 
5960a00956SFelix Kuehling static int map_queues_cpsch(struct device_queue_manager *dqm);
6060a00956SFelix Kuehling 
61bcea3081SBen Goz static void deallocate_sdma_queue(struct device_queue_manager *dqm,
621b4670f6SOak Zeng 				struct queue *q);
63bcea3081SBen Goz 
64d39b7737SOak Zeng static inline void deallocate_hqd(struct device_queue_manager *dqm,
65d39b7737SOak Zeng 				struct queue *q);
66d39b7737SOak Zeng static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q);
67d39b7737SOak Zeng static int allocate_sdma_queue(struct device_queue_manager *dqm,
682485c12cSDavid Yat Sin 				struct queue *q, const uint32_t *restore_sdma_id);
6973ea648dSShaoyun Liu static void kfd_process_hw_exception(struct work_struct *work);
7073ea648dSShaoyun Liu 
71bcea3081SBen Goz static inline
get_mqd_type_from_queue_type(enum kfd_queue_type type)72bcea3081SBen Goz enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)
7364c7f8cfSBen Goz {
741b4670f6SOak Zeng 	if (type == KFD_QUEUE_TYPE_SDMA || type == KFD_QUEUE_TYPE_SDMA_XGMI)
7585d258f9SBen Goz 		return KFD_MQD_TYPE_SDMA;
7685d258f9SBen Goz 	return KFD_MQD_TYPE_CP;
7764c7f8cfSBen Goz }
7864c7f8cfSBen Goz 
is_pipe_enabled(struct device_queue_manager * dqm,int mec,int pipe)79d0b63bb3SAndres Rodriguez static bool is_pipe_enabled(struct device_queue_manager *dqm, int mec, int pipe)
8064c7f8cfSBen Goz {
81d0b63bb3SAndres Rodriguez 	int i;
828dc1db31SMukul Joshi 	int pipe_offset = (mec * dqm->dev->kfd->shared_resources.num_pipe_per_mec
838dc1db31SMukul Joshi 		+ pipe) * dqm->dev->kfd->shared_resources.num_queue_per_pipe;
84d0b63bb3SAndres Rodriguez 
85d0b63bb3SAndres Rodriguez 	/* queue is available for KFD usage if bit is 1 */
868dc1db31SMukul Joshi 	for (i = 0; i <  dqm->dev->kfd->shared_resources.num_queue_per_pipe; ++i)
87d0b63bb3SAndres Rodriguez 		if (test_bit(pipe_offset + i,
888dc1db31SMukul Joshi 			      dqm->dev->kfd->shared_resources.cp_queue_bitmap))
89d0b63bb3SAndres Rodriguez 			return true;
90d0b63bb3SAndres Rodriguez 	return false;
9164c7f8cfSBen Goz }
9264c7f8cfSBen Goz 
get_cp_queues_num(struct device_queue_manager * dqm)93e6945304SYong Zhao unsigned int get_cp_queues_num(struct device_queue_manager *dqm)
9464c7f8cfSBen Goz {
958dc1db31SMukul Joshi 	return bitmap_weight(dqm->dev->kfd->shared_resources.cp_queue_bitmap,
9668fa72a4SMukul Joshi 				AMDGPU_MAX_QUEUES);
97d0b63bb3SAndres Rodriguez }
98d0b63bb3SAndres Rodriguez 
get_queues_per_pipe(struct device_queue_manager * dqm)99d0b63bb3SAndres Rodriguez unsigned int get_queues_per_pipe(struct device_queue_manager *dqm)
100d0b63bb3SAndres Rodriguez {
1018dc1db31SMukul Joshi 	return dqm->dev->kfd->shared_resources.num_queue_per_pipe;
102d0b63bb3SAndres Rodriguez }
103d0b63bb3SAndres Rodriguez 
get_pipes_per_mec(struct device_queue_manager * dqm)104d0b63bb3SAndres Rodriguez unsigned int get_pipes_per_mec(struct device_queue_manager *dqm)
105d0b63bb3SAndres Rodriguez {
1068dc1db31SMukul Joshi 	return dqm->dev->kfd->shared_resources.num_pipe_per_mec;
10764c7f8cfSBen Goz }
10864c7f8cfSBen Goz 
get_num_all_sdma_engines(struct device_queue_manager * dqm)109c7637c95SYong Zhao static unsigned int get_num_all_sdma_engines(struct device_queue_manager *dqm)
110c7637c95SYong Zhao {
111ee2f17f4SAmber Lin 	return kfd_get_num_sdma_engines(dqm->dev) +
112ee2f17f4SAmber Lin 		kfd_get_num_xgmi_sdma_engines(dqm->dev);
113c7637c95SYong Zhao }
114c7637c95SYong Zhao 
get_num_sdma_queues(struct device_queue_manager * dqm)11598bb9222SYong Zhao unsigned int get_num_sdma_queues(struct device_queue_manager *dqm)
11698bb9222SYong Zhao {
117ee2f17f4SAmber Lin 	return kfd_get_num_sdma_engines(dqm->dev) *
1188dc1db31SMukul Joshi 		dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
11998bb9222SYong Zhao }
12098bb9222SYong Zhao 
get_num_xgmi_sdma_queues(struct device_queue_manager * dqm)1211b4670f6SOak Zeng unsigned int get_num_xgmi_sdma_queues(struct device_queue_manager *dqm)
1221b4670f6SOak Zeng {
123ee2f17f4SAmber Lin 	return kfd_get_num_xgmi_sdma_engines(dqm->dev) *
1248dc1db31SMukul Joshi 		dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
1251b4670f6SOak Zeng }
1261b4670f6SOak Zeng 
init_sdma_bitmaps(struct device_queue_manager * dqm)127a805889aSMukul Joshi static void init_sdma_bitmaps(struct device_queue_manager *dqm)
128a805889aSMukul Joshi {
129a805889aSMukul Joshi 	bitmap_zero(dqm->sdma_bitmap, KFD_MAX_SDMA_QUEUES);
130a805889aSMukul Joshi 	bitmap_set(dqm->sdma_bitmap, 0, get_num_sdma_queues(dqm));
131a805889aSMukul Joshi 
132a805889aSMukul Joshi 	bitmap_zero(dqm->xgmi_sdma_bitmap, KFD_MAX_SDMA_QUEUES);
133a805889aSMukul Joshi 	bitmap_set(dqm->xgmi_sdma_bitmap, 0, get_num_xgmi_sdma_queues(dqm));
134597364adSMukul Joshi 
135597364adSMukul Joshi 	/* Mask out the reserved queues */
136597364adSMukul Joshi 	bitmap_andnot(dqm->sdma_bitmap, dqm->sdma_bitmap,
137597364adSMukul Joshi 		      dqm->dev->kfd->device_info.reserved_sdma_queues_bitmap,
138597364adSMukul Joshi 		      KFD_MAX_SDMA_QUEUES);
139a805889aSMukul Joshi }
140a805889aSMukul Joshi 
program_sh_mem_settings(struct device_queue_manager * dqm,struct qcm_process_device * qpd)141a22fc854SBen Goz void program_sh_mem_settings(struct device_queue_manager *dqm,
14264c7f8cfSBen Goz 					struct qcm_process_device *qpd)
14364c7f8cfSBen Goz {
144c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
145c4050ff1SLijo Lazar 	int xcc_id;
146e2069a7bSMukul Joshi 
147c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask)
148e2069a7bSMukul Joshi 		dqm->dev->kfd2kgd->program_sh_mem_settings(
149c4050ff1SLijo Lazar 			dqm->dev->adev, qpd->vmid, qpd->sh_mem_config,
150c4050ff1SLijo Lazar 			qpd->sh_mem_ape1_base, qpd->sh_mem_ape1_limit,
151c4050ff1SLijo Lazar 			qpd->sh_mem_bases, xcc_id);
15264c7f8cfSBen Goz }
15364c7f8cfSBen Goz 
kfd_hws_hang(struct device_queue_manager * dqm)154cc009e61SMukul Joshi static void kfd_hws_hang(struct device_queue_manager *dqm)
155cc009e61SMukul Joshi {
156ee0a469cSJonathan Kim 	struct device_process_node *cur;
157ee0a469cSJonathan Kim 	struct qcm_process_device *qpd;
158ee0a469cSJonathan Kim 	struct queue *q;
159ee0a469cSJonathan Kim 
160ee0a469cSJonathan Kim 	/* Mark all device queues as reset. */
161ee0a469cSJonathan Kim 	list_for_each_entry(cur, &dqm->queues, list) {
162ee0a469cSJonathan Kim 		qpd = cur->qpd;
163ee0a469cSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
164ee0a469cSJonathan Kim 			struct kfd_process_device *pdd = qpd_to_pdd(qpd);
165ee0a469cSJonathan Kim 
166ee0a469cSJonathan Kim 			pdd->has_reset_queue = true;
167ee0a469cSJonathan Kim 		}
168ee0a469cSJonathan Kim 	}
169ee0a469cSJonathan Kim 
170cc009e61SMukul Joshi 	/*
171cc009e61SMukul Joshi 	 * Issue a GPU reset if HWS is unresponsive
172cc009e61SMukul Joshi 	 */
173cc009e61SMukul Joshi 	schedule_work(&dqm->hw_exception_work);
174cc009e61SMukul Joshi }
175cc009e61SMukul Joshi 
convert_to_mes_queue_type(int queue_type)176cc009e61SMukul Joshi static int convert_to_mes_queue_type(int queue_type)
177cc009e61SMukul Joshi {
178cc009e61SMukul Joshi 	int mes_queue_type;
179cc009e61SMukul Joshi 
180cc009e61SMukul Joshi 	switch (queue_type) {
181cc009e61SMukul Joshi 	case KFD_QUEUE_TYPE_COMPUTE:
182cc009e61SMukul Joshi 		mes_queue_type = MES_QUEUE_TYPE_COMPUTE;
183cc009e61SMukul Joshi 		break;
184cc009e61SMukul Joshi 	case KFD_QUEUE_TYPE_SDMA:
185cc009e61SMukul Joshi 		mes_queue_type = MES_QUEUE_TYPE_SDMA;
186cc009e61SMukul Joshi 		break;
187cc009e61SMukul Joshi 	default:
188cc009e61SMukul Joshi 		WARN(1, "Invalid queue type %d", queue_type);
189cc009e61SMukul Joshi 		mes_queue_type = -EINVAL;
190cc009e61SMukul Joshi 		break;
191cc009e61SMukul Joshi 	}
192cc009e61SMukul Joshi 
193cc009e61SMukul Joshi 	return mes_queue_type;
194cc009e61SMukul Joshi }
195cc009e61SMukul Joshi 
add_queue_mes(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd)196cc009e61SMukul Joshi static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
197cc009e61SMukul Joshi 			 struct qcm_process_device *qpd)
198cc009e61SMukul Joshi {
199cc009e61SMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
200cc009e61SMukul Joshi 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
201cc009e61SMukul Joshi 	struct mes_add_queue_input queue_input;
20204fd0739SGraham Sider 	int r, queue_type;
203e77a541fSGraham Sider 	uint64_t wptr_addr_off;
204cc009e61SMukul Joshi 
2051802b042SYunxiang Li 	if (!down_read_trylock(&adev->reset_domain->sem))
206cc009e61SMukul Joshi 		return -EIO;
207cc009e61SMukul Joshi 
208cc009e61SMukul Joshi 	memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input));
209cc009e61SMukul Joshi 	queue_input.process_id = qpd->pqm->process->pasid;
210cc009e61SMukul Joshi 	queue_input.page_table_base_addr =  qpd->page_table_base;
211cc009e61SMukul Joshi 	queue_input.process_va_start = 0;
212cc009e61SMukul Joshi 	queue_input.process_va_end = adev->vm_manager.max_pfn - 1;
213cc009e61SMukul Joshi 	/* MES unit for quantum is 100ns */
214cc009e61SMukul Joshi 	queue_input.process_quantum = KFD_MES_PROCESS_QUANTUM;  /* Equivalent to 10ms. */
215cc009e61SMukul Joshi 	queue_input.process_context_addr = pdd->proc_ctx_gpu_addr;
216cc009e61SMukul Joshi 	queue_input.gang_quantum = KFD_MES_GANG_QUANTUM; /* Equivalent to 1ms */
217cc009e61SMukul Joshi 	queue_input.gang_context_addr = q->gang_ctx_gpu_addr;
218cc009e61SMukul Joshi 	queue_input.inprocess_gang_priority = q->properties.priority;
219cc009e61SMukul Joshi 	queue_input.gang_global_priority_level =
220cc009e61SMukul Joshi 					AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
221cc009e61SMukul Joshi 	queue_input.doorbell_offset = q->properties.doorbell_off;
222cc009e61SMukul Joshi 	queue_input.mqd_addr = q->gart_mqd_addr;
223fe4e9ff9SJack Xiao 	queue_input.wptr_addr = (uint64_t)q->properties.write_ptr;
224e77a541fSGraham Sider 
2257f347e3fSEric Huang 	wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1);
226fb910658SPhilip Yang 	queue_input.wptr_mc_addr = amdgpu_bo_gpu_offset(q->properties.wptr_bo) + wptr_addr_off;
227e77a541fSGraham Sider 
228a9579956SGraham Sider 	queue_input.is_kfd_process = 1;
2293e9cf234SGraham Sider 	queue_input.is_aql_queue = (q->properties.format == KFD_QUEUE_FORMAT_AQL);
2303e9cf234SGraham Sider 	queue_input.queue_size = q->properties.queue_size >> 2;
231a9579956SGraham Sider 
232cc009e61SMukul Joshi 	queue_input.paging = false;
233cc009e61SMukul Joshi 	queue_input.tba_addr = qpd->tba_addr;
234cc009e61SMukul Joshi 	queue_input.tma_addr = qpd->tma_addr;
235cef600e1SJonathan Kim 	queue_input.trap_en = !kfd_dbg_has_cwsr_workaround(q->device);
236d92e5556SJonathan Kim 	queue_input.skip_process_ctx_clear =
237d92e5556SJonathan Kim 		qpd->pqm->process->runtime_info.runtime_state == DEBUG_RUNTIME_STATE_ENABLED &&
238d92e5556SJonathan Kim 						(qpd->pqm->process->debug_trap_enabled ||
239d92e5556SJonathan Kim 						 kfd_dbg_has_ttmps_always_setup(q->device));
240cc009e61SMukul Joshi 
24104fd0739SGraham Sider 	queue_type = convert_to_mes_queue_type(q->properties.type);
24204fd0739SGraham Sider 	if (queue_type < 0) {
24380c74918SAsad Kamal 		dev_err(adev->dev, "Queue type not supported with MES, queue:%d\n",
244cc009e61SMukul Joshi 			q->properties.type);
24539de69c4SDan Carpenter 		up_read(&adev->reset_domain->sem);
246cc009e61SMukul Joshi 		return -EINVAL;
247cc009e61SMukul Joshi 	}
24804fd0739SGraham Sider 	queue_input.queue_type = (uint32_t)queue_type;
249cc009e61SMukul Joshi 
2507a1c5c67SJonathan Kim 	queue_input.exclusively_scheduled = q->properties.is_gws;
251cc009e61SMukul Joshi 
252cc009e61SMukul Joshi 	amdgpu_mes_lock(&adev->mes);
253cc009e61SMukul Joshi 	r = adev->mes.funcs->add_hw_queue(&adev->mes, &queue_input);
254cc009e61SMukul Joshi 	amdgpu_mes_unlock(&adev->mes);
2551802b042SYunxiang Li 	up_read(&adev->reset_domain->sem);
256cc009e61SMukul Joshi 	if (r) {
25780c74918SAsad Kamal 		dev_err(adev->dev, "failed to add hardware queue to MES, doorbell=0x%x\n",
258cc009e61SMukul Joshi 			q->properties.doorbell_off);
25980c74918SAsad Kamal 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
260cc009e61SMukul Joshi 		kfd_hws_hang(dqm);
261cc009e61SMukul Joshi 	}
262cc009e61SMukul Joshi 
263cc009e61SMukul Joshi 	return r;
264cc009e61SMukul Joshi }
265cc009e61SMukul Joshi 
remove_queue_mes(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd)266cc009e61SMukul Joshi static int remove_queue_mes(struct device_queue_manager *dqm, struct queue *q,
267cc009e61SMukul Joshi 			struct qcm_process_device *qpd)
268cc009e61SMukul Joshi {
269cc009e61SMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
270cc009e61SMukul Joshi 	int r;
271cc009e61SMukul Joshi 	struct mes_remove_queue_input queue_input;
272cc009e61SMukul Joshi 
2731802b042SYunxiang Li 	if (!down_read_trylock(&adev->reset_domain->sem))
274cc009e61SMukul Joshi 		return -EIO;
275cc009e61SMukul Joshi 
276cc009e61SMukul Joshi 	memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input));
277cc009e61SMukul Joshi 	queue_input.doorbell_offset = q->properties.doorbell_off;
278cc009e61SMukul Joshi 	queue_input.gang_context_addr = q->gang_ctx_gpu_addr;
279cc009e61SMukul Joshi 
280cc009e61SMukul Joshi 	amdgpu_mes_lock(&adev->mes);
281cc009e61SMukul Joshi 	r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);
282cc009e61SMukul Joshi 	amdgpu_mes_unlock(&adev->mes);
2831802b042SYunxiang Li 	up_read(&adev->reset_domain->sem);
284cc009e61SMukul Joshi 
285cc009e61SMukul Joshi 	if (r) {
28680c74918SAsad Kamal 		dev_err(adev->dev, "failed to remove hardware queue from MES, doorbell=0x%x\n",
287cc009e61SMukul Joshi 			q->properties.doorbell_off);
28880c74918SAsad Kamal 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
289cc009e61SMukul Joshi 		kfd_hws_hang(dqm);
290cc009e61SMukul Joshi 	}
291cc009e61SMukul Joshi 
292cc009e61SMukul Joshi 	return r;
293cc009e61SMukul Joshi }
294cc009e61SMukul Joshi 
remove_all_queues_mes(struct device_queue_manager * dqm)295cc009e61SMukul Joshi static int remove_all_queues_mes(struct device_queue_manager *dqm)
296cc009e61SMukul Joshi {
297cc009e61SMukul Joshi 	struct device_process_node *cur;
29880c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
299cc009e61SMukul Joshi 	struct qcm_process_device *qpd;
300cc009e61SMukul Joshi 	struct queue *q;
301cc009e61SMukul Joshi 	int retval = 0;
302cc009e61SMukul Joshi 
303cc009e61SMukul Joshi 	list_for_each_entry(cur, &dqm->queues, list) {
304cc009e61SMukul Joshi 		qpd = cur->qpd;
305cc009e61SMukul Joshi 		list_for_each_entry(q, &qpd->queues_list, list) {
306cc009e61SMukul Joshi 			if (q->properties.is_active) {
307cc009e61SMukul Joshi 				retval = remove_queue_mes(dqm, q, qpd);
308cc009e61SMukul Joshi 				if (retval) {
30980c74918SAsad Kamal 					dev_err(dev, "%s: Failed to remove queue %d for dev %d",
310cc009e61SMukul Joshi 						__func__,
311cc009e61SMukul Joshi 						q->properties.queue_id,
312cc009e61SMukul Joshi 						dqm->dev->id);
313cc009e61SMukul Joshi 					return retval;
314cc009e61SMukul Joshi 				}
315cc009e61SMukul Joshi 			}
316cc009e61SMukul Joshi 		}
317cc009e61SMukul Joshi 	}
318cc009e61SMukul Joshi 
319cc009e61SMukul Joshi 	return retval;
320cc009e61SMukul Joshi }
321cc009e61SMukul Joshi 
suspend_all_queues_mes(struct device_queue_manager * dqm)3229a16042fSMukul Joshi static int suspend_all_queues_mes(struct device_queue_manager *dqm)
3239a16042fSMukul Joshi {
3249a16042fSMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
3259a16042fSMukul Joshi 	int r = 0;
3269a16042fSMukul Joshi 
3279a16042fSMukul Joshi 	if (!down_read_trylock(&adev->reset_domain->sem))
3289a16042fSMukul Joshi 		return -EIO;
3299a16042fSMukul Joshi 
3309a16042fSMukul Joshi 	r = amdgpu_mes_suspend(adev);
3319a16042fSMukul Joshi 	up_read(&adev->reset_domain->sem);
3329a16042fSMukul Joshi 
3339a16042fSMukul Joshi 	if (r) {
3349a16042fSMukul Joshi 		dev_err(adev->dev, "failed to suspend gangs from MES\n");
3359a16042fSMukul Joshi 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
3369a16042fSMukul Joshi 		kfd_hws_hang(dqm);
3379a16042fSMukul Joshi 	}
3389a16042fSMukul Joshi 
3399a16042fSMukul Joshi 	return r;
3409a16042fSMukul Joshi }
3419a16042fSMukul Joshi 
resume_all_queues_mes(struct device_queue_manager * dqm)3429a16042fSMukul Joshi static int resume_all_queues_mes(struct device_queue_manager *dqm)
3439a16042fSMukul Joshi {
3449a16042fSMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
3459a16042fSMukul Joshi 	int r = 0;
3469a16042fSMukul Joshi 
3479a16042fSMukul Joshi 	if (!down_read_trylock(&adev->reset_domain->sem))
3489a16042fSMukul Joshi 		return -EIO;
3499a16042fSMukul Joshi 
3509a16042fSMukul Joshi 	r = amdgpu_mes_resume(adev);
3519a16042fSMukul Joshi 	up_read(&adev->reset_domain->sem);
3529a16042fSMukul Joshi 
3539a16042fSMukul Joshi 	if (r) {
3549a16042fSMukul Joshi 		dev_err(adev->dev, "failed to resume gangs from MES\n");
3559a16042fSMukul Joshi 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
3569a16042fSMukul Joshi 		kfd_hws_hang(dqm);
3579a16042fSMukul Joshi 	}
3589a16042fSMukul Joshi 
3599a16042fSMukul Joshi 	return r;
3609a16042fSMukul Joshi }
3619a16042fSMukul Joshi 
increment_queue_count(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)362204d8998SNirmoy Das static void increment_queue_count(struct device_queue_manager *dqm,
363ab4d51d4SDavid Yat Sin 				  struct qcm_process_device *qpd,
364ab4d51d4SDavid Yat Sin 				  struct queue *q)
365b42902f4SYong Zhao {
366b42902f4SYong Zhao 	dqm->active_queue_count++;
367ab4d51d4SDavid Yat Sin 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
368ab4d51d4SDavid Yat Sin 	    q->properties.type == KFD_QUEUE_TYPE_DIQ)
369b42902f4SYong Zhao 		dqm->active_cp_queue_count++;
370ab4d51d4SDavid Yat Sin 
371ab4d51d4SDavid Yat Sin 	if (q->properties.is_gws) {
372ab4d51d4SDavid Yat Sin 		dqm->gws_queue_count++;
373ab4d51d4SDavid Yat Sin 		qpd->mapped_gws_queue = true;
374ab4d51d4SDavid Yat Sin 	}
375b42902f4SYong Zhao }
376b42902f4SYong Zhao 
decrement_queue_count(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)377204d8998SNirmoy Das static void decrement_queue_count(struct device_queue_manager *dqm,
378ab4d51d4SDavid Yat Sin 				  struct qcm_process_device *qpd,
379ab4d51d4SDavid Yat Sin 				  struct queue *q)
380b42902f4SYong Zhao {
381b42902f4SYong Zhao 	dqm->active_queue_count--;
382ab4d51d4SDavid Yat Sin 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
383ab4d51d4SDavid Yat Sin 	    q->properties.type == KFD_QUEUE_TYPE_DIQ)
384b42902f4SYong Zhao 		dqm->active_cp_queue_count--;
385ab4d51d4SDavid Yat Sin 
386ab4d51d4SDavid Yat Sin 	if (q->properties.is_gws) {
387ab4d51d4SDavid Yat Sin 		dqm->gws_queue_count--;
388ab4d51d4SDavid Yat Sin 		qpd->mapped_gws_queue = false;
389ab4d51d4SDavid Yat Sin 	}
390b42902f4SYong Zhao }
391b42902f4SYong Zhao 
3925bb6a8faSDavid Yat Sin /*
3935bb6a8faSDavid Yat Sin  * Allocate a doorbell ID to this queue.
3945bb6a8faSDavid Yat Sin  * If doorbell_id is passed in, make sure requested ID is valid then allocate it.
3955bb6a8faSDavid Yat Sin  */
allocate_doorbell(struct qcm_process_device * qpd,struct queue * q,uint32_t const * restore_id)3965bb6a8faSDavid Yat Sin static int allocate_doorbell(struct qcm_process_device *qpd,
3975bb6a8faSDavid Yat Sin 			     struct queue *q,
3985bb6a8faSDavid Yat Sin 			     uint32_t const *restore_id)
399ef568db7SFelix Kuehling {
4008dc1db31SMukul Joshi 	struct kfd_node *dev = qpd->dqm->dev;
401ef568db7SFelix Kuehling 
402dd0ae064SGraham Sider 	if (!KFD_IS_SOC15(dev)) {
403ef568db7SFelix Kuehling 		/* On pre-SOC15 chips we need to use the queue ID to
404ef568db7SFelix Kuehling 		 * preserve the user mode ABI.
405ef568db7SFelix Kuehling 		 */
4065bb6a8faSDavid Yat Sin 
4075bb6a8faSDavid Yat Sin 		if (restore_id && *restore_id != q->properties.queue_id)
4085bb6a8faSDavid Yat Sin 			return -EINVAL;
4095bb6a8faSDavid Yat Sin 
410ef568db7SFelix Kuehling 		q->doorbell_id = q->properties.queue_id;
4111b4670f6SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
4121b4670f6SOak Zeng 			q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
413234441ddSYong Zhao 		/* For SDMA queues on SOC15 with 8-byte doorbell, use static
414234441ddSYong Zhao 		 * doorbell assignments based on the engine and queue id.
415234441ddSYong Zhao 		 * The doobell index distance between RLC (2*i) and (2*i+1)
416234441ddSYong Zhao 		 * for a SDMA engine is 512.
417ef568db7SFelix Kuehling 		 */
418234441ddSYong Zhao 
4198dc1db31SMukul Joshi 		uint32_t *idx_offset = dev->kfd->shared_resources.sdma_doorbell_idx;
420643e40d4SMukul Joshi 
421643e40d4SMukul Joshi 		/*
422643e40d4SMukul Joshi 		 * q->properties.sdma_engine_id corresponds to the virtual
423643e40d4SMukul Joshi 		 * sdma engine number. However, for doorbell allocation,
424643e40d4SMukul Joshi 		 * we need the physical sdma engine id in order to get the
425643e40d4SMukul Joshi 		 * correct doorbell offset.
426643e40d4SMukul Joshi 		 */
427643e40d4SMukul Joshi 		uint32_t valid_id = idx_offset[qpd->dqm->dev->node_id *
428643e40d4SMukul Joshi 					       get_num_all_sdma_engines(qpd->dqm) +
429643e40d4SMukul Joshi 					       q->properties.sdma_engine_id]
430234441ddSYong Zhao 						+ (q->properties.sdma_queue_id & 1)
431234441ddSYong Zhao 						* KFD_QUEUE_DOORBELL_MIRROR_OFFSET
432234441ddSYong Zhao 						+ (q->properties.sdma_queue_id >> 1);
4335bb6a8faSDavid Yat Sin 
4345bb6a8faSDavid Yat Sin 		if (restore_id && *restore_id != valid_id)
4355bb6a8faSDavid Yat Sin 			return -EINVAL;
4365bb6a8faSDavid Yat Sin 		q->doorbell_id = valid_id;
437ef568db7SFelix Kuehling 	} else {
4385bb6a8faSDavid Yat Sin 		/* For CP queues on SOC15 */
4395bb6a8faSDavid Yat Sin 		if (restore_id) {
4405bb6a8faSDavid Yat Sin 			/* make sure that ID is free  */
4415bb6a8faSDavid Yat Sin 			if (__test_and_set_bit(*restore_id, qpd->doorbell_bitmap))
4425bb6a8faSDavid Yat Sin 				return -EINVAL;
4435bb6a8faSDavid Yat Sin 
4445bb6a8faSDavid Yat Sin 			q->doorbell_id = *restore_id;
4455bb6a8faSDavid Yat Sin 		} else {
4465bb6a8faSDavid Yat Sin 			/* or reserve a free doorbell ID */
447ef568db7SFelix Kuehling 			unsigned int found;
448ef568db7SFelix Kuehling 
449ef568db7SFelix Kuehling 			found = find_first_zero_bit(qpd->doorbell_bitmap,
450ef568db7SFelix Kuehling 						    KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
451ef568db7SFelix Kuehling 			if (found >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) {
452ef568db7SFelix Kuehling 				pr_debug("No doorbells available");
453ef568db7SFelix Kuehling 				return -EBUSY;
454ef568db7SFelix Kuehling 			}
455ef568db7SFelix Kuehling 			set_bit(found, qpd->doorbell_bitmap);
456ef568db7SFelix Kuehling 			q->doorbell_id = found;
457ef568db7SFelix Kuehling 		}
4585bb6a8faSDavid Yat Sin 	}
459ef568db7SFelix Kuehling 
4602105a15aSShashank Sharma 	q->properties.doorbell_off = amdgpu_doorbell_index_on_bar(dev->adev,
4612105a15aSShashank Sharma 								  qpd->proc_doorbells,
462367a0af4SArvind Yadav 								  q->doorbell_id,
463367a0af4SArvind Yadav 								  dev->kfd->device_info.doorbell_size);
464ef568db7SFelix Kuehling 	return 0;
465ef568db7SFelix Kuehling }
466ef568db7SFelix Kuehling 
deallocate_doorbell(struct qcm_process_device * qpd,struct queue * q)467ef568db7SFelix Kuehling static void deallocate_doorbell(struct qcm_process_device *qpd,
468ef568db7SFelix Kuehling 				struct queue *q)
469ef568db7SFelix Kuehling {
470ef568db7SFelix Kuehling 	unsigned int old;
4718dc1db31SMukul Joshi 	struct kfd_node *dev = qpd->dqm->dev;
472ef568db7SFelix Kuehling 
473dd0ae064SGraham Sider 	if (!KFD_IS_SOC15(dev) ||
4741b4670f6SOak Zeng 	    q->properties.type == KFD_QUEUE_TYPE_SDMA ||
4751b4670f6SOak Zeng 	    q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
476ef568db7SFelix Kuehling 		return;
477ef568db7SFelix Kuehling 
478ef568db7SFelix Kuehling 	old = test_and_clear_bit(q->doorbell_id, qpd->doorbell_bitmap);
479ef568db7SFelix Kuehling 	WARN_ON(!old);
480ef568db7SFelix Kuehling }
481ef568db7SFelix Kuehling 
program_trap_handler_settings(struct device_queue_manager * dqm,struct qcm_process_device * qpd)482b53ef0dfSMukul Joshi static void program_trap_handler_settings(struct device_queue_manager *dqm,
483b53ef0dfSMukul Joshi 				struct qcm_process_device *qpd)
484b53ef0dfSMukul Joshi {
485c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
486c4050ff1SLijo Lazar 	int xcc_id;
487e2069a7bSMukul Joshi 
488b53ef0dfSMukul Joshi 	if (dqm->dev->kfd2kgd->program_trap_handler_settings)
489c4050ff1SLijo Lazar 		for_each_inst(xcc_id, xcc_mask)
490b53ef0dfSMukul Joshi 			dqm->dev->kfd2kgd->program_trap_handler_settings(
491c4050ff1SLijo Lazar 				dqm->dev->adev, qpd->vmid, qpd->tba_addr,
492c4050ff1SLijo Lazar 				qpd->tma_addr, xcc_id);
493b53ef0dfSMukul Joshi }
494b53ef0dfSMukul Joshi 
allocate_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)49564c7f8cfSBen Goz static int allocate_vmid(struct device_queue_manager *dqm,
49664c7f8cfSBen Goz 			struct qcm_process_device *qpd,
49764c7f8cfSBen Goz 			struct queue *q)
49864c7f8cfSBen Goz {
49980c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
500d9d4623cSYong Zhao 	int allocated_vmid = -1, i;
50164c7f8cfSBen Goz 
502d9d4623cSYong Zhao 	for (i = dqm->dev->vm_info.first_vmid_kfd;
503d9d4623cSYong Zhao 			i <= dqm->dev->vm_info.last_vmid_kfd; i++) {
504d9d4623cSYong Zhao 		if (!dqm->vmid_pasid[i]) {
505d9d4623cSYong Zhao 			allocated_vmid = i;
506d9d4623cSYong Zhao 			break;
507d9d4623cSYong Zhao 		}
508d9d4623cSYong Zhao 	}
50964c7f8cfSBen Goz 
510d9d4623cSYong Zhao 	if (allocated_vmid < 0) {
51180c74918SAsad Kamal 		dev_err(dev, "no more vmid to allocate\n");
512d9d4623cSYong Zhao 		return -ENOSPC;
513d9d4623cSYong Zhao 	}
51464c7f8cfSBen Goz 
515d9d4623cSYong Zhao 	pr_debug("vmid allocated: %d\n", allocated_vmid);
516d9d4623cSYong Zhao 
517d9d4623cSYong Zhao 	dqm->vmid_pasid[allocated_vmid] = q->process->pasid;
518d9d4623cSYong Zhao 
519d9d4623cSYong Zhao 	set_pasid_vmid_mapping(dqm, q->process->pasid, allocated_vmid);
520d9d4623cSYong Zhao 
52164c7f8cfSBen Goz 	qpd->vmid = allocated_vmid;
52264c7f8cfSBen Goz 	q->properties.vmid = allocated_vmid;
52364c7f8cfSBen Goz 
52464c7f8cfSBen Goz 	program_sh_mem_settings(dqm, qpd);
52564c7f8cfSBen Goz 
5268dc1db31SMukul Joshi 	if (KFD_IS_SOC15(dqm->dev) && dqm->dev->kfd->cwsr_enabled)
527b53ef0dfSMukul Joshi 		program_trap_handler_settings(dqm, qpd);
528b53ef0dfSMukul Joshi 
529403575c4SFelix Kuehling 	/* qpd->page_table_base is set earlier when register_process()
530403575c4SFelix Kuehling 	 * is called, i.e. when the first queue is created.
531403575c4SFelix Kuehling 	 */
5323356c38dSGraham Sider 	dqm->dev->kfd2kgd->set_vm_context_page_table_base(dqm->dev->adev,
533403575c4SFelix Kuehling 			qpd->vmid,
534403575c4SFelix Kuehling 			qpd->page_table_base);
535403575c4SFelix Kuehling 	/* invalidate the VM context after pasid and vmid mapping is set up */
5363543b055SEric Huang 	kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
537403575c4SFelix Kuehling 
538c637b36aSYong Zhao 	if (dqm->dev->kfd2kgd->set_scratch_backing_va)
5393356c38dSGraham Sider 		dqm->dev->kfd2kgd->set_scratch_backing_va(dqm->dev->adev,
540c637b36aSYong Zhao 				qpd->sh_hidden_private_base, qpd->vmid);
541d39b7737SOak Zeng 
54264c7f8cfSBen Goz 	return 0;
54364c7f8cfSBen Goz }
54464c7f8cfSBen Goz 
flush_texture_cache_nocpsch(struct kfd_node * kdev,struct qcm_process_device * qpd)5458dc1db31SMukul Joshi static int flush_texture_cache_nocpsch(struct kfd_node *kdev,
546552764b6SFelix Kuehling 				struct qcm_process_device *qpd)
547552764b6SFelix Kuehling {
5489af5379cSOak Zeng 	const struct packet_manager_funcs *pmf = qpd->dqm->packet_mgr.pmf;
549f6e27ff1SFelix Kuehling 	int ret;
550552764b6SFelix Kuehling 
551552764b6SFelix Kuehling 	if (!qpd->ib_kaddr)
552552764b6SFelix Kuehling 		return -ENOMEM;
553552764b6SFelix Kuehling 
554f6e27ff1SFelix Kuehling 	ret = pmf->release_mem(qpd->ib_base, (uint32_t *)qpd->ib_kaddr);
555f6e27ff1SFelix Kuehling 	if (ret)
556f6e27ff1SFelix Kuehling 		return ret;
557552764b6SFelix Kuehling 
5586bfc7c7eSGraham Sider 	return amdgpu_amdkfd_submit_ib(kdev->adev, KGD_ENGINE_MEC1, qpd->vmid,
559f6e27ff1SFelix Kuehling 				qpd->ib_base, (uint32_t *)qpd->ib_kaddr,
560f6e27ff1SFelix Kuehling 				pmf->release_mem_size / sizeof(uint32_t));
561552764b6SFelix Kuehling }
562552764b6SFelix Kuehling 
deallocate_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)56364c7f8cfSBen Goz static void deallocate_vmid(struct device_queue_manager *dqm,
56464c7f8cfSBen Goz 				struct qcm_process_device *qpd,
56564c7f8cfSBen Goz 				struct queue *q)
56664c7f8cfSBen Goz {
56780c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
56880c74918SAsad Kamal 
569552764b6SFelix Kuehling 	/* On GFX v7, CP doesn't flush TC at dequeue */
5707eb0502aSGraham Sider 	if (q->device->adev->asic_type == CHIP_HAWAII)
571552764b6SFelix Kuehling 		if (flush_texture_cache_nocpsch(q->device, qpd))
57280c74918SAsad Kamal 			dev_err(dev, "Failed to flush TC\n");
573552764b6SFelix Kuehling 
5743543b055SEric Huang 	kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
575403575c4SFelix Kuehling 
5762030664bSBen Goz 	/* Release the vmid mapping */
5772030664bSBen Goz 	set_pasid_vmid_mapping(dqm, 0, qpd->vmid);
578d9d4623cSYong Zhao 	dqm->vmid_pasid[qpd->vmid] = 0;
5792030664bSBen Goz 
58064c7f8cfSBen Goz 	qpd->vmid = 0;
58164c7f8cfSBen Goz 	q->properties.vmid = 0;
58264c7f8cfSBen Goz }
58364c7f8cfSBen Goz 
create_queue_nocpsch(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd,const struct kfd_criu_queue_priv_data * qd,const void * restore_mqd,const void * restore_ctl_stack)58464c7f8cfSBen Goz static int create_queue_nocpsch(struct device_queue_manager *dqm,
58564c7f8cfSBen Goz 				struct queue *q,
5862485c12cSDavid Yat Sin 				struct qcm_process_device *qpd,
58742c6c482SDavid Yat Sin 				const struct kfd_criu_queue_priv_data *qd,
5883a9822d7SDavid Yat Sin 				const void *restore_mqd, const void *restore_ctl_stack)
58964c7f8cfSBen Goz {
590d39b7737SOak Zeng 	struct mqd_manager *mqd_mgr;
59164c7f8cfSBen Goz 	int retval;
59264c7f8cfSBen Goz 
593efeaed4dSFelix Kuehling 	dqm_lock(dqm);
59464c7f8cfSBen Goz 
595b8cbab04SOded Gabbay 	if (dqm->total_queue_count >= max_num_of_queues_per_device) {
59679775b62SKent Russell 		pr_warn("Can't create new usermode queue because %d queues were already created\n",
597b8cbab04SOded Gabbay 				dqm->total_queue_count);
598ab7c1648SKent Russell 		retval = -EPERM;
599ab7c1648SKent Russell 		goto out_unlock;
600b8cbab04SOded Gabbay 	}
601b8cbab04SOded Gabbay 
60264c7f8cfSBen Goz 	if (list_empty(&qpd->queues_list)) {
60364c7f8cfSBen Goz 		retval = allocate_vmid(dqm, qpd, q);
604ab7c1648SKent Russell 		if (retval)
605ab7c1648SKent Russell 			goto out_unlock;
60664c7f8cfSBen Goz 	}
60764c7f8cfSBen Goz 	q->properties.vmid = qpd->vmid;
60826103436SFelix Kuehling 	/*
609bb2d2128SFelix Kuehling 	 * Eviction state logic: mark all queues as evicted, even ones
610bb2d2128SFelix Kuehling 	 * not currently active. Restoring inactive queues later only
611bb2d2128SFelix Kuehling 	 * updates the is_evicted flag but is a no-op otherwise.
61226103436SFelix Kuehling 	 */
613bb2d2128SFelix Kuehling 	q->properties.is_evicted = !!qpd->evicted;
61464c7f8cfSBen Goz 
615373d7080SFelix Kuehling 	q->properties.tba_addr = qpd->tba_addr;
616373d7080SFelix Kuehling 	q->properties.tma_addr = qpd->tma_addr;
617373d7080SFelix Kuehling 
618d091bc0aSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
619d091bc0aSOak Zeng 			q->properties.type)];
620d39b7737SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
621d39b7737SOak Zeng 		retval = allocate_hqd(dqm, q);
622d39b7737SOak Zeng 		if (retval)
623d39b7737SOak Zeng 			goto deallocate_vmid;
624d39b7737SOak Zeng 		pr_debug("Loading mqd to hqd on pipe %d, queue %d\n",
625d39b7737SOak Zeng 			q->pipe, q->queue);
626d39b7737SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
627d39b7737SOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
6282485c12cSDavid Yat Sin 		retval = allocate_sdma_queue(dqm, q, qd ? &qd->sdma_id : NULL);
629d39b7737SOak Zeng 		if (retval)
630d39b7737SOak Zeng 			goto deallocate_vmid;
631d39b7737SOak Zeng 		dqm->asic_ops.init_sdma_vm(dqm, q, qpd);
632d39b7737SOak Zeng 	}
63364c7f8cfSBen Goz 
6345bb6a8faSDavid Yat Sin 	retval = allocate_doorbell(qpd, q, qd ? &qd->doorbell_id : NULL);
635d39b7737SOak Zeng 	if (retval)
636d39b7737SOak Zeng 		goto out_deallocate_hqd;
637d39b7737SOak Zeng 
6386a6ef5eeSOak Zeng 	/* Temporarily release dqm lock to avoid a circular lock dependency */
6396a6ef5eeSOak Zeng 	dqm_unlock(dqm);
640d091bc0aSOak Zeng 	q->mqd_mem_obj = mqd_mgr->allocate_mqd(mqd_mgr->dev, &q->properties);
6416a6ef5eeSOak Zeng 	dqm_lock(dqm);
6426a6ef5eeSOak Zeng 
643d091bc0aSOak Zeng 	if (!q->mqd_mem_obj) {
644d091bc0aSOak Zeng 		retval = -ENOMEM;
645d091bc0aSOak Zeng 		goto out_deallocate_doorbell;
646d091bc0aSOak Zeng 	}
64742c6c482SDavid Yat Sin 
64842c6c482SDavid Yat Sin 	if (qd)
64942c6c482SDavid Yat Sin 		mqd_mgr->restore_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj, &q->gart_mqd_addr,
6503a9822d7SDavid Yat Sin 				     &q->properties, restore_mqd, restore_ctl_stack,
6513a9822d7SDavid Yat Sin 				     qd->ctl_stack_size);
65242c6c482SDavid Yat Sin 	else
6538636e53cSOak Zeng 		mqd_mgr->init_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj,
6548636e53cSOak Zeng 					&q->gart_mqd_addr, &q->properties);
65542c6c482SDavid Yat Sin 
656d39b7737SOak Zeng 	if (q->properties.is_active) {
6572c99a547SPhilip Yang 		if (!dqm->sched_running) {
6582c99a547SPhilip Yang 			WARN_ONCE(1, "Load non-HWS mqd while stopped\n");
6592c99a547SPhilip Yang 			goto add_queue_to_list;
6602c99a547SPhilip Yang 		}
661d39b7737SOak Zeng 
662d39b7737SOak Zeng 		if (WARN(q->process->mm != current->mm,
663d39b7737SOak Zeng 					"should only run in user thread"))
664d39b7737SOak Zeng 			retval = -EFAULT;
665d39b7737SOak Zeng 		else
666d39b7737SOak Zeng 			retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe,
667d39b7737SOak Zeng 					q->queue, &q->properties, current->mm);
668d39b7737SOak Zeng 		if (retval)
669d091bc0aSOak Zeng 			goto out_free_mqd;
67064c7f8cfSBen Goz 	}
67164c7f8cfSBen Goz 
6722c99a547SPhilip Yang add_queue_to_list:
67364c7f8cfSBen Goz 	list_add(&q->list, &qpd->queues_list);
674bc920fd4SFelix Kuehling 	qpd->queue_count++;
675b6819cecSJay Cornwall 	if (q->properties.is_active)
676ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, qpd, q);
67764c7f8cfSBen Goz 
678b8cbab04SOded Gabbay 	/*
679b8cbab04SOded Gabbay 	 * Unconditionally increment this counter, regardless of the queue's
680b8cbab04SOded Gabbay 	 * type or whether the queue is active.
681b8cbab04SOded Gabbay 	 */
682b8cbab04SOded Gabbay 	dqm->total_queue_count++;
683b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
684b8cbab04SOded Gabbay 			dqm->total_queue_count);
685d091bc0aSOak Zeng 	goto out_unlock;
686b8cbab04SOded Gabbay 
687d091bc0aSOak Zeng out_free_mqd:
688d091bc0aSOak Zeng 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
689d39b7737SOak Zeng out_deallocate_doorbell:
690d39b7737SOak Zeng 	deallocate_doorbell(qpd, q);
691d39b7737SOak Zeng out_deallocate_hqd:
692d39b7737SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
693d39b7737SOak Zeng 		deallocate_hqd(dqm, q);
694d39b7737SOak Zeng 	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
695d39b7737SOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
696d39b7737SOak Zeng 		deallocate_sdma_queue(dqm, q);
697d39b7737SOak Zeng deallocate_vmid:
698d39b7737SOak Zeng 	if (list_empty(&qpd->queues_list))
699d39b7737SOak Zeng 		deallocate_vmid(dqm, qpd, q);
700ab7c1648SKent Russell out_unlock:
701efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
702ab7c1648SKent Russell 	return retval;
70364c7f8cfSBen Goz }
70464c7f8cfSBen Goz 
allocate_hqd(struct device_queue_manager * dqm,struct queue * q)70564c7f8cfSBen Goz static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q)
70664c7f8cfSBen Goz {
70764c7f8cfSBen Goz 	bool set;
708f0ec5b99SBen Goz 	int pipe, bit, i;
70964c7f8cfSBen Goz 
71064c7f8cfSBen Goz 	set = false;
71164c7f8cfSBen Goz 
7128eabaf54SKent Russell 	for (pipe = dqm->next_pipe_to_allocate, i = 0;
7138eabaf54SKent Russell 			i < get_pipes_per_mec(dqm);
714d0b63bb3SAndres Rodriguez 			pipe = ((pipe + 1) % get_pipes_per_mec(dqm)), ++i) {
715d0b63bb3SAndres Rodriguez 
716d0b63bb3SAndres Rodriguez 		if (!is_pipe_enabled(dqm, 0, pipe))
717d0b63bb3SAndres Rodriguez 			continue;
718d0b63bb3SAndres Rodriguez 
71964c7f8cfSBen Goz 		if (dqm->allocated_queues[pipe] != 0) {
7204252bf68SHarish Kasiviswanathan 			bit = ffs(dqm->allocated_queues[pipe]) - 1;
7214252bf68SHarish Kasiviswanathan 			dqm->allocated_queues[pipe] &= ~(1 << bit);
72264c7f8cfSBen Goz 			q->pipe = pipe;
72364c7f8cfSBen Goz 			q->queue = bit;
72464c7f8cfSBen Goz 			set = true;
72564c7f8cfSBen Goz 			break;
72664c7f8cfSBen Goz 		}
72764c7f8cfSBen Goz 	}
72864c7f8cfSBen Goz 
729991ca8eeSEdward O'Callaghan 	if (!set)
73064c7f8cfSBen Goz 		return -EBUSY;
73164c7f8cfSBen Goz 
73279775b62SKent Russell 	pr_debug("hqd slot - pipe %d, queue %d\n", q->pipe, q->queue);
73364c7f8cfSBen Goz 	/* horizontal hqd allocation */
734d0b63bb3SAndres Rodriguez 	dqm->next_pipe_to_allocate = (pipe + 1) % get_pipes_per_mec(dqm);
73564c7f8cfSBen Goz 
73664c7f8cfSBen Goz 	return 0;
73764c7f8cfSBen Goz }
73864c7f8cfSBen Goz 
deallocate_hqd(struct device_queue_manager * dqm,struct queue * q)73964c7f8cfSBen Goz static inline void deallocate_hqd(struct device_queue_manager *dqm,
74064c7f8cfSBen Goz 				struct queue *q)
74164c7f8cfSBen Goz {
7424252bf68SHarish Kasiviswanathan 	dqm->allocated_queues[q->pipe] |= (1 << q->queue);
74364c7f8cfSBen Goz }
74464c7f8cfSBen Goz 
7455bdd3eb2SMukul Joshi #define SQ_IND_CMD_CMD_KILL		0x00000003
7465bdd3eb2SMukul Joshi #define SQ_IND_CMD_MODE_BROADCAST	0x00000001
7475bdd3eb2SMukul Joshi 
dbgdev_wave_reset_wavefronts(struct kfd_node * dev,struct kfd_process * p)7488dc1db31SMukul Joshi static int dbgdev_wave_reset_wavefronts(struct kfd_node *dev, struct kfd_process *p)
7495bdd3eb2SMukul Joshi {
7505bdd3eb2SMukul Joshi 	int status = 0;
7515bdd3eb2SMukul Joshi 	unsigned int vmid;
7525bdd3eb2SMukul Joshi 	uint16_t queried_pasid;
7535bdd3eb2SMukul Joshi 	union SQ_CMD_BITS reg_sq_cmd;
7545bdd3eb2SMukul Joshi 	union GRBM_GFX_INDEX_BITS reg_gfx_index;
7555bdd3eb2SMukul Joshi 	struct kfd_process_device *pdd;
7565bdd3eb2SMukul Joshi 	int first_vmid_to_scan = dev->vm_info.first_vmid_kfd;
7575bdd3eb2SMukul Joshi 	int last_vmid_to_scan = dev->vm_info.last_vmid_kfd;
758c4050ff1SLijo Lazar 	uint32_t xcc_mask = dev->xcc_mask;
759c4050ff1SLijo Lazar 	int xcc_id;
7605bdd3eb2SMukul Joshi 
7615bdd3eb2SMukul Joshi 	reg_sq_cmd.u32All = 0;
7625bdd3eb2SMukul Joshi 	reg_gfx_index.u32All = 0;
7635bdd3eb2SMukul Joshi 
7645bdd3eb2SMukul Joshi 	pr_debug("Killing all process wavefronts\n");
7655bdd3eb2SMukul Joshi 
766d55957fbSYifan Zhang 	if (!dev->kfd2kgd->get_atc_vmid_pasid_mapping_info) {
76780c74918SAsad Kamal 		dev_err(dev->adev->dev, "no vmid pasid mapping supported\n");
768d55957fbSYifan Zhang 		return -EOPNOTSUPP;
769d55957fbSYifan Zhang 	}
770d55957fbSYifan Zhang 
7715bdd3eb2SMukul Joshi 	/* Scan all registers in the range ATC_VMID8_PASID_MAPPING ..
7725bdd3eb2SMukul Joshi 	 * ATC_VMID15_PASID_MAPPING
7735bdd3eb2SMukul Joshi 	 * to check which VMID the current process is mapped to.
7745bdd3eb2SMukul Joshi 	 */
7755bdd3eb2SMukul Joshi 
7765bdd3eb2SMukul Joshi 	for (vmid = first_vmid_to_scan; vmid <= last_vmid_to_scan; vmid++) {
7775bdd3eb2SMukul Joshi 		status = dev->kfd2kgd->get_atc_vmid_pasid_mapping_info
7785bdd3eb2SMukul Joshi 				(dev->adev, vmid, &queried_pasid);
7795bdd3eb2SMukul Joshi 
7805bdd3eb2SMukul Joshi 		if (status && queried_pasid == p->pasid) {
7815bdd3eb2SMukul Joshi 			pr_debug("Killing wave fronts of vmid %d and pasid 0x%x\n",
7825bdd3eb2SMukul Joshi 					vmid, p->pasid);
7835bdd3eb2SMukul Joshi 			break;
7845bdd3eb2SMukul Joshi 		}
7855bdd3eb2SMukul Joshi 	}
7865bdd3eb2SMukul Joshi 
7875bdd3eb2SMukul Joshi 	if (vmid > last_vmid_to_scan) {
78880c74918SAsad Kamal 		dev_err(dev->adev->dev, "Didn't find vmid for pasid 0x%x\n", p->pasid);
7895bdd3eb2SMukul Joshi 		return -EFAULT;
7905bdd3eb2SMukul Joshi 	}
7915bdd3eb2SMukul Joshi 
7925bdd3eb2SMukul Joshi 	/* taking the VMID for that process on the safe way using PDD */
7935bdd3eb2SMukul Joshi 	pdd = kfd_get_process_device_data(dev, p);
7945bdd3eb2SMukul Joshi 	if (!pdd)
7955bdd3eb2SMukul Joshi 		return -EFAULT;
7965bdd3eb2SMukul Joshi 
7975bdd3eb2SMukul Joshi 	reg_gfx_index.bits.sh_broadcast_writes = 1;
7985bdd3eb2SMukul Joshi 	reg_gfx_index.bits.se_broadcast_writes = 1;
7995bdd3eb2SMukul Joshi 	reg_gfx_index.bits.instance_broadcast_writes = 1;
8005bdd3eb2SMukul Joshi 	reg_sq_cmd.bits.mode = SQ_IND_CMD_MODE_BROADCAST;
8015bdd3eb2SMukul Joshi 	reg_sq_cmd.bits.cmd = SQ_IND_CMD_CMD_KILL;
8025bdd3eb2SMukul Joshi 	reg_sq_cmd.bits.vm_id = vmid;
8035bdd3eb2SMukul Joshi 
804c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask)
805c4050ff1SLijo Lazar 		dev->kfd2kgd->wave_control_execute(
806c4050ff1SLijo Lazar 			dev->adev, reg_gfx_index.u32All,
807c4050ff1SLijo Lazar 			reg_sq_cmd.u32All, xcc_id);
8085bdd3eb2SMukul Joshi 
8095bdd3eb2SMukul Joshi 	return 0;
8105bdd3eb2SMukul Joshi }
8115bdd3eb2SMukul Joshi 
8129fd3f1bfSFelix Kuehling /* Access to DQM has to be locked before calling destroy_queue_nocpsch_locked
8139fd3f1bfSFelix Kuehling  * to avoid asynchronized access
8149fd3f1bfSFelix Kuehling  */
destroy_queue_nocpsch_locked(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)8159fd3f1bfSFelix Kuehling static int destroy_queue_nocpsch_locked(struct device_queue_manager *dqm,
81664c7f8cfSBen Goz 				struct qcm_process_device *qpd,
81764c7f8cfSBen Goz 				struct queue *q)
81864c7f8cfSBen Goz {
81964c7f8cfSBen Goz 	int retval;
8208d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
82164c7f8cfSBen Goz 
822fdfa090bSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
823fdfa090bSOak Zeng 			q->properties.type)];
824c2e1b3a4SBen Goz 
825c7637c95SYong Zhao 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
826c2e1b3a4SBen Goz 		deallocate_hqd(dqm, q);
827c7637c95SYong Zhao 	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
8281b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
829c7637c95SYong Zhao 	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
8301b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
831c7637c95SYong Zhao 	else {
83279775b62SKent Russell 		pr_debug("q->properties.type %d is invalid\n",
8337113cd65SOded Gabbay 				q->properties.type);
8349fd3f1bfSFelix Kuehling 		return -EINVAL;
835bcea3081SBen Goz 	}
8369fd3f1bfSFelix Kuehling 	dqm->total_queue_count--;
83764c7f8cfSBen Goz 
838ef568db7SFelix Kuehling 	deallocate_doorbell(qpd, q);
839ef568db7SFelix Kuehling 
8402c99a547SPhilip Yang 	if (!dqm->sched_running) {
8412c99a547SPhilip Yang 		WARN_ONCE(1, "Destroy non-HWS queue while stopped\n");
8422c99a547SPhilip Yang 		return 0;
8432c99a547SPhilip Yang 	}
8442c99a547SPhilip Yang 
8458d5f3552SYong Zhao 	retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd,
846c2e1b3a4SBen Goz 				KFD_PREEMPT_TYPE_WAVEFRONT_RESET,
847b90e3fbeSFelix Kuehling 				KFD_UNMAP_LATENCY_MS,
84864c7f8cfSBen Goz 				q->pipe, q->queue);
8499fd3f1bfSFelix Kuehling 	if (retval == -ETIME)
8509fd3f1bfSFelix Kuehling 		qpd->reset_wavefronts = true;
85164c7f8cfSBen Goz 
85264c7f8cfSBen Goz 	list_del(&q->list);
8539fd3f1bfSFelix Kuehling 	if (list_empty(&qpd->queues_list)) {
8549fd3f1bfSFelix Kuehling 		if (qpd->reset_wavefronts) {
8559fd3f1bfSFelix Kuehling 			pr_warn("Resetting wave fronts (nocpsch) on dev %p\n",
8569fd3f1bfSFelix Kuehling 					dqm->dev);
8579fd3f1bfSFelix Kuehling 			/* dbgdev_wave_reset_wavefronts has to be called before
8589fd3f1bfSFelix Kuehling 			 * deallocate_vmid(), i.e. when vmid is still in use.
8599fd3f1bfSFelix Kuehling 			 */
8609fd3f1bfSFelix Kuehling 			dbgdev_wave_reset_wavefronts(dqm->dev,
8619fd3f1bfSFelix Kuehling 					qpd->pqm->process);
8629fd3f1bfSFelix Kuehling 			qpd->reset_wavefronts = false;
8639fd3f1bfSFelix Kuehling 		}
8649fd3f1bfSFelix Kuehling 
86564c7f8cfSBen Goz 		deallocate_vmid(dqm, qpd, q);
8669fd3f1bfSFelix Kuehling 	}
867bc920fd4SFelix Kuehling 	qpd->queue_count--;
868ab4d51d4SDavid Yat Sin 	if (q->properties.is_active)
869ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, q);
870b8cbab04SOded Gabbay 
8719fd3f1bfSFelix Kuehling 	return retval;
8729fd3f1bfSFelix Kuehling }
873b8cbab04SOded Gabbay 
destroy_queue_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)8749fd3f1bfSFelix Kuehling static int destroy_queue_nocpsch(struct device_queue_manager *dqm,
8759fd3f1bfSFelix Kuehling 				struct qcm_process_device *qpd,
8769fd3f1bfSFelix Kuehling 				struct queue *q)
8779fd3f1bfSFelix Kuehling {
8789fd3f1bfSFelix Kuehling 	int retval;
879d69fd951SMukul Joshi 	uint64_t sdma_val = 0;
88080c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
881d69fd951SMukul Joshi 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
882a7b2451dSAmber Lin 	struct mqd_manager *mqd_mgr =
883a7b2451dSAmber Lin 		dqm->mqd_mgrs[get_mqd_type_from_queue_type(q->properties.type)];
884d69fd951SMukul Joshi 
885d69fd951SMukul Joshi 	/* Get the SDMA queue stats */
886d69fd951SMukul Joshi 	if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) ||
887d69fd951SMukul Joshi 	    (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
888818b0324SMukul Joshi 		retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr,
889d69fd951SMukul Joshi 							&sdma_val);
890d69fd951SMukul Joshi 		if (retval)
89180c74918SAsad Kamal 			dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n",
892d69fd951SMukul Joshi 				q->properties.queue_id);
893d69fd951SMukul Joshi 	}
8949fd3f1bfSFelix Kuehling 
895efeaed4dSFelix Kuehling 	dqm_lock(dqm);
8969fd3f1bfSFelix Kuehling 	retval = destroy_queue_nocpsch_locked(dqm, qpd, q);
897d69fd951SMukul Joshi 	if (!retval)
898d69fd951SMukul Joshi 		pdd->sdma_past_activity_counter += sdma_val;
899efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
9009fd3f1bfSFelix Kuehling 
901a7b2451dSAmber Lin 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
902a7b2451dSAmber Lin 
90364c7f8cfSBen Goz 	return retval;
90464c7f8cfSBen Goz }
90564c7f8cfSBen Goz 
update_queue(struct device_queue_manager * dqm,struct queue * q,struct mqd_update_info * minfo)906c6e559ebSLang Yu static int update_queue(struct device_queue_manager *dqm, struct queue *q,
907c6e559ebSLang Yu 			struct mqd_update_info *minfo)
90864c7f8cfSBen Goz {
9098636e53cSOak Zeng 	int retval = 0;
91080c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
9118d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
91226103436SFelix Kuehling 	struct kfd_process_device *pdd;
913b6ffbab8SOded Gabbay 	bool prev_active = false;
91464c7f8cfSBen Goz 
915efeaed4dSFelix Kuehling 	dqm_lock(dqm);
91626103436SFelix Kuehling 	pdd = kfd_get_process_device_data(q->device, q->process);
91726103436SFelix Kuehling 	if (!pdd) {
91826103436SFelix Kuehling 		retval = -ENODEV;
91926103436SFelix Kuehling 		goto out_unlock;
92026103436SFelix Kuehling 	}
921fdfa090bSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
922fdfa090bSOak Zeng 			q->properties.type)];
92364c7f8cfSBen Goz 
92460a00956SFelix Kuehling 	/* Save previous activity state for counters */
92560a00956SFelix Kuehling 	prev_active = q->properties.is_active;
92660a00956SFelix Kuehling 
92760a00956SFelix Kuehling 	/* Make sure the queue is unmapped before updating the MQD */
928d146c5a7SFelix Kuehling 	if (dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) {
9298dc1db31SMukul Joshi 		if (!dqm->dev->kfd->shared_resources.enable_mes)
93060a00956SFelix Kuehling 			retval = unmap_queues_cpsch(dqm,
9317cee6a68SJonathan Kim 						    KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD, false);
932cc009e61SMukul Joshi 		else if (prev_active)
933cc009e61SMukul Joshi 			retval = remove_queue_mes(dqm, q, &pdd->qpd);
934cc009e61SMukul Joshi 
935ee0a469cSJonathan Kim 		/* queue is reset so inaccessable  */
936ee0a469cSJonathan Kim 		if (pdd->has_reset_queue) {
937ee0a469cSJonathan Kim 			retval = -EACCES;
938ee0a469cSJonathan Kim 			goto out_unlock;
939ee0a469cSJonathan Kim 		}
940ee0a469cSJonathan Kim 
941894a8293SFelix Kuehling 		if (retval) {
94280c74918SAsad Kamal 			dev_err(dev, "unmap queue failed\n");
94360a00956SFelix Kuehling 			goto out_unlock;
94460a00956SFelix Kuehling 		}
945894a8293SFelix Kuehling 	} else if (prev_active &&
94660a00956SFelix Kuehling 		   (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
9471b4670f6SOak Zeng 		    q->properties.type == KFD_QUEUE_TYPE_SDMA ||
9481b4670f6SOak Zeng 		    q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
9492c99a547SPhilip Yang 
9502c99a547SPhilip Yang 		if (!dqm->sched_running) {
9512c99a547SPhilip Yang 			WARN_ONCE(1, "Update non-HWS queue while stopped\n");
9522c99a547SPhilip Yang 			goto out_unlock;
9532c99a547SPhilip Yang 		}
9542c99a547SPhilip Yang 
9558d5f3552SYong Zhao 		retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd,
9568dc1db31SMukul Joshi 				(dqm->dev->kfd->cwsr_enabled ?
957b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_SAVE :
958b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN),
95960a00956SFelix Kuehling 				KFD_UNMAP_LATENCY_MS, q->pipe, q->queue);
96060a00956SFelix Kuehling 		if (retval) {
96180c74918SAsad Kamal 			dev_err(dev, "destroy mqd failed\n");
96260a00956SFelix Kuehling 			goto out_unlock;
96360a00956SFelix Kuehling 		}
96460a00956SFelix Kuehling 	}
96560a00956SFelix Kuehling 
966c6e559ebSLang Yu 	mqd_mgr->update_mqd(mqd_mgr, q->mqd, &q->properties, minfo);
96760a00956SFelix Kuehling 
968096d1a3eSFelix Kuehling 	/*
969096d1a3eSFelix Kuehling 	 * check active state vs. the previous state and modify
970096d1a3eSFelix Kuehling 	 * counter accordingly. map_queues_cpsch uses the
97181b820b3SYong Zhao 	 * dqm->active_queue_count to determine whether a new runlist must be
972096d1a3eSFelix Kuehling 	 * uploaded.
973096d1a3eSFelix Kuehling 	 */
974ab4d51d4SDavid Yat Sin 	if (q->properties.is_active && !prev_active) {
975ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, &pdd->qpd, q);
976ab4d51d4SDavid Yat Sin 	} else if (!q->properties.is_active && prev_active) {
977ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, &pdd->qpd, q);
978ab4d51d4SDavid Yat Sin 	} else if (q->gws && !q->properties.is_gws) {
979b8020b03SJoseph Greathouse 		if (q->properties.is_active) {
980b8020b03SJoseph Greathouse 			dqm->gws_queue_count++;
981b8020b03SJoseph Greathouse 			pdd->qpd.mapped_gws_queue = true;
982b8020b03SJoseph Greathouse 		}
983b8020b03SJoseph Greathouse 		q->properties.is_gws = true;
984b8020b03SJoseph Greathouse 	} else if (!q->gws && q->properties.is_gws) {
985b8020b03SJoseph Greathouse 		if (q->properties.is_active) {
986b8020b03SJoseph Greathouse 			dqm->gws_queue_count--;
987b8020b03SJoseph Greathouse 			pdd->qpd.mapped_gws_queue = false;
988b8020b03SJoseph Greathouse 		}
989b8020b03SJoseph Greathouse 		q->properties.is_gws = false;
990b8020b03SJoseph Greathouse 	}
991b8020b03SJoseph Greathouse 
992cc009e61SMukul Joshi 	if (dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) {
9938dc1db31SMukul Joshi 		if (!dqm->dev->kfd->shared_resources.enable_mes)
99460a00956SFelix Kuehling 			retval = map_queues_cpsch(dqm);
995f4f9b827SPhilip Yang 		else if (q->properties.is_active)
996cc009e61SMukul Joshi 			retval = add_queue_mes(dqm, q, &pdd->qpd);
997cc009e61SMukul Joshi 	} else if (q->properties.is_active &&
99860a00956SFelix Kuehling 		 (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
9991b4670f6SOak Zeng 		  q->properties.type == KFD_QUEUE_TYPE_SDMA ||
10001b4670f6SOak Zeng 		  q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
10011b19aa5aSFelix Kuehling 		if (WARN(q->process->mm != current->mm,
10021b19aa5aSFelix Kuehling 			 "should only run in user thread"))
10031b19aa5aSFelix Kuehling 			retval = -EFAULT;
10041b19aa5aSFelix Kuehling 		else
10051b19aa5aSFelix Kuehling 			retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd,
10061b19aa5aSFelix Kuehling 						   q->pipe, q->queue,
10071b19aa5aSFelix Kuehling 						   &q->properties, current->mm);
10081b19aa5aSFelix Kuehling 	}
1009b6ffbab8SOded Gabbay 
1010ab7c1648SKent Russell out_unlock:
1011efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
101264c7f8cfSBen Goz 	return retval;
101364c7f8cfSBen Goz }
101464c7f8cfSBen Goz 
1015a70a93faSJonathan Kim /* suspend_single_queue does not lock the dqm like the
1016a70a93faSJonathan Kim  * evict_process_queues_cpsch or evict_process_queues_nocpsch. You should
1017a70a93faSJonathan Kim  * lock the dqm before calling, and unlock after calling.
1018a70a93faSJonathan Kim  *
1019a70a93faSJonathan Kim  * The reason we don't lock the dqm is because this function may be
1020a70a93faSJonathan Kim  * called on multiple queues in a loop, so rather than locking/unlocking
1021a70a93faSJonathan Kim  * multiple times, we will just keep the dqm locked for all of the calls.
1022a70a93faSJonathan Kim  */
suspend_single_queue(struct device_queue_manager * dqm,struct kfd_process_device * pdd,struct queue * q)1023a70a93faSJonathan Kim static int suspend_single_queue(struct device_queue_manager *dqm,
1024a70a93faSJonathan Kim 				      struct kfd_process_device *pdd,
1025a70a93faSJonathan Kim 				      struct queue *q)
1026a70a93faSJonathan Kim {
1027a70a93faSJonathan Kim 	bool is_new;
1028a70a93faSJonathan Kim 
1029a70a93faSJonathan Kim 	if (q->properties.is_suspended)
1030a70a93faSJonathan Kim 		return 0;
1031a70a93faSJonathan Kim 
1032a70a93faSJonathan Kim 	pr_debug("Suspending PASID %u queue [%i]\n",
1033a70a93faSJonathan Kim 			pdd->process->pasid,
1034a70a93faSJonathan Kim 			q->properties.queue_id);
1035a70a93faSJonathan Kim 
1036a70a93faSJonathan Kim 	is_new = q->properties.exception_status & KFD_EC_MASK(EC_QUEUE_NEW);
1037a70a93faSJonathan Kim 
1038a70a93faSJonathan Kim 	if (is_new || q->properties.is_being_destroyed) {
1039a70a93faSJonathan Kim 		pr_debug("Suspend: skip %s queue id %i\n",
1040a70a93faSJonathan Kim 				is_new ? "new" : "destroyed",
1041a70a93faSJonathan Kim 				q->properties.queue_id);
1042a70a93faSJonathan Kim 		return -EBUSY;
1043a70a93faSJonathan Kim 	}
1044a70a93faSJonathan Kim 
1045a70a93faSJonathan Kim 	q->properties.is_suspended = true;
1046a70a93faSJonathan Kim 	if (q->properties.is_active) {
1047a70a93faSJonathan Kim 		if (dqm->dev->kfd->shared_resources.enable_mes) {
1048a70a93faSJonathan Kim 			int r = remove_queue_mes(dqm, q, &pdd->qpd);
1049a70a93faSJonathan Kim 
1050a70a93faSJonathan Kim 			if (r)
1051a70a93faSJonathan Kim 				return r;
1052a70a93faSJonathan Kim 		}
1053a70a93faSJonathan Kim 
1054a70a93faSJonathan Kim 		decrement_queue_count(dqm, &pdd->qpd, q);
1055a70a93faSJonathan Kim 		q->properties.is_active = false;
1056a70a93faSJonathan Kim 	}
1057a70a93faSJonathan Kim 
1058a70a93faSJonathan Kim 	return 0;
1059a70a93faSJonathan Kim }
1060a70a93faSJonathan Kim 
1061a70a93faSJonathan Kim /* resume_single_queue does not lock the dqm like the functions
1062a70a93faSJonathan Kim  * restore_process_queues_cpsch or restore_process_queues_nocpsch. You should
1063a70a93faSJonathan Kim  * lock the dqm before calling, and unlock after calling.
1064a70a93faSJonathan Kim  *
1065a70a93faSJonathan Kim  * The reason we don't lock the dqm is because this function may be
1066a70a93faSJonathan Kim  * called on multiple queues in a loop, so rather than locking/unlocking
1067a70a93faSJonathan Kim  * multiple times, we will just keep the dqm locked for all of the calls.
1068a70a93faSJonathan Kim  */
resume_single_queue(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)1069a70a93faSJonathan Kim static int resume_single_queue(struct device_queue_manager *dqm,
1070a70a93faSJonathan Kim 				      struct qcm_process_device *qpd,
1071a70a93faSJonathan Kim 				      struct queue *q)
1072a70a93faSJonathan Kim {
1073a70a93faSJonathan Kim 	struct kfd_process_device *pdd;
1074a70a93faSJonathan Kim 
1075a70a93faSJonathan Kim 	if (!q->properties.is_suspended)
1076a70a93faSJonathan Kim 		return 0;
1077a70a93faSJonathan Kim 
1078a70a93faSJonathan Kim 	pdd = qpd_to_pdd(qpd);
1079a70a93faSJonathan Kim 
1080a70a93faSJonathan Kim 	pr_debug("Restoring from suspend PASID %u queue [%i]\n",
1081a70a93faSJonathan Kim 			    pdd->process->pasid,
1082a70a93faSJonathan Kim 			    q->properties.queue_id);
1083a70a93faSJonathan Kim 
1084a70a93faSJonathan Kim 	q->properties.is_suspended = false;
1085a70a93faSJonathan Kim 
1086a70a93faSJonathan Kim 	if (QUEUE_IS_ACTIVE(q->properties)) {
1087a70a93faSJonathan Kim 		if (dqm->dev->kfd->shared_resources.enable_mes) {
1088a70a93faSJonathan Kim 			int r = add_queue_mes(dqm, q, &pdd->qpd);
1089a70a93faSJonathan Kim 
1090a70a93faSJonathan Kim 			if (r)
1091a70a93faSJonathan Kim 				return r;
1092a70a93faSJonathan Kim 		}
1093a70a93faSJonathan Kim 
1094a70a93faSJonathan Kim 		q->properties.is_active = true;
1095a70a93faSJonathan Kim 		increment_queue_count(dqm, qpd, q);
1096a70a93faSJonathan Kim 	}
1097a70a93faSJonathan Kim 
1098a70a93faSJonathan Kim 	return 0;
1099a70a93faSJonathan Kim }
1100a70a93faSJonathan Kim 
evict_process_queues_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)110126103436SFelix Kuehling static int evict_process_queues_nocpsch(struct device_queue_manager *dqm,
110226103436SFelix Kuehling 					struct qcm_process_device *qpd)
110326103436SFelix Kuehling {
110426103436SFelix Kuehling 	struct queue *q;
11058d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
110626103436SFelix Kuehling 	struct kfd_process_device *pdd;
1107bb2d2128SFelix Kuehling 	int retval, ret = 0;
110826103436SFelix Kuehling 
1109efeaed4dSFelix Kuehling 	dqm_lock(dqm);
111026103436SFelix Kuehling 	if (qpd->evicted++ > 0) /* already evicted, do nothing */
111126103436SFelix Kuehling 		goto out;
111226103436SFelix Kuehling 
111326103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
1114783a25f4SPhilip Cox 	pr_debug_ratelimited("Evicting PASID 0x%x queues\n",
111526103436SFelix Kuehling 			    pdd->process->pasid);
111626103436SFelix Kuehling 
11174327bed2SPhilip Cox 	pdd->last_evict_timestamp = get_jiffies_64();
1118bb2d2128SFelix Kuehling 	/* Mark all queues as evicted. Deactivate all active queues on
1119bb2d2128SFelix Kuehling 	 * the qpd.
1120bb2d2128SFelix Kuehling 	 */
112126103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
1122bb2d2128SFelix Kuehling 		q->properties.is_evicted = true;
112326103436SFelix Kuehling 		if (!q->properties.is_active)
112426103436SFelix Kuehling 			continue;
1125bb2d2128SFelix Kuehling 
1126fdfa090bSOak Zeng 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
1127fdfa090bSOak Zeng 				q->properties.type)];
112826103436SFelix Kuehling 		q->properties.is_active = false;
1129ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, q);
11302c99a547SPhilip Yang 
11312c99a547SPhilip Yang 		if (WARN_ONCE(!dqm->sched_running, "Evict when stopped\n"))
11322c99a547SPhilip Yang 			continue;
11332c99a547SPhilip Yang 
11348d5f3552SYong Zhao 		retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd,
11358dc1db31SMukul Joshi 				(dqm->dev->kfd->cwsr_enabled ?
1136b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_SAVE :
1137b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN),
113826103436SFelix Kuehling 				KFD_UNMAP_LATENCY_MS, q->pipe, q->queue);
1139bb2d2128SFelix Kuehling 		if (retval && !ret)
1140bb2d2128SFelix Kuehling 			/* Return the first error, but keep going to
1141bb2d2128SFelix Kuehling 			 * maintain a consistent eviction state
1142bb2d2128SFelix Kuehling 			 */
1143bb2d2128SFelix Kuehling 			ret = retval;
114426103436SFelix Kuehling 	}
114526103436SFelix Kuehling 
114626103436SFelix Kuehling out:
1147efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
1148bb2d2128SFelix Kuehling 	return ret;
114926103436SFelix Kuehling }
115026103436SFelix Kuehling 
evict_process_queues_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)115126103436SFelix Kuehling static int evict_process_queues_cpsch(struct device_queue_manager *dqm,
115226103436SFelix Kuehling 				      struct qcm_process_device *qpd)
115326103436SFelix Kuehling {
115426103436SFelix Kuehling 	struct queue *q;
115580c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
115626103436SFelix Kuehling 	struct kfd_process_device *pdd;
115726103436SFelix Kuehling 	int retval = 0;
115826103436SFelix Kuehling 
1159efeaed4dSFelix Kuehling 	dqm_lock(dqm);
116026103436SFelix Kuehling 	if (qpd->evicted++ > 0) /* already evicted, do nothing */
116126103436SFelix Kuehling 		goto out;
116226103436SFelix Kuehling 
116326103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
11640ab2d753SJonathan Kim 
11650ab2d753SJonathan Kim 	/* The debugger creates processes that temporarily have not acquired
11660ab2d753SJonathan Kim 	 * all VMs for all devices and has no VMs itself.
11670ab2d753SJonathan Kim 	 * Skip queue eviction on process eviction.
11680ab2d753SJonathan Kim 	 */
11690ab2d753SJonathan Kim 	if (!pdd->drm_priv)
11700ab2d753SJonathan Kim 		goto out;
11710ab2d753SJonathan Kim 
1172783a25f4SPhilip Cox 	pr_debug_ratelimited("Evicting PASID 0x%x queues\n",
117326103436SFelix Kuehling 			    pdd->process->pasid);
117426103436SFelix Kuehling 
1175bb2d2128SFelix Kuehling 	/* Mark all queues as evicted. Deactivate all active queues on
1176bb2d2128SFelix Kuehling 	 * the qpd.
1177bb2d2128SFelix Kuehling 	 */
117826103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
1179bb2d2128SFelix Kuehling 		q->properties.is_evicted = true;
118026103436SFelix Kuehling 		if (!q->properties.is_active)
118126103436SFelix Kuehling 			continue;
1182bb2d2128SFelix Kuehling 
118326103436SFelix Kuehling 		q->properties.is_active = false;
1184ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, q);
1185cc009e61SMukul Joshi 
11868dc1db31SMukul Joshi 		if (dqm->dev->kfd->shared_resources.enable_mes) {
1187cc009e61SMukul Joshi 			retval = remove_queue_mes(dqm, q, qpd);
1188cc009e61SMukul Joshi 			if (retval) {
118980c74918SAsad Kamal 				dev_err(dev, "Failed to evict queue %d\n",
1190cc009e61SMukul Joshi 					q->properties.queue_id);
1191cc009e61SMukul Joshi 				goto out;
1192cc009e61SMukul Joshi 			}
1193cc009e61SMukul Joshi 		}
119426103436SFelix Kuehling 	}
11954327bed2SPhilip Cox 	pdd->last_evict_timestamp = get_jiffies_64();
11968dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
119726103436SFelix Kuehling 		retval = execute_queues_cpsch(dqm,
119826103436SFelix Kuehling 					      qpd->is_debug ?
119926103436SFelix Kuehling 					      KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES :
12007cee6a68SJonathan Kim 					      KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
12017cee6a68SJonathan Kim 					      USE_DEFAULT_GRACE_PERIOD);
120226103436SFelix Kuehling 
120326103436SFelix Kuehling out:
1204efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
120526103436SFelix Kuehling 	return retval;
120626103436SFelix Kuehling }
120726103436SFelix Kuehling 
restore_process_queues_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)120826103436SFelix Kuehling static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
120926103436SFelix Kuehling 					  struct qcm_process_device *qpd)
121026103436SFelix Kuehling {
12111b19aa5aSFelix Kuehling 	struct mm_struct *mm = NULL;
121226103436SFelix Kuehling 	struct queue *q;
12138d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
121426103436SFelix Kuehling 	struct kfd_process_device *pdd;
1215e715c6d0SShaoyun Liu 	uint64_t pd_base;
12164327bed2SPhilip Cox 	uint64_t eviction_duration;
1217bb2d2128SFelix Kuehling 	int retval, ret = 0;
121826103436SFelix Kuehling 
121926103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
122026103436SFelix Kuehling 	/* Retrieve PD base */
1221b40a6ab2SFelix Kuehling 	pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->drm_priv);
122226103436SFelix Kuehling 
1223efeaed4dSFelix Kuehling 	dqm_lock(dqm);
122426103436SFelix Kuehling 	if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
122526103436SFelix Kuehling 		goto out;
122626103436SFelix Kuehling 	if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */
122726103436SFelix Kuehling 		qpd->evicted--;
122826103436SFelix Kuehling 		goto out;
122926103436SFelix Kuehling 	}
123026103436SFelix Kuehling 
1231783a25f4SPhilip Cox 	pr_debug_ratelimited("Restoring PASID 0x%x queues\n",
123226103436SFelix Kuehling 			    pdd->process->pasid);
123326103436SFelix Kuehling 
123426103436SFelix Kuehling 	/* Update PD Base in QPD */
123526103436SFelix Kuehling 	qpd->page_table_base = pd_base;
1236e715c6d0SShaoyun Liu 	pr_debug("Updated PD address to 0x%llx\n", pd_base);
123726103436SFelix Kuehling 
123826103436SFelix Kuehling 	if (!list_empty(&qpd->queues_list)) {
123926103436SFelix Kuehling 		dqm->dev->kfd2kgd->set_vm_context_page_table_base(
12403356c38dSGraham Sider 				dqm->dev->adev,
124126103436SFelix Kuehling 				qpd->vmid,
124226103436SFelix Kuehling 				qpd->page_table_base);
12433543b055SEric Huang 		kfd_flush_tlb(pdd, TLB_FLUSH_LEGACY);
124426103436SFelix Kuehling 	}
124526103436SFelix Kuehling 
12461b19aa5aSFelix Kuehling 	/* Take a safe reference to the mm_struct, which may otherwise
12471b19aa5aSFelix Kuehling 	 * disappear even while the kfd_process is still referenced.
12481b19aa5aSFelix Kuehling 	 */
12491b19aa5aSFelix Kuehling 	mm = get_task_mm(pdd->process->lead_thread);
12501b19aa5aSFelix Kuehling 	if (!mm) {
1251bb2d2128SFelix Kuehling 		ret = -EFAULT;
12521b19aa5aSFelix Kuehling 		goto out;
12531b19aa5aSFelix Kuehling 	}
12541b19aa5aSFelix Kuehling 
1255bb2d2128SFelix Kuehling 	/* Remove the eviction flags. Activate queues that are not
1256bb2d2128SFelix Kuehling 	 * inactive for other reasons.
1257bb2d2128SFelix Kuehling 	 */
125826103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
1259bb2d2128SFelix Kuehling 		q->properties.is_evicted = false;
1260bb2d2128SFelix Kuehling 		if (!QUEUE_IS_ACTIVE(q->properties))
126126103436SFelix Kuehling 			continue;
1262bb2d2128SFelix Kuehling 
1263fdfa090bSOak Zeng 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
1264fdfa090bSOak Zeng 				q->properties.type)];
126526103436SFelix Kuehling 		q->properties.is_active = true;
1266ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, qpd, q);
12672c99a547SPhilip Yang 
12682c99a547SPhilip Yang 		if (WARN_ONCE(!dqm->sched_running, "Restore when stopped\n"))
12692c99a547SPhilip Yang 			continue;
12702c99a547SPhilip Yang 
12718d5f3552SYong Zhao 		retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe,
12721b19aa5aSFelix Kuehling 				       q->queue, &q->properties, mm);
1273bb2d2128SFelix Kuehling 		if (retval && !ret)
1274bb2d2128SFelix Kuehling 			/* Return the first error, but keep going to
1275bb2d2128SFelix Kuehling 			 * maintain a consistent eviction state
1276bb2d2128SFelix Kuehling 			 */
1277bb2d2128SFelix Kuehling 			ret = retval;
127826103436SFelix Kuehling 	}
127926103436SFelix Kuehling 	qpd->evicted = 0;
12804327bed2SPhilip Cox 	eviction_duration = get_jiffies_64() - pdd->last_evict_timestamp;
12814327bed2SPhilip Cox 	atomic64_add(eviction_duration, &pdd->evict_duration_counter);
128226103436SFelix Kuehling out:
12831b19aa5aSFelix Kuehling 	if (mm)
12841b19aa5aSFelix Kuehling 		mmput(mm);
1285efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
1286bb2d2128SFelix Kuehling 	return ret;
128726103436SFelix Kuehling }
128826103436SFelix Kuehling 
restore_process_queues_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)128926103436SFelix Kuehling static int restore_process_queues_cpsch(struct device_queue_manager *dqm,
129026103436SFelix Kuehling 					struct qcm_process_device *qpd)
129126103436SFelix Kuehling {
129226103436SFelix Kuehling 	struct queue *q;
129380c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
129426103436SFelix Kuehling 	struct kfd_process_device *pdd;
12954327bed2SPhilip Cox 	uint64_t eviction_duration;
129626103436SFelix Kuehling 	int retval = 0;
129726103436SFelix Kuehling 
129826103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
129926103436SFelix Kuehling 
1300efeaed4dSFelix Kuehling 	dqm_lock(dqm);
130126103436SFelix Kuehling 	if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
130226103436SFelix Kuehling 		goto out;
130326103436SFelix Kuehling 	if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */
130426103436SFelix Kuehling 		qpd->evicted--;
130526103436SFelix Kuehling 		goto out;
130626103436SFelix Kuehling 	}
130726103436SFelix Kuehling 
13080ab2d753SJonathan Kim 	/* The debugger creates processes that temporarily have not acquired
13090ab2d753SJonathan Kim 	 * all VMs for all devices and has no VMs itself.
13100ab2d753SJonathan Kim 	 * Skip queue restore on process restore.
13110ab2d753SJonathan Kim 	 */
13120ab2d753SJonathan Kim 	if (!pdd->drm_priv)
13130ab2d753SJonathan Kim 		goto vm_not_acquired;
13140ab2d753SJonathan Kim 
1315783a25f4SPhilip Cox 	pr_debug_ratelimited("Restoring PASID 0x%x queues\n",
131626103436SFelix Kuehling 			    pdd->process->pasid);
131726103436SFelix Kuehling 
131826103436SFelix Kuehling 	/* Update PD Base in QPD */
13190ab2d753SJonathan Kim 	qpd->page_table_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->drm_priv);
13200ab2d753SJonathan Kim 	pr_debug("Updated PD address to 0x%llx\n", qpd->page_table_base);
132126103436SFelix Kuehling 
132226103436SFelix Kuehling 	/* activate all active queues on the qpd */
132326103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
132426103436SFelix Kuehling 		q->properties.is_evicted = false;
1325bb2d2128SFelix Kuehling 		if (!QUEUE_IS_ACTIVE(q->properties))
1326bb2d2128SFelix Kuehling 			continue;
1327bb2d2128SFelix Kuehling 
132826103436SFelix Kuehling 		q->properties.is_active = true;
1329ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, &pdd->qpd, q);
1330cc009e61SMukul Joshi 
13318dc1db31SMukul Joshi 		if (dqm->dev->kfd->shared_resources.enable_mes) {
1332cc009e61SMukul Joshi 			retval = add_queue_mes(dqm, q, qpd);
1333cc009e61SMukul Joshi 			if (retval) {
133480c74918SAsad Kamal 				dev_err(dev, "Failed to restore queue %d\n",
1335cc009e61SMukul Joshi 					q->properties.queue_id);
1336cc009e61SMukul Joshi 				goto out;
133726103436SFelix Kuehling 			}
1338cc009e61SMukul Joshi 		}
1339cc009e61SMukul Joshi 	}
13408dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
134126103436SFelix Kuehling 		retval = execute_queues_cpsch(dqm,
13427cee6a68SJonathan Kim 					      KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD);
13434327bed2SPhilip Cox 	eviction_duration = get_jiffies_64() - pdd->last_evict_timestamp;
13444327bed2SPhilip Cox 	atomic64_add(eviction_duration, &pdd->evict_duration_counter);
13450ab2d753SJonathan Kim vm_not_acquired:
13460ab2d753SJonathan Kim 	qpd->evicted = 0;
134726103436SFelix Kuehling out:
1348efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
134926103436SFelix Kuehling 	return retval;
135026103436SFelix Kuehling }
135126103436SFelix Kuehling 
register_process(struct device_queue_manager * dqm,struct qcm_process_device * qpd)135258dcd5bfSYong Zhao static int register_process(struct device_queue_manager *dqm,
135364c7f8cfSBen Goz 					struct qcm_process_device *qpd)
135464c7f8cfSBen Goz {
135564c7f8cfSBen Goz 	struct device_process_node *n;
1356403575c4SFelix Kuehling 	struct kfd_process_device *pdd;
1357e715c6d0SShaoyun Liu 	uint64_t pd_base;
1358a22fc854SBen Goz 	int retval;
135964c7f8cfSBen Goz 
1360dbf56ab1SKent Russell 	n = kzalloc(sizeof(*n), GFP_KERNEL);
136164c7f8cfSBen Goz 	if (!n)
136264c7f8cfSBen Goz 		return -ENOMEM;
136364c7f8cfSBen Goz 
136464c7f8cfSBen Goz 	n->qpd = qpd;
136564c7f8cfSBen Goz 
1366403575c4SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
1367403575c4SFelix Kuehling 	/* Retrieve PD base */
1368b40a6ab2SFelix Kuehling 	pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->drm_priv);
1369403575c4SFelix Kuehling 
1370efeaed4dSFelix Kuehling 	dqm_lock(dqm);
137164c7f8cfSBen Goz 	list_add(&n->list, &dqm->queues);
137264c7f8cfSBen Goz 
1373403575c4SFelix Kuehling 	/* Update PD Base in QPD */
1374403575c4SFelix Kuehling 	qpd->page_table_base = pd_base;
1375e715c6d0SShaoyun Liu 	pr_debug("Updated PD address to 0x%llx\n", pd_base);
1376403575c4SFelix Kuehling 
1377bfd5e378SYong Zhao 	retval = dqm->asic_ops.update_qpd(dqm, qpd);
1378a22fc854SBen Goz 
1379f756e631SHarish Kasiviswanathan 	dqm->processes_count++;
138064c7f8cfSBen Goz 
1381efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
138264c7f8cfSBen Goz 
138332cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
138432cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
138532cce8bcSFelix Kuehling 	 */
138632cce8bcSFelix Kuehling 	kfd_inc_compute_active(dqm->dev);
138732cce8bcSFelix Kuehling 
1388a22fc854SBen Goz 	return retval;
138964c7f8cfSBen Goz }
139064c7f8cfSBen Goz 
unregister_process(struct device_queue_manager * dqm,struct qcm_process_device * qpd)139158dcd5bfSYong Zhao static int unregister_process(struct device_queue_manager *dqm,
139264c7f8cfSBen Goz 					struct qcm_process_device *qpd)
139364c7f8cfSBen Goz {
139464c7f8cfSBen Goz 	int retval;
139564c7f8cfSBen Goz 	struct device_process_node *cur, *next;
139664c7f8cfSBen Goz 
13971e5ec956SOded Gabbay 	pr_debug("qpd->queues_list is %s\n",
13981e5ec956SOded Gabbay 			list_empty(&qpd->queues_list) ? "empty" : "not empty");
139964c7f8cfSBen Goz 
140064c7f8cfSBen Goz 	retval = 0;
1401efeaed4dSFelix Kuehling 	dqm_lock(dqm);
140264c7f8cfSBen Goz 
140364c7f8cfSBen Goz 	list_for_each_entry_safe(cur, next, &dqm->queues, list) {
140464c7f8cfSBen Goz 		if (qpd == cur->qpd) {
140564c7f8cfSBen Goz 			list_del(&cur->list);
1406f5d896bbSJay Cornwall 			kfree(cur);
1407f756e631SHarish Kasiviswanathan 			dqm->processes_count--;
140864c7f8cfSBen Goz 			goto out;
140964c7f8cfSBen Goz 		}
141064c7f8cfSBen Goz 	}
141164c7f8cfSBen Goz 	/* qpd not found in dqm list */
141264c7f8cfSBen Goz 	retval = 1;
141364c7f8cfSBen Goz out:
1414efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
141532cce8bcSFelix Kuehling 
141632cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
141732cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
141832cce8bcSFelix Kuehling 	 */
141932cce8bcSFelix Kuehling 	if (!retval)
142032cce8bcSFelix Kuehling 		kfd_dec_compute_active(dqm->dev);
142132cce8bcSFelix Kuehling 
142264c7f8cfSBen Goz 	return retval;
142364c7f8cfSBen Goz }
142464c7f8cfSBen Goz 
142564c7f8cfSBen Goz static int
set_pasid_vmid_mapping(struct device_queue_manager * dqm,u32 pasid,unsigned int vmid)1426c7b6bac9SFenghua Yu set_pasid_vmid_mapping(struct device_queue_manager *dqm, u32 pasid,
142764c7f8cfSBen Goz 			unsigned int vmid)
142864c7f8cfSBen Goz {
1429c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
1430c4050ff1SLijo Lazar 	int xcc_id, ret;
1431e2069a7bSMukul Joshi 
1432c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask) {
1433e2069a7bSMukul Joshi 		ret = dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
1434c4050ff1SLijo Lazar 			dqm->dev->adev, pasid, vmid, xcc_id);
1435e2069a7bSMukul Joshi 		if (ret)
1436e2069a7bSMukul Joshi 			break;
1437e2069a7bSMukul Joshi 	}
1438e2069a7bSMukul Joshi 
1439e2069a7bSMukul Joshi 	return ret;
144064c7f8cfSBen Goz }
144164c7f8cfSBen Goz 
init_interrupts(struct device_queue_manager * dqm)14422249d558SAndrew Lewycky static void init_interrupts(struct device_queue_manager *dqm)
14432249d558SAndrew Lewycky {
1444c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
1445c4050ff1SLijo Lazar 	unsigned int i, xcc_id;
14462249d558SAndrew Lewycky 
1447b695c97bSLijo Lazar 	for_each_inst(xcc_id, xcc_mask) {
1448e2069a7bSMukul Joshi 		for (i = 0 ; i < get_pipes_per_mec(dqm) ; i++) {
1449e2069a7bSMukul Joshi 			if (is_pipe_enabled(dqm, 0, i)) {
1450e2069a7bSMukul Joshi 				dqm->dev->kfd2kgd->init_interrupts(
1451c4050ff1SLijo Lazar 					dqm->dev->adev, i, xcc_id);
1452e2069a7bSMukul Joshi 			}
1453e2069a7bSMukul Joshi 		}
14542249d558SAndrew Lewycky 	}
1455b695c97bSLijo Lazar }
14562249d558SAndrew Lewycky 
initialize_nocpsch(struct device_queue_manager * dqm)145764c7f8cfSBen Goz static int initialize_nocpsch(struct device_queue_manager *dqm)
145864c7f8cfSBen Goz {
145986194cf8SFelix Kuehling 	int pipe, queue;
146064c7f8cfSBen Goz 
146179775b62SKent Russell 	pr_debug("num of pipes: %d\n", get_pipes_per_mec(dqm));
146264c7f8cfSBen Goz 
1463ab7c1648SKent Russell 	dqm->allocated_queues = kcalloc(get_pipes_per_mec(dqm),
1464ab7c1648SKent Russell 					sizeof(unsigned int), GFP_KERNEL);
1465ab7c1648SKent Russell 	if (!dqm->allocated_queues)
1466ab7c1648SKent Russell 		return -ENOMEM;
1467ab7c1648SKent Russell 
1468efeaed4dSFelix Kuehling 	mutex_init(&dqm->lock_hidden);
146964c7f8cfSBen Goz 	INIT_LIST_HEAD(&dqm->queues);
147081b820b3SYong Zhao 	dqm->active_queue_count = dqm->next_pipe_to_allocate = 0;
1471b42902f4SYong Zhao 	dqm->active_cp_queue_count = 0;
1472b8020b03SJoseph Greathouse 	dqm->gws_queue_count = 0;
147364c7f8cfSBen Goz 
147486194cf8SFelix Kuehling 	for (pipe = 0; pipe < get_pipes_per_mec(dqm); pipe++) {
147586194cf8SFelix Kuehling 		int pipe_offset = pipe * get_queues_per_pipe(dqm);
147686194cf8SFelix Kuehling 
147786194cf8SFelix Kuehling 		for (queue = 0; queue < get_queues_per_pipe(dqm); queue++)
147886194cf8SFelix Kuehling 			if (test_bit(pipe_offset + queue,
14798dc1db31SMukul Joshi 				     dqm->dev->kfd->shared_resources.cp_queue_bitmap))
148086194cf8SFelix Kuehling 				dqm->allocated_queues[pipe] |= 1 << queue;
148186194cf8SFelix Kuehling 	}
148264c7f8cfSBen Goz 
1483d9d4623cSYong Zhao 	memset(dqm->vmid_pasid, 0, sizeof(dqm->vmid_pasid));
1484d9d4623cSYong Zhao 
1485b292cafeSFelix Kuehling 	init_sdma_bitmaps(dqm);
148664c7f8cfSBen Goz 
148764c7f8cfSBen Goz 	return 0;
148864c7f8cfSBen Goz }
148964c7f8cfSBen Goz 
uninitialize(struct device_queue_manager * dqm)149058dcd5bfSYong Zhao static void uninitialize(struct device_queue_manager *dqm)
149164c7f8cfSBen Goz {
14926f9d54fdSOded Gabbay 	int i;
14936f9d54fdSOded Gabbay 
149481b820b3SYong Zhao 	WARN_ON(dqm->active_queue_count > 0 || dqm->processes_count > 0);
149564c7f8cfSBen Goz 
149664c7f8cfSBen Goz 	kfree(dqm->allocated_queues);
14976f9d54fdSOded Gabbay 	for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++)
14988d5f3552SYong Zhao 		kfree(dqm->mqd_mgrs[i]);
1499efeaed4dSFelix Kuehling 	mutex_destroy(&dqm->lock_hidden);
150064c7f8cfSBen Goz }
150164c7f8cfSBen Goz 
start_nocpsch(struct device_queue_manager * dqm)150264c7f8cfSBen Goz static int start_nocpsch(struct device_queue_manager *dqm)
150364c7f8cfSBen Goz {
15046f4cb84aSFelix Kuehling 	int r = 0;
15056f4cb84aSFelix Kuehling 
150652055039SYong Zhao 	pr_info("SW scheduler is used");
15072249d558SAndrew Lewycky 	init_interrupts(dqm);
1508424b5442SYong Zhao 
15097eb0502aSGraham Sider 	if (dqm->dev->adev->asic_type == CHIP_HAWAII)
15106f4cb84aSFelix Kuehling 		r = pm_init(&dqm->packet_mgr, dqm);
15116f4cb84aSFelix Kuehling 	if (!r)
15122c99a547SPhilip Yang 		dqm->sched_running = true;
1513424b5442SYong Zhao 
15146f4cb84aSFelix Kuehling 	return r;
151564c7f8cfSBen Goz }
151664c7f8cfSBen Goz 
stop_nocpsch(struct device_queue_manager * dqm)151764c7f8cfSBen Goz static int stop_nocpsch(struct device_queue_manager *dqm)
151864c7f8cfSBen Goz {
15195e406012SMukul Joshi 	dqm_lock(dqm);
15205e406012SMukul Joshi 	if (!dqm->sched_running) {
15215e406012SMukul Joshi 		dqm_unlock(dqm);
15225e406012SMukul Joshi 		return 0;
15235e406012SMukul Joshi 	}
15245e406012SMukul Joshi 
15257eb0502aSGraham Sider 	if (dqm->dev->adev->asic_type == CHIP_HAWAII)
15261802b042SYunxiang Li 		pm_uninit(&dqm->packet_mgr);
15272c99a547SPhilip Yang 	dqm->sched_running = false;
15285e406012SMukul Joshi 	dqm_unlock(dqm);
1529424b5442SYong Zhao 
153064c7f8cfSBen Goz 	return 0;
153164c7f8cfSBen Goz }
153264c7f8cfSBen Goz 
allocate_sdma_queue(struct device_queue_manager * dqm,struct queue * q,const uint32_t * restore_sdma_id)1533bcea3081SBen Goz static int allocate_sdma_queue(struct device_queue_manager *dqm,
15342485c12cSDavid Yat Sin 				struct queue *q, const uint32_t *restore_sdma_id)
1535bcea3081SBen Goz {
153680c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
1537bcea3081SBen Goz 	int bit;
1538bcea3081SBen Goz 
15391b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
1540a805889aSMukul Joshi 		if (bitmap_empty(dqm->sdma_bitmap, KFD_MAX_SDMA_QUEUES)) {
154180c74918SAsad Kamal 			dev_err(dev, "No more SDMA queue to allocate\n");
1542bcea3081SBen Goz 			return -ENOMEM;
1543c7637c95SYong Zhao 		}
1544c7637c95SYong Zhao 
15452485c12cSDavid Yat Sin 		if (restore_sdma_id) {
15462485c12cSDavid Yat Sin 			/* Re-use existing sdma_id */
1547a805889aSMukul Joshi 			if (!test_bit(*restore_sdma_id, dqm->sdma_bitmap)) {
154880c74918SAsad Kamal 				dev_err(dev, "SDMA queue already in use\n");
15492485c12cSDavid Yat Sin 				return -EBUSY;
15502485c12cSDavid Yat Sin 			}
1551a805889aSMukul Joshi 			clear_bit(*restore_sdma_id, dqm->sdma_bitmap);
15522485c12cSDavid Yat Sin 			q->sdma_id = *restore_sdma_id;
15532485c12cSDavid Yat Sin 		} else {
15542485c12cSDavid Yat Sin 			/* Find first available sdma_id */
1555a805889aSMukul Joshi 			bit = find_first_bit(dqm->sdma_bitmap,
1556a805889aSMukul Joshi 					     get_num_sdma_queues(dqm));
1557a805889aSMukul Joshi 			clear_bit(bit, dqm->sdma_bitmap);
1558e78579aaSYong Zhao 			q->sdma_id = bit;
15592485c12cSDavid Yat Sin 		}
15602485c12cSDavid Yat Sin 
1561a805889aSMukul Joshi 		q->properties.sdma_engine_id =
1562a805889aSMukul Joshi 			q->sdma_id % kfd_get_num_sdma_engines(dqm->dev);
15631b4670f6SOak Zeng 		q->properties.sdma_queue_id = q->sdma_id /
1564ee2f17f4SAmber Lin 				kfd_get_num_sdma_engines(dqm->dev);
15651b4670f6SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
1566a805889aSMukul Joshi 		if (bitmap_empty(dqm->xgmi_sdma_bitmap, KFD_MAX_SDMA_QUEUES)) {
156780c74918SAsad Kamal 			dev_err(dev, "No more XGMI SDMA queue to allocate\n");
15681b4670f6SOak Zeng 			return -ENOMEM;
1569c7637c95SYong Zhao 		}
15702485c12cSDavid Yat Sin 		if (restore_sdma_id) {
15712485c12cSDavid Yat Sin 			/* Re-use existing sdma_id */
1572a805889aSMukul Joshi 			if (!test_bit(*restore_sdma_id, dqm->xgmi_sdma_bitmap)) {
157380c74918SAsad Kamal 				dev_err(dev, "SDMA queue already in use\n");
15742485c12cSDavid Yat Sin 				return -EBUSY;
15752485c12cSDavid Yat Sin 			}
1576a805889aSMukul Joshi 			clear_bit(*restore_sdma_id, dqm->xgmi_sdma_bitmap);
15772485c12cSDavid Yat Sin 			q->sdma_id = *restore_sdma_id;
15782485c12cSDavid Yat Sin 		} else {
1579a805889aSMukul Joshi 			bit = find_first_bit(dqm->xgmi_sdma_bitmap,
1580a805889aSMukul Joshi 					     get_num_xgmi_sdma_queues(dqm));
1581a805889aSMukul Joshi 			clear_bit(bit, dqm->xgmi_sdma_bitmap);
15821b4670f6SOak Zeng 			q->sdma_id = bit;
15832485c12cSDavid Yat Sin 		}
15841b4670f6SOak Zeng 		/* sdma_engine_id is sdma id including
15851b4670f6SOak Zeng 		 * both PCIe-optimized SDMAs and XGMI-
15861b4670f6SOak Zeng 		 * optimized SDMAs. The calculation below
15871b4670f6SOak Zeng 		 * assumes the first N engines are always
15881b4670f6SOak Zeng 		 * PCIe-optimized ones
15891b4670f6SOak Zeng 		 */
1590ee2f17f4SAmber Lin 		q->properties.sdma_engine_id =
1591ee2f17f4SAmber Lin 			kfd_get_num_sdma_engines(dqm->dev) +
1592ee2f17f4SAmber Lin 			q->sdma_id % kfd_get_num_xgmi_sdma_engines(dqm->dev);
15931b4670f6SOak Zeng 		q->properties.sdma_queue_id = q->sdma_id /
1594ee2f17f4SAmber Lin 			kfd_get_num_xgmi_sdma_engines(dqm->dev);
1595e06b71b2SJonathan Kim 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_BY_ENG_ID) {
1596e06b71b2SJonathan Kim 		int i, num_queues, num_engines, eng_offset = 0, start_engine;
1597e06b71b2SJonathan Kim 		bool free_bit_found = false, is_xgmi = false;
1598e06b71b2SJonathan Kim 
1599e06b71b2SJonathan Kim 		if (q->properties.sdma_engine_id < kfd_get_num_sdma_engines(dqm->dev)) {
1600e06b71b2SJonathan Kim 			num_queues = get_num_sdma_queues(dqm);
1601e06b71b2SJonathan Kim 			num_engines = kfd_get_num_sdma_engines(dqm->dev);
1602e06b71b2SJonathan Kim 			q->properties.type = KFD_QUEUE_TYPE_SDMA;
1603e06b71b2SJonathan Kim 		} else {
1604e06b71b2SJonathan Kim 			num_queues = get_num_xgmi_sdma_queues(dqm);
1605e06b71b2SJonathan Kim 			num_engines = kfd_get_num_xgmi_sdma_engines(dqm->dev);
1606e06b71b2SJonathan Kim 			eng_offset = kfd_get_num_sdma_engines(dqm->dev);
1607e06b71b2SJonathan Kim 			q->properties.type = KFD_QUEUE_TYPE_SDMA_XGMI;
1608e06b71b2SJonathan Kim 			is_xgmi = true;
1609e06b71b2SJonathan Kim 		}
1610e06b71b2SJonathan Kim 
1611e06b71b2SJonathan Kim 		/* Scan available bit based on target engine ID. */
1612e06b71b2SJonathan Kim 		start_engine = q->properties.sdma_engine_id - eng_offset;
1613e06b71b2SJonathan Kim 		for (i = start_engine; i < num_queues; i += num_engines) {
1614e06b71b2SJonathan Kim 
1615e06b71b2SJonathan Kim 			if (!test_bit(i, is_xgmi ? dqm->xgmi_sdma_bitmap : dqm->sdma_bitmap))
1616e06b71b2SJonathan Kim 				continue;
1617e06b71b2SJonathan Kim 
1618e06b71b2SJonathan Kim 			clear_bit(i, is_xgmi ? dqm->xgmi_sdma_bitmap : dqm->sdma_bitmap);
1619e06b71b2SJonathan Kim 			q->sdma_id = i;
1620e06b71b2SJonathan Kim 			q->properties.sdma_queue_id = q->sdma_id / num_engines;
1621e06b71b2SJonathan Kim 			free_bit_found = true;
1622e06b71b2SJonathan Kim 			break;
1623e06b71b2SJonathan Kim 		}
1624e06b71b2SJonathan Kim 
1625e06b71b2SJonathan Kim 		if (!free_bit_found) {
1626e06b71b2SJonathan Kim 			dev_err(dev, "No more SDMA queue to allocate for target ID %i\n",
1627e06b71b2SJonathan Kim 				q->properties.sdma_engine_id);
1628e06b71b2SJonathan Kim 			return -ENOMEM;
1629e06b71b2SJonathan Kim 		}
16301b4670f6SOak Zeng 	}
1631e78579aaSYong Zhao 
1632e78579aaSYong Zhao 	pr_debug("SDMA engine id: %d\n", q->properties.sdma_engine_id);
1633e78579aaSYong Zhao 	pr_debug("SDMA queue id: %d\n", q->properties.sdma_queue_id);
1634bcea3081SBen Goz 
1635bcea3081SBen Goz 	return 0;
1636bcea3081SBen Goz }
1637bcea3081SBen Goz 
deallocate_sdma_queue(struct device_queue_manager * dqm,struct queue * q)1638bcea3081SBen Goz static void deallocate_sdma_queue(struct device_queue_manager *dqm,
16391b4670f6SOak Zeng 				struct queue *q)
1640bcea3081SBen Goz {
16411b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
16421b4670f6SOak Zeng 		if (q->sdma_id >= get_num_sdma_queues(dqm))
1643bcea3081SBen Goz 			return;
1644a805889aSMukul Joshi 		set_bit(q->sdma_id, dqm->sdma_bitmap);
16451b4670f6SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
16461b4670f6SOak Zeng 		if (q->sdma_id >= get_num_xgmi_sdma_queues(dqm))
16471b4670f6SOak Zeng 			return;
1648a805889aSMukul Joshi 		set_bit(q->sdma_id, dqm->xgmi_sdma_bitmap);
16491b4670f6SOak Zeng 	}
1650bcea3081SBen Goz }
1651bcea3081SBen Goz 
165264c7f8cfSBen Goz /*
165364c7f8cfSBen Goz  * Device Queue Manager implementation for cp scheduler
165464c7f8cfSBen Goz  */
165564c7f8cfSBen Goz 
set_sched_resources(struct device_queue_manager * dqm)165664c7f8cfSBen Goz static int set_sched_resources(struct device_queue_manager *dqm)
165764c7f8cfSBen Goz {
1658d0b63bb3SAndres Rodriguez 	int i, mec;
165964c7f8cfSBen Goz 	struct scheduling_resources res;
166080c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
166164c7f8cfSBen Goz 
166274c5b85dSMukul Joshi 	res.vmid_mask = dqm->dev->compute_vmid_bitmap;
1663d0b63bb3SAndres Rodriguez 
1664d0b63bb3SAndres Rodriguez 	res.queue_mask = 0;
166568fa72a4SMukul Joshi 	for (i = 0; i < AMDGPU_MAX_QUEUES; ++i) {
16668dc1db31SMukul Joshi 		mec = (i / dqm->dev->kfd->shared_resources.num_queue_per_pipe)
16678dc1db31SMukul Joshi 			/ dqm->dev->kfd->shared_resources.num_pipe_per_mec;
1668d0b63bb3SAndres Rodriguez 
16698dc1db31SMukul Joshi 		if (!test_bit(i, dqm->dev->kfd->shared_resources.cp_queue_bitmap))
1670d0b63bb3SAndres Rodriguez 			continue;
1671d0b63bb3SAndres Rodriguez 
1672d0b63bb3SAndres Rodriguez 		/* only acquire queues from the first MEC */
1673d0b63bb3SAndres Rodriguez 		if (mec > 0)
1674d0b63bb3SAndres Rodriguez 			continue;
1675d0b63bb3SAndres Rodriguez 
1676d0b63bb3SAndres Rodriguez 		/* This situation may be hit in the future if a new HW
1677d0b63bb3SAndres Rodriguez 		 * generation exposes more than 64 queues. If so, the
16788eabaf54SKent Russell 		 * definition of res.queue_mask needs updating
16798eabaf54SKent Russell 		 */
16801d11ee89SDan Carpenter 		if (WARN_ON(i >= (sizeof(res.queue_mask)*8))) {
168180c74918SAsad Kamal 			dev_err(dev, "Invalid queue enabled by amdgpu: %d\n", i);
1682d0b63bb3SAndres Rodriguez 			break;
1683d0b63bb3SAndres Rodriguez 		}
1684d0b63bb3SAndres Rodriguez 
1685d09f85d5SYong Zhao 		res.queue_mask |= 1ull
1686d09f85d5SYong Zhao 			<< amdgpu_queue_mask_bit_to_set_resource_bit(
168756c5977eSGraham Sider 				dqm->dev->adev, i);
1688d0b63bb3SAndres Rodriguez 	}
1689d9848e14SOak Zeng 	res.gws_mask = ~0ull;
1690d9848e14SOak Zeng 	res.oac_mask = res.gds_heap_base = res.gds_heap_size = 0;
169164c7f8cfSBen Goz 
169279775b62SKent Russell 	pr_debug("Scheduling resources:\n"
169364c7f8cfSBen Goz 			"vmid mask: 0x%8X\n"
169464c7f8cfSBen Goz 			"queue mask: 0x%8llX\n",
169564c7f8cfSBen Goz 			res.vmid_mask, res.queue_mask);
169664c7f8cfSBen Goz 
16979af5379cSOak Zeng 	return pm_send_set_resources(&dqm->packet_mgr, &res);
169864c7f8cfSBen Goz }
169964c7f8cfSBen Goz 
initialize_cpsch(struct device_queue_manager * dqm)170064c7f8cfSBen Goz static int initialize_cpsch(struct device_queue_manager *dqm)
170164c7f8cfSBen Goz {
170279775b62SKent Russell 	pr_debug("num of pipes: %d\n", get_pipes_per_mec(dqm));
170364c7f8cfSBen Goz 
1704efeaed4dSFelix Kuehling 	mutex_init(&dqm->lock_hidden);
170564c7f8cfSBen Goz 	INIT_LIST_HEAD(&dqm->queues);
170681b820b3SYong Zhao 	dqm->active_queue_count = dqm->processes_count = 0;
1707b42902f4SYong Zhao 	dqm->active_cp_queue_count = 0;
1708b8020b03SJoseph Greathouse 	dqm->gws_queue_count = 0;
170964c7f8cfSBen Goz 	dqm->active_runlist = false;
171073ea648dSShaoyun Liu 	INIT_WORK(&dqm->hw_exception_work, kfd_process_hw_exception);
171197ae3c8cSJonathan Kim 	dqm->trap_debug_vmid = 0;
171273ea648dSShaoyun Liu 
1713b292cafeSFelix Kuehling 	init_sdma_bitmaps(dqm);
1714b292cafeSFelix Kuehling 
17157cee6a68SJonathan Kim 	if (dqm->dev->kfd2kgd->get_iq_wait_times)
17167cee6a68SJonathan Kim 		dqm->dev->kfd2kgd->get_iq_wait_times(dqm->dev->adev,
1717036e348fSEric Huang 					&dqm->wait_times,
17181879e009SMukul Joshi 					ffs(dqm->dev->xcc_mask) - 1);
1719bfd5e378SYong Zhao 	return 0;
172064c7f8cfSBen Goz }
172164c7f8cfSBen Goz 
1722234eebe1SAmber Lin /* halt_cpsch:
1723234eebe1SAmber Lin  * Unmap queues so the schedule doesn't continue remaining jobs in the queue.
1724234eebe1SAmber Lin  * Then set dqm->sched_halt so queues don't map to runlist until unhalt_cpsch
1725234eebe1SAmber Lin  * is called.
1726234eebe1SAmber Lin  */
halt_cpsch(struct device_queue_manager * dqm)1727234eebe1SAmber Lin static int halt_cpsch(struct device_queue_manager *dqm)
1728234eebe1SAmber Lin {
1729234eebe1SAmber Lin 	int ret = 0;
1730234eebe1SAmber Lin 
1731234eebe1SAmber Lin 	dqm_lock(dqm);
1732234eebe1SAmber Lin 	if (!dqm->sched_running) {
1733234eebe1SAmber Lin 		dqm_unlock(dqm);
1734234eebe1SAmber Lin 		return 0;
1735234eebe1SAmber Lin 	}
1736234eebe1SAmber Lin 
1737234eebe1SAmber Lin 	WARN_ONCE(dqm->sched_halt, "Scheduling is already on halt\n");
1738234eebe1SAmber Lin 
1739234eebe1SAmber Lin 	if (!dqm->is_hws_hang) {
1740234eebe1SAmber Lin 		if (!dqm->dev->kfd->shared_resources.enable_mes)
1741234eebe1SAmber Lin 			ret = unmap_queues_cpsch(dqm,
1742234eebe1SAmber Lin 						 KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
1743234eebe1SAmber Lin 				USE_DEFAULT_GRACE_PERIOD, false);
1744234eebe1SAmber Lin 		else
1745234eebe1SAmber Lin 			ret = remove_all_queues_mes(dqm);
1746234eebe1SAmber Lin 	}
1747234eebe1SAmber Lin 	dqm->sched_halt = true;
1748234eebe1SAmber Lin 	dqm_unlock(dqm);
1749234eebe1SAmber Lin 
1750234eebe1SAmber Lin 	return ret;
1751234eebe1SAmber Lin }
1752234eebe1SAmber Lin 
1753234eebe1SAmber Lin /* unhalt_cpsch
1754234eebe1SAmber Lin  * Unset dqm->sched_halt and map queues back to runlist
1755234eebe1SAmber Lin  */
unhalt_cpsch(struct device_queue_manager * dqm)1756234eebe1SAmber Lin static int unhalt_cpsch(struct device_queue_manager *dqm)
1757234eebe1SAmber Lin {
1758234eebe1SAmber Lin 	int ret = 0;
1759234eebe1SAmber Lin 
1760234eebe1SAmber Lin 	dqm_lock(dqm);
1761234eebe1SAmber Lin 	if (!dqm->sched_running || !dqm->sched_halt) {
1762234eebe1SAmber Lin 		WARN_ONCE(!dqm->sched_halt, "Scheduling is not on halt.\n");
1763234eebe1SAmber Lin 		dqm_unlock(dqm);
1764234eebe1SAmber Lin 		return 0;
1765234eebe1SAmber Lin 	}
1766234eebe1SAmber Lin 	dqm->sched_halt = false;
1767234eebe1SAmber Lin 	if (!dqm->dev->kfd->shared_resources.enable_mes)
1768234eebe1SAmber Lin 		ret = execute_queues_cpsch(dqm,
1769234eebe1SAmber Lin 					   KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES,
1770234eebe1SAmber Lin 			0, USE_DEFAULT_GRACE_PERIOD);
1771234eebe1SAmber Lin 	dqm_unlock(dqm);
1772234eebe1SAmber Lin 
1773234eebe1SAmber Lin 	return ret;
1774234eebe1SAmber Lin }
1775234eebe1SAmber Lin 
start_cpsch(struct device_queue_manager * dqm)177664c7f8cfSBen Goz static int start_cpsch(struct device_queue_manager *dqm)
177764c7f8cfSBen Goz {
177880c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
1779ee0a469cSJonathan Kim 	int retval, num_hw_queue_slots;
178064c7f8cfSBen Goz 
178164c7f8cfSBen Goz 	retval = 0;
178264c7f8cfSBen Goz 
17834f942aaeSOak Zeng 	dqm_lock(dqm);
1784cc009e61SMukul Joshi 
17858dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes) {
17869af5379cSOak Zeng 		retval = pm_init(&dqm->packet_mgr, dqm);
17874eacc26bSKent Russell 		if (retval)
178864c7f8cfSBen Goz 			goto fail_packet_manager_init;
178964c7f8cfSBen Goz 
179064c7f8cfSBen Goz 		retval = set_sched_resources(dqm);
17914eacc26bSKent Russell 		if (retval)
179264c7f8cfSBen Goz 			goto fail_set_sched_resources;
1793cc009e61SMukul Joshi 	}
179479775b62SKent Russell 	pr_debug("Allocating fence memory\n");
179564c7f8cfSBen Goz 
179664c7f8cfSBen Goz 	/* allocate fence memory on the gart */
1797a86aa3caSOded Gabbay 	retval = kfd_gtt_sa_allocate(dqm->dev, sizeof(*dqm->fence_addr),
1798a86aa3caSOded Gabbay 					&dqm->fence_mem);
179964c7f8cfSBen Goz 
18004eacc26bSKent Russell 	if (retval)
180164c7f8cfSBen Goz 		goto fail_allocate_vidmem;
180264c7f8cfSBen Goz 
1803b010affeSQu Huang 	dqm->fence_addr = (uint64_t *)dqm->fence_mem->cpu_ptr;
180464c7f8cfSBen Goz 	dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
18052249d558SAndrew Lewycky 
18062249d558SAndrew Lewycky 	init_interrupts(dqm);
18072249d558SAndrew Lewycky 
180873ea648dSShaoyun Liu 	/* clear hang status when driver try to start the hw scheduler */
18092c99a547SPhilip Yang 	dqm->sched_running = true;
18107cee6a68SJonathan Kim 
18118dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18127cee6a68SJonathan Kim 		execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD);
18131879e009SMukul Joshi 
18141879e009SMukul Joshi 	/* Set CWSR grace period to 1x1000 cycle for GFX9.4.3 APU */
18151879e009SMukul Joshi 	if (amdgpu_emu_mode == 0 && dqm->dev->adev->gmc.is_app_apu &&
18161879e009SMukul Joshi 	    (KFD_GC_VERSION(dqm->dev) == IP_VERSION(9, 4, 3))) {
18171879e009SMukul Joshi 		uint32_t reg_offset = 0;
18181879e009SMukul Joshi 		uint32_t grace_period = 1;
18191879e009SMukul Joshi 
18201879e009SMukul Joshi 		retval = pm_update_grace_period(&dqm->packet_mgr,
18211879e009SMukul Joshi 						grace_period);
18221879e009SMukul Joshi 		if (retval)
182380c74918SAsad Kamal 			dev_err(dev, "Setting grace timeout failed\n");
18241879e009SMukul Joshi 		else if (dqm->dev->kfd2kgd->build_grace_period_packet_info)
18251879e009SMukul Joshi 			/* Update dqm->wait_times maintained in software */
18261879e009SMukul Joshi 			dqm->dev->kfd2kgd->build_grace_period_packet_info(
18271879e009SMukul Joshi 					dqm->dev->adev,	dqm->wait_times,
18281879e009SMukul Joshi 					grace_period, &reg_offset,
182956d6daa3SMukul Joshi 					&dqm->wait_times);
18301879e009SMukul Joshi 	}
18311879e009SMukul Joshi 
1832ee0a469cSJonathan Kim 	/* setup per-queue reset detection buffer  */
1833ee0a469cSJonathan Kim 	num_hw_queue_slots =  dqm->dev->kfd->shared_resources.num_queue_per_pipe *
1834ee0a469cSJonathan Kim 			      dqm->dev->kfd->shared_resources.num_pipe_per_mec *
1835ee0a469cSJonathan Kim 			      NUM_XCC(dqm->dev->xcc_mask);
1836ee0a469cSJonathan Kim 
1837ee0a469cSJonathan Kim 	dqm->detect_hang_info_size = num_hw_queue_slots * sizeof(struct dqm_detect_hang_info);
1838ee0a469cSJonathan Kim 	dqm->detect_hang_info = kzalloc(dqm->detect_hang_info_size, GFP_KERNEL);
1839ee0a469cSJonathan Kim 
1840ee0a469cSJonathan Kim 	if (!dqm->detect_hang_info) {
1841ee0a469cSJonathan Kim 		retval = -ENOMEM;
1842ee0a469cSJonathan Kim 		goto fail_detect_hang_buffer;
1843ee0a469cSJonathan Kim 	}
1844ee0a469cSJonathan Kim 
1845efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
184664c7f8cfSBen Goz 
184764c7f8cfSBen Goz 	return 0;
1848ee0a469cSJonathan Kim fail_detect_hang_buffer:
1849ee0a469cSJonathan Kim 	kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
185064c7f8cfSBen Goz fail_allocate_vidmem:
185164c7f8cfSBen Goz fail_set_sched_resources:
18528dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18531802b042SYunxiang Li 		pm_uninit(&dqm->packet_mgr);
185464c7f8cfSBen Goz fail_packet_manager_init:
18554f942aaeSOak Zeng 	dqm_unlock(dqm);
185664c7f8cfSBen Goz 	return retval;
185764c7f8cfSBen Goz }
185864c7f8cfSBen Goz 
stop_cpsch(struct device_queue_manager * dqm)185964c7f8cfSBen Goz static int stop_cpsch(struct device_queue_manager *dqm)
186064c7f8cfSBen Goz {
1861efeaed4dSFelix Kuehling 	dqm_lock(dqm);
1862c96cb659Sshaoyunl 	if (!dqm->sched_running) {
1863c96cb659Sshaoyunl 		dqm_unlock(dqm);
1864c96cb659Sshaoyunl 		return 0;
1865c96cb659Sshaoyunl 	}
1866c96cb659Sshaoyunl 
18678dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18687cee6a68SJonathan Kim 		unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD, false);
1869cc009e61SMukul Joshi 	else
1870cc009e61SMukul Joshi 		remove_all_queues_mes(dqm);
1871cc009e61SMukul Joshi 
18722c99a547SPhilip Yang 	dqm->sched_running = false;
187364c7f8cfSBen Goz 
18748dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18759af5379cSOak Zeng 		pm_release_ib(&dqm->packet_mgr);
1876087d7641SDennis Li 
1877a86aa3caSOded Gabbay 	kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
18788dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18791802b042SYunxiang Li 		pm_uninit(&dqm->packet_mgr);
1880ee0a469cSJonathan Kim 	kfree(dqm->detect_hang_info);
1881ee0a469cSJonathan Kim 	dqm->detect_hang_info = NULL;
18824f942aaeSOak Zeng 	dqm_unlock(dqm);
188364c7f8cfSBen Goz 
188464c7f8cfSBen Goz 	return 0;
188564c7f8cfSBen Goz }
188664c7f8cfSBen Goz 
create_kernel_queue_cpsch(struct device_queue_manager * dqm,struct kernel_queue * kq,struct qcm_process_device * qpd)188764c7f8cfSBen Goz static int create_kernel_queue_cpsch(struct device_queue_manager *dqm,
188864c7f8cfSBen Goz 					struct kernel_queue *kq,
188964c7f8cfSBen Goz 					struct qcm_process_device *qpd)
189064c7f8cfSBen Goz {
1891efeaed4dSFelix Kuehling 	dqm_lock(dqm);
1892b8cbab04SOded Gabbay 	if (dqm->total_queue_count >= max_num_of_queues_per_device) {
189379775b62SKent Russell 		pr_warn("Can't create new kernel queue because %d queues were already created\n",
1894b8cbab04SOded Gabbay 				dqm->total_queue_count);
1895efeaed4dSFelix Kuehling 		dqm_unlock(dqm);
1896b8cbab04SOded Gabbay 		return -EPERM;
1897b8cbab04SOded Gabbay 	}
1898b8cbab04SOded Gabbay 
1899b8cbab04SOded Gabbay 	/*
1900b8cbab04SOded Gabbay 	 * Unconditionally increment this counter, regardless of the queue's
1901b8cbab04SOded Gabbay 	 * type or whether the queue is active.
1902b8cbab04SOded Gabbay 	 */
1903b8cbab04SOded Gabbay 	dqm->total_queue_count++;
1904b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
1905b8cbab04SOded Gabbay 			dqm->total_queue_count);
1906b8cbab04SOded Gabbay 
190764c7f8cfSBen Goz 	list_add(&kq->list, &qpd->priv_queue_list);
1908ab4d51d4SDavid Yat Sin 	increment_queue_count(dqm, qpd, kq->queue);
190964c7f8cfSBen Goz 	qpd->is_debug = true;
19107cee6a68SJonathan Kim 	execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
19117cee6a68SJonathan Kim 			USE_DEFAULT_GRACE_PERIOD);
1912efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
191364c7f8cfSBen Goz 
191464c7f8cfSBen Goz 	return 0;
191564c7f8cfSBen Goz }
191664c7f8cfSBen Goz 
destroy_kernel_queue_cpsch(struct device_queue_manager * dqm,struct kernel_queue * kq,struct qcm_process_device * qpd)191764c7f8cfSBen Goz static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm,
191864c7f8cfSBen Goz 					struct kernel_queue *kq,
191964c7f8cfSBen Goz 					struct qcm_process_device *qpd)
192064c7f8cfSBen Goz {
1921efeaed4dSFelix Kuehling 	dqm_lock(dqm);
192264c7f8cfSBen Goz 	list_del(&kq->list);
1923ab4d51d4SDavid Yat Sin 	decrement_queue_count(dqm, qpd, kq->queue);
192464c7f8cfSBen Goz 	qpd->is_debug = false;
19257cee6a68SJonathan Kim 	execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
19267cee6a68SJonathan Kim 			USE_DEFAULT_GRACE_PERIOD);
1927b8cbab04SOded Gabbay 	/*
1928b8cbab04SOded Gabbay 	 * Unconditionally decrement this counter, regardless of the queue's
1929b8cbab04SOded Gabbay 	 * type.
1930b8cbab04SOded Gabbay 	 */
19318b58f261SOded Gabbay 	dqm->total_queue_count--;
1932b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
1933b8cbab04SOded Gabbay 			dqm->total_queue_count);
1934efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
193564c7f8cfSBen Goz }
193664c7f8cfSBen Goz 
create_queue_cpsch(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd,const struct kfd_criu_queue_priv_data * qd,const void * restore_mqd,const void * restore_ctl_stack)193764c7f8cfSBen Goz static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
19382485c12cSDavid Yat Sin 			struct qcm_process_device *qpd,
193942c6c482SDavid Yat Sin 			const struct kfd_criu_queue_priv_data *qd,
19403a9822d7SDavid Yat Sin 			const void *restore_mqd, const void *restore_ctl_stack)
194164c7f8cfSBen Goz {
194264c7f8cfSBen Goz 	int retval;
19438d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
194464c7f8cfSBen Goz 
1945b8cbab04SOded Gabbay 	if (dqm->total_queue_count >= max_num_of_queues_per_device) {
194679775b62SKent Russell 		pr_warn("Can't create new usermode queue because %d queues were already created\n",
1947b8cbab04SOded Gabbay 				dqm->total_queue_count);
194870d488fbSOak Zeng 		retval = -EPERM;
194970d488fbSOak Zeng 		goto out;
1950b8cbab04SOded Gabbay 	}
1951b8cbab04SOded Gabbay 
19521b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
1953e06b71b2SJonathan Kim 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI ||
1954e06b71b2SJonathan Kim 		q->properties.type == KFD_QUEUE_TYPE_SDMA_BY_ENG_ID) {
195538bb4226SOak Zeng 		dqm_lock(dqm);
19562485c12cSDavid Yat Sin 		retval = allocate_sdma_queue(dqm, q, qd ? &qd->sdma_id : NULL);
195738bb4226SOak Zeng 		dqm_unlock(dqm);
1958894a8293SFelix Kuehling 		if (retval)
195970d488fbSOak Zeng 			goto out;
1960e139cd2aSshaoyunl 	}
1961ef568db7SFelix Kuehling 
19625bb6a8faSDavid Yat Sin 	retval = allocate_doorbell(qpd, q, qd ? &qd->doorbell_id : NULL);
1963ef568db7SFelix Kuehling 	if (retval)
1964ef568db7SFelix Kuehling 		goto out_deallocate_sdma_queue;
1965ef568db7SFelix Kuehling 
196670d488fbSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
196770d488fbSOak Zeng 			q->properties.type)];
196870df8273SEric Huang 
1969eec0b4cfSOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
1970eec0b4cfSOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
1971bfd5e378SYong Zhao 		dqm->asic_ops.init_sdma_vm(dqm, q, qpd);
1972373d7080SFelix Kuehling 	q->properties.tba_addr = qpd->tba_addr;
1973373d7080SFelix Kuehling 	q->properties.tma_addr = qpd->tma_addr;
197470d488fbSOak Zeng 	q->mqd_mem_obj = mqd_mgr->allocate_mqd(mqd_mgr->dev, &q->properties);
197570d488fbSOak Zeng 	if (!q->mqd_mem_obj) {
197670d488fbSOak Zeng 		retval = -ENOMEM;
197770d488fbSOak Zeng 		goto out_deallocate_doorbell;
197870d488fbSOak Zeng 	}
197970df8273SEric Huang 
198070df8273SEric Huang 	dqm_lock(dqm);
198170df8273SEric Huang 	/*
198270df8273SEric Huang 	 * Eviction state logic: mark all queues as evicted, even ones
198370df8273SEric Huang 	 * not currently active. Restoring inactive queues later only
198470df8273SEric Huang 	 * updates the is_evicted flag but is a no-op otherwise.
198570df8273SEric Huang 	 */
198670df8273SEric Huang 	q->properties.is_evicted = !!qpd->evicted;
198769a8c3aeSJonathan Kim 	q->properties.is_dbg_wa = qpd->pqm->process->debug_trap_enabled &&
1988cef600e1SJonathan Kim 				  kfd_dbg_has_cwsr_workaround(q->device);
198942c6c482SDavid Yat Sin 
199042c6c482SDavid Yat Sin 	if (qd)
199142c6c482SDavid Yat Sin 		mqd_mgr->restore_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj, &q->gart_mqd_addr,
19923a9822d7SDavid Yat Sin 				     &q->properties, restore_mqd, restore_ctl_stack,
19933a9822d7SDavid Yat Sin 				     qd->ctl_stack_size);
199442c6c482SDavid Yat Sin 	else
19958636e53cSOak Zeng 		mqd_mgr->init_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj,
19968636e53cSOak Zeng 					&q->gart_mqd_addr, &q->properties);
199789cd9d23SPhilip Yang 
199864c7f8cfSBen Goz 	list_add(&q->list, &qpd->queues_list);
1999bc920fd4SFelix Kuehling 	qpd->queue_count++;
2000f38abc15SYong Zhao 
200164c7f8cfSBen Goz 	if (q->properties.is_active) {
2002ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, qpd, q);
2003b42902f4SYong Zhao 
20048dc1db31SMukul Joshi 		if (!dqm->dev->kfd->shared_resources.enable_mes)
2005cc009e61SMukul Joshi 			retval = execute_queues_cpsch(dqm,
20067cee6a68SJonathan Kim 					KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD);
2007cc3cb791Sxinhui pan 		else
2008cc009e61SMukul Joshi 			retval = add_queue_mes(dqm, q, qpd);
2009cc009e61SMukul Joshi 		if (retval)
2010cc009e61SMukul Joshi 			goto cleanup_queue;
2011cc009e61SMukul Joshi 	}
201264c7f8cfSBen Goz 
2013b8cbab04SOded Gabbay 	/*
2014b8cbab04SOded Gabbay 	 * Unconditionally increment this counter, regardless of the queue's
2015b8cbab04SOded Gabbay 	 * type or whether the queue is active.
2016b8cbab04SOded Gabbay 	 */
2017b8cbab04SOded Gabbay 	dqm->total_queue_count++;
2018b8cbab04SOded Gabbay 
2019b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
2020b8cbab04SOded Gabbay 			dqm->total_queue_count);
2021b8cbab04SOded Gabbay 
2022efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
202372a01d23SFelix Kuehling 	return retval;
202472a01d23SFelix Kuehling 
2025cc009e61SMukul Joshi cleanup_queue:
2026cc009e61SMukul Joshi 	qpd->queue_count--;
2027cc009e61SMukul Joshi 	list_del(&q->list);
2028cc009e61SMukul Joshi 	if (q->properties.is_active)
2029cc009e61SMukul Joshi 		decrement_queue_count(dqm, qpd, q);
2030cc009e61SMukul Joshi 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
2031cc009e61SMukul Joshi 	dqm_unlock(dqm);
203270d488fbSOak Zeng out_deallocate_doorbell:
203370d488fbSOak Zeng 	deallocate_doorbell(qpd, q);
203472a01d23SFelix Kuehling out_deallocate_sdma_queue:
20351b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
203638bb4226SOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
203738bb4226SOak Zeng 		dqm_lock(dqm);
20381b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
203938bb4226SOak Zeng 		dqm_unlock(dqm);
204038bb4226SOak Zeng 	}
204170d488fbSOak Zeng out:
204264c7f8cfSBen Goz 	return retval;
204364c7f8cfSBen Goz }
204464c7f8cfSBen Goz 
amdkfd_fence_wait_timeout(struct device_queue_manager * dqm,uint64_t fence_value,unsigned int timeout_ms)204580c74918SAsad Kamal int amdkfd_fence_wait_timeout(struct device_queue_manager *dqm,
2046b010affeSQu Huang 			      uint64_t fence_value,
20478c72c3d7SYong Zhao 			      unsigned int timeout_ms)
204864c7f8cfSBen Goz {
20498c72c3d7SYong Zhao 	unsigned long end_jiffies = msecs_to_jiffies(timeout_ms) + jiffies;
205080c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
205180c74918SAsad Kamal 	uint64_t *fence_addr =  dqm->fence_addr;
205264c7f8cfSBen Goz 
205364c7f8cfSBen Goz 	while (*fence_addr != fence_value) {
2054e1f6746fSLijo Lazar 		/* Fatal err detected, this response won't come */
2055e1f6746fSLijo Lazar 		if (amdgpu_amdkfd_is_fed(dqm->dev->adev))
2056e1f6746fSLijo Lazar 			return -EIO;
2057e1f6746fSLijo Lazar 
20588c72c3d7SYong Zhao 		if (time_after(jiffies, end_jiffies)) {
205980c74918SAsad Kamal 			dev_err(dev, "qcm fence wait loop timeout expired\n");
20600e9a860cSYong Zhao 			/* In HWS case, this is used to halt the driver thread
20610e9a860cSYong Zhao 			 * in order not to mess up CP states before doing
20620e9a860cSYong Zhao 			 * scandumps for FW debugging.
20630e9a860cSYong Zhao 			 */
20640e9a860cSYong Zhao 			while (halt_if_hws_hang)
20650e9a860cSYong Zhao 				schedule();
20660e9a860cSYong Zhao 
206764c7f8cfSBen Goz 			return -ETIME;
206864c7f8cfSBen Goz 		}
206999331a51SOded Gabbay 		schedule();
207064c7f8cfSBen Goz 	}
207164c7f8cfSBen Goz 
207264c7f8cfSBen Goz 	return 0;
207364c7f8cfSBen Goz }
207464c7f8cfSBen Goz 
2075ac30c783SYong Zhao /* dqm->lock mutex has to be locked before calling this function */
map_queues_cpsch(struct device_queue_manager * dqm)207660a00956SFelix Kuehling static int map_queues_cpsch(struct device_queue_manager *dqm)
207760a00956SFelix Kuehling {
207880c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
207960a00956SFelix Kuehling 	int retval;
208060a00956SFelix Kuehling 
2081234eebe1SAmber Lin 	if (!dqm->sched_running || dqm->sched_halt)
20822c99a547SPhilip Yang 		return 0;
208381b820b3SYong Zhao 	if (dqm->active_queue_count <= 0 || dqm->processes_count <= 0)
208460a00956SFelix Kuehling 		return 0;
208560a00956SFelix Kuehling 	if (dqm->active_runlist)
208660a00956SFelix Kuehling 		return 0;
208760a00956SFelix Kuehling 
20889af5379cSOak Zeng 	retval = pm_send_runlist(&dqm->packet_mgr, &dqm->queues);
208914328aa5SPhilip Cox 	pr_debug("%s sent runlist\n", __func__);
209060a00956SFelix Kuehling 	if (retval) {
209180c74918SAsad Kamal 		dev_err(dev, "failed to execute runlist\n");
209260a00956SFelix Kuehling 		return retval;
209360a00956SFelix Kuehling 	}
209460a00956SFelix Kuehling 	dqm->active_runlist = true;
209560a00956SFelix Kuehling 
209660a00956SFelix Kuehling 	return retval;
209760a00956SFelix Kuehling }
209860a00956SFelix Kuehling 
set_queue_as_reset(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd)2099ee0a469cSJonathan Kim static void set_queue_as_reset(struct device_queue_manager *dqm, struct queue *q,
2100ee0a469cSJonathan Kim 			       struct qcm_process_device *qpd)
2101ee0a469cSJonathan Kim {
2102ee0a469cSJonathan Kim 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
2103ee0a469cSJonathan Kim 
2104ee0a469cSJonathan Kim 	dev_err(dqm->dev->adev->dev, "queue id 0x%0x at pasid 0x%0x is reset\n",
2105ee0a469cSJonathan Kim 		q->properties.queue_id, q->process->pasid);
2106ee0a469cSJonathan Kim 
2107ee0a469cSJonathan Kim 	pdd->has_reset_queue = true;
2108ee0a469cSJonathan Kim 	if (q->properties.is_active) {
2109ee0a469cSJonathan Kim 		q->properties.is_active = false;
2110ee0a469cSJonathan Kim 		decrement_queue_count(dqm, qpd, q);
2111ee0a469cSJonathan Kim 	}
2112ee0a469cSJonathan Kim }
2113ee0a469cSJonathan Kim 
detect_queue_hang(struct device_queue_manager * dqm)2114ee0a469cSJonathan Kim static int detect_queue_hang(struct device_queue_manager *dqm)
2115ee0a469cSJonathan Kim {
2116ee0a469cSJonathan Kim 	int i;
2117ee0a469cSJonathan Kim 
2118ee0a469cSJonathan Kim 	/* detect should be used only in dqm locked queue reset */
2119ee0a469cSJonathan Kim 	if (WARN_ON(dqm->detect_hang_count > 0))
2120ee0a469cSJonathan Kim 		return 0;
2121ee0a469cSJonathan Kim 
2122ee0a469cSJonathan Kim 	memset(dqm->detect_hang_info, 0, dqm->detect_hang_info_size);
2123ee0a469cSJonathan Kim 
2124ee0a469cSJonathan Kim 	for (i = 0; i < AMDGPU_MAX_QUEUES; ++i) {
2125ee0a469cSJonathan Kim 		uint32_t mec, pipe, queue;
2126ee0a469cSJonathan Kim 		int xcc_id;
2127ee0a469cSJonathan Kim 
2128ee0a469cSJonathan Kim 		mec = (i / dqm->dev->kfd->shared_resources.num_queue_per_pipe)
2129ee0a469cSJonathan Kim 			/ dqm->dev->kfd->shared_resources.num_pipe_per_mec;
2130ee0a469cSJonathan Kim 
2131ee0a469cSJonathan Kim 		if (mec || !test_bit(i, dqm->dev->kfd->shared_resources.cp_queue_bitmap))
2132ee0a469cSJonathan Kim 			continue;
2133ee0a469cSJonathan Kim 
2134ee0a469cSJonathan Kim 		amdgpu_queue_mask_bit_to_mec_queue(dqm->dev->adev, i, &mec, &pipe, &queue);
2135ee0a469cSJonathan Kim 
2136ee0a469cSJonathan Kim 		for_each_inst(xcc_id, dqm->dev->xcc_mask) {
2137ee0a469cSJonathan Kim 			uint64_t queue_addr = dqm->dev->kfd2kgd->hqd_get_pq_addr(
2138ee0a469cSJonathan Kim 						dqm->dev->adev, pipe, queue, xcc_id);
2139ee0a469cSJonathan Kim 			struct dqm_detect_hang_info hang_info;
2140ee0a469cSJonathan Kim 
2141ee0a469cSJonathan Kim 			if (!queue_addr)
2142ee0a469cSJonathan Kim 				continue;
2143ee0a469cSJonathan Kim 
2144ee0a469cSJonathan Kim 			hang_info.pipe_id = pipe;
2145ee0a469cSJonathan Kim 			hang_info.queue_id = queue;
2146ee0a469cSJonathan Kim 			hang_info.xcc_id = xcc_id;
2147ee0a469cSJonathan Kim 			hang_info.queue_address = queue_addr;
2148ee0a469cSJonathan Kim 
2149ee0a469cSJonathan Kim 			dqm->detect_hang_info[dqm->detect_hang_count] = hang_info;
2150ee0a469cSJonathan Kim 			dqm->detect_hang_count++;
2151ee0a469cSJonathan Kim 		}
2152ee0a469cSJonathan Kim 	}
2153ee0a469cSJonathan Kim 
2154ee0a469cSJonathan Kim 	return dqm->detect_hang_count;
2155ee0a469cSJonathan Kim }
2156ee0a469cSJonathan Kim 
find_queue_by_address(struct device_queue_manager * dqm,uint64_t queue_address)2157ee0a469cSJonathan Kim static struct queue *find_queue_by_address(struct device_queue_manager *dqm, uint64_t queue_address)
2158ee0a469cSJonathan Kim {
2159ee0a469cSJonathan Kim 	struct device_process_node *cur;
2160ee0a469cSJonathan Kim 	struct qcm_process_device *qpd;
2161ee0a469cSJonathan Kim 	struct queue *q;
2162ee0a469cSJonathan Kim 
2163ee0a469cSJonathan Kim 	list_for_each_entry(cur, &dqm->queues, list) {
2164ee0a469cSJonathan Kim 		qpd = cur->qpd;
2165ee0a469cSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
2166ee0a469cSJonathan Kim 			if (queue_address == q->properties.queue_address)
2167ee0a469cSJonathan Kim 				return q;
2168ee0a469cSJonathan Kim 		}
2169ee0a469cSJonathan Kim 	}
2170ee0a469cSJonathan Kim 
2171ee0a469cSJonathan Kim 	return NULL;
2172ee0a469cSJonathan Kim }
2173ee0a469cSJonathan Kim 
2174ee0a469cSJonathan Kim /* only for compute queue */
reset_queues_on_hws_hang(struct device_queue_manager * dqm)2175ee0a469cSJonathan Kim static int reset_queues_on_hws_hang(struct device_queue_manager *dqm)
2176ee0a469cSJonathan Kim {
2177ee0a469cSJonathan Kim 	int r = 0, reset_count = 0, i;
2178ee0a469cSJonathan Kim 
2179ee0a469cSJonathan Kim 	if (!dqm->detect_hang_info || dqm->is_hws_hang)
2180ee0a469cSJonathan Kim 		return -EIO;
2181ee0a469cSJonathan Kim 
2182ee0a469cSJonathan Kim 	/* assume dqm locked. */
2183ee0a469cSJonathan Kim 	if (!detect_queue_hang(dqm))
2184ee0a469cSJonathan Kim 		return -ENOTRECOVERABLE;
2185ee0a469cSJonathan Kim 
2186ee0a469cSJonathan Kim 	for (i = 0; i < dqm->detect_hang_count; i++) {
2187ee0a469cSJonathan Kim 		struct dqm_detect_hang_info hang_info = dqm->detect_hang_info[i];
2188ee0a469cSJonathan Kim 		struct queue *q = find_queue_by_address(dqm, hang_info.queue_address);
2189ee0a469cSJonathan Kim 		struct kfd_process_device *pdd;
2190ee0a469cSJonathan Kim 		uint64_t queue_addr = 0;
2191ee0a469cSJonathan Kim 
2192ee0a469cSJonathan Kim 		if (!q) {
2193ee0a469cSJonathan Kim 			r = -ENOTRECOVERABLE;
2194ee0a469cSJonathan Kim 			goto reset_fail;
2195ee0a469cSJonathan Kim 		}
2196ee0a469cSJonathan Kim 
2197ee0a469cSJonathan Kim 		pdd = kfd_get_process_device_data(dqm->dev, q->process);
2198ee0a469cSJonathan Kim 		if (!pdd) {
2199ee0a469cSJonathan Kim 			r = -ENOTRECOVERABLE;
2200ee0a469cSJonathan Kim 			goto reset_fail;
2201ee0a469cSJonathan Kim 		}
2202ee0a469cSJonathan Kim 
2203ee0a469cSJonathan Kim 		queue_addr = dqm->dev->kfd2kgd->hqd_reset(dqm->dev->adev,
2204ee0a469cSJonathan Kim 				hang_info.pipe_id, hang_info.queue_id, hang_info.xcc_id,
2205ee0a469cSJonathan Kim 				KFD_UNMAP_LATENCY_MS);
2206ee0a469cSJonathan Kim 
2207ee0a469cSJonathan Kim 		/* either reset failed or we reset an unexpected queue. */
2208ee0a469cSJonathan Kim 		if (queue_addr != q->properties.queue_address) {
2209ee0a469cSJonathan Kim 			r = -ENOTRECOVERABLE;
2210ee0a469cSJonathan Kim 			goto reset_fail;
2211ee0a469cSJonathan Kim 		}
2212ee0a469cSJonathan Kim 
2213ee0a469cSJonathan Kim 		set_queue_as_reset(dqm, q, &pdd->qpd);
2214ee0a469cSJonathan Kim 		reset_count++;
2215ee0a469cSJonathan Kim 	}
2216ee0a469cSJonathan Kim 
2217ee0a469cSJonathan Kim 	if (reset_count == dqm->detect_hang_count)
2218ee0a469cSJonathan Kim 		kfd_signal_reset_event(dqm->dev);
2219ee0a469cSJonathan Kim 	else
2220ee0a469cSJonathan Kim 		r = -ENOTRECOVERABLE;
2221ee0a469cSJonathan Kim 
2222ee0a469cSJonathan Kim reset_fail:
2223ee0a469cSJonathan Kim 	dqm->detect_hang_count = 0;
2224ee0a469cSJonathan Kim 
2225ee0a469cSJonathan Kim 	return r;
2226ee0a469cSJonathan Kim }
2227ee0a469cSJonathan Kim 
222860a00956SFelix Kuehling /* dqm->lock mutex has to be locked before calling this function */
unmap_queues_cpsch(struct device_queue_manager * dqm,enum kfd_unmap_queues_filter filter,uint32_t filter_param,uint32_t grace_period,bool reset)22297da2bcf8SYong Zhao static int unmap_queues_cpsch(struct device_queue_manager *dqm,
22304465f466SYong Zhao 				enum kfd_unmap_queues_filter filter,
22317cee6a68SJonathan Kim 				uint32_t filter_param,
22327cee6a68SJonathan Kim 				uint32_t grace_period,
22337cee6a68SJonathan Kim 				bool reset)
223464c7f8cfSBen Goz {
223580c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
223651a0f459SOak Zeng 	struct mqd_manager *mqd_mgr;
22371802b042SYunxiang Li 	int retval;
223864c7f8cfSBen Goz 
22392c99a547SPhilip Yang 	if (!dqm->sched_running)
22402c99a547SPhilip Yang 		return 0;
2241991ca8eeSEdward O'Callaghan 	if (!dqm->active_runlist)
22421802b042SYunxiang Li 		return 0;
22431802b042SYunxiang Li 	if (!down_read_trylock(&dqm->dev->adev->reset_domain->sem))
22441802b042SYunxiang Li 		return -EIO;
2245bcea3081SBen Goz 
22467cee6a68SJonathan Kim 	if (grace_period != USE_DEFAULT_GRACE_PERIOD) {
22477cee6a68SJonathan Kim 		retval = pm_update_grace_period(&dqm->packet_mgr, grace_period);
22487cee6a68SJonathan Kim 		if (retval)
22491802b042SYunxiang Li 			goto out;
22507cee6a68SJonathan Kim 	}
22517cee6a68SJonathan Kim 
2252d2cb0b21SJonathan Kim 	retval = pm_send_unmap_queue(&dqm->packet_mgr, filter, filter_param, reset);
22534eacc26bSKent Russell 	if (retval)
22541802b042SYunxiang Li 		goto out;
225564c7f8cfSBen Goz 
225664c7f8cfSBen Goz 	*dqm->fence_addr = KFD_FENCE_INIT;
22579af5379cSOak Zeng 	pm_send_query_status(&dqm->packet_mgr, dqm->fence_gpu_addr,
225864c7f8cfSBen Goz 				KFD_FENCE_COMPLETED);
225964c7f8cfSBen Goz 	/* should be timed out */
226080c74918SAsad Kamal 	retval = amdkfd_fence_wait_timeout(dqm, KFD_FENCE_COMPLETED,
226114328aa5SPhilip Cox 					   queue_preemption_timeout_ms);
226209c34e8dSFelix Kuehling 	if (retval) {
226380c74918SAsad Kamal 		dev_err(dev, "The cp might be in an unrecoverable state due to an unsuccessful queues preemption\n");
2264cc009e61SMukul Joshi 		kfd_hws_hang(dqm);
22651802b042SYunxiang Li 		goto out;
226609c34e8dSFelix Kuehling 	}
22679fd3f1bfSFelix Kuehling 
226851a0f459SOak Zeng 	/* In the current MEC firmware implementation, if compute queue
226951a0f459SOak Zeng 	 * doesn't response to the preemption request in time, HIQ will
227051a0f459SOak Zeng 	 * abandon the unmap request without returning any timeout error
227151a0f459SOak Zeng 	 * to driver. Instead, MEC firmware will log the doorbell of the
227251a0f459SOak Zeng 	 * unresponding compute queue to HIQ.MQD.queue_doorbell_id fields.
227351a0f459SOak Zeng 	 * To make sure the queue unmap was successful, driver need to
227451a0f459SOak Zeng 	 * check those fields
227551a0f459SOak Zeng 	 */
227651a0f459SOak Zeng 	mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ];
22770991a4c1SMukul Joshi 	if (mqd_mgr->check_preemption_failed(mqd_mgr, dqm->packet_mgr.priv_queue->queue->mqd)) {
2278ee0a469cSJonathan Kim 		if (reset_queues_on_hws_hang(dqm)) {
227951a0f459SOak Zeng 			while (halt_if_hws_hang)
228051a0f459SOak Zeng 				schedule();
2281ee0a469cSJonathan Kim 			dqm->is_hws_hang = true;
2282d7e8ddc3SHarish Kasiviswanathan 			kfd_hws_hang(dqm);
22831802b042SYunxiang Li 			retval = -ETIME;
22841802b042SYunxiang Li 			goto out;
228551a0f459SOak Zeng 		}
2286ee0a469cSJonathan Kim 	}
228751a0f459SOak Zeng 
22887cee6a68SJonathan Kim 	/* We need to reset the grace period value for this device */
22897cee6a68SJonathan Kim 	if (grace_period != USE_DEFAULT_GRACE_PERIOD) {
22907cee6a68SJonathan Kim 		if (pm_update_grace_period(&dqm->packet_mgr,
22917cee6a68SJonathan Kim 					USE_DEFAULT_GRACE_PERIOD))
229280c74918SAsad Kamal 			dev_err(dev, "Failed to reset grace period\n");
22937cee6a68SJonathan Kim 	}
22947cee6a68SJonathan Kim 
22959af5379cSOak Zeng 	pm_release_ib(&dqm->packet_mgr);
229664c7f8cfSBen Goz 	dqm->active_runlist = false;
229764c7f8cfSBen Goz 
22981802b042SYunxiang Li out:
22991802b042SYunxiang Li 	up_read(&dqm->dev->adev->reset_domain->sem);
230064c7f8cfSBen Goz 	return retval;
230164c7f8cfSBen Goz }
230264c7f8cfSBen Goz 
2303dec63443STao Zhou /* only for compute queue */
reset_queues_cpsch(struct device_queue_manager * dqm,uint16_t pasid)2304ee0a469cSJonathan Kim static int reset_queues_cpsch(struct device_queue_manager *dqm, uint16_t pasid)
2305dec63443STao Zhou {
2306dec63443STao Zhou 	int retval;
2307dec63443STao Zhou 
2308dec63443STao Zhou 	dqm_lock(dqm);
2309dec63443STao Zhou 
2310dec63443STao Zhou 	retval = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_BY_PASID,
23117cee6a68SJonathan Kim 			pasid, USE_DEFAULT_GRACE_PERIOD, true);
2312dec63443STao Zhou 
2313dec63443STao Zhou 	dqm_unlock(dqm);
2314dec63443STao Zhou 	return retval;
2315dec63443STao Zhou }
2316dec63443STao Zhou 
2317ac30c783SYong Zhao /* dqm->lock mutex has to be locked before calling this function */
execute_queues_cpsch(struct device_queue_manager * dqm,enum kfd_unmap_queues_filter filter,uint32_t filter_param,uint32_t grace_period)2318c4744e24SYong Zhao static int execute_queues_cpsch(struct device_queue_manager *dqm,
2319c4744e24SYong Zhao 				enum kfd_unmap_queues_filter filter,
23207cee6a68SJonathan Kim 				uint32_t filter_param,
23217cee6a68SJonathan Kim 				uint32_t grace_period)
232264c7f8cfSBen Goz {
232364c7f8cfSBen Goz 	int retval;
232464c7f8cfSBen Goz 
23251802b042SYunxiang Li 	if (!down_read_trylock(&dqm->dev->adev->reset_domain->sem))
232673ea648dSShaoyun Liu 		return -EIO;
23277cee6a68SJonathan Kim 	retval = unmap_queues_cpsch(dqm, filter, filter_param, grace_period, false);
23281802b042SYunxiang Li 	if (!retval)
23291802b042SYunxiang Li 		retval = map_queues_cpsch(dqm);
23301802b042SYunxiang Li 	up_read(&dqm->dev->adev->reset_domain->sem);
2331ac30c783SYong Zhao 	return retval;
233264c7f8cfSBen Goz }
233364c7f8cfSBen Goz 
wait_on_destroy_queue(struct device_queue_manager * dqm,struct queue * q)2334a70a93faSJonathan Kim static int wait_on_destroy_queue(struct device_queue_manager *dqm,
2335a70a93faSJonathan Kim 				 struct queue *q)
2336a70a93faSJonathan Kim {
2337a70a93faSJonathan Kim 	struct kfd_process_device *pdd = kfd_get_process_device_data(q->device,
2338a70a93faSJonathan Kim 								q->process);
2339a70a93faSJonathan Kim 	int ret = 0;
2340a70a93faSJonathan Kim 
2341a70a93faSJonathan Kim 	if (pdd->qpd.is_debug)
2342a70a93faSJonathan Kim 		return ret;
2343a70a93faSJonathan Kim 
2344a70a93faSJonathan Kim 	q->properties.is_being_destroyed = true;
2345a70a93faSJonathan Kim 
2346a70a93faSJonathan Kim 	if (pdd->process->debug_trap_enabled && q->properties.is_suspended) {
2347a70a93faSJonathan Kim 		dqm_unlock(dqm);
2348a70a93faSJonathan Kim 		mutex_unlock(&q->process->mutex);
2349a70a93faSJonathan Kim 		ret = wait_event_interruptible(dqm->destroy_wait,
2350a70a93faSJonathan Kim 						!q->properties.is_suspended);
2351a70a93faSJonathan Kim 
2352a70a93faSJonathan Kim 		mutex_lock(&q->process->mutex);
2353a70a93faSJonathan Kim 		dqm_lock(dqm);
2354a70a93faSJonathan Kim 	}
2355a70a93faSJonathan Kim 
2356a70a93faSJonathan Kim 	return ret;
2357a70a93faSJonathan Kim }
2358a70a93faSJonathan Kim 
destroy_queue_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)235964c7f8cfSBen Goz static int destroy_queue_cpsch(struct device_queue_manager *dqm,
236064c7f8cfSBen Goz 				struct qcm_process_device *qpd,
236164c7f8cfSBen Goz 				struct queue *q)
236264c7f8cfSBen Goz {
236364c7f8cfSBen Goz 	int retval;
23648d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
2365d69fd951SMukul Joshi 	uint64_t sdma_val = 0;
2366d69fd951SMukul Joshi 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
236780c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
2368d69fd951SMukul Joshi 
2369d69fd951SMukul Joshi 	/* Get the SDMA queue stats */
2370d69fd951SMukul Joshi 	if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) ||
2371d69fd951SMukul Joshi 	    (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
2372818b0324SMukul Joshi 		retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr,
2373d69fd951SMukul Joshi 							&sdma_val);
2374d69fd951SMukul Joshi 		if (retval)
237580c74918SAsad Kamal 			dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n",
2376d69fd951SMukul Joshi 				q->properties.queue_id);
2377d69fd951SMukul Joshi 	}
2378992839adSYair Shachar 
237964c7f8cfSBen Goz 	/* remove queue from list to prevent rescheduling after preemption */
2380efeaed4dSFelix Kuehling 	dqm_lock(dqm);
2381992839adSYair Shachar 
2382a70a93faSJonathan Kim 	retval = wait_on_destroy_queue(dqm, q);
2383a70a93faSJonathan Kim 
2384a70a93faSJonathan Kim 	if (retval) {
2385a70a93faSJonathan Kim 		dqm_unlock(dqm);
2386a70a93faSJonathan Kim 		return retval;
2387a70a93faSJonathan Kim 	}
2388a70a93faSJonathan Kim 
2389992839adSYair Shachar 	if (qpd->is_debug) {
2390992839adSYair Shachar 		/*
2391992839adSYair Shachar 		 * error, currently we do not allow to destroy a queue
2392992839adSYair Shachar 		 * of a currently debugged process
2393992839adSYair Shachar 		 */
2394992839adSYair Shachar 		retval = -EBUSY;
2395992839adSYair Shachar 		goto failed_try_destroy_debugged_queue;
2396992839adSYair Shachar 
2397992839adSYair Shachar 	}
2398992839adSYair Shachar 
2399fdfa090bSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
2400fdfa090bSOak Zeng 			q->properties.type)];
240164c7f8cfSBen Goz 
2402ef568db7SFelix Kuehling 	deallocate_doorbell(qpd, q);
2403ef568db7SFelix Kuehling 
2404d69fd951SMukul Joshi 	if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) ||
2405d69fd951SMukul Joshi 	    (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
24061b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
2407d69fd951SMukul Joshi 		pdd->sdma_past_activity_counter += sdma_val;
2408d69fd951SMukul Joshi 	}
2409bcea3081SBen Goz 
24108c07f33eSPhilip Yang 	if (q->properties.is_active) {
24118c07f33eSPhilip Yang 		decrement_queue_count(dqm, qpd, q);
2412101025e9SJonathan Kim 		q->properties.is_active = false;
241380a780abSJonathan Kim 		if (!dqm->dev->kfd->shared_resources.enable_mes) {
24148c07f33eSPhilip Yang 			retval = execute_queues_cpsch(dqm,
24157cee6a68SJonathan Kim 						      KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
24167cee6a68SJonathan Kim 						      USE_DEFAULT_GRACE_PERIOD);
24178c07f33eSPhilip Yang 			if (retval == -ETIME)
24188c07f33eSPhilip Yang 				qpd->reset_wavefronts = true;
24198c07f33eSPhilip Yang 		} else {
24208c07f33eSPhilip Yang 			retval = remove_queue_mes(dqm, q, qpd);
24218c07f33eSPhilip Yang 		}
24228c07f33eSPhilip Yang 	}
2423101025e9SJonathan Kim 	list_del(&q->list);
2424101025e9SJonathan Kim 	qpd->queue_count--;
242564c7f8cfSBen Goz 
2426b8cbab04SOded Gabbay 	/*
2427b8cbab04SOded Gabbay 	 * Unconditionally decrement this counter, regardless of the queue's
2428b8cbab04SOded Gabbay 	 * type
2429b8cbab04SOded Gabbay 	 */
2430b8cbab04SOded Gabbay 	dqm->total_queue_count--;
2431b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
2432b8cbab04SOded Gabbay 			dqm->total_queue_count);
2433b8cbab04SOded Gabbay 
2434efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
243564c7f8cfSBen Goz 
2436a70a93faSJonathan Kim 	/*
2437a70a93faSJonathan Kim 	 * Do free_mqd and raise delete event after dqm_unlock(dqm) to avoid
2438a70a93faSJonathan Kim 	 * circular locking
2439a70a93faSJonathan Kim 	 */
2440a70a93faSJonathan Kim 	kfd_dbg_ev_raise(KFD_EC_MASK(EC_DEVICE_QUEUE_DELETE),
2441a70a93faSJonathan Kim 				qpd->pqm->process, q->device,
2442a70a93faSJonathan Kim 				-1, false, NULL, 0);
2443a70a93faSJonathan Kim 
24448636e53cSOak Zeng 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
244589cd9d23SPhilip Yang 
24469e827224SYong Zhao 	return retval;
244764c7f8cfSBen Goz 
2448992839adSYair Shachar failed_try_destroy_debugged_queue:
2449992839adSYair Shachar 
2450efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
245164c7f8cfSBen Goz 	return retval;
245264c7f8cfSBen Goz }
245364c7f8cfSBen Goz 
245464c7f8cfSBen Goz /*
245564c7f8cfSBen Goz  * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to
245664c7f8cfSBen Goz  * stay in user mode.
245764c7f8cfSBen Goz  */
245864c7f8cfSBen Goz #define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL
245964c7f8cfSBen Goz /* APE1 limit is inclusive and 64K aligned. */
246064c7f8cfSBen Goz #define APE1_LIMIT_ALIGNMENT 0xFFFF
246164c7f8cfSBen Goz 
set_cache_memory_policy(struct device_queue_manager * dqm,struct qcm_process_device * qpd,enum cache_policy default_policy,enum cache_policy alternate_policy,void __user * alternate_aperture_base,uint64_t alternate_aperture_size)246264c7f8cfSBen Goz static bool set_cache_memory_policy(struct device_queue_manager *dqm,
246364c7f8cfSBen Goz 				   struct qcm_process_device *qpd,
246464c7f8cfSBen Goz 				   enum cache_policy default_policy,
246564c7f8cfSBen Goz 				   enum cache_policy alternate_policy,
246664c7f8cfSBen Goz 				   void __user *alternate_aperture_base,
246764c7f8cfSBen Goz 				   uint64_t alternate_aperture_size)
246864c7f8cfSBen Goz {
2469bed4f110SFelix Kuehling 	bool retval = true;
2470bed4f110SFelix Kuehling 
2471bed4f110SFelix Kuehling 	if (!dqm->asic_ops.set_cache_memory_policy)
2472bed4f110SFelix Kuehling 		return retval;
247364c7f8cfSBen Goz 
2474efeaed4dSFelix Kuehling 	dqm_lock(dqm);
247564c7f8cfSBen Goz 
247664c7f8cfSBen Goz 	if (alternate_aperture_size == 0) {
247764c7f8cfSBen Goz 		/* base > limit disables APE1 */
247864c7f8cfSBen Goz 		qpd->sh_mem_ape1_base = 1;
247964c7f8cfSBen Goz 		qpd->sh_mem_ape1_limit = 0;
248064c7f8cfSBen Goz 	} else {
248164c7f8cfSBen Goz 		/*
248264c7f8cfSBen Goz 		 * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]},
248364c7f8cfSBen Goz 		 *			SH_MEM_APE1_BASE[31:0], 0x0000 }
248464c7f8cfSBen Goz 		 * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]},
248564c7f8cfSBen Goz 		 *			SH_MEM_APE1_LIMIT[31:0], 0xFFFF }
248664c7f8cfSBen Goz 		 * Verify that the base and size parameters can be
248764c7f8cfSBen Goz 		 * represented in this format and convert them.
248864c7f8cfSBen Goz 		 * Additionally restrict APE1 to user-mode addresses.
248964c7f8cfSBen Goz 		 */
249064c7f8cfSBen Goz 
249164c7f8cfSBen Goz 		uint64_t base = (uintptr_t)alternate_aperture_base;
249264c7f8cfSBen Goz 		uint64_t limit = base + alternate_aperture_size - 1;
249364c7f8cfSBen Goz 
2494ab7c1648SKent Russell 		if (limit <= base || (base & APE1_FIXED_BITS_MASK) != 0 ||
2495ab7c1648SKent Russell 		   (limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT) {
2496ab7c1648SKent Russell 			retval = false;
249764c7f8cfSBen Goz 			goto out;
2498ab7c1648SKent Russell 		}
249964c7f8cfSBen Goz 
250064c7f8cfSBen Goz 		qpd->sh_mem_ape1_base = base >> 16;
250164c7f8cfSBen Goz 		qpd->sh_mem_ape1_limit = limit >> 16;
250264c7f8cfSBen Goz 	}
250364c7f8cfSBen Goz 
2504bfd5e378SYong Zhao 	retval = dqm->asic_ops.set_cache_memory_policy(
2505a22fc854SBen Goz 			dqm,
2506a22fc854SBen Goz 			qpd,
2507a22fc854SBen Goz 			default_policy,
2508a22fc854SBen Goz 			alternate_policy,
2509a22fc854SBen Goz 			alternate_aperture_base,
2510a22fc854SBen Goz 			alternate_aperture_size);
251164c7f8cfSBen Goz 
2512d146c5a7SFelix Kuehling 	if ((dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0))
251364c7f8cfSBen Goz 		program_sh_mem_settings(dqm, qpd);
251464c7f8cfSBen Goz 
251579775b62SKent Russell 	pr_debug("sh_mem_config: 0x%x, ape1_base: 0x%x, ape1_limit: 0x%x\n",
251664c7f8cfSBen Goz 		qpd->sh_mem_config, qpd->sh_mem_ape1_base,
251764c7f8cfSBen Goz 		qpd->sh_mem_ape1_limit);
251864c7f8cfSBen Goz 
251964c7f8cfSBen Goz out:
2520efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
2521ab7c1648SKent Russell 	return retval;
252264c7f8cfSBen Goz }
252364c7f8cfSBen Goz 
process_termination_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)25249fd3f1bfSFelix Kuehling static int process_termination_nocpsch(struct device_queue_manager *dqm,
25259fd3f1bfSFelix Kuehling 		struct qcm_process_device *qpd)
25269fd3f1bfSFelix Kuehling {
2527a7b2451dSAmber Lin 	struct queue *q;
25289fd3f1bfSFelix Kuehling 	struct device_process_node *cur, *next_dpn;
25299fd3f1bfSFelix Kuehling 	int retval = 0;
253032cce8bcSFelix Kuehling 	bool found = false;
25319fd3f1bfSFelix Kuehling 
2532efeaed4dSFelix Kuehling 	dqm_lock(dqm);
25339fd3f1bfSFelix Kuehling 
25349fd3f1bfSFelix Kuehling 	/* Clear all user mode queues */
2535a7b2451dSAmber Lin 	while (!list_empty(&qpd->queues_list)) {
2536a7b2451dSAmber Lin 		struct mqd_manager *mqd_mgr;
25379fd3f1bfSFelix Kuehling 		int ret;
25389fd3f1bfSFelix Kuehling 
2539a7b2451dSAmber Lin 		q = list_first_entry(&qpd->queues_list, struct queue, list);
2540a7b2451dSAmber Lin 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
2541a7b2451dSAmber Lin 				q->properties.type)];
25429fd3f1bfSFelix Kuehling 		ret = destroy_queue_nocpsch_locked(dqm, qpd, q);
25439fd3f1bfSFelix Kuehling 		if (ret)
25449fd3f1bfSFelix Kuehling 			retval = ret;
2545a7b2451dSAmber Lin 		dqm_unlock(dqm);
2546a7b2451dSAmber Lin 		mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
2547a7b2451dSAmber Lin 		dqm_lock(dqm);
25489fd3f1bfSFelix Kuehling 	}
25499fd3f1bfSFelix Kuehling 
25509fd3f1bfSFelix Kuehling 	/* Unregister process */
25519fd3f1bfSFelix Kuehling 	list_for_each_entry_safe(cur, next_dpn, &dqm->queues, list) {
25529fd3f1bfSFelix Kuehling 		if (qpd == cur->qpd) {
25539fd3f1bfSFelix Kuehling 			list_del(&cur->list);
25549fd3f1bfSFelix Kuehling 			kfree(cur);
25559fd3f1bfSFelix Kuehling 			dqm->processes_count--;
255632cce8bcSFelix Kuehling 			found = true;
25579fd3f1bfSFelix Kuehling 			break;
25589fd3f1bfSFelix Kuehling 		}
25599fd3f1bfSFelix Kuehling 	}
25609fd3f1bfSFelix Kuehling 
2561efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
256232cce8bcSFelix Kuehling 
256332cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
256432cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
256532cce8bcSFelix Kuehling 	 */
256632cce8bcSFelix Kuehling 	if (found)
256732cce8bcSFelix Kuehling 		kfd_dec_compute_active(dqm->dev);
256832cce8bcSFelix Kuehling 
25699fd3f1bfSFelix Kuehling 	return retval;
25709fd3f1bfSFelix Kuehling }
25719fd3f1bfSFelix Kuehling 
get_wave_state(struct device_queue_manager * dqm,struct queue * q,void __user * ctl_stack,u32 * ctl_stack_used_size,u32 * save_area_used_size)25725df099e8SJay Cornwall static int get_wave_state(struct device_queue_manager *dqm,
25735df099e8SJay Cornwall 			  struct queue *q,
25745df099e8SJay Cornwall 			  void __user *ctl_stack,
25755df099e8SJay Cornwall 			  u32 *ctl_stack_used_size,
25765df099e8SJay Cornwall 			  u32 *save_area_used_size)
25775df099e8SJay Cornwall {
25784e6c6fc1SYong Zhao 	struct mqd_manager *mqd_mgr;
25795df099e8SJay Cornwall 
25805df099e8SJay Cornwall 	dqm_lock(dqm);
25815df099e8SJay Cornwall 
2582d7c0b047SYong Zhao 	mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_CP];
25835df099e8SJay Cornwall 
258463f6e012SJonathan Kim 	if (q->properties.type != KFD_QUEUE_TYPE_COMPUTE ||
25858dc1db31SMukul Joshi 	    q->properties.is_active || !q->device->kfd->cwsr_enabled ||
258663f6e012SJonathan Kim 	    !mqd_mgr->get_wave_state) {
258763f6e012SJonathan Kim 		dqm_unlock(dqm);
258863f6e012SJonathan Kim 		return -EINVAL;
25895df099e8SJay Cornwall 	}
25905df099e8SJay Cornwall 
25915df099e8SJay Cornwall 	dqm_unlock(dqm);
259263f6e012SJonathan Kim 
259363f6e012SJonathan Kim 	/*
259463f6e012SJonathan Kim 	 * get_wave_state is outside the dqm lock to prevent circular locking
259563f6e012SJonathan Kim 	 * and the queue should be protected against destruction by the process
259663f6e012SJonathan Kim 	 * lock.
259763f6e012SJonathan Kim 	 */
25987fe51e6fSMukul Joshi 	return mqd_mgr->get_wave_state(mqd_mgr, q->mqd, &q->properties,
25997fe51e6fSMukul Joshi 			ctl_stack, ctl_stack_used_size, save_area_used_size);
26005df099e8SJay Cornwall }
26019fd3f1bfSFelix Kuehling 
get_queue_checkpoint_info(struct device_queue_manager * dqm,const struct queue * q,u32 * mqd_size,u32 * ctl_stack_size)260242c6c482SDavid Yat Sin static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
260342c6c482SDavid Yat Sin 			const struct queue *q,
26043a9822d7SDavid Yat Sin 			u32 *mqd_size,
26053a9822d7SDavid Yat Sin 			u32 *ctl_stack_size)
260642c6c482SDavid Yat Sin {
260742c6c482SDavid Yat Sin 	struct mqd_manager *mqd_mgr;
260842c6c482SDavid Yat Sin 	enum KFD_MQD_TYPE mqd_type =
260942c6c482SDavid Yat Sin 			get_mqd_type_from_queue_type(q->properties.type);
261042c6c482SDavid Yat Sin 
261142c6c482SDavid Yat Sin 	dqm_lock(dqm);
261242c6c482SDavid Yat Sin 	mqd_mgr = dqm->mqd_mgrs[mqd_type];
261342c6c482SDavid Yat Sin 	*mqd_size = mqd_mgr->mqd_size;
26143a9822d7SDavid Yat Sin 	*ctl_stack_size = 0;
26153a9822d7SDavid Yat Sin 
26163a9822d7SDavid Yat Sin 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE && mqd_mgr->get_checkpoint_info)
26173a9822d7SDavid Yat Sin 		mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size);
261842c6c482SDavid Yat Sin 
261942c6c482SDavid Yat Sin 	dqm_unlock(dqm);
262042c6c482SDavid Yat Sin }
262142c6c482SDavid Yat Sin 
checkpoint_mqd(struct device_queue_manager * dqm,const struct queue * q,void * mqd,void * ctl_stack)262242c6c482SDavid Yat Sin static int checkpoint_mqd(struct device_queue_manager *dqm,
262342c6c482SDavid Yat Sin 			  const struct queue *q,
26243a9822d7SDavid Yat Sin 			  void *mqd,
26253a9822d7SDavid Yat Sin 			  void *ctl_stack)
262642c6c482SDavid Yat Sin {
262742c6c482SDavid Yat Sin 	struct mqd_manager *mqd_mgr;
262842c6c482SDavid Yat Sin 	int r = 0;
262942c6c482SDavid Yat Sin 	enum KFD_MQD_TYPE mqd_type =
263042c6c482SDavid Yat Sin 			get_mqd_type_from_queue_type(q->properties.type);
263142c6c482SDavid Yat Sin 
263242c6c482SDavid Yat Sin 	dqm_lock(dqm);
263342c6c482SDavid Yat Sin 
26348dc1db31SMukul Joshi 	if (q->properties.is_active || !q->device->kfd->cwsr_enabled) {
263542c6c482SDavid Yat Sin 		r = -EINVAL;
263642c6c482SDavid Yat Sin 		goto dqm_unlock;
263742c6c482SDavid Yat Sin 	}
263842c6c482SDavid Yat Sin 
263942c6c482SDavid Yat Sin 	mqd_mgr = dqm->mqd_mgrs[mqd_type];
264042c6c482SDavid Yat Sin 	if (!mqd_mgr->checkpoint_mqd) {
264142c6c482SDavid Yat Sin 		r = -EOPNOTSUPP;
264242c6c482SDavid Yat Sin 		goto dqm_unlock;
264342c6c482SDavid Yat Sin 	}
264442c6c482SDavid Yat Sin 
26453a9822d7SDavid Yat Sin 	mqd_mgr->checkpoint_mqd(mqd_mgr, q->mqd, mqd, ctl_stack);
264642c6c482SDavid Yat Sin 
264742c6c482SDavid Yat Sin dqm_unlock:
264842c6c482SDavid Yat Sin 	dqm_unlock(dqm);
264942c6c482SDavid Yat Sin 	return r;
265042c6c482SDavid Yat Sin }
265142c6c482SDavid Yat Sin 
process_termination_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)26529fd3f1bfSFelix Kuehling static int process_termination_cpsch(struct device_queue_manager *dqm,
26539fd3f1bfSFelix Kuehling 		struct qcm_process_device *qpd)
26549fd3f1bfSFelix Kuehling {
26559fd3f1bfSFelix Kuehling 	int retval;
265656f221b6Sxinhui pan 	struct queue *q;
265780c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
26589fd3f1bfSFelix Kuehling 	struct kernel_queue *kq, *kq_next;
26598d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
26609fd3f1bfSFelix Kuehling 	struct device_process_node *cur, *next_dpn;
26619fd3f1bfSFelix Kuehling 	enum kfd_unmap_queues_filter filter =
26629fd3f1bfSFelix Kuehling 		KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES;
266332cce8bcSFelix Kuehling 	bool found = false;
26649fd3f1bfSFelix Kuehling 
26659fd3f1bfSFelix Kuehling 	retval = 0;
26669fd3f1bfSFelix Kuehling 
2667efeaed4dSFelix Kuehling 	dqm_lock(dqm);
26689fd3f1bfSFelix Kuehling 
26699fd3f1bfSFelix Kuehling 	/* Clean all kernel queues */
26709fd3f1bfSFelix Kuehling 	list_for_each_entry_safe(kq, kq_next, &qpd->priv_queue_list, list) {
26719fd3f1bfSFelix Kuehling 		list_del(&kq->list);
2672ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, kq->queue);
26739fd3f1bfSFelix Kuehling 		qpd->is_debug = false;
26749fd3f1bfSFelix Kuehling 		dqm->total_queue_count--;
26759fd3f1bfSFelix Kuehling 		filter = KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES;
26769fd3f1bfSFelix Kuehling 	}
26779fd3f1bfSFelix Kuehling 
26789fd3f1bfSFelix Kuehling 	/* Clear all user mode queues */
26799fd3f1bfSFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
2680c7637c95SYong Zhao 		if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
26811b4670f6SOak Zeng 			deallocate_sdma_queue(dqm, q);
2682c7637c95SYong Zhao 		else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
26831b4670f6SOak Zeng 			deallocate_sdma_queue(dqm, q);
26849fd3f1bfSFelix Kuehling 
2685cc009e61SMukul Joshi 		if (q->properties.is_active) {
2686ab4d51d4SDavid Yat Sin 			decrement_queue_count(dqm, qpd, q);
26879fd3f1bfSFelix Kuehling 
26888dc1db31SMukul Joshi 			if (dqm->dev->kfd->shared_resources.enable_mes) {
2689cc009e61SMukul Joshi 				retval = remove_queue_mes(dqm, q, qpd);
2690cc009e61SMukul Joshi 				if (retval)
269180c74918SAsad Kamal 					dev_err(dev, "Failed to remove queue %d\n",
2692cc009e61SMukul Joshi 						q->properties.queue_id);
2693cc009e61SMukul Joshi 			}
2694cc009e61SMukul Joshi 		}
2695cc009e61SMukul Joshi 
26969fd3f1bfSFelix Kuehling 		dqm->total_queue_count--;
26979fd3f1bfSFelix Kuehling 	}
26989fd3f1bfSFelix Kuehling 
26999fd3f1bfSFelix Kuehling 	/* Unregister process */
27009fd3f1bfSFelix Kuehling 	list_for_each_entry_safe(cur, next_dpn, &dqm->queues, list) {
27019fd3f1bfSFelix Kuehling 		if (qpd == cur->qpd) {
27029fd3f1bfSFelix Kuehling 			list_del(&cur->list);
27039fd3f1bfSFelix Kuehling 			kfree(cur);
27049fd3f1bfSFelix Kuehling 			dqm->processes_count--;
270532cce8bcSFelix Kuehling 			found = true;
27069fd3f1bfSFelix Kuehling 			break;
27079fd3f1bfSFelix Kuehling 		}
27089fd3f1bfSFelix Kuehling 	}
27099fd3f1bfSFelix Kuehling 
27108dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
27117cee6a68SJonathan Kim 		retval = execute_queues_cpsch(dqm, filter, 0, USE_DEFAULT_GRACE_PERIOD);
2712cc009e61SMukul Joshi 
27131802b042SYunxiang Li 	if ((retval || qpd->reset_wavefronts) &&
27141802b042SYunxiang Li 	    down_read_trylock(&dqm->dev->adev->reset_domain->sem)) {
27159fd3f1bfSFelix Kuehling 		pr_warn("Resetting wave fronts (cpsch) on dev %p\n", dqm->dev);
27169fd3f1bfSFelix Kuehling 		dbgdev_wave_reset_wavefronts(dqm->dev, qpd->pqm->process);
27179fd3f1bfSFelix Kuehling 		qpd->reset_wavefronts = false;
27181802b042SYunxiang Li 		up_read(&dqm->dev->adev->reset_domain->sem);
27199fd3f1bfSFelix Kuehling 	}
27209fd3f1bfSFelix Kuehling 
272156f221b6Sxinhui pan 	/* Lastly, free mqd resources.
272256f221b6Sxinhui pan 	 * Do free_mqd() after dqm_unlock to avoid circular locking.
272356f221b6Sxinhui pan 	 */
272456f221b6Sxinhui pan 	while (!list_empty(&qpd->queues_list)) {
272556f221b6Sxinhui pan 		q = list_first_entry(&qpd->queues_list, struct queue, list);
272656f221b6Sxinhui pan 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
272756f221b6Sxinhui pan 				q->properties.type)];
272856f221b6Sxinhui pan 		list_del(&q->list);
272956f221b6Sxinhui pan 		qpd->queue_count--;
273056f221b6Sxinhui pan 		dqm_unlock(dqm);
273156f221b6Sxinhui pan 		mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
273256f221b6Sxinhui pan 		dqm_lock(dqm);
273356f221b6Sxinhui pan 	}
273489cd9d23SPhilip Yang 	dqm_unlock(dqm);
273589cd9d23SPhilip Yang 
273632cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
273732cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
273832cce8bcSFelix Kuehling 	 */
273932cce8bcSFelix Kuehling 	if (found)
274032cce8bcSFelix Kuehling 		kfd_dec_compute_active(dqm->dev);
274132cce8bcSFelix Kuehling 
27429fd3f1bfSFelix Kuehling 	return retval;
27439fd3f1bfSFelix Kuehling }
27449fd3f1bfSFelix Kuehling 
init_mqd_managers(struct device_queue_manager * dqm)2745fdfa090bSOak Zeng static int init_mqd_managers(struct device_queue_manager *dqm)
2746fdfa090bSOak Zeng {
2747fdfa090bSOak Zeng 	int i, j;
274880c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
2749fdfa090bSOak Zeng 	struct mqd_manager *mqd_mgr;
2750fdfa090bSOak Zeng 
2751fdfa090bSOak Zeng 	for (i = 0; i < KFD_MQD_TYPE_MAX; i++) {
2752fdfa090bSOak Zeng 		mqd_mgr = dqm->asic_ops.mqd_manager_init(i, dqm->dev);
2753fdfa090bSOak Zeng 		if (!mqd_mgr) {
275480c74918SAsad Kamal 			dev_err(dev, "mqd manager [%d] initialization failed\n", i);
2755fdfa090bSOak Zeng 			goto out_free;
2756fdfa090bSOak Zeng 		}
2757fdfa090bSOak Zeng 		dqm->mqd_mgrs[i] = mqd_mgr;
2758fdfa090bSOak Zeng 	}
2759fdfa090bSOak Zeng 
2760fdfa090bSOak Zeng 	return 0;
2761fdfa090bSOak Zeng 
2762fdfa090bSOak Zeng out_free:
2763fdfa090bSOak Zeng 	for (j = 0; j < i; j++) {
2764fdfa090bSOak Zeng 		kfree(dqm->mqd_mgrs[j]);
2765fdfa090bSOak Zeng 		dqm->mqd_mgrs[j] = NULL;
2766fdfa090bSOak Zeng 	}
2767fdfa090bSOak Zeng 
2768fdfa090bSOak Zeng 	return -ENOMEM;
2769fdfa090bSOak Zeng }
277011614c36SOak Zeng 
277111614c36SOak Zeng /* Allocate one hiq mqd (HWS) and all SDMA mqd in a continuous trunk*/
allocate_hiq_sdma_mqd(struct device_queue_manager * dqm)277211614c36SOak Zeng static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm)
277311614c36SOak Zeng {
277411614c36SOak Zeng 	int retval;
27758dc1db31SMukul Joshi 	struct kfd_node *dev = dqm->dev;
277611614c36SOak Zeng 	struct kfd_mem_obj *mem_obj = &dqm->hiq_sdma_mqd;
277711614c36SOak Zeng 	uint32_t size = dqm->mqd_mgrs[KFD_MQD_TYPE_SDMA]->mqd_size *
2778c7637c95SYong Zhao 		get_num_all_sdma_engines(dqm) *
27798dc1db31SMukul Joshi 		dev->kfd->device_info.num_sdma_queues_per_engine +
27802f77b9a2SMukul Joshi 		(dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size *
2781c4050ff1SLijo Lazar 		NUM_XCC(dqm->dev->xcc_mask));
278211614c36SOak Zeng 
27836bfc7c7eSGraham Sider 	retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, size,
278411614c36SOak Zeng 		&(mem_obj->gtt_mem), &(mem_obj->gpu_addr),
2785f2cc50ceSEric Huang 		(void *)&(mem_obj->cpu_ptr), false);
278611614c36SOak Zeng 
278711614c36SOak Zeng 	return retval;
278811614c36SOak Zeng }
278911614c36SOak Zeng 
device_queue_manager_init(struct kfd_node * dev)27908dc1db31SMukul Joshi struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev)
279164c7f8cfSBen Goz {
279264c7f8cfSBen Goz 	struct device_queue_manager *dqm;
279364c7f8cfSBen Goz 
279479775b62SKent Russell 	pr_debug("Loading device queue manager\n");
2795a22fc854SBen Goz 
2796dbf56ab1SKent Russell 	dqm = kzalloc(sizeof(*dqm), GFP_KERNEL);
279764c7f8cfSBen Goz 	if (!dqm)
279864c7f8cfSBen Goz 		return NULL;
279964c7f8cfSBen Goz 
28007eb0502aSGraham Sider 	switch (dev->adev->asic_type) {
2801d146c5a7SFelix Kuehling 	/* HWS is not available on Hawaii. */
2802d146c5a7SFelix Kuehling 	case CHIP_HAWAII:
2803d146c5a7SFelix Kuehling 	/* HWS depends on CWSR for timely dequeue. CWSR is not
2804d146c5a7SFelix Kuehling 	 * available on Tonga.
2805d146c5a7SFelix Kuehling 	 *
2806d146c5a7SFelix Kuehling 	 * FIXME: This argument also applies to Kaveri.
2807d146c5a7SFelix Kuehling 	 */
2808d146c5a7SFelix Kuehling 	case CHIP_TONGA:
2809d146c5a7SFelix Kuehling 		dqm->sched_policy = KFD_SCHED_POLICY_NO_HWS;
2810d146c5a7SFelix Kuehling 		break;
2811d146c5a7SFelix Kuehling 	default:
2812d146c5a7SFelix Kuehling 		dqm->sched_policy = sched_policy;
2813d146c5a7SFelix Kuehling 		break;
2814d146c5a7SFelix Kuehling 	}
2815d146c5a7SFelix Kuehling 
281664c7f8cfSBen Goz 	dqm->dev = dev;
2817d146c5a7SFelix Kuehling 	switch (dqm->sched_policy) {
281864c7f8cfSBen Goz 	case KFD_SCHED_POLICY_HWS:
281964c7f8cfSBen Goz 	case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION:
282064c7f8cfSBen Goz 		/* initialize dqm for cp scheduling */
282145c9a5e4SOded Gabbay 		dqm->ops.create_queue = create_queue_cpsch;
282245c9a5e4SOded Gabbay 		dqm->ops.initialize = initialize_cpsch;
282345c9a5e4SOded Gabbay 		dqm->ops.start = start_cpsch;
282445c9a5e4SOded Gabbay 		dqm->ops.stop = stop_cpsch;
2825234eebe1SAmber Lin 		dqm->ops.halt = halt_cpsch;
2826234eebe1SAmber Lin 		dqm->ops.unhalt = unhalt_cpsch;
282745c9a5e4SOded Gabbay 		dqm->ops.destroy_queue = destroy_queue_cpsch;
282845c9a5e4SOded Gabbay 		dqm->ops.update_queue = update_queue;
282958dcd5bfSYong Zhao 		dqm->ops.register_process = register_process;
283058dcd5bfSYong Zhao 		dqm->ops.unregister_process = unregister_process;
283158dcd5bfSYong Zhao 		dqm->ops.uninitialize = uninitialize;
283245c9a5e4SOded Gabbay 		dqm->ops.create_kernel_queue = create_kernel_queue_cpsch;
283345c9a5e4SOded Gabbay 		dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch;
283445c9a5e4SOded Gabbay 		dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
28359fd3f1bfSFelix Kuehling 		dqm->ops.process_termination = process_termination_cpsch;
283626103436SFelix Kuehling 		dqm->ops.evict_process_queues = evict_process_queues_cpsch;
283726103436SFelix Kuehling 		dqm->ops.restore_process_queues = restore_process_queues_cpsch;
28385df099e8SJay Cornwall 		dqm->ops.get_wave_state = get_wave_state;
2839dec63443STao Zhou 		dqm->ops.reset_queues = reset_queues_cpsch;
284042c6c482SDavid Yat Sin 		dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info;
284142c6c482SDavid Yat Sin 		dqm->ops.checkpoint_mqd = checkpoint_mqd;
284264c7f8cfSBen Goz 		break;
284364c7f8cfSBen Goz 	case KFD_SCHED_POLICY_NO_HWS:
284464c7f8cfSBen Goz 		/* initialize dqm for no cp scheduling */
284545c9a5e4SOded Gabbay 		dqm->ops.start = start_nocpsch;
284645c9a5e4SOded Gabbay 		dqm->ops.stop = stop_nocpsch;
284745c9a5e4SOded Gabbay 		dqm->ops.create_queue = create_queue_nocpsch;
284845c9a5e4SOded Gabbay 		dqm->ops.destroy_queue = destroy_queue_nocpsch;
284945c9a5e4SOded Gabbay 		dqm->ops.update_queue = update_queue;
285058dcd5bfSYong Zhao 		dqm->ops.register_process = register_process;
285158dcd5bfSYong Zhao 		dqm->ops.unregister_process = unregister_process;
285245c9a5e4SOded Gabbay 		dqm->ops.initialize = initialize_nocpsch;
285358dcd5bfSYong Zhao 		dqm->ops.uninitialize = uninitialize;
285445c9a5e4SOded Gabbay 		dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
28559fd3f1bfSFelix Kuehling 		dqm->ops.process_termination = process_termination_nocpsch;
285626103436SFelix Kuehling 		dqm->ops.evict_process_queues = evict_process_queues_nocpsch;
285726103436SFelix Kuehling 		dqm->ops.restore_process_queues =
285826103436SFelix Kuehling 			restore_process_queues_nocpsch;
28595df099e8SJay Cornwall 		dqm->ops.get_wave_state = get_wave_state;
286042c6c482SDavid Yat Sin 		dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info;
286142c6c482SDavid Yat Sin 		dqm->ops.checkpoint_mqd = checkpoint_mqd;
286264c7f8cfSBen Goz 		break;
286364c7f8cfSBen Goz 	default:
286480c74918SAsad Kamal 		dev_err(dev->adev->dev, "Invalid scheduling policy %d\n", dqm->sched_policy);
286532fa8219SFelix Kuehling 		goto out_free;
286664c7f8cfSBen Goz 	}
286764c7f8cfSBen Goz 
28687eb0502aSGraham Sider 	switch (dev->adev->asic_type) {
2869a22fc854SBen Goz 	case CHIP_KAVERI:
287097672cbeSFelix Kuehling 	case CHIP_HAWAII:
2871c99a2e7aSAlex Deucher 		device_queue_manager_init_cik(&dqm->asic_ops);
287297672cbeSFelix Kuehling 		break;
287397672cbeSFelix Kuehling 
287499c15019SAlex Deucher 	case CHIP_CARRIZO:
287597672cbeSFelix Kuehling 	case CHIP_TONGA:
287697672cbeSFelix Kuehling 	case CHIP_FIJI:
287797672cbeSFelix Kuehling 	case CHIP_POLARIS10:
287897672cbeSFelix Kuehling 	case CHIP_POLARIS11:
2879846a44d7SGang Ba 	case CHIP_POLARIS12:
2880ed81cd6eSKent Russell 	case CHIP_VEGAM:
2881c99a2e7aSAlex Deucher 		device_queue_manager_init_vi(&dqm->asic_ops);
288297672cbeSFelix Kuehling 		break;
2883bed4f110SFelix Kuehling 
2884e596b903SYong Zhao 	default:
288547fa09b7SDavid Belanger 		if (KFD_GC_VERSION(dev) >= IP_VERSION(12, 0, 0))
288647fa09b7SDavid Belanger 			device_queue_manager_init_v12(&dqm->asic_ops);
288747fa09b7SDavid Belanger 		else if (KFD_GC_VERSION(dev) >= IP_VERSION(11, 0, 0))
2888cc009e61SMukul Joshi 			device_queue_manager_init_v11(&dqm->asic_ops);
2889cc009e61SMukul Joshi 		else if (KFD_GC_VERSION(dev) >= IP_VERSION(10, 1, 1))
289080e28aafSAlex Deucher 			device_queue_manager_init_v10(&dqm->asic_ops);
2891e4804a39SGraham Sider 		else if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 0, 1))
2892e4804a39SGraham Sider 			device_queue_manager_init_v9(&dqm->asic_ops);
2893e4804a39SGraham Sider 		else {
2894e596b903SYong Zhao 			WARN(1, "Unexpected ASIC family %u",
28957eb0502aSGraham Sider 			     dev->adev->asic_type);
2896e596b903SYong Zhao 			goto out_free;
2897a22fc854SBen Goz 		}
2898e4804a39SGraham Sider 	}
2899a22fc854SBen Goz 
2900fdfa090bSOak Zeng 	if (init_mqd_managers(dqm))
2901fdfa090bSOak Zeng 		goto out_free;
2902fdfa090bSOak Zeng 
29038dc1db31SMukul Joshi 	if (!dev->kfd->shared_resources.enable_mes && allocate_hiq_sdma_mqd(dqm)) {
290480c74918SAsad Kamal 		dev_err(dev->adev->dev, "Failed to allocate hiq sdma mqd trunk buffer\n");
290511614c36SOak Zeng 		goto out_free;
290611614c36SOak Zeng 	}
290711614c36SOak Zeng 
2908a70a93faSJonathan Kim 	if (!dqm->ops.initialize(dqm)) {
2909a70a93faSJonathan Kim 		init_waitqueue_head(&dqm->destroy_wait);
291032fa8219SFelix Kuehling 		return dqm;
2911a70a93faSJonathan Kim 	}
291232fa8219SFelix Kuehling 
291332fa8219SFelix Kuehling out_free:
291464c7f8cfSBen Goz 	kfree(dqm);
291564c7f8cfSBen Goz 	return NULL;
291664c7f8cfSBen Goz }
291764c7f8cfSBen Goz 
deallocate_hiq_sdma_mqd(struct kfd_node * dev,struct kfd_mem_obj * mqd)29188dc1db31SMukul Joshi static void deallocate_hiq_sdma_mqd(struct kfd_node *dev,
29197fd5a6fbSYueHaibing 				    struct kfd_mem_obj *mqd)
292011614c36SOak Zeng {
292111614c36SOak Zeng 	WARN(!mqd, "No hiq sdma mqd trunk to free");
292211614c36SOak Zeng 
2923c86ad391SPhilip Yang 	amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem);
292411614c36SOak Zeng }
292511614c36SOak Zeng 
device_queue_manager_uninit(struct device_queue_manager * dqm)292664c7f8cfSBen Goz void device_queue_manager_uninit(struct device_queue_manager *dqm)
292764c7f8cfSBen Goz {
29285e406012SMukul Joshi 	dqm->ops.stop(dqm);
292945c9a5e4SOded Gabbay 	dqm->ops.uninitialize(dqm);
29308dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
293111614c36SOak Zeng 		deallocate_hiq_sdma_mqd(dqm->dev, &dqm->hiq_sdma_mqd);
293264c7f8cfSBen Goz 	kfree(dqm);
293364c7f8cfSBen Goz }
2934851a645eSFelix Kuehling 
kfd_dqm_suspend_bad_queue_mes(struct kfd_node * knode,u32 pasid,u32 doorbell_id)2935eb067d65SMukul Joshi int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbell_id)
2936eb067d65SMukul Joshi {
2937eb067d65SMukul Joshi 	struct kfd_process_device *pdd;
2938eb067d65SMukul Joshi 	struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
2939eb067d65SMukul Joshi 	struct device_queue_manager *dqm = knode->dqm;
2940eb067d65SMukul Joshi 	struct device *dev = dqm->dev->adev->dev;
2941eb067d65SMukul Joshi 	struct qcm_process_device *qpd;
2942eb067d65SMukul Joshi 	struct queue *q = NULL;
2943eb067d65SMukul Joshi 	int ret = 0;
2944eb067d65SMukul Joshi 
2945eb067d65SMukul Joshi 	if (!p)
2946eb067d65SMukul Joshi 		return -EINVAL;
2947eb067d65SMukul Joshi 
2948eb067d65SMukul Joshi 	dqm_lock(dqm);
2949eb067d65SMukul Joshi 
2950eb067d65SMukul Joshi 	pdd = kfd_get_process_device_data(dqm->dev, p);
2951eb067d65SMukul Joshi 	if (pdd) {
2952eb067d65SMukul Joshi 		qpd = &pdd->qpd;
2953eb067d65SMukul Joshi 
2954eb067d65SMukul Joshi 		list_for_each_entry(q, &qpd->queues_list, list) {
2955eb067d65SMukul Joshi 			if (q->doorbell_id == doorbell_id && q->properties.is_active) {
2956eb067d65SMukul Joshi 				ret = suspend_all_queues_mes(dqm);
2957eb067d65SMukul Joshi 				if (ret) {
2958eb067d65SMukul Joshi 					dev_err(dev, "Suspending all queues failed");
2959eb067d65SMukul Joshi 					goto out;
2960eb067d65SMukul Joshi 				}
2961eb067d65SMukul Joshi 
2962eb067d65SMukul Joshi 				q->properties.is_evicted = true;
2963eb067d65SMukul Joshi 				q->properties.is_active = false;
2964eb067d65SMukul Joshi 				decrement_queue_count(dqm, qpd, q);
2965eb067d65SMukul Joshi 
2966eb067d65SMukul Joshi 				ret = remove_queue_mes(dqm, q, qpd);
2967eb067d65SMukul Joshi 				if (ret) {
2968eb067d65SMukul Joshi 					dev_err(dev, "Removing bad queue failed");
2969eb067d65SMukul Joshi 					goto out;
2970eb067d65SMukul Joshi 				}
2971eb067d65SMukul Joshi 
2972eb067d65SMukul Joshi 				ret = resume_all_queues_mes(dqm);
2973eb067d65SMukul Joshi 				if (ret)
2974eb067d65SMukul Joshi 					dev_err(dev, "Resuming all queues failed");
2975eb067d65SMukul Joshi 
2976eb067d65SMukul Joshi 				break;
2977eb067d65SMukul Joshi 			}
2978eb067d65SMukul Joshi 		}
2979eb067d65SMukul Joshi 	}
2980eb067d65SMukul Joshi 
2981eb067d65SMukul Joshi out:
2982eb067d65SMukul Joshi 	dqm_unlock(dqm);
2983eb067d65SMukul Joshi 	return ret;
2984eb067d65SMukul Joshi }
2985eb067d65SMukul Joshi 
kfd_dqm_evict_pasid_mes(struct device_queue_manager * dqm,struct qcm_process_device * qpd)29869a16042fSMukul Joshi static int kfd_dqm_evict_pasid_mes(struct device_queue_manager *dqm,
29879a16042fSMukul Joshi 				   struct qcm_process_device *qpd)
29889a16042fSMukul Joshi {
29899a16042fSMukul Joshi 	struct device *dev = dqm->dev->adev->dev;
29909a16042fSMukul Joshi 	int ret = 0;
29919a16042fSMukul Joshi 
29929a16042fSMukul Joshi 	/* Check if process is already evicted */
29939a16042fSMukul Joshi 	dqm_lock(dqm);
29949a16042fSMukul Joshi 	if (qpd->evicted) {
29959a16042fSMukul Joshi 		/* Increment the evicted count to make sure the
29969a16042fSMukul Joshi 		 * process stays evicted before its terminated.
29979a16042fSMukul Joshi 		 */
29989a16042fSMukul Joshi 		qpd->evicted++;
29999a16042fSMukul Joshi 		dqm_unlock(dqm);
30009a16042fSMukul Joshi 		goto out;
30019a16042fSMukul Joshi 	}
30029a16042fSMukul Joshi 	dqm_unlock(dqm);
30039a16042fSMukul Joshi 
30049a16042fSMukul Joshi 	ret = suspend_all_queues_mes(dqm);
30059a16042fSMukul Joshi 	if (ret) {
30069a16042fSMukul Joshi 		dev_err(dev, "Suspending all queues failed");
30079a16042fSMukul Joshi 		goto out;
30089a16042fSMukul Joshi 	}
30099a16042fSMukul Joshi 
30109a16042fSMukul Joshi 	ret = dqm->ops.evict_process_queues(dqm, qpd);
30119a16042fSMukul Joshi 	if (ret) {
30129a16042fSMukul Joshi 		dev_err(dev, "Evicting process queues failed");
30139a16042fSMukul Joshi 		goto out;
30149a16042fSMukul Joshi 	}
30159a16042fSMukul Joshi 
30169a16042fSMukul Joshi 	ret = resume_all_queues_mes(dqm);
30179a16042fSMukul Joshi 	if (ret)
30189a16042fSMukul Joshi 		dev_err(dev, "Resuming all queues failed");
30199a16042fSMukul Joshi 
30209a16042fSMukul Joshi out:
30219a16042fSMukul Joshi 	return ret;
30229a16042fSMukul Joshi }
30239a16042fSMukul Joshi 
kfd_dqm_evict_pasid(struct device_queue_manager * dqm,u32 pasid)302403e5b167STao Zhou int kfd_dqm_evict_pasid(struct device_queue_manager *dqm, u32 pasid)
30252640c3faSshaoyunl {
30262640c3faSshaoyunl 	struct kfd_process_device *pdd;
30272640c3faSshaoyunl 	struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
30282640c3faSshaoyunl 	int ret = 0;
30292640c3faSshaoyunl 
30302640c3faSshaoyunl 	if (!p)
30312640c3faSshaoyunl 		return -EINVAL;
30328a491bb3SPhilip Cox 	WARN(debug_evictions, "Evicting pid %d", p->lead_thread->pid);
30332640c3faSshaoyunl 	pdd = kfd_get_process_device_data(dqm->dev, p);
30349a16042fSMukul Joshi 	if (pdd) {
30359a16042fSMukul Joshi 		if (dqm->dev->kfd->shared_resources.enable_mes)
30369a16042fSMukul Joshi 			ret = kfd_dqm_evict_pasid_mes(dqm, &pdd->qpd);
30379a16042fSMukul Joshi 		else
30382640c3faSshaoyunl 			ret = dqm->ops.evict_process_queues(dqm, &pdd->qpd);
30399a16042fSMukul Joshi 	}
30409a16042fSMukul Joshi 
30412640c3faSshaoyunl 	kfd_unref_process(p);
30422640c3faSshaoyunl 
30432640c3faSshaoyunl 	return ret;
30442640c3faSshaoyunl }
30452640c3faSshaoyunl 
kfd_process_hw_exception(struct work_struct * work)304673ea648dSShaoyun Liu static void kfd_process_hw_exception(struct work_struct *work)
304773ea648dSShaoyun Liu {
304873ea648dSShaoyun Liu 	struct device_queue_manager *dqm = container_of(work,
304973ea648dSShaoyun Liu 			struct device_queue_manager, hw_exception_work);
30506bfc7c7eSGraham Sider 	amdgpu_amdkfd_gpu_reset(dqm->dev->adev);
305173ea648dSShaoyun Liu }
305273ea648dSShaoyun Liu 
reserve_debug_trap_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd)305397ae3c8cSJonathan Kim int reserve_debug_trap_vmid(struct device_queue_manager *dqm,
305497ae3c8cSJonathan Kim 				struct qcm_process_device *qpd)
305597ae3c8cSJonathan Kim {
305697ae3c8cSJonathan Kim 	int r;
305780c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
305897ae3c8cSJonathan Kim 	int updated_vmid_mask;
305997ae3c8cSJonathan Kim 
306097ae3c8cSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
306180c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
306297ae3c8cSJonathan Kim 		return -EINVAL;
306397ae3c8cSJonathan Kim 	}
306497ae3c8cSJonathan Kim 
306597ae3c8cSJonathan Kim 	dqm_lock(dqm);
306697ae3c8cSJonathan Kim 
306797ae3c8cSJonathan Kim 	if (dqm->trap_debug_vmid != 0) {
306880c74918SAsad Kamal 		dev_err(dev, "Trap debug id already reserved\n");
306997ae3c8cSJonathan Kim 		r = -EBUSY;
307097ae3c8cSJonathan Kim 		goto out_unlock;
307197ae3c8cSJonathan Kim 	}
307297ae3c8cSJonathan Kim 
307397ae3c8cSJonathan Kim 	r = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
307497ae3c8cSJonathan Kim 			USE_DEFAULT_GRACE_PERIOD, false);
307597ae3c8cSJonathan Kim 	if (r)
307697ae3c8cSJonathan Kim 		goto out_unlock;
307797ae3c8cSJonathan Kim 
307897ae3c8cSJonathan Kim 	updated_vmid_mask = dqm->dev->kfd->shared_resources.compute_vmid_bitmap;
307997ae3c8cSJonathan Kim 	updated_vmid_mask &= ~(1 << dqm->dev->vm_info.last_vmid_kfd);
308097ae3c8cSJonathan Kim 
308197ae3c8cSJonathan Kim 	dqm->dev->kfd->shared_resources.compute_vmid_bitmap = updated_vmid_mask;
308297ae3c8cSJonathan Kim 	dqm->trap_debug_vmid = dqm->dev->vm_info.last_vmid_kfd;
308397ae3c8cSJonathan Kim 	r = set_sched_resources(dqm);
308497ae3c8cSJonathan Kim 	if (r)
308597ae3c8cSJonathan Kim 		goto out_unlock;
308697ae3c8cSJonathan Kim 
308797ae3c8cSJonathan Kim 	r = map_queues_cpsch(dqm);
308897ae3c8cSJonathan Kim 	if (r)
308997ae3c8cSJonathan Kim 		goto out_unlock;
309097ae3c8cSJonathan Kim 
309197ae3c8cSJonathan Kim 	pr_debug("Reserved VMID for trap debug: %i\n", dqm->trap_debug_vmid);
309297ae3c8cSJonathan Kim 
309397ae3c8cSJonathan Kim out_unlock:
309497ae3c8cSJonathan Kim 	dqm_unlock(dqm);
309597ae3c8cSJonathan Kim 	return r;
309697ae3c8cSJonathan Kim }
309797ae3c8cSJonathan Kim 
309897ae3c8cSJonathan Kim /*
309997ae3c8cSJonathan Kim  * Releases vmid for the trap debugger
310097ae3c8cSJonathan Kim  */
release_debug_trap_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd)310197ae3c8cSJonathan Kim int release_debug_trap_vmid(struct device_queue_manager *dqm,
310297ae3c8cSJonathan Kim 			struct qcm_process_device *qpd)
310397ae3c8cSJonathan Kim {
310480c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
310597ae3c8cSJonathan Kim 	int r;
310697ae3c8cSJonathan Kim 	int updated_vmid_mask;
310797ae3c8cSJonathan Kim 	uint32_t trap_debug_vmid;
310897ae3c8cSJonathan Kim 
310997ae3c8cSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
311080c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
311197ae3c8cSJonathan Kim 		return -EINVAL;
311297ae3c8cSJonathan Kim 	}
311397ae3c8cSJonathan Kim 
311497ae3c8cSJonathan Kim 	dqm_lock(dqm);
311597ae3c8cSJonathan Kim 	trap_debug_vmid = dqm->trap_debug_vmid;
311697ae3c8cSJonathan Kim 	if (dqm->trap_debug_vmid == 0) {
311780c74918SAsad Kamal 		dev_err(dev, "Trap debug id is not reserved\n");
311897ae3c8cSJonathan Kim 		r = -EINVAL;
311997ae3c8cSJonathan Kim 		goto out_unlock;
312097ae3c8cSJonathan Kim 	}
312197ae3c8cSJonathan Kim 
312297ae3c8cSJonathan Kim 	r = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
312397ae3c8cSJonathan Kim 			USE_DEFAULT_GRACE_PERIOD, false);
312497ae3c8cSJonathan Kim 	if (r)
312597ae3c8cSJonathan Kim 		goto out_unlock;
312697ae3c8cSJonathan Kim 
312797ae3c8cSJonathan Kim 	updated_vmid_mask = dqm->dev->kfd->shared_resources.compute_vmid_bitmap;
312897ae3c8cSJonathan Kim 	updated_vmid_mask |= (1 << dqm->dev->vm_info.last_vmid_kfd);
312997ae3c8cSJonathan Kim 
313097ae3c8cSJonathan Kim 	dqm->dev->kfd->shared_resources.compute_vmid_bitmap = updated_vmid_mask;
313197ae3c8cSJonathan Kim 	dqm->trap_debug_vmid = 0;
313297ae3c8cSJonathan Kim 	r = set_sched_resources(dqm);
313397ae3c8cSJonathan Kim 	if (r)
313497ae3c8cSJonathan Kim 		goto out_unlock;
313597ae3c8cSJonathan Kim 
313697ae3c8cSJonathan Kim 	r = map_queues_cpsch(dqm);
313797ae3c8cSJonathan Kim 	if (r)
313897ae3c8cSJonathan Kim 		goto out_unlock;
313997ae3c8cSJonathan Kim 
314097ae3c8cSJonathan Kim 	pr_debug("Released VMID for trap debug: %i\n", trap_debug_vmid);
314197ae3c8cSJonathan Kim 
314297ae3c8cSJonathan Kim out_unlock:
314397ae3c8cSJonathan Kim 	dqm_unlock(dqm);
314497ae3c8cSJonathan Kim 	return r;
314597ae3c8cSJonathan Kim }
314697ae3c8cSJonathan Kim 
3147a70a93faSJonathan Kim #define QUEUE_NOT_FOUND		-1
3148a70a93faSJonathan Kim /* invalidate queue operation in array */
q_array_invalidate(uint32_t num_queues,uint32_t * queue_ids)3149a70a93faSJonathan Kim static void q_array_invalidate(uint32_t num_queues, uint32_t *queue_ids)
3150a70a93faSJonathan Kim {
3151a70a93faSJonathan Kim 	int i;
3152a70a93faSJonathan Kim 
3153a70a93faSJonathan Kim 	for (i = 0; i < num_queues; i++)
3154a70a93faSJonathan Kim 		queue_ids[i] |= KFD_DBG_QUEUE_INVALID_MASK;
3155a70a93faSJonathan Kim }
3156a70a93faSJonathan Kim 
3157a70a93faSJonathan Kim /* find queue index in array */
q_array_get_index(unsigned int queue_id,uint32_t num_queues,uint32_t * queue_ids)3158a70a93faSJonathan Kim static int q_array_get_index(unsigned int queue_id,
3159a70a93faSJonathan Kim 		uint32_t num_queues,
3160a70a93faSJonathan Kim 		uint32_t *queue_ids)
3161a70a93faSJonathan Kim {
3162a70a93faSJonathan Kim 	int i;
3163a70a93faSJonathan Kim 
3164a70a93faSJonathan Kim 	for (i = 0; i < num_queues; i++)
3165a70a93faSJonathan Kim 		if (queue_id == (queue_ids[i] & ~KFD_DBG_QUEUE_INVALID_MASK))
3166a70a93faSJonathan Kim 			return i;
3167a70a93faSJonathan Kim 
3168a70a93faSJonathan Kim 	return QUEUE_NOT_FOUND;
3169a70a93faSJonathan Kim }
3170a70a93faSJonathan Kim 
3171a70a93faSJonathan Kim struct copy_context_work_handler_workarea {
3172a70a93faSJonathan Kim 	struct work_struct copy_context_work;
3173a70a93faSJonathan Kim 	struct kfd_process *p;
3174a70a93faSJonathan Kim };
3175a70a93faSJonathan Kim 
copy_context_work_handler(struct work_struct * work)3176a70a93faSJonathan Kim static void copy_context_work_handler (struct work_struct *work)
3177a70a93faSJonathan Kim {
3178a70a93faSJonathan Kim 	struct copy_context_work_handler_workarea *workarea;
3179a70a93faSJonathan Kim 	struct mqd_manager *mqd_mgr;
3180a70a93faSJonathan Kim 	struct queue *q;
3181a70a93faSJonathan Kim 	struct mm_struct *mm;
3182a70a93faSJonathan Kim 	struct kfd_process *p;
3183a70a93faSJonathan Kim 	uint32_t tmp_ctl_stack_used_size, tmp_save_area_used_size;
3184a70a93faSJonathan Kim 	int i;
3185a70a93faSJonathan Kim 
3186a70a93faSJonathan Kim 	workarea = container_of(work,
3187a70a93faSJonathan Kim 			struct copy_context_work_handler_workarea,
3188a70a93faSJonathan Kim 			copy_context_work);
3189a70a93faSJonathan Kim 
3190a70a93faSJonathan Kim 	p = workarea->p;
3191a70a93faSJonathan Kim 	mm = get_task_mm(p->lead_thread);
3192a70a93faSJonathan Kim 
3193a70a93faSJonathan Kim 	if (!mm)
3194a70a93faSJonathan Kim 		return;
3195a70a93faSJonathan Kim 
3196a70a93faSJonathan Kim 	kthread_use_mm(mm);
3197a70a93faSJonathan Kim 	for (i = 0; i < p->n_pdds; i++) {
3198a70a93faSJonathan Kim 		struct kfd_process_device *pdd = p->pdds[i];
3199a70a93faSJonathan Kim 		struct device_queue_manager *dqm = pdd->dev->dqm;
3200a70a93faSJonathan Kim 		struct qcm_process_device *qpd = &pdd->qpd;
3201a70a93faSJonathan Kim 
3202a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3203a70a93faSJonathan Kim 			mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_CP];
3204a70a93faSJonathan Kim 
3205a70a93faSJonathan Kim 			/* We ignore the return value from get_wave_state
3206a70a93faSJonathan Kim 			 * because
3207a70a93faSJonathan Kim 			 * i) right now, it always returns 0, and
3208a70a93faSJonathan Kim 			 * ii) if we hit an error, we would continue to the
3209a70a93faSJonathan Kim 			 *      next queue anyway.
3210a70a93faSJonathan Kim 			 */
3211a70a93faSJonathan Kim 			mqd_mgr->get_wave_state(mqd_mgr,
3212a70a93faSJonathan Kim 					q->mqd,
3213a70a93faSJonathan Kim 					&q->properties,
3214a70a93faSJonathan Kim 					(void __user *)	q->properties.ctx_save_restore_area_address,
3215a70a93faSJonathan Kim 					&tmp_ctl_stack_used_size,
3216a70a93faSJonathan Kim 					&tmp_save_area_used_size);
3217a70a93faSJonathan Kim 		}
3218a70a93faSJonathan Kim 	}
3219a70a93faSJonathan Kim 	kthread_unuse_mm(mm);
3220a70a93faSJonathan Kim 	mmput(mm);
3221a70a93faSJonathan Kim }
3222a70a93faSJonathan Kim 
get_queue_ids(uint32_t num_queues,uint32_t * usr_queue_id_array)3223a70a93faSJonathan Kim static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
3224a70a93faSJonathan Kim {
3225a70a93faSJonathan Kim 	size_t array_size = num_queues * sizeof(uint32_t);
3226a70a93faSJonathan Kim 
3227a70a93faSJonathan Kim 	if (!usr_queue_id_array)
3228a70a93faSJonathan Kim 		return NULL;
3229a70a93faSJonathan Kim 
3230bd6040b0SAtul Raut 	return memdup_user(usr_queue_id_array, array_size);
3231a70a93faSJonathan Kim }
3232a70a93faSJonathan Kim 
resume_queues(struct kfd_process * p,uint32_t num_queues,uint32_t * usr_queue_id_array)3233a70a93faSJonathan Kim int resume_queues(struct kfd_process *p,
3234a70a93faSJonathan Kim 		uint32_t num_queues,
3235a70a93faSJonathan Kim 		uint32_t *usr_queue_id_array)
3236a70a93faSJonathan Kim {
3237a70a93faSJonathan Kim 	uint32_t *queue_ids = NULL;
3238a70a93faSJonathan Kim 	int total_resumed = 0;
3239a70a93faSJonathan Kim 	int i;
3240a70a93faSJonathan Kim 
3241a70a93faSJonathan Kim 	if (usr_queue_id_array) {
3242a70a93faSJonathan Kim 		queue_ids = get_queue_ids(num_queues, usr_queue_id_array);
3243a70a93faSJonathan Kim 
3244a70a93faSJonathan Kim 		if (IS_ERR(queue_ids))
3245a70a93faSJonathan Kim 			return PTR_ERR(queue_ids);
3246a70a93faSJonathan Kim 
3247a70a93faSJonathan Kim 		/* mask all queues as invalid.  unmask per successful request */
3248a70a93faSJonathan Kim 		q_array_invalidate(num_queues, queue_ids);
3249a70a93faSJonathan Kim 	}
3250a70a93faSJonathan Kim 
3251a70a93faSJonathan Kim 	for (i = 0; i < p->n_pdds; i++) {
3252a70a93faSJonathan Kim 		struct kfd_process_device *pdd = p->pdds[i];
3253a70a93faSJonathan Kim 		struct device_queue_manager *dqm = pdd->dev->dqm;
325480c74918SAsad Kamal 		struct device *dev = dqm->dev->adev->dev;
3255a70a93faSJonathan Kim 		struct qcm_process_device *qpd = &pdd->qpd;
3256a70a93faSJonathan Kim 		struct queue *q;
3257a70a93faSJonathan Kim 		int r, per_device_resumed = 0;
3258a70a93faSJonathan Kim 
3259a70a93faSJonathan Kim 		dqm_lock(dqm);
3260a70a93faSJonathan Kim 
3261a70a93faSJonathan Kim 		/* unmask queues that resume or already resumed as valid */
3262a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3263a70a93faSJonathan Kim 			int q_idx = QUEUE_NOT_FOUND;
3264a70a93faSJonathan Kim 
3265a70a93faSJonathan Kim 			if (queue_ids)
3266a70a93faSJonathan Kim 				q_idx = q_array_get_index(
3267a70a93faSJonathan Kim 						q->properties.queue_id,
3268a70a93faSJonathan Kim 						num_queues,
3269a70a93faSJonathan Kim 						queue_ids);
3270a70a93faSJonathan Kim 
3271a70a93faSJonathan Kim 			if (!queue_ids || q_idx != QUEUE_NOT_FOUND) {
3272a70a93faSJonathan Kim 				int err = resume_single_queue(dqm, &pdd->qpd, q);
3273a70a93faSJonathan Kim 
3274a70a93faSJonathan Kim 				if (queue_ids) {
3275a70a93faSJonathan Kim 					if (!err) {
3276a70a93faSJonathan Kim 						queue_ids[q_idx] &=
3277a70a93faSJonathan Kim 							~KFD_DBG_QUEUE_INVALID_MASK;
3278a70a93faSJonathan Kim 					} else {
3279a70a93faSJonathan Kim 						queue_ids[q_idx] |=
3280a70a93faSJonathan Kim 							KFD_DBG_QUEUE_ERROR_MASK;
3281a70a93faSJonathan Kim 						break;
3282a70a93faSJonathan Kim 					}
3283a70a93faSJonathan Kim 				}
3284a70a93faSJonathan Kim 
3285a70a93faSJonathan Kim 				if (dqm->dev->kfd->shared_resources.enable_mes) {
3286a70a93faSJonathan Kim 					wake_up_all(&dqm->destroy_wait);
3287a70a93faSJonathan Kim 					if (!err)
3288a70a93faSJonathan Kim 						total_resumed++;
3289a70a93faSJonathan Kim 				} else {
3290a70a93faSJonathan Kim 					per_device_resumed++;
3291a70a93faSJonathan Kim 				}
3292a70a93faSJonathan Kim 			}
3293a70a93faSJonathan Kim 		}
3294a70a93faSJonathan Kim 
3295a70a93faSJonathan Kim 		if (!per_device_resumed) {
3296a70a93faSJonathan Kim 			dqm_unlock(dqm);
3297a70a93faSJonathan Kim 			continue;
3298a70a93faSJonathan Kim 		}
3299a70a93faSJonathan Kim 
3300a70a93faSJonathan Kim 		r = execute_queues_cpsch(dqm,
3301a70a93faSJonathan Kim 					KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES,
3302a70a93faSJonathan Kim 					0,
3303a70a93faSJonathan Kim 					USE_DEFAULT_GRACE_PERIOD);
3304a70a93faSJonathan Kim 		if (r) {
330580c74918SAsad Kamal 			dev_err(dev, "Failed to resume process queues\n");
3306a70a93faSJonathan Kim 			if (queue_ids) {
3307a70a93faSJonathan Kim 				list_for_each_entry(q, &qpd->queues_list, list) {
3308a70a93faSJonathan Kim 					int q_idx = q_array_get_index(
3309a70a93faSJonathan Kim 							q->properties.queue_id,
3310a70a93faSJonathan Kim 							num_queues,
3311a70a93faSJonathan Kim 							queue_ids);
3312a70a93faSJonathan Kim 
3313a70a93faSJonathan Kim 					/* mask queue as error on resume fail */
3314a70a93faSJonathan Kim 					if (q_idx != QUEUE_NOT_FOUND)
3315a70a93faSJonathan Kim 						queue_ids[q_idx] |=
3316a70a93faSJonathan Kim 							KFD_DBG_QUEUE_ERROR_MASK;
3317a70a93faSJonathan Kim 				}
3318a70a93faSJonathan Kim 			}
3319a70a93faSJonathan Kim 		} else {
3320a70a93faSJonathan Kim 			wake_up_all(&dqm->destroy_wait);
3321a70a93faSJonathan Kim 			total_resumed += per_device_resumed;
3322a70a93faSJonathan Kim 		}
3323a70a93faSJonathan Kim 
3324a70a93faSJonathan Kim 		dqm_unlock(dqm);
3325a70a93faSJonathan Kim 	}
3326a70a93faSJonathan Kim 
3327a70a93faSJonathan Kim 	if (queue_ids) {
3328a70a93faSJonathan Kim 		if (copy_to_user((void __user *)usr_queue_id_array, queue_ids,
3329a70a93faSJonathan Kim 				num_queues * sizeof(uint32_t)))
3330a70a93faSJonathan Kim 			pr_err("copy_to_user failed on queue resume\n");
3331a70a93faSJonathan Kim 
3332a70a93faSJonathan Kim 		kfree(queue_ids);
3333a70a93faSJonathan Kim 	}
3334a70a93faSJonathan Kim 
3335a70a93faSJonathan Kim 	return total_resumed;
3336a70a93faSJonathan Kim }
3337a70a93faSJonathan Kim 
suspend_queues(struct kfd_process * p,uint32_t num_queues,uint32_t grace_period,uint64_t exception_clear_mask,uint32_t * usr_queue_id_array)3338a70a93faSJonathan Kim int suspend_queues(struct kfd_process *p,
3339a70a93faSJonathan Kim 			uint32_t num_queues,
3340a70a93faSJonathan Kim 			uint32_t grace_period,
3341a70a93faSJonathan Kim 			uint64_t exception_clear_mask,
3342a70a93faSJonathan Kim 			uint32_t *usr_queue_id_array)
3343a70a93faSJonathan Kim {
3344a70a93faSJonathan Kim 	uint32_t *queue_ids = get_queue_ids(num_queues, usr_queue_id_array);
3345a70a93faSJonathan Kim 	int total_suspended = 0;
3346a70a93faSJonathan Kim 	int i;
3347a70a93faSJonathan Kim 
3348a70a93faSJonathan Kim 	if (IS_ERR(queue_ids))
3349a70a93faSJonathan Kim 		return PTR_ERR(queue_ids);
3350a70a93faSJonathan Kim 
3351a70a93faSJonathan Kim 	/* mask all queues as invalid.  umask on successful request */
3352a70a93faSJonathan Kim 	q_array_invalidate(num_queues, queue_ids);
3353a70a93faSJonathan Kim 
3354a70a93faSJonathan Kim 	for (i = 0; i < p->n_pdds; i++) {
3355a70a93faSJonathan Kim 		struct kfd_process_device *pdd = p->pdds[i];
3356a70a93faSJonathan Kim 		struct device_queue_manager *dqm = pdd->dev->dqm;
335780c74918SAsad Kamal 		struct device *dev = dqm->dev->adev->dev;
3358a70a93faSJonathan Kim 		struct qcm_process_device *qpd = &pdd->qpd;
3359a70a93faSJonathan Kim 		struct queue *q;
3360a70a93faSJonathan Kim 		int r, per_device_suspended = 0;
3361a70a93faSJonathan Kim 
3362a70a93faSJonathan Kim 		mutex_lock(&p->event_mutex);
3363a70a93faSJonathan Kim 		dqm_lock(dqm);
3364a70a93faSJonathan Kim 
3365a70a93faSJonathan Kim 		/* unmask queues that suspend or already suspended */
3366a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3367a70a93faSJonathan Kim 			int q_idx = q_array_get_index(q->properties.queue_id,
3368a70a93faSJonathan Kim 							num_queues,
3369a70a93faSJonathan Kim 							queue_ids);
3370a70a93faSJonathan Kim 
3371a70a93faSJonathan Kim 			if (q_idx != QUEUE_NOT_FOUND) {
3372a70a93faSJonathan Kim 				int err = suspend_single_queue(dqm, pdd, q);
3373a70a93faSJonathan Kim 				bool is_mes = dqm->dev->kfd->shared_resources.enable_mes;
3374a70a93faSJonathan Kim 
3375a70a93faSJonathan Kim 				if (!err) {
3376a70a93faSJonathan Kim 					queue_ids[q_idx] &= ~KFD_DBG_QUEUE_INVALID_MASK;
3377a70a93faSJonathan Kim 					if (exception_clear_mask && is_mes)
3378a70a93faSJonathan Kim 						q->properties.exception_status &=
3379a70a93faSJonathan Kim 							~exception_clear_mask;
3380a70a93faSJonathan Kim 
3381a70a93faSJonathan Kim 					if (is_mes)
3382a70a93faSJonathan Kim 						total_suspended++;
3383a70a93faSJonathan Kim 					else
3384a70a93faSJonathan Kim 						per_device_suspended++;
3385a70a93faSJonathan Kim 				} else if (err != -EBUSY) {
3386a70a93faSJonathan Kim 					r = err;
3387a70a93faSJonathan Kim 					queue_ids[q_idx] |= KFD_DBG_QUEUE_ERROR_MASK;
3388a70a93faSJonathan Kim 					break;
3389a70a93faSJonathan Kim 				}
3390a70a93faSJonathan Kim 			}
3391a70a93faSJonathan Kim 		}
3392a70a93faSJonathan Kim 
3393a70a93faSJonathan Kim 		if (!per_device_suspended) {
3394a70a93faSJonathan Kim 			dqm_unlock(dqm);
3395a70a93faSJonathan Kim 			mutex_unlock(&p->event_mutex);
3396a70a93faSJonathan Kim 			if (total_suspended)
3397a70a93faSJonathan Kim 				amdgpu_amdkfd_debug_mem_fence(dqm->dev->adev);
3398a70a93faSJonathan Kim 			continue;
3399a70a93faSJonathan Kim 		}
3400a70a93faSJonathan Kim 
3401a70a93faSJonathan Kim 		r = execute_queues_cpsch(dqm,
3402a70a93faSJonathan Kim 			KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
3403a70a93faSJonathan Kim 			grace_period);
3404a70a93faSJonathan Kim 
3405a70a93faSJonathan Kim 		if (r)
340680c74918SAsad Kamal 			dev_err(dev, "Failed to suspend process queues.\n");
3407a70a93faSJonathan Kim 		else
3408a70a93faSJonathan Kim 			total_suspended += per_device_suspended;
3409a70a93faSJonathan Kim 
3410a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3411a70a93faSJonathan Kim 			int q_idx = q_array_get_index(q->properties.queue_id,
3412a70a93faSJonathan Kim 						num_queues, queue_ids);
3413a70a93faSJonathan Kim 
3414a70a93faSJonathan Kim 			if (q_idx == QUEUE_NOT_FOUND)
3415a70a93faSJonathan Kim 				continue;
3416a70a93faSJonathan Kim 
3417a70a93faSJonathan Kim 			/* mask queue as error on suspend fail */
3418a70a93faSJonathan Kim 			if (r)
3419a70a93faSJonathan Kim 				queue_ids[q_idx] |= KFD_DBG_QUEUE_ERROR_MASK;
3420a70a93faSJonathan Kim 			else if (exception_clear_mask)
3421a70a93faSJonathan Kim 				q->properties.exception_status &=
3422a70a93faSJonathan Kim 							~exception_clear_mask;
3423a70a93faSJonathan Kim 		}
3424a70a93faSJonathan Kim 
3425a70a93faSJonathan Kim 		dqm_unlock(dqm);
3426a70a93faSJonathan Kim 		mutex_unlock(&p->event_mutex);
3427a70a93faSJonathan Kim 		amdgpu_device_flush_hdp(dqm->dev->adev, NULL);
3428a70a93faSJonathan Kim 	}
3429a70a93faSJonathan Kim 
3430a70a93faSJonathan Kim 	if (total_suspended) {
3431a70a93faSJonathan Kim 		struct copy_context_work_handler_workarea copy_context_worker;
3432a70a93faSJonathan Kim 
3433a70a93faSJonathan Kim 		INIT_WORK_ONSTACK(
3434a70a93faSJonathan Kim 				&copy_context_worker.copy_context_work,
3435a70a93faSJonathan Kim 				copy_context_work_handler);
3436a70a93faSJonathan Kim 
3437a70a93faSJonathan Kim 		copy_context_worker.p = p;
3438a70a93faSJonathan Kim 
3439a70a93faSJonathan Kim 		schedule_work(&copy_context_worker.copy_context_work);
3440a70a93faSJonathan Kim 
3441a70a93faSJonathan Kim 
3442a70a93faSJonathan Kim 		flush_work(&copy_context_worker.copy_context_work);
3443a70a93faSJonathan Kim 		destroy_work_on_stack(&copy_context_worker.copy_context_work);
3444a70a93faSJonathan Kim 	}
3445a70a93faSJonathan Kim 
3446a70a93faSJonathan Kim 	if (copy_to_user((void __user *)usr_queue_id_array, queue_ids,
3447a70a93faSJonathan Kim 			num_queues * sizeof(uint32_t)))
3448a70a93faSJonathan Kim 		pr_err("copy_to_user failed on queue suspend\n");
3449a70a93faSJonathan Kim 
3450a70a93faSJonathan Kim 	kfree(queue_ids);
3451a70a93faSJonathan Kim 
3452a70a93faSJonathan Kim 	return total_suspended;
3453a70a93faSJonathan Kim }
3454a70a93faSJonathan Kim 
set_queue_type_for_user(struct queue_properties * q_props)3455b17bd5dbSJonathan Kim static uint32_t set_queue_type_for_user(struct queue_properties *q_props)
3456b17bd5dbSJonathan Kim {
3457b17bd5dbSJonathan Kim 	switch (q_props->type) {
3458b17bd5dbSJonathan Kim 	case KFD_QUEUE_TYPE_COMPUTE:
3459b17bd5dbSJonathan Kim 		return q_props->format == KFD_QUEUE_FORMAT_PM4
3460b17bd5dbSJonathan Kim 					? KFD_IOC_QUEUE_TYPE_COMPUTE
3461b17bd5dbSJonathan Kim 					: KFD_IOC_QUEUE_TYPE_COMPUTE_AQL;
3462b17bd5dbSJonathan Kim 	case KFD_QUEUE_TYPE_SDMA:
3463b17bd5dbSJonathan Kim 		return KFD_IOC_QUEUE_TYPE_SDMA;
3464b17bd5dbSJonathan Kim 	case KFD_QUEUE_TYPE_SDMA_XGMI:
3465b17bd5dbSJonathan Kim 		return KFD_IOC_QUEUE_TYPE_SDMA_XGMI;
3466b17bd5dbSJonathan Kim 	default:
3467b17bd5dbSJonathan Kim 		WARN_ONCE(true, "queue type not recognized!");
3468b17bd5dbSJonathan Kim 		return 0xffffffff;
3469b17bd5dbSJonathan Kim 	};
3470b17bd5dbSJonathan Kim }
3471b17bd5dbSJonathan Kim 
set_queue_snapshot_entry(struct queue * q,uint64_t exception_clear_mask,struct kfd_queue_snapshot_entry * qss_entry)3472b17bd5dbSJonathan Kim void set_queue_snapshot_entry(struct queue *q,
3473b17bd5dbSJonathan Kim 			      uint64_t exception_clear_mask,
3474b17bd5dbSJonathan Kim 			      struct kfd_queue_snapshot_entry *qss_entry)
3475b17bd5dbSJonathan Kim {
3476b17bd5dbSJonathan Kim 	qss_entry->ring_base_address = q->properties.queue_address;
3477b17bd5dbSJonathan Kim 	qss_entry->write_pointer_address = (uint64_t)q->properties.write_ptr;
3478b17bd5dbSJonathan Kim 	qss_entry->read_pointer_address = (uint64_t)q->properties.read_ptr;
3479b17bd5dbSJonathan Kim 	qss_entry->ctx_save_restore_address =
3480b17bd5dbSJonathan Kim 				q->properties.ctx_save_restore_area_address;
3481b17bd5dbSJonathan Kim 	qss_entry->ctx_save_restore_area_size =
3482b17bd5dbSJonathan Kim 				q->properties.ctx_save_restore_area_size;
3483b17bd5dbSJonathan Kim 	qss_entry->exception_status = q->properties.exception_status;
3484b17bd5dbSJonathan Kim 	qss_entry->queue_id = q->properties.queue_id;
3485b17bd5dbSJonathan Kim 	qss_entry->gpu_id = q->device->id;
3486b17bd5dbSJonathan Kim 	qss_entry->ring_size = (uint32_t)q->properties.queue_size;
3487b17bd5dbSJonathan Kim 	qss_entry->queue_type = set_queue_type_for_user(&q->properties);
3488b17bd5dbSJonathan Kim 	q->properties.exception_status &= ~exception_clear_mask;
3489b17bd5dbSJonathan Kim }
3490b17bd5dbSJonathan Kim 
debug_lock_and_unmap(struct device_queue_manager * dqm)34910de4ec9aSJonathan Kim int debug_lock_and_unmap(struct device_queue_manager *dqm)
34920de4ec9aSJonathan Kim {
349380c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
34940de4ec9aSJonathan Kim 	int r;
34950de4ec9aSJonathan Kim 
34960de4ec9aSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
349780c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
34980de4ec9aSJonathan Kim 		return -EINVAL;
34990de4ec9aSJonathan Kim 	}
35000de4ec9aSJonathan Kim 
35010de4ec9aSJonathan Kim 	if (!kfd_dbg_is_per_vmid_supported(dqm->dev))
35020de4ec9aSJonathan Kim 		return 0;
35030de4ec9aSJonathan Kim 
35040de4ec9aSJonathan Kim 	dqm_lock(dqm);
35050de4ec9aSJonathan Kim 
35060de4ec9aSJonathan Kim 	r = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0, 0, false);
35070de4ec9aSJonathan Kim 	if (r)
35080de4ec9aSJonathan Kim 		dqm_unlock(dqm);
35090de4ec9aSJonathan Kim 
35100de4ec9aSJonathan Kim 	return r;
35110de4ec9aSJonathan Kim }
35120de4ec9aSJonathan Kim 
debug_map_and_unlock(struct device_queue_manager * dqm)35130de4ec9aSJonathan Kim int debug_map_and_unlock(struct device_queue_manager *dqm)
35140de4ec9aSJonathan Kim {
351580c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
35160de4ec9aSJonathan Kim 	int r;
35170de4ec9aSJonathan Kim 
35180de4ec9aSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
351980c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
35200de4ec9aSJonathan Kim 		return -EINVAL;
35210de4ec9aSJonathan Kim 	}
35220de4ec9aSJonathan Kim 
35230de4ec9aSJonathan Kim 	if (!kfd_dbg_is_per_vmid_supported(dqm->dev))
35240de4ec9aSJonathan Kim 		return 0;
35250de4ec9aSJonathan Kim 
35260de4ec9aSJonathan Kim 	r = map_queues_cpsch(dqm);
35270de4ec9aSJonathan Kim 
35280de4ec9aSJonathan Kim 	dqm_unlock(dqm);
35290de4ec9aSJonathan Kim 
35300de4ec9aSJonathan Kim 	return r;
35310de4ec9aSJonathan Kim }
35320de4ec9aSJonathan Kim 
debug_refresh_runlist(struct device_queue_manager * dqm)35330de4ec9aSJonathan Kim int debug_refresh_runlist(struct device_queue_manager *dqm)
35340de4ec9aSJonathan Kim {
35350de4ec9aSJonathan Kim 	int r = debug_lock_and_unmap(dqm);
35360de4ec9aSJonathan Kim 
35370de4ec9aSJonathan Kim 	if (r)
35380de4ec9aSJonathan Kim 		return r;
35390de4ec9aSJonathan Kim 
35400de4ec9aSJonathan Kim 	return debug_map_and_unlock(dqm);
35410de4ec9aSJonathan Kim }
35420de4ec9aSJonathan Kim 
kfd_dqm_is_queue_in_process(struct device_queue_manager * dqm,struct qcm_process_device * qpd,int doorbell_off,u32 * queue_format)35436ae9e1abSMukul Joshi bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm,
35446ae9e1abSMukul Joshi 				 struct qcm_process_device *qpd,
3545*e45b011dSMukul Joshi 				 int doorbell_off, u32 *queue_format)
35466ae9e1abSMukul Joshi {
35476ae9e1abSMukul Joshi 	struct queue *q;
35486ae9e1abSMukul Joshi 	bool r = false;
35496ae9e1abSMukul Joshi 
3550*e45b011dSMukul Joshi 	if (!queue_format)
3551*e45b011dSMukul Joshi 		return r;
3552*e45b011dSMukul Joshi 
35536ae9e1abSMukul Joshi 	dqm_lock(dqm);
35546ae9e1abSMukul Joshi 
35556ae9e1abSMukul Joshi 	list_for_each_entry(q, &qpd->queues_list, list) {
35566ae9e1abSMukul Joshi 		if (q->properties.doorbell_off == doorbell_off) {
3557*e45b011dSMukul Joshi 			*queue_format = q->properties.format;
35586ae9e1abSMukul Joshi 			r = true;
35596ae9e1abSMukul Joshi 			goto out;
35606ae9e1abSMukul Joshi 		}
35616ae9e1abSMukul Joshi 	}
35626ae9e1abSMukul Joshi 
35636ae9e1abSMukul Joshi out:
35646ae9e1abSMukul Joshi 	dqm_unlock(dqm);
35656ae9e1abSMukul Joshi 	return r;
35666ae9e1abSMukul Joshi }
3567851a645eSFelix Kuehling #if defined(CONFIG_DEBUG_FS)
3568851a645eSFelix Kuehling 
seq_reg_dump(struct seq_file * m,uint32_t (* dump)[2],uint32_t n_regs)3569851a645eSFelix Kuehling static void seq_reg_dump(struct seq_file *m,
3570851a645eSFelix Kuehling 			 uint32_t (*dump)[2], uint32_t n_regs)
3571851a645eSFelix Kuehling {
3572851a645eSFelix Kuehling 	uint32_t i, count;
3573851a645eSFelix Kuehling 
3574851a645eSFelix Kuehling 	for (i = 0, count = 0; i < n_regs; i++) {
3575851a645eSFelix Kuehling 		if (count == 0 ||
3576851a645eSFelix Kuehling 		    dump[i-1][0] + sizeof(uint32_t) != dump[i][0]) {
3577851a645eSFelix Kuehling 			seq_printf(m, "%s    %08x: %08x",
3578851a645eSFelix Kuehling 				   i ? "\n" : "",
3579851a645eSFelix Kuehling 				   dump[i][0], dump[i][1]);
3580851a645eSFelix Kuehling 			count = 7;
3581851a645eSFelix Kuehling 		} else {
3582851a645eSFelix Kuehling 			seq_printf(m, " %08x", dump[i][1]);
3583851a645eSFelix Kuehling 			count--;
3584851a645eSFelix Kuehling 		}
3585851a645eSFelix Kuehling 	}
3586851a645eSFelix Kuehling 
3587851a645eSFelix Kuehling 	seq_puts(m, "\n");
3588851a645eSFelix Kuehling }
3589851a645eSFelix Kuehling 
dqm_debugfs_hqds(struct seq_file * m,void * data)3590851a645eSFelix Kuehling int dqm_debugfs_hqds(struct seq_file *m, void *data)
3591851a645eSFelix Kuehling {
3592851a645eSFelix Kuehling 	struct device_queue_manager *dqm = data;
3593c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
3594851a645eSFelix Kuehling 	uint32_t (*dump)[2], n_regs;
3595851a645eSFelix Kuehling 	int pipe, queue;
3596c4050ff1SLijo Lazar 	int r = 0, xcc_id;
3597643e40d4SMukul Joshi 	uint32_t sdma_engine_start;
3598851a645eSFelix Kuehling 
35992c99a547SPhilip Yang 	if (!dqm->sched_running) {
36002243f493SRajneesh Bhardwaj 		seq_puts(m, " Device is stopped\n");
36012c99a547SPhilip Yang 		return 0;
36022c99a547SPhilip Yang 	}
36032c99a547SPhilip Yang 
3604c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask) {
3605420185fdSGraham Sider 		r = dqm->dev->kfd2kgd->hqd_dump(dqm->dev->adev,
3606c4050ff1SLijo Lazar 						KFD_CIK_HIQ_PIPE,
3607c4050ff1SLijo Lazar 						KFD_CIK_HIQ_QUEUE, &dump,
3608c4050ff1SLijo Lazar 						&n_regs, xcc_id);
360924f48a42SOak Zeng 		if (!r) {
3610c4050ff1SLijo Lazar 			seq_printf(
3611c4050ff1SLijo Lazar 				m,
3612e2069a7bSMukul Joshi 				"   Inst %d, HIQ on MEC %d Pipe %d Queue %d\n",
3613c4050ff1SLijo Lazar 				xcc_id,
3614c4050ff1SLijo Lazar 				KFD_CIK_HIQ_PIPE / get_pipes_per_mec(dqm) + 1,
361524f48a42SOak Zeng 				KFD_CIK_HIQ_PIPE % get_pipes_per_mec(dqm),
361624f48a42SOak Zeng 				KFD_CIK_HIQ_QUEUE);
361724f48a42SOak Zeng 			seq_reg_dump(m, dump, n_regs);
361824f48a42SOak Zeng 
361924f48a42SOak Zeng 			kfree(dump);
362024f48a42SOak Zeng 		}
362124f48a42SOak Zeng 
3622851a645eSFelix Kuehling 		for (pipe = 0; pipe < get_pipes_per_mec(dqm); pipe++) {
3623851a645eSFelix Kuehling 			int pipe_offset = pipe * get_queues_per_pipe(dqm);
3624851a645eSFelix Kuehling 
3625851a645eSFelix Kuehling 			for (queue = 0; queue < get_queues_per_pipe(dqm); queue++) {
3626851a645eSFelix Kuehling 				if (!test_bit(pipe_offset + queue,
36278dc1db31SMukul Joshi 				      dqm->dev->kfd->shared_resources.cp_queue_bitmap))
3628851a645eSFelix Kuehling 					continue;
3629851a645eSFelix Kuehling 
3630c4050ff1SLijo Lazar 				r = dqm->dev->kfd2kgd->hqd_dump(dqm->dev->adev,
3631c4050ff1SLijo Lazar 								pipe, queue,
3632c4050ff1SLijo Lazar 								&dump, &n_regs,
3633c4050ff1SLijo Lazar 								xcc_id);
3634851a645eSFelix Kuehling 				if (r)
3635851a645eSFelix Kuehling 					break;
3636851a645eSFelix Kuehling 
3637c4050ff1SLijo Lazar 				seq_printf(m,
3638c4050ff1SLijo Lazar 					   " Inst %d,  CP Pipe %d, Queue %d\n",
3639c4050ff1SLijo Lazar 					   xcc_id, pipe, queue);
3640851a645eSFelix Kuehling 				seq_reg_dump(m, dump, n_regs);
3641851a645eSFelix Kuehling 
3642851a645eSFelix Kuehling 				kfree(dump);
3643851a645eSFelix Kuehling 			}
3644851a645eSFelix Kuehling 		}
3645e2069a7bSMukul Joshi 	}
3646851a645eSFelix Kuehling 
3647643e40d4SMukul Joshi 	sdma_engine_start = dqm->dev->node_id * get_num_all_sdma_engines(dqm);
3648643e40d4SMukul Joshi 	for (pipe = sdma_engine_start;
3649643e40d4SMukul Joshi 	     pipe < (sdma_engine_start + get_num_all_sdma_engines(dqm));
3650643e40d4SMukul Joshi 	     pipe++) {
3651d5094189SShaoyun Liu 		for (queue = 0;
36528dc1db31SMukul Joshi 		     queue < dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
3653d5094189SShaoyun Liu 		     queue++) {
3654851a645eSFelix Kuehling 			r = dqm->dev->kfd2kgd->hqd_sdma_dump(
3655420185fdSGraham Sider 				dqm->dev->adev, pipe, queue, &dump, &n_regs);
3656851a645eSFelix Kuehling 			if (r)
3657851a645eSFelix Kuehling 				break;
3658851a645eSFelix Kuehling 
3659851a645eSFelix Kuehling 			seq_printf(m, "  SDMA Engine %d, RLC %d\n",
3660851a645eSFelix Kuehling 				  pipe, queue);
3661851a645eSFelix Kuehling 			seq_reg_dump(m, dump, n_regs);
3662851a645eSFelix Kuehling 
3663851a645eSFelix Kuehling 			kfree(dump);
3664851a645eSFelix Kuehling 		}
3665851a645eSFelix Kuehling 	}
3666851a645eSFelix Kuehling 
3667851a645eSFelix Kuehling 	return r;
3668851a645eSFelix Kuehling }
3669851a645eSFelix Kuehling 
dqm_debugfs_hang_hws(struct device_queue_manager * dqm)36704f942aaeSOak Zeng int dqm_debugfs_hang_hws(struct device_queue_manager *dqm)
3671a29ec470SShaoyun Liu {
3672a29ec470SShaoyun Liu 	int r = 0;
3673a29ec470SShaoyun Liu 
3674a29ec470SShaoyun Liu 	dqm_lock(dqm);
36754f942aaeSOak Zeng 	r = pm_debugfs_hang_hws(&dqm->packet_mgr);
36764f942aaeSOak Zeng 	if (r) {
36774f942aaeSOak Zeng 		dqm_unlock(dqm);
36784f942aaeSOak Zeng 		return r;
36794f942aaeSOak Zeng 	}
3680a29ec470SShaoyun Liu 	dqm->active_runlist = true;
36817cee6a68SJonathan Kim 	r = execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES,
36827cee6a68SJonathan Kim 				0, USE_DEFAULT_GRACE_PERIOD);
3683a29ec470SShaoyun Liu 	dqm_unlock(dqm);
3684a29ec470SShaoyun Liu 
3685a29ec470SShaoyun Liu 	return r;
3686a29ec470SShaoyun Liu }
3687a29ec470SShaoyun Liu 
3688851a645eSFelix Kuehling #endif
3689