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"
39bac38ca8SJonathan Kim #include "amdgpu_sdma.h"
40f2a1fbddSAlex Deucher #include "mes_v11_api_def.h"
410de4ec9aSJonathan Kim #include "kfd_debug.h"
4264c7f8cfSBen Goz 
4364c7f8cfSBen Goz /* Size of the per-pipe EOP queue */
4464c7f8cfSBen Goz #define CIK_HPD_EOP_BYTES_LOG2 11
4564c7f8cfSBen Goz #define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
46ed962f8dSHarish Kasiviswanathan /* See unmap_queues_cpsch() */
47ed962f8dSHarish Kasiviswanathan #define USE_DEFAULT_GRACE_PERIOD 0xffffffff
4864c7f8cfSBen Goz 
4964c7f8cfSBen Goz static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,
50c7b6bac9SFenghua Yu 				  u32 pasid, unsigned int vmid);
5164c7f8cfSBen Goz 
52c4744e24SYong Zhao static int execute_queues_cpsch(struct device_queue_manager *dqm,
53c4744e24SYong Zhao 				enum kfd_unmap_queues_filter filter,
547cee6a68SJonathan Kim 				uint32_t filter_param,
557cee6a68SJonathan Kim 				uint32_t grace_period);
567da2bcf8SYong Zhao static int unmap_queues_cpsch(struct device_queue_manager *dqm,
574465f466SYong Zhao 				enum kfd_unmap_queues_filter filter,
587cee6a68SJonathan Kim 				uint32_t filter_param,
597cee6a68SJonathan Kim 				uint32_t grace_period,
607cee6a68SJonathan Kim 				bool reset);
6164c7f8cfSBen Goz 
6260a00956SFelix Kuehling static int map_queues_cpsch(struct device_queue_manager *dqm);
6360a00956SFelix Kuehling 
64bcea3081SBen Goz static void deallocate_sdma_queue(struct device_queue_manager *dqm,
651b4670f6SOak Zeng 				struct queue *q);
66bcea3081SBen Goz 
67d39b7737SOak Zeng static inline void deallocate_hqd(struct device_queue_manager *dqm,
68d39b7737SOak Zeng 				struct queue *q);
69d39b7737SOak Zeng static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q);
70d39b7737SOak Zeng static int allocate_sdma_queue(struct device_queue_manager *dqm,
712485c12cSDavid Yat Sin 				struct queue *q, const uint32_t *restore_sdma_id);
7273ea648dSShaoyun Liu 
73bac38ca8SJonathan Kim static int reset_queues_on_hws_hang(struct device_queue_manager *dqm, bool is_sdma);
74bac38ca8SJonathan Kim 
75bcea3081SBen Goz static inline
get_mqd_type_from_queue_type(enum kfd_queue_type type)76bcea3081SBen Goz enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)
7764c7f8cfSBen Goz {
781b4670f6SOak Zeng 	if (type == KFD_QUEUE_TYPE_SDMA || type == KFD_QUEUE_TYPE_SDMA_XGMI)
7985d258f9SBen Goz 		return KFD_MQD_TYPE_SDMA;
8085d258f9SBen Goz 	return KFD_MQD_TYPE_CP;
8164c7f8cfSBen Goz }
8264c7f8cfSBen Goz 
is_pipe_enabled(struct device_queue_manager * dqm,int mec,int pipe)83d0b63bb3SAndres Rodriguez static bool is_pipe_enabled(struct device_queue_manager *dqm, int mec, int pipe)
8464c7f8cfSBen Goz {
85d0b63bb3SAndres Rodriguez 	int i;
868dc1db31SMukul Joshi 	int pipe_offset = (mec * dqm->dev->kfd->shared_resources.num_pipe_per_mec
878dc1db31SMukul Joshi 		+ pipe) * dqm->dev->kfd->shared_resources.num_queue_per_pipe;
88d0b63bb3SAndres Rodriguez 
89d0b63bb3SAndres Rodriguez 	/* queue is available for KFD usage if bit is 1 */
908dc1db31SMukul Joshi 	for (i = 0; i <  dqm->dev->kfd->shared_resources.num_queue_per_pipe; ++i)
91d0b63bb3SAndres Rodriguez 		if (test_bit(pipe_offset + i,
928dc1db31SMukul Joshi 			      dqm->dev->kfd->shared_resources.cp_queue_bitmap))
93d0b63bb3SAndres Rodriguez 			return true;
94d0b63bb3SAndres Rodriguez 	return false;
9564c7f8cfSBen Goz }
9664c7f8cfSBen Goz 
get_cp_queues_num(struct device_queue_manager * dqm)97e6945304SYong Zhao unsigned int get_cp_queues_num(struct device_queue_manager *dqm)
9864c7f8cfSBen Goz {
998dc1db31SMukul Joshi 	return bitmap_weight(dqm->dev->kfd->shared_resources.cp_queue_bitmap,
10068fa72a4SMukul Joshi 				AMDGPU_MAX_QUEUES);
101d0b63bb3SAndres Rodriguez }
102d0b63bb3SAndres Rodriguez 
get_queues_per_pipe(struct device_queue_manager * dqm)103d0b63bb3SAndres Rodriguez unsigned int get_queues_per_pipe(struct device_queue_manager *dqm)
104d0b63bb3SAndres Rodriguez {
1058dc1db31SMukul Joshi 	return dqm->dev->kfd->shared_resources.num_queue_per_pipe;
106d0b63bb3SAndres Rodriguez }
107d0b63bb3SAndres Rodriguez 
get_pipes_per_mec(struct device_queue_manager * dqm)108d0b63bb3SAndres Rodriguez unsigned int get_pipes_per_mec(struct device_queue_manager *dqm)
109d0b63bb3SAndres Rodriguez {
1108dc1db31SMukul Joshi 	return dqm->dev->kfd->shared_resources.num_pipe_per_mec;
11164c7f8cfSBen Goz }
11264c7f8cfSBen Goz 
get_num_all_sdma_engines(struct device_queue_manager * dqm)113c7637c95SYong Zhao static unsigned int get_num_all_sdma_engines(struct device_queue_manager *dqm)
114c7637c95SYong Zhao {
115ee2f17f4SAmber Lin 	return kfd_get_num_sdma_engines(dqm->dev) +
116ee2f17f4SAmber Lin 		kfd_get_num_xgmi_sdma_engines(dqm->dev);
117c7637c95SYong Zhao }
118c7637c95SYong Zhao 
get_num_sdma_queues(struct device_queue_manager * dqm)11998bb9222SYong Zhao unsigned int get_num_sdma_queues(struct device_queue_manager *dqm)
12098bb9222SYong Zhao {
121ee2f17f4SAmber Lin 	return kfd_get_num_sdma_engines(dqm->dev) *
1228dc1db31SMukul Joshi 		dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
12398bb9222SYong Zhao }
12498bb9222SYong Zhao 
get_num_xgmi_sdma_queues(struct device_queue_manager * dqm)1251b4670f6SOak Zeng unsigned int get_num_xgmi_sdma_queues(struct device_queue_manager *dqm)
1261b4670f6SOak Zeng {
127ee2f17f4SAmber Lin 	return kfd_get_num_xgmi_sdma_engines(dqm->dev) *
1288dc1db31SMukul Joshi 		dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
1291b4670f6SOak Zeng }
1301b4670f6SOak Zeng 
init_sdma_bitmaps(struct device_queue_manager * dqm)131a805889aSMukul Joshi static void init_sdma_bitmaps(struct device_queue_manager *dqm)
132a805889aSMukul Joshi {
133a805889aSMukul Joshi 	bitmap_zero(dqm->sdma_bitmap, KFD_MAX_SDMA_QUEUES);
134a805889aSMukul Joshi 	bitmap_set(dqm->sdma_bitmap, 0, get_num_sdma_queues(dqm));
135a805889aSMukul Joshi 
136a805889aSMukul Joshi 	bitmap_zero(dqm->xgmi_sdma_bitmap, KFD_MAX_SDMA_QUEUES);
137a805889aSMukul Joshi 	bitmap_set(dqm->xgmi_sdma_bitmap, 0, get_num_xgmi_sdma_queues(dqm));
138597364adSMukul Joshi 
139597364adSMukul Joshi 	/* Mask out the reserved queues */
140597364adSMukul Joshi 	bitmap_andnot(dqm->sdma_bitmap, dqm->sdma_bitmap,
141597364adSMukul Joshi 		      dqm->dev->kfd->device_info.reserved_sdma_queues_bitmap,
142597364adSMukul Joshi 		      KFD_MAX_SDMA_QUEUES);
143a805889aSMukul Joshi }
144a805889aSMukul Joshi 
program_sh_mem_settings(struct device_queue_manager * dqm,struct qcm_process_device * qpd)145a22fc854SBen Goz void program_sh_mem_settings(struct device_queue_manager *dqm,
14664c7f8cfSBen Goz 					struct qcm_process_device *qpd)
14764c7f8cfSBen Goz {
148c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
149c4050ff1SLijo Lazar 	int xcc_id;
150e2069a7bSMukul Joshi 
151c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask)
152e2069a7bSMukul Joshi 		dqm->dev->kfd2kgd->program_sh_mem_settings(
153c4050ff1SLijo Lazar 			dqm->dev->adev, qpd->vmid, qpd->sh_mem_config,
154c4050ff1SLijo Lazar 			qpd->sh_mem_ape1_base, qpd->sh_mem_ape1_limit,
155c4050ff1SLijo Lazar 			qpd->sh_mem_bases, xcc_id);
15664c7f8cfSBen Goz }
15764c7f8cfSBen Goz 
kfd_hws_hang(struct device_queue_manager * dqm)158cc009e61SMukul Joshi static void kfd_hws_hang(struct device_queue_manager *dqm)
159cc009e61SMukul Joshi {
160ee0a469cSJonathan Kim 	struct device_process_node *cur;
161ee0a469cSJonathan Kim 	struct qcm_process_device *qpd;
162ee0a469cSJonathan Kim 	struct queue *q;
163ee0a469cSJonathan Kim 
164ee0a469cSJonathan Kim 	/* Mark all device queues as reset. */
165ee0a469cSJonathan Kim 	list_for_each_entry(cur, &dqm->queues, list) {
166ee0a469cSJonathan Kim 		qpd = cur->qpd;
167ee0a469cSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
168ee0a469cSJonathan Kim 			struct kfd_process_device *pdd = qpd_to_pdd(qpd);
169ee0a469cSJonathan Kim 
170ee0a469cSJonathan Kim 			pdd->has_reset_queue = true;
171ee0a469cSJonathan Kim 		}
172ee0a469cSJonathan Kim 	}
173ee0a469cSJonathan Kim 
174cc009e61SMukul Joshi 	/*
175cc009e61SMukul Joshi 	 * Issue a GPU reset if HWS is unresponsive
176cc009e61SMukul Joshi 	 */
177ee3ed100SPhilip Yang 	amdgpu_amdkfd_gpu_reset(dqm->dev->adev);
178cc009e61SMukul Joshi }
179cc009e61SMukul Joshi 
convert_to_mes_queue_type(int queue_type)180cc009e61SMukul Joshi static int convert_to_mes_queue_type(int queue_type)
181cc009e61SMukul Joshi {
182cc009e61SMukul Joshi 	int mes_queue_type;
183cc009e61SMukul Joshi 
184cc009e61SMukul Joshi 	switch (queue_type) {
185cc009e61SMukul Joshi 	case KFD_QUEUE_TYPE_COMPUTE:
186cc009e61SMukul Joshi 		mes_queue_type = MES_QUEUE_TYPE_COMPUTE;
187cc009e61SMukul Joshi 		break;
188cc009e61SMukul Joshi 	case KFD_QUEUE_TYPE_SDMA:
189cc009e61SMukul Joshi 		mes_queue_type = MES_QUEUE_TYPE_SDMA;
190cc009e61SMukul Joshi 		break;
191cc009e61SMukul Joshi 	default:
192cc009e61SMukul Joshi 		WARN(1, "Invalid queue type %d", queue_type);
193cc009e61SMukul Joshi 		mes_queue_type = -EINVAL;
194cc009e61SMukul Joshi 		break;
195cc009e61SMukul Joshi 	}
196cc009e61SMukul Joshi 
197cc009e61SMukul Joshi 	return mes_queue_type;
198cc009e61SMukul Joshi }
199cc009e61SMukul Joshi 
add_queue_mes(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd)200cc009e61SMukul Joshi static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
201cc009e61SMukul Joshi 			 struct qcm_process_device *qpd)
202cc009e61SMukul Joshi {
203cc009e61SMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
204cc009e61SMukul Joshi 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
205cc009e61SMukul Joshi 	struct mes_add_queue_input queue_input;
20604fd0739SGraham Sider 	int r, queue_type;
207e77a541fSGraham Sider 	uint64_t wptr_addr_off;
208cc009e61SMukul Joshi 
209af5661c7SShaoyun Liu 	if (!dqm->sched_running || dqm->sched_halt)
210af5661c7SShaoyun Liu 		return 0;
2111802b042SYunxiang Li 	if (!down_read_trylock(&adev->reset_domain->sem))
212cc009e61SMukul Joshi 		return -EIO;
213cc009e61SMukul Joshi 
214cc009e61SMukul Joshi 	memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input));
2158544374cSXiaogang Chen 	queue_input.process_id = pdd->pasid;
216cc009e61SMukul Joshi 	queue_input.page_table_base_addr =  qpd->page_table_base;
217cc009e61SMukul Joshi 	queue_input.process_va_start = 0;
218cc009e61SMukul Joshi 	queue_input.process_va_end = adev->vm_manager.max_pfn - 1;
219cc009e61SMukul Joshi 	/* MES unit for quantum is 100ns */
220cc009e61SMukul Joshi 	queue_input.process_quantum = KFD_MES_PROCESS_QUANTUM;  /* Equivalent to 10ms. */
221cc009e61SMukul Joshi 	queue_input.process_context_addr = pdd->proc_ctx_gpu_addr;
222cc009e61SMukul Joshi 	queue_input.gang_quantum = KFD_MES_GANG_QUANTUM; /* Equivalent to 1ms */
223cc009e61SMukul Joshi 	queue_input.gang_context_addr = q->gang_ctx_gpu_addr;
224cc009e61SMukul Joshi 	queue_input.inprocess_gang_priority = q->properties.priority;
225cc009e61SMukul Joshi 	queue_input.gang_global_priority_level =
226cc009e61SMukul Joshi 					AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
227cc009e61SMukul Joshi 	queue_input.doorbell_offset = q->properties.doorbell_off;
228cc009e61SMukul Joshi 	queue_input.mqd_addr = q->gart_mqd_addr;
229fe4e9ff9SJack Xiao 	queue_input.wptr_addr = (uint64_t)q->properties.write_ptr;
230e77a541fSGraham Sider 
2317f347e3fSEric Huang 	wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1);
232fb910658SPhilip Yang 	queue_input.wptr_mc_addr = amdgpu_bo_gpu_offset(q->properties.wptr_bo) + wptr_addr_off;
233e77a541fSGraham Sider 
234a9579956SGraham Sider 	queue_input.is_kfd_process = 1;
2353e9cf234SGraham Sider 	queue_input.is_aql_queue = (q->properties.format == KFD_QUEUE_FORMAT_AQL);
2363e9cf234SGraham Sider 	queue_input.queue_size = q->properties.queue_size >> 2;
237a9579956SGraham Sider 
238cc009e61SMukul Joshi 	queue_input.paging = false;
239cc009e61SMukul Joshi 	queue_input.tba_addr = qpd->tba_addr;
240cc009e61SMukul Joshi 	queue_input.tma_addr = qpd->tma_addr;
241cef600e1SJonathan Kim 	queue_input.trap_en = !kfd_dbg_has_cwsr_workaround(q->device);
242d92e5556SJonathan Kim 	queue_input.skip_process_ctx_clear =
243d92e5556SJonathan Kim 		qpd->pqm->process->runtime_info.runtime_state == DEBUG_RUNTIME_STATE_ENABLED &&
244d92e5556SJonathan Kim 						(qpd->pqm->process->debug_trap_enabled ||
245d92e5556SJonathan Kim 						 kfd_dbg_has_ttmps_always_setup(q->device));
246cc009e61SMukul Joshi 
24704fd0739SGraham Sider 	queue_type = convert_to_mes_queue_type(q->properties.type);
24804fd0739SGraham Sider 	if (queue_type < 0) {
24980c74918SAsad Kamal 		dev_err(adev->dev, "Queue type not supported with MES, queue:%d\n",
250cc009e61SMukul Joshi 			q->properties.type);
25139de69c4SDan Carpenter 		up_read(&adev->reset_domain->sem);
252cc009e61SMukul Joshi 		return -EINVAL;
253cc009e61SMukul Joshi 	}
25404fd0739SGraham Sider 	queue_input.queue_type = (uint32_t)queue_type;
255cc009e61SMukul Joshi 
2567a1c5c67SJonathan Kim 	queue_input.exclusively_scheduled = q->properties.is_gws;
257cc009e61SMukul Joshi 
258cc009e61SMukul Joshi 	amdgpu_mes_lock(&adev->mes);
259cc009e61SMukul Joshi 	r = adev->mes.funcs->add_hw_queue(&adev->mes, &queue_input);
260cc009e61SMukul Joshi 	amdgpu_mes_unlock(&adev->mes);
2611802b042SYunxiang Li 	up_read(&adev->reset_domain->sem);
262cc009e61SMukul Joshi 	if (r) {
26380c74918SAsad Kamal 		dev_err(adev->dev, "failed to add hardware queue to MES, doorbell=0x%x\n",
264cc009e61SMukul Joshi 			q->properties.doorbell_off);
26580c74918SAsad Kamal 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
266cc009e61SMukul Joshi 		kfd_hws_hang(dqm);
267cc009e61SMukul Joshi 	}
268cc009e61SMukul Joshi 
269cc009e61SMukul Joshi 	return r;
270cc009e61SMukul Joshi }
271cc009e61SMukul Joshi 
remove_queue_mes(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd)272cc009e61SMukul Joshi static int remove_queue_mes(struct device_queue_manager *dqm, struct queue *q,
273cc009e61SMukul Joshi 			struct qcm_process_device *qpd)
274cc009e61SMukul Joshi {
275cc009e61SMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
276cc009e61SMukul Joshi 	int r;
277cc009e61SMukul Joshi 	struct mes_remove_queue_input queue_input;
278cc009e61SMukul Joshi 
279af5661c7SShaoyun Liu 	if (!dqm->sched_running || dqm->sched_halt)
280af5661c7SShaoyun Liu 		return 0;
2811802b042SYunxiang Li 	if (!down_read_trylock(&adev->reset_domain->sem))
282cc009e61SMukul Joshi 		return -EIO;
283cc009e61SMukul Joshi 
284cc009e61SMukul Joshi 	memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input));
285cc009e61SMukul Joshi 	queue_input.doorbell_offset = q->properties.doorbell_off;
286cc009e61SMukul Joshi 	queue_input.gang_context_addr = q->gang_ctx_gpu_addr;
287cc009e61SMukul Joshi 
288cc009e61SMukul Joshi 	amdgpu_mes_lock(&adev->mes);
289cc009e61SMukul Joshi 	r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);
290cc009e61SMukul Joshi 	amdgpu_mes_unlock(&adev->mes);
2911802b042SYunxiang Li 	up_read(&adev->reset_domain->sem);
292cc009e61SMukul Joshi 
293cc009e61SMukul Joshi 	if (r) {
29480c74918SAsad Kamal 		dev_err(adev->dev, "failed to remove hardware queue from MES, doorbell=0x%x\n",
295cc009e61SMukul Joshi 			q->properties.doorbell_off);
29680c74918SAsad Kamal 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
297cc009e61SMukul Joshi 		kfd_hws_hang(dqm);
298cc009e61SMukul Joshi 	}
299cc009e61SMukul Joshi 
300cc009e61SMukul Joshi 	return r;
301cc009e61SMukul Joshi }
302cc009e61SMukul Joshi 
remove_all_kfd_queues_mes(struct device_queue_manager * dqm)303af5661c7SShaoyun Liu static int remove_all_kfd_queues_mes(struct device_queue_manager *dqm)
304cc009e61SMukul Joshi {
305cc009e61SMukul Joshi 	struct device_process_node *cur;
30680c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
307cc009e61SMukul Joshi 	struct qcm_process_device *qpd;
308cc009e61SMukul Joshi 	struct queue *q;
309cc009e61SMukul Joshi 	int retval = 0;
310cc009e61SMukul Joshi 
311cc009e61SMukul Joshi 	list_for_each_entry(cur, &dqm->queues, list) {
312cc009e61SMukul Joshi 		qpd = cur->qpd;
313cc009e61SMukul Joshi 		list_for_each_entry(q, &qpd->queues_list, list) {
314cc009e61SMukul Joshi 			if (q->properties.is_active) {
315cc009e61SMukul Joshi 				retval = remove_queue_mes(dqm, q, qpd);
316cc009e61SMukul Joshi 				if (retval) {
31780c74918SAsad Kamal 					dev_err(dev, "%s: Failed to remove queue %d for dev %d",
318cc009e61SMukul Joshi 						__func__,
319cc009e61SMukul Joshi 						q->properties.queue_id,
320cc009e61SMukul Joshi 						dqm->dev->id);
321cc009e61SMukul Joshi 					return retval;
322cc009e61SMukul Joshi 				}
323cc009e61SMukul Joshi 			}
324cc009e61SMukul Joshi 		}
325cc009e61SMukul Joshi 	}
326cc009e61SMukul Joshi 
327cc009e61SMukul Joshi 	return retval;
328cc009e61SMukul Joshi }
329cc009e61SMukul Joshi 
add_all_kfd_queues_mes(struct device_queue_manager * dqm)330af5661c7SShaoyun Liu static int add_all_kfd_queues_mes(struct device_queue_manager *dqm)
331af5661c7SShaoyun Liu {
332af5661c7SShaoyun Liu 	struct device_process_node *cur;
333af5661c7SShaoyun Liu 	struct device *dev = dqm->dev->adev->dev;
334af5661c7SShaoyun Liu 	struct qcm_process_device *qpd;
335af5661c7SShaoyun Liu 	struct queue *q;
336af5661c7SShaoyun Liu 	int retval = 0;
337af5661c7SShaoyun Liu 
338af5661c7SShaoyun Liu 	list_for_each_entry(cur, &dqm->queues, list) {
339af5661c7SShaoyun Liu 		qpd = cur->qpd;
340af5661c7SShaoyun Liu 		list_for_each_entry(q, &qpd->queues_list, list) {
341af5661c7SShaoyun Liu 			if (!q->properties.is_active)
342af5661c7SShaoyun Liu 				continue;
343af5661c7SShaoyun Liu 			retval = add_queue_mes(dqm, q, qpd);
344af5661c7SShaoyun Liu 			if (retval) {
345af5661c7SShaoyun Liu 				dev_err(dev, "%s: Failed to add queue %d for dev %d",
346af5661c7SShaoyun Liu 					__func__,
347af5661c7SShaoyun Liu 					q->properties.queue_id,
348af5661c7SShaoyun Liu 					dqm->dev->id);
349af5661c7SShaoyun Liu 				return retval;
350af5661c7SShaoyun Liu 			}
351af5661c7SShaoyun Liu 		}
352af5661c7SShaoyun Liu 	}
353af5661c7SShaoyun Liu 
354af5661c7SShaoyun Liu 	return retval;
355af5661c7SShaoyun Liu }
356af5661c7SShaoyun Liu 
suspend_all_queues_mes(struct device_queue_manager * dqm)3579a16042fSMukul Joshi static int suspend_all_queues_mes(struct device_queue_manager *dqm)
3589a16042fSMukul Joshi {
3599a16042fSMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
3609a16042fSMukul Joshi 	int r = 0;
3619a16042fSMukul Joshi 
3629a16042fSMukul Joshi 	if (!down_read_trylock(&adev->reset_domain->sem))
3639a16042fSMukul Joshi 		return -EIO;
3649a16042fSMukul Joshi 
3659a16042fSMukul Joshi 	r = amdgpu_mes_suspend(adev);
3669a16042fSMukul Joshi 	up_read(&adev->reset_domain->sem);
3679a16042fSMukul Joshi 
3689a16042fSMukul Joshi 	if (r) {
3699a16042fSMukul Joshi 		dev_err(adev->dev, "failed to suspend gangs from MES\n");
3709a16042fSMukul Joshi 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
3719a16042fSMukul Joshi 		kfd_hws_hang(dqm);
3729a16042fSMukul Joshi 	}
3739a16042fSMukul Joshi 
3749a16042fSMukul Joshi 	return r;
3759a16042fSMukul Joshi }
3769a16042fSMukul Joshi 
resume_all_queues_mes(struct device_queue_manager * dqm)3779a16042fSMukul Joshi static int resume_all_queues_mes(struct device_queue_manager *dqm)
3789a16042fSMukul Joshi {
3799a16042fSMukul Joshi 	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;
3809a16042fSMukul Joshi 	int r = 0;
3819a16042fSMukul Joshi 
3829a16042fSMukul Joshi 	if (!down_read_trylock(&adev->reset_domain->sem))
3839a16042fSMukul Joshi 		return -EIO;
3849a16042fSMukul Joshi 
3859a16042fSMukul Joshi 	r = amdgpu_mes_resume(adev);
3869a16042fSMukul Joshi 	up_read(&adev->reset_domain->sem);
3879a16042fSMukul Joshi 
3889a16042fSMukul Joshi 	if (r) {
3899a16042fSMukul Joshi 		dev_err(adev->dev, "failed to resume gangs from MES\n");
3909a16042fSMukul Joshi 		dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n");
3919a16042fSMukul Joshi 		kfd_hws_hang(dqm);
3929a16042fSMukul Joshi 	}
3939a16042fSMukul Joshi 
3949a16042fSMukul Joshi 	return r;
3959a16042fSMukul Joshi }
3969a16042fSMukul Joshi 
increment_queue_count(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)397204d8998SNirmoy Das static void increment_queue_count(struct device_queue_manager *dqm,
398ab4d51d4SDavid Yat Sin 				  struct qcm_process_device *qpd,
399ab4d51d4SDavid Yat Sin 				  struct queue *q)
400b42902f4SYong Zhao {
401b42902f4SYong Zhao 	dqm->active_queue_count++;
402ab4d51d4SDavid Yat Sin 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
403ab4d51d4SDavid Yat Sin 	    q->properties.type == KFD_QUEUE_TYPE_DIQ)
404b42902f4SYong Zhao 		dqm->active_cp_queue_count++;
405ab4d51d4SDavid Yat Sin 
406ab4d51d4SDavid Yat Sin 	if (q->properties.is_gws) {
407ab4d51d4SDavid Yat Sin 		dqm->gws_queue_count++;
408ab4d51d4SDavid Yat Sin 		qpd->mapped_gws_queue = true;
409ab4d51d4SDavid Yat Sin 	}
410b42902f4SYong Zhao }
411b42902f4SYong Zhao 
decrement_queue_count(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)412204d8998SNirmoy Das static void decrement_queue_count(struct device_queue_manager *dqm,
413ab4d51d4SDavid Yat Sin 				  struct qcm_process_device *qpd,
414ab4d51d4SDavid Yat Sin 				  struct queue *q)
415b42902f4SYong Zhao {
416b42902f4SYong Zhao 	dqm->active_queue_count--;
417ab4d51d4SDavid Yat Sin 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
418ab4d51d4SDavid Yat Sin 	    q->properties.type == KFD_QUEUE_TYPE_DIQ)
419b42902f4SYong Zhao 		dqm->active_cp_queue_count--;
420ab4d51d4SDavid Yat Sin 
421ab4d51d4SDavid Yat Sin 	if (q->properties.is_gws) {
422ab4d51d4SDavid Yat Sin 		dqm->gws_queue_count--;
423ab4d51d4SDavid Yat Sin 		qpd->mapped_gws_queue = false;
424ab4d51d4SDavid Yat Sin 	}
425b42902f4SYong Zhao }
426b42902f4SYong Zhao 
4275bb6a8faSDavid Yat Sin /*
4285bb6a8faSDavid Yat Sin  * Allocate a doorbell ID to this queue.
4295bb6a8faSDavid Yat Sin  * If doorbell_id is passed in, make sure requested ID is valid then allocate it.
4305bb6a8faSDavid Yat Sin  */
allocate_doorbell(struct qcm_process_device * qpd,struct queue * q,uint32_t const * restore_id)4315bb6a8faSDavid Yat Sin static int allocate_doorbell(struct qcm_process_device *qpd,
4325bb6a8faSDavid Yat Sin 			     struct queue *q,
4335bb6a8faSDavid Yat Sin 			     uint32_t const *restore_id)
434ef568db7SFelix Kuehling {
4358dc1db31SMukul Joshi 	struct kfd_node *dev = qpd->dqm->dev;
436ef568db7SFelix Kuehling 
437dd0ae064SGraham Sider 	if (!KFD_IS_SOC15(dev)) {
438ef568db7SFelix Kuehling 		/* On pre-SOC15 chips we need to use the queue ID to
439ef568db7SFelix Kuehling 		 * preserve the user mode ABI.
440ef568db7SFelix Kuehling 		 */
4415bb6a8faSDavid Yat Sin 
4425bb6a8faSDavid Yat Sin 		if (restore_id && *restore_id != q->properties.queue_id)
4435bb6a8faSDavid Yat Sin 			return -EINVAL;
4445bb6a8faSDavid Yat Sin 
445ef568db7SFelix Kuehling 		q->doorbell_id = q->properties.queue_id;
4461b4670f6SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
4471b4670f6SOak Zeng 			q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
448234441ddSYong Zhao 		/* For SDMA queues on SOC15 with 8-byte doorbell, use static
449234441ddSYong Zhao 		 * doorbell assignments based on the engine and queue id.
450234441ddSYong Zhao 		 * The doobell index distance between RLC (2*i) and (2*i+1)
451234441ddSYong Zhao 		 * for a SDMA engine is 512.
452ef568db7SFelix Kuehling 		 */
453234441ddSYong Zhao 
4548dc1db31SMukul Joshi 		uint32_t *idx_offset = dev->kfd->shared_resources.sdma_doorbell_idx;
455643e40d4SMukul Joshi 
456643e40d4SMukul Joshi 		/*
457643e40d4SMukul Joshi 		 * q->properties.sdma_engine_id corresponds to the virtual
458643e40d4SMukul Joshi 		 * sdma engine number. However, for doorbell allocation,
459643e40d4SMukul Joshi 		 * we need the physical sdma engine id in order to get the
460643e40d4SMukul Joshi 		 * correct doorbell offset.
461643e40d4SMukul Joshi 		 */
462643e40d4SMukul Joshi 		uint32_t valid_id = idx_offset[qpd->dqm->dev->node_id *
463643e40d4SMukul Joshi 					       get_num_all_sdma_engines(qpd->dqm) +
464643e40d4SMukul Joshi 					       q->properties.sdma_engine_id]
465234441ddSYong Zhao 						+ (q->properties.sdma_queue_id & 1)
466234441ddSYong Zhao 						* KFD_QUEUE_DOORBELL_MIRROR_OFFSET
467234441ddSYong Zhao 						+ (q->properties.sdma_queue_id >> 1);
4685bb6a8faSDavid Yat Sin 
4695bb6a8faSDavid Yat Sin 		if (restore_id && *restore_id != valid_id)
4705bb6a8faSDavid Yat Sin 			return -EINVAL;
4715bb6a8faSDavid Yat Sin 		q->doorbell_id = valid_id;
472ef568db7SFelix Kuehling 	} else {
4735bb6a8faSDavid Yat Sin 		/* For CP queues on SOC15 */
4745bb6a8faSDavid Yat Sin 		if (restore_id) {
4755bb6a8faSDavid Yat Sin 			/* make sure that ID is free  */
4765bb6a8faSDavid Yat Sin 			if (__test_and_set_bit(*restore_id, qpd->doorbell_bitmap))
4775bb6a8faSDavid Yat Sin 				return -EINVAL;
4785bb6a8faSDavid Yat Sin 
4795bb6a8faSDavid Yat Sin 			q->doorbell_id = *restore_id;
4805bb6a8faSDavid Yat Sin 		} else {
4815bb6a8faSDavid Yat Sin 			/* or reserve a free doorbell ID */
482ef568db7SFelix Kuehling 			unsigned int found;
483ef568db7SFelix Kuehling 
484ef568db7SFelix Kuehling 			found = find_first_zero_bit(qpd->doorbell_bitmap,
485ef568db7SFelix Kuehling 						    KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
486ef568db7SFelix Kuehling 			if (found >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) {
487ef568db7SFelix Kuehling 				pr_debug("No doorbells available");
488ef568db7SFelix Kuehling 				return -EBUSY;
489ef568db7SFelix Kuehling 			}
490ef568db7SFelix Kuehling 			set_bit(found, qpd->doorbell_bitmap);
491ef568db7SFelix Kuehling 			q->doorbell_id = found;
492ef568db7SFelix Kuehling 		}
4935bb6a8faSDavid Yat Sin 	}
494ef568db7SFelix Kuehling 
4952105a15aSShashank Sharma 	q->properties.doorbell_off = amdgpu_doorbell_index_on_bar(dev->adev,
4962105a15aSShashank Sharma 								  qpd->proc_doorbells,
497367a0af4SArvind Yadav 								  q->doorbell_id,
498367a0af4SArvind Yadav 								  dev->kfd->device_info.doorbell_size);
499ef568db7SFelix Kuehling 	return 0;
500ef568db7SFelix Kuehling }
501ef568db7SFelix Kuehling 
deallocate_doorbell(struct qcm_process_device * qpd,struct queue * q)502ef568db7SFelix Kuehling static void deallocate_doorbell(struct qcm_process_device *qpd,
503ef568db7SFelix Kuehling 				struct queue *q)
504ef568db7SFelix Kuehling {
505ef568db7SFelix Kuehling 	unsigned int old;
5068dc1db31SMukul Joshi 	struct kfd_node *dev = qpd->dqm->dev;
507ef568db7SFelix Kuehling 
508dd0ae064SGraham Sider 	if (!KFD_IS_SOC15(dev) ||
5091b4670f6SOak Zeng 	    q->properties.type == KFD_QUEUE_TYPE_SDMA ||
5101b4670f6SOak Zeng 	    q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
511ef568db7SFelix Kuehling 		return;
512ef568db7SFelix Kuehling 
513ef568db7SFelix Kuehling 	old = test_and_clear_bit(q->doorbell_id, qpd->doorbell_bitmap);
514ef568db7SFelix Kuehling 	WARN_ON(!old);
515ef568db7SFelix Kuehling }
516ef568db7SFelix Kuehling 
program_trap_handler_settings(struct device_queue_manager * dqm,struct qcm_process_device * qpd)517b53ef0dfSMukul Joshi static void program_trap_handler_settings(struct device_queue_manager *dqm,
518b53ef0dfSMukul Joshi 				struct qcm_process_device *qpd)
519b53ef0dfSMukul Joshi {
520c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
521c4050ff1SLijo Lazar 	int xcc_id;
522e2069a7bSMukul Joshi 
523b53ef0dfSMukul Joshi 	if (dqm->dev->kfd2kgd->program_trap_handler_settings)
524c4050ff1SLijo Lazar 		for_each_inst(xcc_id, xcc_mask)
525b53ef0dfSMukul Joshi 			dqm->dev->kfd2kgd->program_trap_handler_settings(
526c4050ff1SLijo Lazar 				dqm->dev->adev, qpd->vmid, qpd->tba_addr,
527c4050ff1SLijo Lazar 				qpd->tma_addr, xcc_id);
528b53ef0dfSMukul Joshi }
529b53ef0dfSMukul Joshi 
allocate_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)53064c7f8cfSBen Goz static int allocate_vmid(struct device_queue_manager *dqm,
53164c7f8cfSBen Goz 			struct qcm_process_device *qpd,
53264c7f8cfSBen Goz 			struct queue *q)
53364c7f8cfSBen Goz {
5348544374cSXiaogang Chen 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
53580c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
536d9d4623cSYong Zhao 	int allocated_vmid = -1, i;
53764c7f8cfSBen Goz 
538d9d4623cSYong Zhao 	for (i = dqm->dev->vm_info.first_vmid_kfd;
539d9d4623cSYong Zhao 			i <= dqm->dev->vm_info.last_vmid_kfd; i++) {
540d9d4623cSYong Zhao 		if (!dqm->vmid_pasid[i]) {
541d9d4623cSYong Zhao 			allocated_vmid = i;
542d9d4623cSYong Zhao 			break;
543d9d4623cSYong Zhao 		}
544d9d4623cSYong Zhao 	}
54564c7f8cfSBen Goz 
546d9d4623cSYong Zhao 	if (allocated_vmid < 0) {
54780c74918SAsad Kamal 		dev_err(dev, "no more vmid to allocate\n");
548d9d4623cSYong Zhao 		return -ENOSPC;
549d9d4623cSYong Zhao 	}
55064c7f8cfSBen Goz 
551d9d4623cSYong Zhao 	pr_debug("vmid allocated: %d\n", allocated_vmid);
552d9d4623cSYong Zhao 
5538544374cSXiaogang Chen 	dqm->vmid_pasid[allocated_vmid] = pdd->pasid;
554d9d4623cSYong Zhao 
5558544374cSXiaogang Chen 	set_pasid_vmid_mapping(dqm, pdd->pasid, allocated_vmid);
556d9d4623cSYong Zhao 
55764c7f8cfSBen Goz 	qpd->vmid = allocated_vmid;
55864c7f8cfSBen Goz 	q->properties.vmid = allocated_vmid;
55964c7f8cfSBen Goz 
56064c7f8cfSBen Goz 	program_sh_mem_settings(dqm, qpd);
56164c7f8cfSBen Goz 
5628dc1db31SMukul Joshi 	if (KFD_IS_SOC15(dqm->dev) && dqm->dev->kfd->cwsr_enabled)
563b53ef0dfSMukul Joshi 		program_trap_handler_settings(dqm, qpd);
564b53ef0dfSMukul Joshi 
565403575c4SFelix Kuehling 	/* qpd->page_table_base is set earlier when register_process()
566403575c4SFelix Kuehling 	 * is called, i.e. when the first queue is created.
567403575c4SFelix Kuehling 	 */
5683356c38dSGraham Sider 	dqm->dev->kfd2kgd->set_vm_context_page_table_base(dqm->dev->adev,
569403575c4SFelix Kuehling 			qpd->vmid,
570403575c4SFelix Kuehling 			qpd->page_table_base);
571403575c4SFelix Kuehling 	/* invalidate the VM context after pasid and vmid mapping is set up */
5723543b055SEric Huang 	kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
573403575c4SFelix Kuehling 
574c637b36aSYong Zhao 	if (dqm->dev->kfd2kgd->set_scratch_backing_va)
5753356c38dSGraham Sider 		dqm->dev->kfd2kgd->set_scratch_backing_va(dqm->dev->adev,
576c637b36aSYong Zhao 				qpd->sh_hidden_private_base, qpd->vmid);
577d39b7737SOak Zeng 
57864c7f8cfSBen Goz 	return 0;
57964c7f8cfSBen Goz }
58064c7f8cfSBen Goz 
flush_texture_cache_nocpsch(struct kfd_node * kdev,struct qcm_process_device * qpd)5818dc1db31SMukul Joshi static int flush_texture_cache_nocpsch(struct kfd_node *kdev,
582552764b6SFelix Kuehling 				struct qcm_process_device *qpd)
583552764b6SFelix Kuehling {
5849af5379cSOak Zeng 	const struct packet_manager_funcs *pmf = qpd->dqm->packet_mgr.pmf;
585f6e27ff1SFelix Kuehling 	int ret;
586552764b6SFelix Kuehling 
587552764b6SFelix Kuehling 	if (!qpd->ib_kaddr)
588552764b6SFelix Kuehling 		return -ENOMEM;
589552764b6SFelix Kuehling 
590f6e27ff1SFelix Kuehling 	ret = pmf->release_mem(qpd->ib_base, (uint32_t *)qpd->ib_kaddr);
591f6e27ff1SFelix Kuehling 	if (ret)
592f6e27ff1SFelix Kuehling 		return ret;
593552764b6SFelix Kuehling 
5946bfc7c7eSGraham Sider 	return amdgpu_amdkfd_submit_ib(kdev->adev, KGD_ENGINE_MEC1, qpd->vmid,
595f6e27ff1SFelix Kuehling 				qpd->ib_base, (uint32_t *)qpd->ib_kaddr,
596f6e27ff1SFelix Kuehling 				pmf->release_mem_size / sizeof(uint32_t));
597552764b6SFelix Kuehling }
598552764b6SFelix Kuehling 
deallocate_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)59964c7f8cfSBen Goz static void deallocate_vmid(struct device_queue_manager *dqm,
60064c7f8cfSBen Goz 				struct qcm_process_device *qpd,
60164c7f8cfSBen Goz 				struct queue *q)
60264c7f8cfSBen Goz {
60380c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
60480c74918SAsad Kamal 
605552764b6SFelix Kuehling 	/* On GFX v7, CP doesn't flush TC at dequeue */
6067eb0502aSGraham Sider 	if (q->device->adev->asic_type == CHIP_HAWAII)
607552764b6SFelix Kuehling 		if (flush_texture_cache_nocpsch(q->device, qpd))
60880c74918SAsad Kamal 			dev_err(dev, "Failed to flush TC\n");
609552764b6SFelix Kuehling 
6103543b055SEric Huang 	kfd_flush_tlb(qpd_to_pdd(qpd), TLB_FLUSH_LEGACY);
611403575c4SFelix Kuehling 
6122030664bSBen Goz 	/* Release the vmid mapping */
6132030664bSBen Goz 	set_pasid_vmid_mapping(dqm, 0, qpd->vmid);
614d9d4623cSYong Zhao 	dqm->vmid_pasid[qpd->vmid] = 0;
6152030664bSBen Goz 
61664c7f8cfSBen Goz 	qpd->vmid = 0;
61764c7f8cfSBen Goz 	q->properties.vmid = 0;
61864c7f8cfSBen Goz }
61964c7f8cfSBen 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)62064c7f8cfSBen Goz static int create_queue_nocpsch(struct device_queue_manager *dqm,
62164c7f8cfSBen Goz 				struct queue *q,
6222485c12cSDavid Yat Sin 				struct qcm_process_device *qpd,
62342c6c482SDavid Yat Sin 				const struct kfd_criu_queue_priv_data *qd,
6243a9822d7SDavid Yat Sin 				const void *restore_mqd, const void *restore_ctl_stack)
62564c7f8cfSBen Goz {
626d39b7737SOak Zeng 	struct mqd_manager *mqd_mgr;
62764c7f8cfSBen Goz 	int retval;
62864c7f8cfSBen Goz 
629efeaed4dSFelix Kuehling 	dqm_lock(dqm);
63064c7f8cfSBen Goz 
631b8cbab04SOded Gabbay 	if (dqm->total_queue_count >= max_num_of_queues_per_device) {
63279775b62SKent Russell 		pr_warn("Can't create new usermode queue because %d queues were already created\n",
633b8cbab04SOded Gabbay 				dqm->total_queue_count);
634ab7c1648SKent Russell 		retval = -EPERM;
635ab7c1648SKent Russell 		goto out_unlock;
636b8cbab04SOded Gabbay 	}
637b8cbab04SOded Gabbay 
63864c7f8cfSBen Goz 	if (list_empty(&qpd->queues_list)) {
63964c7f8cfSBen Goz 		retval = allocate_vmid(dqm, qpd, q);
640ab7c1648SKent Russell 		if (retval)
641ab7c1648SKent Russell 			goto out_unlock;
64264c7f8cfSBen Goz 	}
64364c7f8cfSBen Goz 	q->properties.vmid = qpd->vmid;
64426103436SFelix Kuehling 	/*
645bb2d2128SFelix Kuehling 	 * Eviction state logic: mark all queues as evicted, even ones
646bb2d2128SFelix Kuehling 	 * not currently active. Restoring inactive queues later only
647bb2d2128SFelix Kuehling 	 * updates the is_evicted flag but is a no-op otherwise.
64826103436SFelix Kuehling 	 */
649bb2d2128SFelix Kuehling 	q->properties.is_evicted = !!qpd->evicted;
65064c7f8cfSBen Goz 
651373d7080SFelix Kuehling 	q->properties.tba_addr = qpd->tba_addr;
652373d7080SFelix Kuehling 	q->properties.tma_addr = qpd->tma_addr;
653373d7080SFelix Kuehling 
654d091bc0aSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
655d091bc0aSOak Zeng 			q->properties.type)];
656d39b7737SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
657d39b7737SOak Zeng 		retval = allocate_hqd(dqm, q);
658d39b7737SOak Zeng 		if (retval)
659d39b7737SOak Zeng 			goto deallocate_vmid;
660d39b7737SOak Zeng 		pr_debug("Loading mqd to hqd on pipe %d, queue %d\n",
661d39b7737SOak Zeng 			q->pipe, q->queue);
662d39b7737SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
663d39b7737SOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
6642485c12cSDavid Yat Sin 		retval = allocate_sdma_queue(dqm, q, qd ? &qd->sdma_id : NULL);
665d39b7737SOak Zeng 		if (retval)
666d39b7737SOak Zeng 			goto deallocate_vmid;
667d39b7737SOak Zeng 		dqm->asic_ops.init_sdma_vm(dqm, q, qpd);
668d39b7737SOak Zeng 	}
66964c7f8cfSBen Goz 
6705bb6a8faSDavid Yat Sin 	retval = allocate_doorbell(qpd, q, qd ? &qd->doorbell_id : NULL);
671d39b7737SOak Zeng 	if (retval)
672d39b7737SOak Zeng 		goto out_deallocate_hqd;
673d39b7737SOak Zeng 
6746a6ef5eeSOak Zeng 	/* Temporarily release dqm lock to avoid a circular lock dependency */
6756a6ef5eeSOak Zeng 	dqm_unlock(dqm);
676d091bc0aSOak Zeng 	q->mqd_mem_obj = mqd_mgr->allocate_mqd(mqd_mgr->dev, &q->properties);
6776a6ef5eeSOak Zeng 	dqm_lock(dqm);
6786a6ef5eeSOak Zeng 
679d091bc0aSOak Zeng 	if (!q->mqd_mem_obj) {
680d091bc0aSOak Zeng 		retval = -ENOMEM;
681d091bc0aSOak Zeng 		goto out_deallocate_doorbell;
682d091bc0aSOak Zeng 	}
68342c6c482SDavid Yat Sin 
68442c6c482SDavid Yat Sin 	if (qd)
68542c6c482SDavid Yat Sin 		mqd_mgr->restore_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj, &q->gart_mqd_addr,
6863a9822d7SDavid Yat Sin 				     &q->properties, restore_mqd, restore_ctl_stack,
6873a9822d7SDavid Yat Sin 				     qd->ctl_stack_size);
68842c6c482SDavid Yat Sin 	else
6898636e53cSOak Zeng 		mqd_mgr->init_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj,
6908636e53cSOak Zeng 					&q->gart_mqd_addr, &q->properties);
69142c6c482SDavid Yat Sin 
692d39b7737SOak Zeng 	if (q->properties.is_active) {
6932c99a547SPhilip Yang 		if (!dqm->sched_running) {
6942c99a547SPhilip Yang 			WARN_ONCE(1, "Load non-HWS mqd while stopped\n");
6952c99a547SPhilip Yang 			goto add_queue_to_list;
6962c99a547SPhilip Yang 		}
697d39b7737SOak Zeng 
698d39b7737SOak Zeng 		if (WARN(q->process->mm != current->mm,
699d39b7737SOak Zeng 					"should only run in user thread"))
700d39b7737SOak Zeng 			retval = -EFAULT;
701d39b7737SOak Zeng 		else
702d39b7737SOak Zeng 			retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe,
703d39b7737SOak Zeng 					q->queue, &q->properties, current->mm);
704d39b7737SOak Zeng 		if (retval)
705d091bc0aSOak Zeng 			goto out_free_mqd;
70664c7f8cfSBen Goz 	}
70764c7f8cfSBen Goz 
7082c99a547SPhilip Yang add_queue_to_list:
70964c7f8cfSBen Goz 	list_add(&q->list, &qpd->queues_list);
710bc920fd4SFelix Kuehling 	qpd->queue_count++;
711b6819cecSJay Cornwall 	if (q->properties.is_active)
712ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, qpd, q);
71364c7f8cfSBen Goz 
714b8cbab04SOded Gabbay 	/*
715b8cbab04SOded Gabbay 	 * Unconditionally increment this counter, regardless of the queue's
716b8cbab04SOded Gabbay 	 * type or whether the queue is active.
717b8cbab04SOded Gabbay 	 */
718b8cbab04SOded Gabbay 	dqm->total_queue_count++;
719b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
720b8cbab04SOded Gabbay 			dqm->total_queue_count);
721d091bc0aSOak Zeng 	goto out_unlock;
722b8cbab04SOded Gabbay 
723d091bc0aSOak Zeng out_free_mqd:
724d091bc0aSOak Zeng 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
725d39b7737SOak Zeng out_deallocate_doorbell:
726d39b7737SOak Zeng 	deallocate_doorbell(qpd, q);
727d39b7737SOak Zeng out_deallocate_hqd:
728d39b7737SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
729d39b7737SOak Zeng 		deallocate_hqd(dqm, q);
730d39b7737SOak Zeng 	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
731d39b7737SOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
732d39b7737SOak Zeng 		deallocate_sdma_queue(dqm, q);
733d39b7737SOak Zeng deallocate_vmid:
734d39b7737SOak Zeng 	if (list_empty(&qpd->queues_list))
735d39b7737SOak Zeng 		deallocate_vmid(dqm, qpd, q);
736ab7c1648SKent Russell out_unlock:
737efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
738ab7c1648SKent Russell 	return retval;
73964c7f8cfSBen Goz }
74064c7f8cfSBen Goz 
allocate_hqd(struct device_queue_manager * dqm,struct queue * q)74164c7f8cfSBen Goz static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q)
74264c7f8cfSBen Goz {
74364c7f8cfSBen Goz 	bool set;
744f0ec5b99SBen Goz 	int pipe, bit, i;
74564c7f8cfSBen Goz 
74664c7f8cfSBen Goz 	set = false;
74764c7f8cfSBen Goz 
7488eabaf54SKent Russell 	for (pipe = dqm->next_pipe_to_allocate, i = 0;
7498eabaf54SKent Russell 			i < get_pipes_per_mec(dqm);
750d0b63bb3SAndres Rodriguez 			pipe = ((pipe + 1) % get_pipes_per_mec(dqm)), ++i) {
751d0b63bb3SAndres Rodriguez 
752d0b63bb3SAndres Rodriguez 		if (!is_pipe_enabled(dqm, 0, pipe))
753d0b63bb3SAndres Rodriguez 			continue;
754d0b63bb3SAndres Rodriguez 
75564c7f8cfSBen Goz 		if (dqm->allocated_queues[pipe] != 0) {
7564252bf68SHarish Kasiviswanathan 			bit = ffs(dqm->allocated_queues[pipe]) - 1;
7574252bf68SHarish Kasiviswanathan 			dqm->allocated_queues[pipe] &= ~(1 << bit);
75864c7f8cfSBen Goz 			q->pipe = pipe;
75964c7f8cfSBen Goz 			q->queue = bit;
76064c7f8cfSBen Goz 			set = true;
76164c7f8cfSBen Goz 			break;
76264c7f8cfSBen Goz 		}
76364c7f8cfSBen Goz 	}
76464c7f8cfSBen Goz 
765991ca8eeSEdward O'Callaghan 	if (!set)
76664c7f8cfSBen Goz 		return -EBUSY;
76764c7f8cfSBen Goz 
76879775b62SKent Russell 	pr_debug("hqd slot - pipe %d, queue %d\n", q->pipe, q->queue);
76964c7f8cfSBen Goz 	/* horizontal hqd allocation */
770d0b63bb3SAndres Rodriguez 	dqm->next_pipe_to_allocate = (pipe + 1) % get_pipes_per_mec(dqm);
77164c7f8cfSBen Goz 
77264c7f8cfSBen Goz 	return 0;
77364c7f8cfSBen Goz }
77464c7f8cfSBen Goz 
deallocate_hqd(struct device_queue_manager * dqm,struct queue * q)77564c7f8cfSBen Goz static inline void deallocate_hqd(struct device_queue_manager *dqm,
77664c7f8cfSBen Goz 				struct queue *q)
77764c7f8cfSBen Goz {
7784252bf68SHarish Kasiviswanathan 	dqm->allocated_queues[q->pipe] |= (1 << q->queue);
77964c7f8cfSBen Goz }
78064c7f8cfSBen Goz 
7815bdd3eb2SMukul Joshi #define SQ_IND_CMD_CMD_KILL		0x00000003
7825bdd3eb2SMukul Joshi #define SQ_IND_CMD_MODE_BROADCAST	0x00000001
7835bdd3eb2SMukul Joshi 
dbgdev_wave_reset_wavefronts(struct kfd_node * dev,struct kfd_process * p)7848dc1db31SMukul Joshi static int dbgdev_wave_reset_wavefronts(struct kfd_node *dev, struct kfd_process *p)
7855bdd3eb2SMukul Joshi {
7865bdd3eb2SMukul Joshi 	int status = 0;
7875bdd3eb2SMukul Joshi 	unsigned int vmid;
7885bdd3eb2SMukul Joshi 	uint16_t queried_pasid;
7895bdd3eb2SMukul Joshi 	union SQ_CMD_BITS reg_sq_cmd;
7905bdd3eb2SMukul Joshi 	union GRBM_GFX_INDEX_BITS reg_gfx_index;
7915bdd3eb2SMukul Joshi 	struct kfd_process_device *pdd;
7925bdd3eb2SMukul Joshi 	int first_vmid_to_scan = dev->vm_info.first_vmid_kfd;
7935bdd3eb2SMukul Joshi 	int last_vmid_to_scan = dev->vm_info.last_vmid_kfd;
794c4050ff1SLijo Lazar 	uint32_t xcc_mask = dev->xcc_mask;
795c4050ff1SLijo Lazar 	int xcc_id;
7965bdd3eb2SMukul Joshi 
7975bdd3eb2SMukul Joshi 	reg_sq_cmd.u32All = 0;
7985bdd3eb2SMukul Joshi 	reg_gfx_index.u32All = 0;
7995bdd3eb2SMukul Joshi 
8005bdd3eb2SMukul Joshi 	pr_debug("Killing all process wavefronts\n");
8015bdd3eb2SMukul Joshi 
802d55957fbSYifan Zhang 	if (!dev->kfd2kgd->get_atc_vmid_pasid_mapping_info) {
80380c74918SAsad Kamal 		dev_err(dev->adev->dev, "no vmid pasid mapping supported\n");
804d55957fbSYifan Zhang 		return -EOPNOTSUPP;
805d55957fbSYifan Zhang 	}
806d55957fbSYifan Zhang 
8078544374cSXiaogang Chen 	/* taking the VMID for that process on the safe way using PDD */
8088544374cSXiaogang Chen 	pdd = kfd_get_process_device_data(dev, p);
8098544374cSXiaogang Chen 	if (!pdd)
8108544374cSXiaogang Chen 		return -EFAULT;
8118544374cSXiaogang Chen 
8125bdd3eb2SMukul Joshi 	/* Scan all registers in the range ATC_VMID8_PASID_MAPPING ..
8135bdd3eb2SMukul Joshi 	 * ATC_VMID15_PASID_MAPPING
8145bdd3eb2SMukul Joshi 	 * to check which VMID the current process is mapped to.
8155bdd3eb2SMukul Joshi 	 */
8165bdd3eb2SMukul Joshi 
8175bdd3eb2SMukul Joshi 	for (vmid = first_vmid_to_scan; vmid <= last_vmid_to_scan; vmid++) {
8185bdd3eb2SMukul Joshi 		status = dev->kfd2kgd->get_atc_vmid_pasid_mapping_info
8195bdd3eb2SMukul Joshi 				(dev->adev, vmid, &queried_pasid);
8205bdd3eb2SMukul Joshi 
8218544374cSXiaogang Chen 		if (status && queried_pasid == pdd->pasid) {
8228544374cSXiaogang Chen 			pr_debug("Killing wave fronts of vmid %d and process pid %d\n",
8238544374cSXiaogang Chen 					vmid, p->lead_thread->pid);
8245bdd3eb2SMukul Joshi 			break;
8255bdd3eb2SMukul Joshi 		}
8265bdd3eb2SMukul Joshi 	}
8275bdd3eb2SMukul Joshi 
8285bdd3eb2SMukul Joshi 	if (vmid > last_vmid_to_scan) {
8298544374cSXiaogang Chen 		dev_err(dev->adev->dev, "Didn't find vmid for process pid %d\n",
8308544374cSXiaogang Chen 				p->lead_thread->pid);
8315bdd3eb2SMukul Joshi 		return -EFAULT;
8325bdd3eb2SMukul Joshi 	}
8335bdd3eb2SMukul Joshi 
8345bdd3eb2SMukul Joshi 	reg_gfx_index.bits.sh_broadcast_writes = 1;
8355bdd3eb2SMukul Joshi 	reg_gfx_index.bits.se_broadcast_writes = 1;
8365bdd3eb2SMukul Joshi 	reg_gfx_index.bits.instance_broadcast_writes = 1;
8375bdd3eb2SMukul Joshi 	reg_sq_cmd.bits.mode = SQ_IND_CMD_MODE_BROADCAST;
8385bdd3eb2SMukul Joshi 	reg_sq_cmd.bits.cmd = SQ_IND_CMD_CMD_KILL;
8395bdd3eb2SMukul Joshi 	reg_sq_cmd.bits.vm_id = vmid;
8405bdd3eb2SMukul Joshi 
841c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask)
842c4050ff1SLijo Lazar 		dev->kfd2kgd->wave_control_execute(
843c4050ff1SLijo Lazar 			dev->adev, reg_gfx_index.u32All,
844c4050ff1SLijo Lazar 			reg_sq_cmd.u32All, xcc_id);
8455bdd3eb2SMukul Joshi 
8465bdd3eb2SMukul Joshi 	return 0;
8475bdd3eb2SMukul Joshi }
8485bdd3eb2SMukul Joshi 
8499fd3f1bfSFelix Kuehling /* Access to DQM has to be locked before calling destroy_queue_nocpsch_locked
8509fd3f1bfSFelix Kuehling  * to avoid asynchronized access
8519fd3f1bfSFelix Kuehling  */
destroy_queue_nocpsch_locked(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)8529fd3f1bfSFelix Kuehling static int destroy_queue_nocpsch_locked(struct device_queue_manager *dqm,
85364c7f8cfSBen Goz 				struct qcm_process_device *qpd,
85464c7f8cfSBen Goz 				struct queue *q)
85564c7f8cfSBen Goz {
85664c7f8cfSBen Goz 	int retval;
8578d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
85864c7f8cfSBen Goz 
859fdfa090bSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
860fdfa090bSOak Zeng 			q->properties.type)];
861c2e1b3a4SBen Goz 
862c7637c95SYong Zhao 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
863c2e1b3a4SBen Goz 		deallocate_hqd(dqm, q);
864c7637c95SYong Zhao 	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
8651b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
866c7637c95SYong Zhao 	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
8671b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
868c7637c95SYong Zhao 	else {
86979775b62SKent Russell 		pr_debug("q->properties.type %d is invalid\n",
8707113cd65SOded Gabbay 				q->properties.type);
8719fd3f1bfSFelix Kuehling 		return -EINVAL;
872bcea3081SBen Goz 	}
8739fd3f1bfSFelix Kuehling 	dqm->total_queue_count--;
87464c7f8cfSBen Goz 
875ef568db7SFelix Kuehling 	deallocate_doorbell(qpd, q);
876ef568db7SFelix Kuehling 
8772c99a547SPhilip Yang 	if (!dqm->sched_running) {
8782c99a547SPhilip Yang 		WARN_ONCE(1, "Destroy non-HWS queue while stopped\n");
8792c99a547SPhilip Yang 		return 0;
8802c99a547SPhilip Yang 	}
8812c99a547SPhilip Yang 
8828d5f3552SYong Zhao 	retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd,
883c2e1b3a4SBen Goz 				KFD_PREEMPT_TYPE_WAVEFRONT_RESET,
884b90e3fbeSFelix Kuehling 				KFD_UNMAP_LATENCY_MS,
88564c7f8cfSBen Goz 				q->pipe, q->queue);
8869fd3f1bfSFelix Kuehling 	if (retval == -ETIME)
8879fd3f1bfSFelix Kuehling 		qpd->reset_wavefronts = true;
88864c7f8cfSBen Goz 
88964c7f8cfSBen Goz 	list_del(&q->list);
8909fd3f1bfSFelix Kuehling 	if (list_empty(&qpd->queues_list)) {
8919fd3f1bfSFelix Kuehling 		if (qpd->reset_wavefronts) {
8929fd3f1bfSFelix Kuehling 			pr_warn("Resetting wave fronts (nocpsch) on dev %p\n",
8939fd3f1bfSFelix Kuehling 					dqm->dev);
8949fd3f1bfSFelix Kuehling 			/* dbgdev_wave_reset_wavefronts has to be called before
8959fd3f1bfSFelix Kuehling 			 * deallocate_vmid(), i.e. when vmid is still in use.
8969fd3f1bfSFelix Kuehling 			 */
8979fd3f1bfSFelix Kuehling 			dbgdev_wave_reset_wavefronts(dqm->dev,
8989fd3f1bfSFelix Kuehling 					qpd->pqm->process);
8999fd3f1bfSFelix Kuehling 			qpd->reset_wavefronts = false;
9009fd3f1bfSFelix Kuehling 		}
9019fd3f1bfSFelix Kuehling 
90264c7f8cfSBen Goz 		deallocate_vmid(dqm, qpd, q);
9039fd3f1bfSFelix Kuehling 	}
904bc920fd4SFelix Kuehling 	qpd->queue_count--;
905ab4d51d4SDavid Yat Sin 	if (q->properties.is_active)
906ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, q);
907b8cbab04SOded Gabbay 
9089fd3f1bfSFelix Kuehling 	return retval;
9099fd3f1bfSFelix Kuehling }
910b8cbab04SOded Gabbay 
destroy_queue_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)9119fd3f1bfSFelix Kuehling static int destroy_queue_nocpsch(struct device_queue_manager *dqm,
9129fd3f1bfSFelix Kuehling 				struct qcm_process_device *qpd,
9139fd3f1bfSFelix Kuehling 				struct queue *q)
9149fd3f1bfSFelix Kuehling {
9159fd3f1bfSFelix Kuehling 	int retval;
916d69fd951SMukul Joshi 	uint64_t sdma_val = 0;
91780c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
918d69fd951SMukul Joshi 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
919a7b2451dSAmber Lin 	struct mqd_manager *mqd_mgr =
920a7b2451dSAmber Lin 		dqm->mqd_mgrs[get_mqd_type_from_queue_type(q->properties.type)];
921d69fd951SMukul Joshi 
922d69fd951SMukul Joshi 	/* Get the SDMA queue stats */
923d69fd951SMukul Joshi 	if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) ||
924d69fd951SMukul Joshi 	    (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
925818b0324SMukul Joshi 		retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr,
926d69fd951SMukul Joshi 							&sdma_val);
927d69fd951SMukul Joshi 		if (retval)
92880c74918SAsad Kamal 			dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n",
929d69fd951SMukul Joshi 				q->properties.queue_id);
930d69fd951SMukul Joshi 	}
9319fd3f1bfSFelix Kuehling 
932efeaed4dSFelix Kuehling 	dqm_lock(dqm);
9339fd3f1bfSFelix Kuehling 	retval = destroy_queue_nocpsch_locked(dqm, qpd, q);
934d69fd951SMukul Joshi 	if (!retval)
935d69fd951SMukul Joshi 		pdd->sdma_past_activity_counter += sdma_val;
936efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
9379fd3f1bfSFelix Kuehling 
938a7b2451dSAmber Lin 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
939a7b2451dSAmber Lin 
94064c7f8cfSBen Goz 	return retval;
94164c7f8cfSBen Goz }
94264c7f8cfSBen Goz 
update_queue(struct device_queue_manager * dqm,struct queue * q,struct mqd_update_info * minfo)943c6e559ebSLang Yu static int update_queue(struct device_queue_manager *dqm, struct queue *q,
944c6e559ebSLang Yu 			struct mqd_update_info *minfo)
94564c7f8cfSBen Goz {
9468636e53cSOak Zeng 	int retval = 0;
94780c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
9488d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
94926103436SFelix Kuehling 	struct kfd_process_device *pdd;
950b6ffbab8SOded Gabbay 	bool prev_active = false;
95164c7f8cfSBen Goz 
952efeaed4dSFelix Kuehling 	dqm_lock(dqm);
95326103436SFelix Kuehling 	pdd = kfd_get_process_device_data(q->device, q->process);
95426103436SFelix Kuehling 	if (!pdd) {
95526103436SFelix Kuehling 		retval = -ENODEV;
95626103436SFelix Kuehling 		goto out_unlock;
95726103436SFelix Kuehling 	}
958fdfa090bSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
959fdfa090bSOak Zeng 			q->properties.type)];
96064c7f8cfSBen Goz 
96160a00956SFelix Kuehling 	/* Save previous activity state for counters */
96260a00956SFelix Kuehling 	prev_active = q->properties.is_active;
96360a00956SFelix Kuehling 
96460a00956SFelix Kuehling 	/* Make sure the queue is unmapped before updating the MQD */
965d146c5a7SFelix Kuehling 	if (dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) {
9668dc1db31SMukul Joshi 		if (!dqm->dev->kfd->shared_resources.enable_mes)
96760a00956SFelix Kuehling 			retval = unmap_queues_cpsch(dqm,
9687cee6a68SJonathan Kim 						    KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD, false);
969cc009e61SMukul Joshi 		else if (prev_active)
970cc009e61SMukul Joshi 			retval = remove_queue_mes(dqm, q, &pdd->qpd);
971cc009e61SMukul Joshi 
972ee0a469cSJonathan Kim 		/* queue is reset so inaccessable  */
973ee0a469cSJonathan Kim 		if (pdd->has_reset_queue) {
974ee0a469cSJonathan Kim 			retval = -EACCES;
975ee0a469cSJonathan Kim 			goto out_unlock;
976ee0a469cSJonathan Kim 		}
977ee0a469cSJonathan Kim 
978894a8293SFelix Kuehling 		if (retval) {
97980c74918SAsad Kamal 			dev_err(dev, "unmap queue failed\n");
98060a00956SFelix Kuehling 			goto out_unlock;
98160a00956SFelix Kuehling 		}
982894a8293SFelix Kuehling 	} else if (prev_active &&
98360a00956SFelix Kuehling 		   (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
9841b4670f6SOak Zeng 		    q->properties.type == KFD_QUEUE_TYPE_SDMA ||
9851b4670f6SOak Zeng 		    q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
9862c99a547SPhilip Yang 
9872c99a547SPhilip Yang 		if (!dqm->sched_running) {
9882c99a547SPhilip Yang 			WARN_ONCE(1, "Update non-HWS queue while stopped\n");
9892c99a547SPhilip Yang 			goto out_unlock;
9902c99a547SPhilip Yang 		}
9912c99a547SPhilip Yang 
9928d5f3552SYong Zhao 		retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd,
9938dc1db31SMukul Joshi 				(dqm->dev->kfd->cwsr_enabled ?
994b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_SAVE :
995b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN),
99660a00956SFelix Kuehling 				KFD_UNMAP_LATENCY_MS, q->pipe, q->queue);
99760a00956SFelix Kuehling 		if (retval) {
99880c74918SAsad Kamal 			dev_err(dev, "destroy mqd failed\n");
99960a00956SFelix Kuehling 			goto out_unlock;
100060a00956SFelix Kuehling 		}
100160a00956SFelix Kuehling 	}
100260a00956SFelix Kuehling 
1003c6e559ebSLang Yu 	mqd_mgr->update_mqd(mqd_mgr, q->mqd, &q->properties, minfo);
100460a00956SFelix Kuehling 
1005096d1a3eSFelix Kuehling 	/*
1006096d1a3eSFelix Kuehling 	 * check active state vs. the previous state and modify
1007096d1a3eSFelix Kuehling 	 * counter accordingly. map_queues_cpsch uses the
100881b820b3SYong Zhao 	 * dqm->active_queue_count to determine whether a new runlist must be
1009096d1a3eSFelix Kuehling 	 * uploaded.
1010096d1a3eSFelix Kuehling 	 */
1011ab4d51d4SDavid Yat Sin 	if (q->properties.is_active && !prev_active) {
1012ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, &pdd->qpd, q);
1013ab4d51d4SDavid Yat Sin 	} else if (!q->properties.is_active && prev_active) {
1014ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, &pdd->qpd, q);
1015ab4d51d4SDavid Yat Sin 	} else if (q->gws && !q->properties.is_gws) {
1016b8020b03SJoseph Greathouse 		if (q->properties.is_active) {
1017b8020b03SJoseph Greathouse 			dqm->gws_queue_count++;
1018b8020b03SJoseph Greathouse 			pdd->qpd.mapped_gws_queue = true;
1019b8020b03SJoseph Greathouse 		}
1020b8020b03SJoseph Greathouse 		q->properties.is_gws = true;
1021b8020b03SJoseph Greathouse 	} else if (!q->gws && q->properties.is_gws) {
1022b8020b03SJoseph Greathouse 		if (q->properties.is_active) {
1023b8020b03SJoseph Greathouse 			dqm->gws_queue_count--;
1024b8020b03SJoseph Greathouse 			pdd->qpd.mapped_gws_queue = false;
1025b8020b03SJoseph Greathouse 		}
1026b8020b03SJoseph Greathouse 		q->properties.is_gws = false;
1027b8020b03SJoseph Greathouse 	}
1028b8020b03SJoseph Greathouse 
1029cc009e61SMukul Joshi 	if (dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) {
10308dc1db31SMukul Joshi 		if (!dqm->dev->kfd->shared_resources.enable_mes)
103160a00956SFelix Kuehling 			retval = map_queues_cpsch(dqm);
1032f4f9b827SPhilip Yang 		else if (q->properties.is_active)
1033cc009e61SMukul Joshi 			retval = add_queue_mes(dqm, q, &pdd->qpd);
1034cc009e61SMukul Joshi 	} else if (q->properties.is_active &&
103560a00956SFelix Kuehling 		 (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
10361b4670f6SOak Zeng 		  q->properties.type == KFD_QUEUE_TYPE_SDMA ||
10371b4670f6SOak Zeng 		  q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
10381b19aa5aSFelix Kuehling 		if (WARN(q->process->mm != current->mm,
10391b19aa5aSFelix Kuehling 			 "should only run in user thread"))
10401b19aa5aSFelix Kuehling 			retval = -EFAULT;
10411b19aa5aSFelix Kuehling 		else
10421b19aa5aSFelix Kuehling 			retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd,
10431b19aa5aSFelix Kuehling 						   q->pipe, q->queue,
10441b19aa5aSFelix Kuehling 						   &q->properties, current->mm);
10451b19aa5aSFelix Kuehling 	}
1046b6ffbab8SOded Gabbay 
1047ab7c1648SKent Russell out_unlock:
1048efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
104964c7f8cfSBen Goz 	return retval;
105064c7f8cfSBen Goz }
105164c7f8cfSBen Goz 
1052a70a93faSJonathan Kim /* suspend_single_queue does not lock the dqm like the
1053a70a93faSJonathan Kim  * evict_process_queues_cpsch or evict_process_queues_nocpsch. You should
1054a70a93faSJonathan Kim  * lock the dqm before calling, and unlock after calling.
1055a70a93faSJonathan Kim  *
1056a70a93faSJonathan Kim  * The reason we don't lock the dqm is because this function may be
1057a70a93faSJonathan Kim  * called on multiple queues in a loop, so rather than locking/unlocking
1058a70a93faSJonathan Kim  * multiple times, we will just keep the dqm locked for all of the calls.
1059a70a93faSJonathan Kim  */
suspend_single_queue(struct device_queue_manager * dqm,struct kfd_process_device * pdd,struct queue * q)1060a70a93faSJonathan Kim static int suspend_single_queue(struct device_queue_manager *dqm,
1061a70a93faSJonathan Kim 				      struct kfd_process_device *pdd,
1062a70a93faSJonathan Kim 				      struct queue *q)
1063a70a93faSJonathan Kim {
1064a70a93faSJonathan Kim 	bool is_new;
1065a70a93faSJonathan Kim 
1066a70a93faSJonathan Kim 	if (q->properties.is_suspended)
1067a70a93faSJonathan Kim 		return 0;
1068a70a93faSJonathan Kim 
10698544374cSXiaogang Chen 	pr_debug("Suspending process pid %d queue [%i]\n",
10708544374cSXiaogang Chen 			pdd->process->lead_thread->pid,
1071a70a93faSJonathan Kim 			q->properties.queue_id);
1072a70a93faSJonathan Kim 
1073a70a93faSJonathan Kim 	is_new = q->properties.exception_status & KFD_EC_MASK(EC_QUEUE_NEW);
1074a70a93faSJonathan Kim 
1075a70a93faSJonathan Kim 	if (is_new || q->properties.is_being_destroyed) {
1076a70a93faSJonathan Kim 		pr_debug("Suspend: skip %s queue id %i\n",
1077a70a93faSJonathan Kim 				is_new ? "new" : "destroyed",
1078a70a93faSJonathan Kim 				q->properties.queue_id);
1079a70a93faSJonathan Kim 		return -EBUSY;
1080a70a93faSJonathan Kim 	}
1081a70a93faSJonathan Kim 
1082a70a93faSJonathan Kim 	q->properties.is_suspended = true;
1083a70a93faSJonathan Kim 	if (q->properties.is_active) {
1084a70a93faSJonathan Kim 		if (dqm->dev->kfd->shared_resources.enable_mes) {
1085a70a93faSJonathan Kim 			int r = remove_queue_mes(dqm, q, &pdd->qpd);
1086a70a93faSJonathan Kim 
1087a70a93faSJonathan Kim 			if (r)
1088a70a93faSJonathan Kim 				return r;
1089a70a93faSJonathan Kim 		}
1090a70a93faSJonathan Kim 
1091a70a93faSJonathan Kim 		decrement_queue_count(dqm, &pdd->qpd, q);
1092a70a93faSJonathan Kim 		q->properties.is_active = false;
1093a70a93faSJonathan Kim 	}
1094a70a93faSJonathan Kim 
1095a70a93faSJonathan Kim 	return 0;
1096a70a93faSJonathan Kim }
1097a70a93faSJonathan Kim 
1098a70a93faSJonathan Kim /* resume_single_queue does not lock the dqm like the functions
1099a70a93faSJonathan Kim  * restore_process_queues_cpsch or restore_process_queues_nocpsch. You should
1100a70a93faSJonathan Kim  * lock the dqm before calling, and unlock after calling.
1101a70a93faSJonathan Kim  *
1102a70a93faSJonathan Kim  * The reason we don't lock the dqm is because this function may be
1103a70a93faSJonathan Kim  * called on multiple queues in a loop, so rather than locking/unlocking
1104a70a93faSJonathan Kim  * multiple times, we will just keep the dqm locked for all of the calls.
1105a70a93faSJonathan Kim  */
resume_single_queue(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)1106a70a93faSJonathan Kim static int resume_single_queue(struct device_queue_manager *dqm,
1107a70a93faSJonathan Kim 				      struct qcm_process_device *qpd,
1108a70a93faSJonathan Kim 				      struct queue *q)
1109a70a93faSJonathan Kim {
1110a70a93faSJonathan Kim 	struct kfd_process_device *pdd;
1111a70a93faSJonathan Kim 
1112a70a93faSJonathan Kim 	if (!q->properties.is_suspended)
1113a70a93faSJonathan Kim 		return 0;
1114a70a93faSJonathan Kim 
1115a70a93faSJonathan Kim 	pdd = qpd_to_pdd(qpd);
1116a70a93faSJonathan Kim 
11178544374cSXiaogang Chen 	pr_debug("Restoring from suspend process pid %d queue [%i]\n",
11188544374cSXiaogang Chen 			    pdd->process->lead_thread->pid,
1119a70a93faSJonathan Kim 			    q->properties.queue_id);
1120a70a93faSJonathan Kim 
1121a70a93faSJonathan Kim 	q->properties.is_suspended = false;
1122a70a93faSJonathan Kim 
1123a70a93faSJonathan Kim 	if (QUEUE_IS_ACTIVE(q->properties)) {
1124a70a93faSJonathan Kim 		if (dqm->dev->kfd->shared_resources.enable_mes) {
1125a70a93faSJonathan Kim 			int r = add_queue_mes(dqm, q, &pdd->qpd);
1126a70a93faSJonathan Kim 
1127a70a93faSJonathan Kim 			if (r)
1128a70a93faSJonathan Kim 				return r;
1129a70a93faSJonathan Kim 		}
1130a70a93faSJonathan Kim 
1131a70a93faSJonathan Kim 		q->properties.is_active = true;
1132a70a93faSJonathan Kim 		increment_queue_count(dqm, qpd, q);
1133a70a93faSJonathan Kim 	}
1134a70a93faSJonathan Kim 
1135a70a93faSJonathan Kim 	return 0;
1136a70a93faSJonathan Kim }
1137a70a93faSJonathan Kim 
evict_process_queues_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)113826103436SFelix Kuehling static int evict_process_queues_nocpsch(struct device_queue_manager *dqm,
113926103436SFelix Kuehling 					struct qcm_process_device *qpd)
114026103436SFelix Kuehling {
114126103436SFelix Kuehling 	struct queue *q;
11428d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
114326103436SFelix Kuehling 	struct kfd_process_device *pdd;
1144bb2d2128SFelix Kuehling 	int retval, ret = 0;
114526103436SFelix Kuehling 
1146efeaed4dSFelix Kuehling 	dqm_lock(dqm);
114726103436SFelix Kuehling 	if (qpd->evicted++ > 0) /* already evicted, do nothing */
114826103436SFelix Kuehling 		goto out;
114926103436SFelix Kuehling 
115026103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
11518544374cSXiaogang Chen 	pr_debug_ratelimited("Evicting process pid %d queues\n",
11528544374cSXiaogang Chen 			    pdd->process->lead_thread->pid);
115326103436SFelix Kuehling 
11544327bed2SPhilip Cox 	pdd->last_evict_timestamp = get_jiffies_64();
1155bb2d2128SFelix Kuehling 	/* Mark all queues as evicted. Deactivate all active queues on
1156bb2d2128SFelix Kuehling 	 * the qpd.
1157bb2d2128SFelix Kuehling 	 */
115826103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
1159bb2d2128SFelix Kuehling 		q->properties.is_evicted = true;
116026103436SFelix Kuehling 		if (!q->properties.is_active)
116126103436SFelix Kuehling 			continue;
1162bb2d2128SFelix Kuehling 
1163fdfa090bSOak Zeng 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
1164fdfa090bSOak Zeng 				q->properties.type)];
116526103436SFelix Kuehling 		q->properties.is_active = false;
1166ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, q);
11672c99a547SPhilip Yang 
11682c99a547SPhilip Yang 		if (WARN_ONCE(!dqm->sched_running, "Evict when stopped\n"))
11692c99a547SPhilip Yang 			continue;
11702c99a547SPhilip Yang 
11718d5f3552SYong Zhao 		retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd,
11728dc1db31SMukul Joshi 				(dqm->dev->kfd->cwsr_enabled ?
1173b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_SAVE :
1174b53ef0dfSMukul Joshi 				 KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN),
117526103436SFelix Kuehling 				KFD_UNMAP_LATENCY_MS, q->pipe, q->queue);
1176bb2d2128SFelix Kuehling 		if (retval && !ret)
1177bb2d2128SFelix Kuehling 			/* Return the first error, but keep going to
1178bb2d2128SFelix Kuehling 			 * maintain a consistent eviction state
1179bb2d2128SFelix Kuehling 			 */
1180bb2d2128SFelix Kuehling 			ret = retval;
118126103436SFelix Kuehling 	}
118226103436SFelix Kuehling 
118326103436SFelix Kuehling out:
1184efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
1185bb2d2128SFelix Kuehling 	return ret;
118626103436SFelix Kuehling }
118726103436SFelix Kuehling 
evict_process_queues_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)118826103436SFelix Kuehling static int evict_process_queues_cpsch(struct device_queue_manager *dqm,
118926103436SFelix Kuehling 				      struct qcm_process_device *qpd)
119026103436SFelix Kuehling {
119126103436SFelix Kuehling 	struct queue *q;
119280c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
119326103436SFelix Kuehling 	struct kfd_process_device *pdd;
119426103436SFelix Kuehling 	int retval = 0;
119526103436SFelix Kuehling 
1196efeaed4dSFelix Kuehling 	dqm_lock(dqm);
119726103436SFelix Kuehling 	if (qpd->evicted++ > 0) /* already evicted, do nothing */
119826103436SFelix Kuehling 		goto out;
119926103436SFelix Kuehling 
120026103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
12010ab2d753SJonathan Kim 
12020ab2d753SJonathan Kim 	/* The debugger creates processes that temporarily have not acquired
12030ab2d753SJonathan Kim 	 * all VMs for all devices and has no VMs itself.
12040ab2d753SJonathan Kim 	 * Skip queue eviction on process eviction.
12050ab2d753SJonathan Kim 	 */
12060ab2d753SJonathan Kim 	if (!pdd->drm_priv)
12070ab2d753SJonathan Kim 		goto out;
12080ab2d753SJonathan Kim 
12098544374cSXiaogang Chen 	pr_debug_ratelimited("Evicting process pid %d queues\n",
12108544374cSXiaogang Chen 			    pdd->process->lead_thread->pid);
121126103436SFelix Kuehling 
1212bb2d2128SFelix Kuehling 	/* Mark all queues as evicted. Deactivate all active queues on
1213bb2d2128SFelix Kuehling 	 * the qpd.
1214bb2d2128SFelix Kuehling 	 */
121526103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
1216bb2d2128SFelix Kuehling 		q->properties.is_evicted = true;
121726103436SFelix Kuehling 		if (!q->properties.is_active)
121826103436SFelix Kuehling 			continue;
1219bb2d2128SFelix Kuehling 
122026103436SFelix Kuehling 		q->properties.is_active = false;
1221ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, q);
1222cc009e61SMukul Joshi 
12238dc1db31SMukul Joshi 		if (dqm->dev->kfd->shared_resources.enable_mes) {
122442c854b8SYifan Zha 			int err;
122542c854b8SYifan Zha 
122642c854b8SYifan Zha 			err = remove_queue_mes(dqm, q, qpd);
122742c854b8SYifan Zha 			if (err) {
122880c74918SAsad Kamal 				dev_err(dev, "Failed to evict queue %d\n",
1229cc009e61SMukul Joshi 					q->properties.queue_id);
123042c854b8SYifan Zha 				retval = err;
1231cc009e61SMukul Joshi 			}
1232cc009e61SMukul Joshi 		}
123326103436SFelix Kuehling 	}
12344327bed2SPhilip Cox 	pdd->last_evict_timestamp = get_jiffies_64();
12358dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
123626103436SFelix Kuehling 		retval = execute_queues_cpsch(dqm,
123726103436SFelix Kuehling 					      qpd->is_debug ?
123826103436SFelix Kuehling 					      KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES :
12397cee6a68SJonathan Kim 					      KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
12407cee6a68SJonathan Kim 					      USE_DEFAULT_GRACE_PERIOD);
124126103436SFelix Kuehling 
124226103436SFelix Kuehling out:
1243efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
124426103436SFelix Kuehling 	return retval;
124526103436SFelix Kuehling }
124626103436SFelix Kuehling 
restore_process_queues_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)124726103436SFelix Kuehling static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
124826103436SFelix Kuehling 					  struct qcm_process_device *qpd)
124926103436SFelix Kuehling {
12501b19aa5aSFelix Kuehling 	struct mm_struct *mm = NULL;
125126103436SFelix Kuehling 	struct queue *q;
12528d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
125326103436SFelix Kuehling 	struct kfd_process_device *pdd;
1254e715c6d0SShaoyun Liu 	uint64_t pd_base;
12554327bed2SPhilip Cox 	uint64_t eviction_duration;
1256bb2d2128SFelix Kuehling 	int retval, ret = 0;
125726103436SFelix Kuehling 
125826103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
125926103436SFelix Kuehling 	/* Retrieve PD base */
1260b40a6ab2SFelix Kuehling 	pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->drm_priv);
126126103436SFelix Kuehling 
1262efeaed4dSFelix Kuehling 	dqm_lock(dqm);
126326103436SFelix Kuehling 	if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
126426103436SFelix Kuehling 		goto out;
126526103436SFelix Kuehling 	if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */
126626103436SFelix Kuehling 		qpd->evicted--;
126726103436SFelix Kuehling 		goto out;
126826103436SFelix Kuehling 	}
126926103436SFelix Kuehling 
12708544374cSXiaogang Chen 	pr_debug_ratelimited("Restoring process pid %d queues\n",
12718544374cSXiaogang Chen 			    pdd->process->lead_thread->pid);
127226103436SFelix Kuehling 
127326103436SFelix Kuehling 	/* Update PD Base in QPD */
127426103436SFelix Kuehling 	qpd->page_table_base = pd_base;
1275e715c6d0SShaoyun Liu 	pr_debug("Updated PD address to 0x%llx\n", pd_base);
127626103436SFelix Kuehling 
127726103436SFelix Kuehling 	if (!list_empty(&qpd->queues_list)) {
127826103436SFelix Kuehling 		dqm->dev->kfd2kgd->set_vm_context_page_table_base(
12793356c38dSGraham Sider 				dqm->dev->adev,
128026103436SFelix Kuehling 				qpd->vmid,
128126103436SFelix Kuehling 				qpd->page_table_base);
12823543b055SEric Huang 		kfd_flush_tlb(pdd, TLB_FLUSH_LEGACY);
128326103436SFelix Kuehling 	}
128426103436SFelix Kuehling 
12851b19aa5aSFelix Kuehling 	/* Take a safe reference to the mm_struct, which may otherwise
12861b19aa5aSFelix Kuehling 	 * disappear even while the kfd_process is still referenced.
12871b19aa5aSFelix Kuehling 	 */
12881b19aa5aSFelix Kuehling 	mm = get_task_mm(pdd->process->lead_thread);
12891b19aa5aSFelix Kuehling 	if (!mm) {
1290bb2d2128SFelix Kuehling 		ret = -EFAULT;
12911b19aa5aSFelix Kuehling 		goto out;
12921b19aa5aSFelix Kuehling 	}
12931b19aa5aSFelix Kuehling 
1294bb2d2128SFelix Kuehling 	/* Remove the eviction flags. Activate queues that are not
1295bb2d2128SFelix Kuehling 	 * inactive for other reasons.
1296bb2d2128SFelix Kuehling 	 */
129726103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
1298bb2d2128SFelix Kuehling 		q->properties.is_evicted = false;
1299bb2d2128SFelix Kuehling 		if (!QUEUE_IS_ACTIVE(q->properties))
130026103436SFelix Kuehling 			continue;
1301bb2d2128SFelix Kuehling 
1302fdfa090bSOak Zeng 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
1303fdfa090bSOak Zeng 				q->properties.type)];
130426103436SFelix Kuehling 		q->properties.is_active = true;
1305ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, qpd, q);
13062c99a547SPhilip Yang 
13072c99a547SPhilip Yang 		if (WARN_ONCE(!dqm->sched_running, "Restore when stopped\n"))
13082c99a547SPhilip Yang 			continue;
13092c99a547SPhilip Yang 
13108d5f3552SYong Zhao 		retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe,
13111b19aa5aSFelix Kuehling 				       q->queue, &q->properties, mm);
1312bb2d2128SFelix Kuehling 		if (retval && !ret)
1313bb2d2128SFelix Kuehling 			/* Return the first error, but keep going to
1314bb2d2128SFelix Kuehling 			 * maintain a consistent eviction state
1315bb2d2128SFelix Kuehling 			 */
1316bb2d2128SFelix Kuehling 			ret = retval;
131726103436SFelix Kuehling 	}
131826103436SFelix Kuehling 	qpd->evicted = 0;
13194327bed2SPhilip Cox 	eviction_duration = get_jiffies_64() - pdd->last_evict_timestamp;
13204327bed2SPhilip Cox 	atomic64_add(eviction_duration, &pdd->evict_duration_counter);
132126103436SFelix Kuehling out:
13221b19aa5aSFelix Kuehling 	if (mm)
13231b19aa5aSFelix Kuehling 		mmput(mm);
1324efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
1325bb2d2128SFelix Kuehling 	return ret;
132626103436SFelix Kuehling }
132726103436SFelix Kuehling 
restore_process_queues_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)132826103436SFelix Kuehling static int restore_process_queues_cpsch(struct device_queue_manager *dqm,
132926103436SFelix Kuehling 					struct qcm_process_device *qpd)
133026103436SFelix Kuehling {
133126103436SFelix Kuehling 	struct queue *q;
133280c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
133326103436SFelix Kuehling 	struct kfd_process_device *pdd;
13344327bed2SPhilip Cox 	uint64_t eviction_duration;
133526103436SFelix Kuehling 	int retval = 0;
133626103436SFelix Kuehling 
133726103436SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
133826103436SFelix Kuehling 
1339efeaed4dSFelix Kuehling 	dqm_lock(dqm);
134026103436SFelix Kuehling 	if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
134126103436SFelix Kuehling 		goto out;
134226103436SFelix Kuehling 	if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */
134326103436SFelix Kuehling 		qpd->evicted--;
134426103436SFelix Kuehling 		goto out;
134526103436SFelix Kuehling 	}
134626103436SFelix Kuehling 
13470ab2d753SJonathan Kim 	/* The debugger creates processes that temporarily have not acquired
13480ab2d753SJonathan Kim 	 * all VMs for all devices and has no VMs itself.
13490ab2d753SJonathan Kim 	 * Skip queue restore on process restore.
13500ab2d753SJonathan Kim 	 */
13510ab2d753SJonathan Kim 	if (!pdd->drm_priv)
13520ab2d753SJonathan Kim 		goto vm_not_acquired;
13530ab2d753SJonathan Kim 
13548544374cSXiaogang Chen 	pr_debug_ratelimited("Restoring process pid %d queues\n",
13558544374cSXiaogang Chen 			    pdd->process->lead_thread->pid);
135626103436SFelix Kuehling 
135726103436SFelix Kuehling 	/* Update PD Base in QPD */
13580ab2d753SJonathan Kim 	qpd->page_table_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->drm_priv);
13590ab2d753SJonathan Kim 	pr_debug("Updated PD address to 0x%llx\n", qpd->page_table_base);
136026103436SFelix Kuehling 
136126103436SFelix Kuehling 	/* activate all active queues on the qpd */
136226103436SFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
136326103436SFelix Kuehling 		q->properties.is_evicted = false;
1364bb2d2128SFelix Kuehling 		if (!QUEUE_IS_ACTIVE(q->properties))
1365bb2d2128SFelix Kuehling 			continue;
1366bb2d2128SFelix Kuehling 
136726103436SFelix Kuehling 		q->properties.is_active = true;
1368ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, &pdd->qpd, q);
1369cc009e61SMukul Joshi 
13708dc1db31SMukul Joshi 		if (dqm->dev->kfd->shared_resources.enable_mes) {
1371cc009e61SMukul Joshi 			retval = add_queue_mes(dqm, q, qpd);
1372cc009e61SMukul Joshi 			if (retval) {
137380c74918SAsad Kamal 				dev_err(dev, "Failed to restore queue %d\n",
1374cc009e61SMukul Joshi 					q->properties.queue_id);
1375cc009e61SMukul Joshi 				goto out;
137626103436SFelix Kuehling 			}
1377cc009e61SMukul Joshi 		}
1378cc009e61SMukul Joshi 	}
13798dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
138026103436SFelix Kuehling 		retval = execute_queues_cpsch(dqm,
13817cee6a68SJonathan Kim 					      KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD);
13824327bed2SPhilip Cox 	eviction_duration = get_jiffies_64() - pdd->last_evict_timestamp;
13834327bed2SPhilip Cox 	atomic64_add(eviction_duration, &pdd->evict_duration_counter);
13840ab2d753SJonathan Kim vm_not_acquired:
13850ab2d753SJonathan Kim 	qpd->evicted = 0;
138626103436SFelix Kuehling out:
1387efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
138826103436SFelix Kuehling 	return retval;
138926103436SFelix Kuehling }
139026103436SFelix Kuehling 
register_process(struct device_queue_manager * dqm,struct qcm_process_device * qpd)139158dcd5bfSYong Zhao static int register_process(struct device_queue_manager *dqm,
139264c7f8cfSBen Goz 					struct qcm_process_device *qpd)
139364c7f8cfSBen Goz {
139464c7f8cfSBen Goz 	struct device_process_node *n;
1395403575c4SFelix Kuehling 	struct kfd_process_device *pdd;
1396e715c6d0SShaoyun Liu 	uint64_t pd_base;
1397a22fc854SBen Goz 	int retval;
139864c7f8cfSBen Goz 
1399dbf56ab1SKent Russell 	n = kzalloc(sizeof(*n), GFP_KERNEL);
140064c7f8cfSBen Goz 	if (!n)
140164c7f8cfSBen Goz 		return -ENOMEM;
140264c7f8cfSBen Goz 
140364c7f8cfSBen Goz 	n->qpd = qpd;
140464c7f8cfSBen Goz 
1405403575c4SFelix Kuehling 	pdd = qpd_to_pdd(qpd);
1406403575c4SFelix Kuehling 	/* Retrieve PD base */
1407b40a6ab2SFelix Kuehling 	pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->drm_priv);
1408403575c4SFelix Kuehling 
1409efeaed4dSFelix Kuehling 	dqm_lock(dqm);
141064c7f8cfSBen Goz 	list_add(&n->list, &dqm->queues);
141164c7f8cfSBen Goz 
1412403575c4SFelix Kuehling 	/* Update PD Base in QPD */
1413403575c4SFelix Kuehling 	qpd->page_table_base = pd_base;
1414e715c6d0SShaoyun Liu 	pr_debug("Updated PD address to 0x%llx\n", pd_base);
1415403575c4SFelix Kuehling 
1416bfd5e378SYong Zhao 	retval = dqm->asic_ops.update_qpd(dqm, qpd);
1417a22fc854SBen Goz 
1418f756e631SHarish Kasiviswanathan 	dqm->processes_count++;
141964c7f8cfSBen Goz 
1420efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
142164c7f8cfSBen Goz 
142232cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
142332cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
142432cce8bcSFelix Kuehling 	 */
142532cce8bcSFelix Kuehling 	kfd_inc_compute_active(dqm->dev);
142632cce8bcSFelix Kuehling 
1427a22fc854SBen Goz 	return retval;
142864c7f8cfSBen Goz }
142964c7f8cfSBen Goz 
unregister_process(struct device_queue_manager * dqm,struct qcm_process_device * qpd)143058dcd5bfSYong Zhao static int unregister_process(struct device_queue_manager *dqm,
143164c7f8cfSBen Goz 					struct qcm_process_device *qpd)
143264c7f8cfSBen Goz {
143364c7f8cfSBen Goz 	int retval;
143464c7f8cfSBen Goz 	struct device_process_node *cur, *next;
143564c7f8cfSBen Goz 
14361e5ec956SOded Gabbay 	pr_debug("qpd->queues_list is %s\n",
14371e5ec956SOded Gabbay 			list_empty(&qpd->queues_list) ? "empty" : "not empty");
143864c7f8cfSBen Goz 
143964c7f8cfSBen Goz 	retval = 0;
1440efeaed4dSFelix Kuehling 	dqm_lock(dqm);
144164c7f8cfSBen Goz 
144264c7f8cfSBen Goz 	list_for_each_entry_safe(cur, next, &dqm->queues, list) {
144364c7f8cfSBen Goz 		if (qpd == cur->qpd) {
144464c7f8cfSBen Goz 			list_del(&cur->list);
1445f5d896bbSJay Cornwall 			kfree(cur);
1446f756e631SHarish Kasiviswanathan 			dqm->processes_count--;
144764c7f8cfSBen Goz 			goto out;
144864c7f8cfSBen Goz 		}
144964c7f8cfSBen Goz 	}
145064c7f8cfSBen Goz 	/* qpd not found in dqm list */
145164c7f8cfSBen Goz 	retval = 1;
145264c7f8cfSBen Goz out:
1453efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
145432cce8bcSFelix Kuehling 
145532cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
145632cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
145732cce8bcSFelix Kuehling 	 */
145832cce8bcSFelix Kuehling 	if (!retval)
145932cce8bcSFelix Kuehling 		kfd_dec_compute_active(dqm->dev);
146032cce8bcSFelix Kuehling 
146164c7f8cfSBen Goz 	return retval;
146264c7f8cfSBen Goz }
146364c7f8cfSBen Goz 
146464c7f8cfSBen Goz static int
set_pasid_vmid_mapping(struct device_queue_manager * dqm,u32 pasid,unsigned int vmid)1465c7b6bac9SFenghua Yu set_pasid_vmid_mapping(struct device_queue_manager *dqm, u32 pasid,
146664c7f8cfSBen Goz 			unsigned int vmid)
146764c7f8cfSBen Goz {
1468c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
1469c4050ff1SLijo Lazar 	int xcc_id, ret;
1470e2069a7bSMukul Joshi 
1471c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask) {
1472e2069a7bSMukul Joshi 		ret = dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
1473c4050ff1SLijo Lazar 			dqm->dev->adev, pasid, vmid, xcc_id);
1474e2069a7bSMukul Joshi 		if (ret)
1475e2069a7bSMukul Joshi 			break;
1476e2069a7bSMukul Joshi 	}
1477e2069a7bSMukul Joshi 
1478e2069a7bSMukul Joshi 	return ret;
147964c7f8cfSBen Goz }
148064c7f8cfSBen Goz 
init_interrupts(struct device_queue_manager * dqm)14812249d558SAndrew Lewycky static void init_interrupts(struct device_queue_manager *dqm)
14822249d558SAndrew Lewycky {
1483c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
1484c4050ff1SLijo Lazar 	unsigned int i, xcc_id;
14852249d558SAndrew Lewycky 
1486b695c97bSLijo Lazar 	for_each_inst(xcc_id, xcc_mask) {
1487e2069a7bSMukul Joshi 		for (i = 0 ; i < get_pipes_per_mec(dqm) ; i++) {
1488e2069a7bSMukul Joshi 			if (is_pipe_enabled(dqm, 0, i)) {
1489e2069a7bSMukul Joshi 				dqm->dev->kfd2kgd->init_interrupts(
1490c4050ff1SLijo Lazar 					dqm->dev->adev, i, xcc_id);
1491e2069a7bSMukul Joshi 			}
1492e2069a7bSMukul Joshi 		}
14932249d558SAndrew Lewycky 	}
1494b695c97bSLijo Lazar }
14952249d558SAndrew Lewycky 
initialize_nocpsch(struct device_queue_manager * dqm)149664c7f8cfSBen Goz static int initialize_nocpsch(struct device_queue_manager *dqm)
149764c7f8cfSBen Goz {
149886194cf8SFelix Kuehling 	int pipe, queue;
149964c7f8cfSBen Goz 
150079775b62SKent Russell 	pr_debug("num of pipes: %d\n", get_pipes_per_mec(dqm));
150164c7f8cfSBen Goz 
1502ab7c1648SKent Russell 	dqm->allocated_queues = kcalloc(get_pipes_per_mec(dqm),
1503ab7c1648SKent Russell 					sizeof(unsigned int), GFP_KERNEL);
1504ab7c1648SKent Russell 	if (!dqm->allocated_queues)
1505ab7c1648SKent Russell 		return -ENOMEM;
1506ab7c1648SKent Russell 
1507efeaed4dSFelix Kuehling 	mutex_init(&dqm->lock_hidden);
150864c7f8cfSBen Goz 	INIT_LIST_HEAD(&dqm->queues);
150981b820b3SYong Zhao 	dqm->active_queue_count = dqm->next_pipe_to_allocate = 0;
1510b42902f4SYong Zhao 	dqm->active_cp_queue_count = 0;
1511b8020b03SJoseph Greathouse 	dqm->gws_queue_count = 0;
151264c7f8cfSBen Goz 
151386194cf8SFelix Kuehling 	for (pipe = 0; pipe < get_pipes_per_mec(dqm); pipe++) {
151486194cf8SFelix Kuehling 		int pipe_offset = pipe * get_queues_per_pipe(dqm);
151586194cf8SFelix Kuehling 
151686194cf8SFelix Kuehling 		for (queue = 0; queue < get_queues_per_pipe(dqm); queue++)
151786194cf8SFelix Kuehling 			if (test_bit(pipe_offset + queue,
15188dc1db31SMukul Joshi 				     dqm->dev->kfd->shared_resources.cp_queue_bitmap))
151986194cf8SFelix Kuehling 				dqm->allocated_queues[pipe] |= 1 << queue;
152086194cf8SFelix Kuehling 	}
152164c7f8cfSBen Goz 
1522d9d4623cSYong Zhao 	memset(dqm->vmid_pasid, 0, sizeof(dqm->vmid_pasid));
1523d9d4623cSYong Zhao 
1524b292cafeSFelix Kuehling 	init_sdma_bitmaps(dqm);
152564c7f8cfSBen Goz 
152664c7f8cfSBen Goz 	return 0;
152764c7f8cfSBen Goz }
152864c7f8cfSBen Goz 
uninitialize(struct device_queue_manager * dqm)152958dcd5bfSYong Zhao static void uninitialize(struct device_queue_manager *dqm)
153064c7f8cfSBen Goz {
15316f9d54fdSOded Gabbay 	int i;
15326f9d54fdSOded Gabbay 
153381b820b3SYong Zhao 	WARN_ON(dqm->active_queue_count > 0 || dqm->processes_count > 0);
153464c7f8cfSBen Goz 
153564c7f8cfSBen Goz 	kfree(dqm->allocated_queues);
15366f9d54fdSOded Gabbay 	for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++)
15378d5f3552SYong Zhao 		kfree(dqm->mqd_mgrs[i]);
1538efeaed4dSFelix Kuehling 	mutex_destroy(&dqm->lock_hidden);
153964c7f8cfSBen Goz }
154064c7f8cfSBen Goz 
start_nocpsch(struct device_queue_manager * dqm)154164c7f8cfSBen Goz static int start_nocpsch(struct device_queue_manager *dqm)
154264c7f8cfSBen Goz {
15436f4cb84aSFelix Kuehling 	int r = 0;
15446f4cb84aSFelix Kuehling 
154552055039SYong Zhao 	pr_info("SW scheduler is used");
15462249d558SAndrew Lewycky 	init_interrupts(dqm);
1547424b5442SYong Zhao 
15487eb0502aSGraham Sider 	if (dqm->dev->adev->asic_type == CHIP_HAWAII)
15496f4cb84aSFelix Kuehling 		r = pm_init(&dqm->packet_mgr, dqm);
15506f4cb84aSFelix Kuehling 	if (!r)
15512c99a547SPhilip Yang 		dqm->sched_running = true;
1552424b5442SYong Zhao 
15536f4cb84aSFelix Kuehling 	return r;
155464c7f8cfSBen Goz }
155564c7f8cfSBen Goz 
stop_nocpsch(struct device_queue_manager * dqm)155664c7f8cfSBen Goz static int stop_nocpsch(struct device_queue_manager *dqm)
155764c7f8cfSBen Goz {
15585e406012SMukul Joshi 	dqm_lock(dqm);
15595e406012SMukul Joshi 	if (!dqm->sched_running) {
15605e406012SMukul Joshi 		dqm_unlock(dqm);
15615e406012SMukul Joshi 		return 0;
15625e406012SMukul Joshi 	}
15635e406012SMukul Joshi 
15647eb0502aSGraham Sider 	if (dqm->dev->adev->asic_type == CHIP_HAWAII)
15651802b042SYunxiang Li 		pm_uninit(&dqm->packet_mgr);
15662c99a547SPhilip Yang 	dqm->sched_running = false;
15675e406012SMukul Joshi 	dqm_unlock(dqm);
1568424b5442SYong Zhao 
156964c7f8cfSBen Goz 	return 0;
157064c7f8cfSBen Goz }
157164c7f8cfSBen Goz 
allocate_sdma_queue(struct device_queue_manager * dqm,struct queue * q,const uint32_t * restore_sdma_id)1572bcea3081SBen Goz static int allocate_sdma_queue(struct device_queue_manager *dqm,
15732485c12cSDavid Yat Sin 				struct queue *q, const uint32_t *restore_sdma_id)
1574bcea3081SBen Goz {
157580c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
1576bcea3081SBen Goz 	int bit;
1577bcea3081SBen Goz 
15781b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
1579a805889aSMukul Joshi 		if (bitmap_empty(dqm->sdma_bitmap, KFD_MAX_SDMA_QUEUES)) {
158080c74918SAsad Kamal 			dev_err(dev, "No more SDMA queue to allocate\n");
1581bcea3081SBen Goz 			return -ENOMEM;
1582c7637c95SYong Zhao 		}
1583c7637c95SYong Zhao 
15842485c12cSDavid Yat Sin 		if (restore_sdma_id) {
15852485c12cSDavid Yat Sin 			/* Re-use existing sdma_id */
1586a805889aSMukul Joshi 			if (!test_bit(*restore_sdma_id, dqm->sdma_bitmap)) {
158780c74918SAsad Kamal 				dev_err(dev, "SDMA queue already in use\n");
15882485c12cSDavid Yat Sin 				return -EBUSY;
15892485c12cSDavid Yat Sin 			}
1590a805889aSMukul Joshi 			clear_bit(*restore_sdma_id, dqm->sdma_bitmap);
15912485c12cSDavid Yat Sin 			q->sdma_id = *restore_sdma_id;
15922485c12cSDavid Yat Sin 		} else {
15932485c12cSDavid Yat Sin 			/* Find first available sdma_id */
1594a805889aSMukul Joshi 			bit = find_first_bit(dqm->sdma_bitmap,
1595a805889aSMukul Joshi 					     get_num_sdma_queues(dqm));
1596a805889aSMukul Joshi 			clear_bit(bit, dqm->sdma_bitmap);
1597e78579aaSYong Zhao 			q->sdma_id = bit;
15982485c12cSDavid Yat Sin 		}
15992485c12cSDavid Yat Sin 
1600a805889aSMukul Joshi 		q->properties.sdma_engine_id =
1601a805889aSMukul Joshi 			q->sdma_id % kfd_get_num_sdma_engines(dqm->dev);
16021b4670f6SOak Zeng 		q->properties.sdma_queue_id = q->sdma_id /
1603ee2f17f4SAmber Lin 				kfd_get_num_sdma_engines(dqm->dev);
16041b4670f6SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
1605a805889aSMukul Joshi 		if (bitmap_empty(dqm->xgmi_sdma_bitmap, KFD_MAX_SDMA_QUEUES)) {
160680c74918SAsad Kamal 			dev_err(dev, "No more XGMI SDMA queue to allocate\n");
16071b4670f6SOak Zeng 			return -ENOMEM;
1608c7637c95SYong Zhao 		}
16092485c12cSDavid Yat Sin 		if (restore_sdma_id) {
16102485c12cSDavid Yat Sin 			/* Re-use existing sdma_id */
1611a805889aSMukul Joshi 			if (!test_bit(*restore_sdma_id, dqm->xgmi_sdma_bitmap)) {
161280c74918SAsad Kamal 				dev_err(dev, "SDMA queue already in use\n");
16132485c12cSDavid Yat Sin 				return -EBUSY;
16142485c12cSDavid Yat Sin 			}
1615a805889aSMukul Joshi 			clear_bit(*restore_sdma_id, dqm->xgmi_sdma_bitmap);
16162485c12cSDavid Yat Sin 			q->sdma_id = *restore_sdma_id;
16172485c12cSDavid Yat Sin 		} else {
1618a805889aSMukul Joshi 			bit = find_first_bit(dqm->xgmi_sdma_bitmap,
1619a805889aSMukul Joshi 					     get_num_xgmi_sdma_queues(dqm));
1620a805889aSMukul Joshi 			clear_bit(bit, dqm->xgmi_sdma_bitmap);
16211b4670f6SOak Zeng 			q->sdma_id = bit;
16222485c12cSDavid Yat Sin 		}
16231b4670f6SOak Zeng 		/* sdma_engine_id is sdma id including
16241b4670f6SOak Zeng 		 * both PCIe-optimized SDMAs and XGMI-
16251b4670f6SOak Zeng 		 * optimized SDMAs. The calculation below
16261b4670f6SOak Zeng 		 * assumes the first N engines are always
16271b4670f6SOak Zeng 		 * PCIe-optimized ones
16281b4670f6SOak Zeng 		 */
1629ee2f17f4SAmber Lin 		q->properties.sdma_engine_id =
1630ee2f17f4SAmber Lin 			kfd_get_num_sdma_engines(dqm->dev) +
1631ee2f17f4SAmber Lin 			q->sdma_id % kfd_get_num_xgmi_sdma_engines(dqm->dev);
16321b4670f6SOak Zeng 		q->properties.sdma_queue_id = q->sdma_id /
1633ee2f17f4SAmber Lin 			kfd_get_num_xgmi_sdma_engines(dqm->dev);
1634e06b71b2SJonathan Kim 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_BY_ENG_ID) {
1635e06b71b2SJonathan Kim 		int i, num_queues, num_engines, eng_offset = 0, start_engine;
1636e06b71b2SJonathan Kim 		bool free_bit_found = false, is_xgmi = false;
1637e06b71b2SJonathan Kim 
1638e06b71b2SJonathan Kim 		if (q->properties.sdma_engine_id < kfd_get_num_sdma_engines(dqm->dev)) {
1639e06b71b2SJonathan Kim 			num_queues = get_num_sdma_queues(dqm);
1640e06b71b2SJonathan Kim 			num_engines = kfd_get_num_sdma_engines(dqm->dev);
1641e06b71b2SJonathan Kim 			q->properties.type = KFD_QUEUE_TYPE_SDMA;
1642e06b71b2SJonathan Kim 		} else {
1643e06b71b2SJonathan Kim 			num_queues = get_num_xgmi_sdma_queues(dqm);
1644e06b71b2SJonathan Kim 			num_engines = kfd_get_num_xgmi_sdma_engines(dqm->dev);
1645e06b71b2SJonathan Kim 			eng_offset = kfd_get_num_sdma_engines(dqm->dev);
1646e06b71b2SJonathan Kim 			q->properties.type = KFD_QUEUE_TYPE_SDMA_XGMI;
1647e06b71b2SJonathan Kim 			is_xgmi = true;
1648e06b71b2SJonathan Kim 		}
1649e06b71b2SJonathan Kim 
1650e06b71b2SJonathan Kim 		/* Scan available bit based on target engine ID. */
1651e06b71b2SJonathan Kim 		start_engine = q->properties.sdma_engine_id - eng_offset;
1652e06b71b2SJonathan Kim 		for (i = start_engine; i < num_queues; i += num_engines) {
1653e06b71b2SJonathan Kim 
1654e06b71b2SJonathan Kim 			if (!test_bit(i, is_xgmi ? dqm->xgmi_sdma_bitmap : dqm->sdma_bitmap))
1655e06b71b2SJonathan Kim 				continue;
1656e06b71b2SJonathan Kim 
1657e06b71b2SJonathan Kim 			clear_bit(i, is_xgmi ? dqm->xgmi_sdma_bitmap : dqm->sdma_bitmap);
1658e06b71b2SJonathan Kim 			q->sdma_id = i;
1659e06b71b2SJonathan Kim 			q->properties.sdma_queue_id = q->sdma_id / num_engines;
1660e06b71b2SJonathan Kim 			free_bit_found = true;
1661e06b71b2SJonathan Kim 			break;
1662e06b71b2SJonathan Kim 		}
1663e06b71b2SJonathan Kim 
1664e06b71b2SJonathan Kim 		if (!free_bit_found) {
1665e06b71b2SJonathan Kim 			dev_err(dev, "No more SDMA queue to allocate for target ID %i\n",
1666e06b71b2SJonathan Kim 				q->properties.sdma_engine_id);
1667e06b71b2SJonathan Kim 			return -ENOMEM;
1668e06b71b2SJonathan Kim 		}
16691b4670f6SOak Zeng 	}
1670e78579aaSYong Zhao 
1671e78579aaSYong Zhao 	pr_debug("SDMA engine id: %d\n", q->properties.sdma_engine_id);
1672e78579aaSYong Zhao 	pr_debug("SDMA queue id: %d\n", q->properties.sdma_queue_id);
1673bcea3081SBen Goz 
1674bcea3081SBen Goz 	return 0;
1675bcea3081SBen Goz }
1676bcea3081SBen Goz 
deallocate_sdma_queue(struct device_queue_manager * dqm,struct queue * q)1677bcea3081SBen Goz static void deallocate_sdma_queue(struct device_queue_manager *dqm,
16781b4670f6SOak Zeng 				struct queue *q)
1679bcea3081SBen Goz {
16801b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
16811b4670f6SOak Zeng 		if (q->sdma_id >= get_num_sdma_queues(dqm))
1682bcea3081SBen Goz 			return;
1683a805889aSMukul Joshi 		set_bit(q->sdma_id, dqm->sdma_bitmap);
16841b4670f6SOak Zeng 	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
16851b4670f6SOak Zeng 		if (q->sdma_id >= get_num_xgmi_sdma_queues(dqm))
16861b4670f6SOak Zeng 			return;
1687a805889aSMukul Joshi 		set_bit(q->sdma_id, dqm->xgmi_sdma_bitmap);
16881b4670f6SOak Zeng 	}
1689bcea3081SBen Goz }
1690bcea3081SBen Goz 
169164c7f8cfSBen Goz /*
169264c7f8cfSBen Goz  * Device Queue Manager implementation for cp scheduler
169364c7f8cfSBen Goz  */
169464c7f8cfSBen Goz 
set_sched_resources(struct device_queue_manager * dqm)169564c7f8cfSBen Goz static int set_sched_resources(struct device_queue_manager *dqm)
169664c7f8cfSBen Goz {
1697d0b63bb3SAndres Rodriguez 	int i, mec;
169864c7f8cfSBen Goz 	struct scheduling_resources res;
169980c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
170064c7f8cfSBen Goz 
170174c5b85dSMukul Joshi 	res.vmid_mask = dqm->dev->compute_vmid_bitmap;
1702d0b63bb3SAndres Rodriguez 
1703d0b63bb3SAndres Rodriguez 	res.queue_mask = 0;
170468fa72a4SMukul Joshi 	for (i = 0; i < AMDGPU_MAX_QUEUES; ++i) {
17058dc1db31SMukul Joshi 		mec = (i / dqm->dev->kfd->shared_resources.num_queue_per_pipe)
17068dc1db31SMukul Joshi 			/ dqm->dev->kfd->shared_resources.num_pipe_per_mec;
1707d0b63bb3SAndres Rodriguez 
17088dc1db31SMukul Joshi 		if (!test_bit(i, dqm->dev->kfd->shared_resources.cp_queue_bitmap))
1709d0b63bb3SAndres Rodriguez 			continue;
1710d0b63bb3SAndres Rodriguez 
1711d0b63bb3SAndres Rodriguez 		/* only acquire queues from the first MEC */
1712d0b63bb3SAndres Rodriguez 		if (mec > 0)
1713d0b63bb3SAndres Rodriguez 			continue;
1714d0b63bb3SAndres Rodriguez 
1715d0b63bb3SAndres Rodriguez 		/* This situation may be hit in the future if a new HW
1716d0b63bb3SAndres Rodriguez 		 * generation exposes more than 64 queues. If so, the
17178eabaf54SKent Russell 		 * definition of res.queue_mask needs updating
17188eabaf54SKent Russell 		 */
17191d11ee89SDan Carpenter 		if (WARN_ON(i >= (sizeof(res.queue_mask)*8))) {
172080c74918SAsad Kamal 			dev_err(dev, "Invalid queue enabled by amdgpu: %d\n", i);
1721d0b63bb3SAndres Rodriguez 			break;
1722d0b63bb3SAndres Rodriguez 		}
1723d0b63bb3SAndres Rodriguez 
1724d09f85d5SYong Zhao 		res.queue_mask |= 1ull
1725d09f85d5SYong Zhao 			<< amdgpu_queue_mask_bit_to_set_resource_bit(
172656c5977eSGraham Sider 				dqm->dev->adev, i);
1727d0b63bb3SAndres Rodriguez 	}
1728d9848e14SOak Zeng 	res.gws_mask = ~0ull;
1729d9848e14SOak Zeng 	res.oac_mask = res.gds_heap_base = res.gds_heap_size = 0;
173064c7f8cfSBen Goz 
173179775b62SKent Russell 	pr_debug("Scheduling resources:\n"
173264c7f8cfSBen Goz 			"vmid mask: 0x%8X\n"
173364c7f8cfSBen Goz 			"queue mask: 0x%8llX\n",
173464c7f8cfSBen Goz 			res.vmid_mask, res.queue_mask);
173564c7f8cfSBen Goz 
17369af5379cSOak Zeng 	return pm_send_set_resources(&dqm->packet_mgr, &res);
173764c7f8cfSBen Goz }
173864c7f8cfSBen Goz 
initialize_cpsch(struct device_queue_manager * dqm)173964c7f8cfSBen Goz static int initialize_cpsch(struct device_queue_manager *dqm)
174064c7f8cfSBen Goz {
174179775b62SKent Russell 	pr_debug("num of pipes: %d\n", get_pipes_per_mec(dqm));
174264c7f8cfSBen Goz 
1743efeaed4dSFelix Kuehling 	mutex_init(&dqm->lock_hidden);
174464c7f8cfSBen Goz 	INIT_LIST_HEAD(&dqm->queues);
174581b820b3SYong Zhao 	dqm->active_queue_count = dqm->processes_count = 0;
1746b42902f4SYong Zhao 	dqm->active_cp_queue_count = 0;
1747b8020b03SJoseph Greathouse 	dqm->gws_queue_count = 0;
174864c7f8cfSBen Goz 	dqm->active_runlist = false;
174997ae3c8cSJonathan Kim 	dqm->trap_debug_vmid = 0;
175073ea648dSShaoyun Liu 
1751b292cafeSFelix Kuehling 	init_sdma_bitmaps(dqm);
1752b292cafeSFelix Kuehling 
1753ed962f8dSHarish Kasiviswanathan 	update_dqm_wait_times(dqm);
1754bfd5e378SYong Zhao 	return 0;
175564c7f8cfSBen Goz }
175664c7f8cfSBen Goz 
1757234eebe1SAmber Lin /* halt_cpsch:
1758234eebe1SAmber Lin  * Unmap queues so the schedule doesn't continue remaining jobs in the queue.
1759234eebe1SAmber Lin  * Then set dqm->sched_halt so queues don't map to runlist until unhalt_cpsch
1760234eebe1SAmber Lin  * is called.
1761234eebe1SAmber Lin  */
halt_cpsch(struct device_queue_manager * dqm)1762234eebe1SAmber Lin static int halt_cpsch(struct device_queue_manager *dqm)
1763234eebe1SAmber Lin {
1764234eebe1SAmber Lin 	int ret = 0;
1765234eebe1SAmber Lin 
1766234eebe1SAmber Lin 	dqm_lock(dqm);
1767234eebe1SAmber Lin 	if (!dqm->sched_running) {
1768234eebe1SAmber Lin 		dqm_unlock(dqm);
1769234eebe1SAmber Lin 		return 0;
1770234eebe1SAmber Lin 	}
1771234eebe1SAmber Lin 
1772234eebe1SAmber Lin 	WARN_ONCE(dqm->sched_halt, "Scheduling is already on halt\n");
1773234eebe1SAmber Lin 
1774234eebe1SAmber Lin 	if (!dqm->is_hws_hang) {
1775234eebe1SAmber Lin 		if (!dqm->dev->kfd->shared_resources.enable_mes)
1776234eebe1SAmber Lin 			ret = unmap_queues_cpsch(dqm,
1777234eebe1SAmber Lin 						 KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
1778234eebe1SAmber Lin 				USE_DEFAULT_GRACE_PERIOD, false);
1779234eebe1SAmber Lin 		else
1780af5661c7SShaoyun Liu 			ret = remove_all_kfd_queues_mes(dqm);
1781234eebe1SAmber Lin 	}
1782234eebe1SAmber Lin 	dqm->sched_halt = true;
1783234eebe1SAmber Lin 	dqm_unlock(dqm);
1784234eebe1SAmber Lin 
1785234eebe1SAmber Lin 	return ret;
1786234eebe1SAmber Lin }
1787234eebe1SAmber Lin 
1788234eebe1SAmber Lin /* unhalt_cpsch
1789234eebe1SAmber Lin  * Unset dqm->sched_halt and map queues back to runlist
1790234eebe1SAmber Lin  */
unhalt_cpsch(struct device_queue_manager * dqm)1791234eebe1SAmber Lin static int unhalt_cpsch(struct device_queue_manager *dqm)
1792234eebe1SAmber Lin {
1793234eebe1SAmber Lin 	int ret = 0;
1794234eebe1SAmber Lin 
1795234eebe1SAmber Lin 	dqm_lock(dqm);
1796234eebe1SAmber Lin 	if (!dqm->sched_running || !dqm->sched_halt) {
1797234eebe1SAmber Lin 		WARN_ONCE(!dqm->sched_halt, "Scheduling is not on halt.\n");
1798234eebe1SAmber Lin 		dqm_unlock(dqm);
1799234eebe1SAmber Lin 		return 0;
1800234eebe1SAmber Lin 	}
1801234eebe1SAmber Lin 	dqm->sched_halt = false;
1802234eebe1SAmber Lin 	if (!dqm->dev->kfd->shared_resources.enable_mes)
1803234eebe1SAmber Lin 		ret = execute_queues_cpsch(dqm,
1804234eebe1SAmber Lin 					   KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES,
1805234eebe1SAmber Lin 			0, USE_DEFAULT_GRACE_PERIOD);
1806af5661c7SShaoyun Liu 	else
1807af5661c7SShaoyun Liu 		ret = add_all_kfd_queues_mes(dqm);
1808af5661c7SShaoyun Liu 
1809234eebe1SAmber Lin 	dqm_unlock(dqm);
1810234eebe1SAmber Lin 
1811234eebe1SAmber Lin 	return ret;
1812234eebe1SAmber Lin }
1813234eebe1SAmber Lin 
start_cpsch(struct device_queue_manager * dqm)181464c7f8cfSBen Goz static int start_cpsch(struct device_queue_manager *dqm)
181564c7f8cfSBen Goz {
181680c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
1817ee0a469cSJonathan Kim 	int retval, num_hw_queue_slots;
181864c7f8cfSBen Goz 
181964c7f8cfSBen Goz 	retval = 0;
182064c7f8cfSBen Goz 
18214f942aaeSOak Zeng 	dqm_lock(dqm);
1822cc009e61SMukul Joshi 
18238dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes) {
18249af5379cSOak Zeng 		retval = pm_init(&dqm->packet_mgr, dqm);
18254eacc26bSKent Russell 		if (retval)
182664c7f8cfSBen Goz 			goto fail_packet_manager_init;
182764c7f8cfSBen Goz 
182864c7f8cfSBen Goz 		retval = set_sched_resources(dqm);
18294eacc26bSKent Russell 		if (retval)
183064c7f8cfSBen Goz 			goto fail_set_sched_resources;
1831cc009e61SMukul Joshi 	}
183279775b62SKent Russell 	pr_debug("Allocating fence memory\n");
183364c7f8cfSBen Goz 
183464c7f8cfSBen Goz 	/* allocate fence memory on the gart */
1835a86aa3caSOded Gabbay 	retval = kfd_gtt_sa_allocate(dqm->dev, sizeof(*dqm->fence_addr),
1836a86aa3caSOded Gabbay 					&dqm->fence_mem);
183764c7f8cfSBen Goz 
18384eacc26bSKent Russell 	if (retval)
183964c7f8cfSBen Goz 		goto fail_allocate_vidmem;
184064c7f8cfSBen Goz 
1841b010affeSQu Huang 	dqm->fence_addr = (uint64_t *)dqm->fence_mem->cpu_ptr;
184264c7f8cfSBen Goz 	dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
18432249d558SAndrew Lewycky 
18442249d558SAndrew Lewycky 	init_interrupts(dqm);
18452249d558SAndrew Lewycky 
184673ea648dSShaoyun Liu 	/* clear hang status when driver try to start the hw scheduler */
18472c99a547SPhilip Yang 	dqm->sched_running = true;
18487cee6a68SJonathan Kim 
1849ed962f8dSHarish Kasiviswanathan 	if (!dqm->dev->kfd->shared_resources.enable_mes) {
1850ed962f8dSHarish Kasiviswanathan 		if (pm_config_dequeue_wait_counts(&dqm->packet_mgr,
1851ed962f8dSHarish Kasiviswanathan 				KFD_DEQUEUE_WAIT_INIT, 0 /* unused */))
1852ed962f8dSHarish Kasiviswanathan 			dev_err(dev, "Setting optimized dequeue wait failed. Using default values\n");
18537cee6a68SJonathan Kim 		execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD);
18541879e009SMukul Joshi 	}
18551879e009SMukul Joshi 
1856ee0a469cSJonathan Kim 	/* setup per-queue reset detection buffer  */
1857ee0a469cSJonathan Kim 	num_hw_queue_slots =  dqm->dev->kfd->shared_resources.num_queue_per_pipe *
1858ee0a469cSJonathan Kim 			      dqm->dev->kfd->shared_resources.num_pipe_per_mec *
1859ee0a469cSJonathan Kim 			      NUM_XCC(dqm->dev->xcc_mask);
1860ee0a469cSJonathan Kim 
1861ee0a469cSJonathan Kim 	dqm->detect_hang_info_size = num_hw_queue_slots * sizeof(struct dqm_detect_hang_info);
1862ee0a469cSJonathan Kim 	dqm->detect_hang_info = kzalloc(dqm->detect_hang_info_size, GFP_KERNEL);
1863ee0a469cSJonathan Kim 
1864ee0a469cSJonathan Kim 	if (!dqm->detect_hang_info) {
1865ee0a469cSJonathan Kim 		retval = -ENOMEM;
1866ee0a469cSJonathan Kim 		goto fail_detect_hang_buffer;
1867ee0a469cSJonathan Kim 	}
1868ee0a469cSJonathan Kim 
1869efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
187064c7f8cfSBen Goz 
187164c7f8cfSBen Goz 	return 0;
1872ee0a469cSJonathan Kim fail_detect_hang_buffer:
1873ee0a469cSJonathan Kim 	kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
187464c7f8cfSBen Goz fail_allocate_vidmem:
187564c7f8cfSBen Goz fail_set_sched_resources:
18768dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18771802b042SYunxiang Li 		pm_uninit(&dqm->packet_mgr);
187864c7f8cfSBen Goz fail_packet_manager_init:
18794f942aaeSOak Zeng 	dqm_unlock(dqm);
188064c7f8cfSBen Goz 	return retval;
188164c7f8cfSBen Goz }
188264c7f8cfSBen Goz 
stop_cpsch(struct device_queue_manager * dqm)188364c7f8cfSBen Goz static int stop_cpsch(struct device_queue_manager *dqm)
188464c7f8cfSBen Goz {
1885efeaed4dSFelix Kuehling 	dqm_lock(dqm);
1886c96cb659Sshaoyunl 	if (!dqm->sched_running) {
1887c96cb659Sshaoyunl 		dqm_unlock(dqm);
1888c96cb659Sshaoyunl 		return 0;
1889c96cb659Sshaoyunl 	}
1890c96cb659Sshaoyunl 
18918dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18927cee6a68SJonathan Kim 		unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD, false);
1893cc009e61SMukul Joshi 	else
1894af5661c7SShaoyun Liu 		remove_all_kfd_queues_mes(dqm);
1895cc009e61SMukul Joshi 
18962c99a547SPhilip Yang 	dqm->sched_running = false;
189764c7f8cfSBen Goz 
18988dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
18999af5379cSOak Zeng 		pm_release_ib(&dqm->packet_mgr);
1900087d7641SDennis Li 
1901a86aa3caSOded Gabbay 	kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
19028dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
19031802b042SYunxiang Li 		pm_uninit(&dqm->packet_mgr);
1904ee0a469cSJonathan Kim 	kfree(dqm->detect_hang_info);
1905ee0a469cSJonathan Kim 	dqm->detect_hang_info = NULL;
19064f942aaeSOak Zeng 	dqm_unlock(dqm);
190764c7f8cfSBen Goz 
190864c7f8cfSBen Goz 	return 0;
190964c7f8cfSBen Goz }
191064c7f8cfSBen Goz 
create_kernel_queue_cpsch(struct device_queue_manager * dqm,struct kernel_queue * kq,struct qcm_process_device * qpd)191164c7f8cfSBen Goz static int create_kernel_queue_cpsch(struct device_queue_manager *dqm,
191264c7f8cfSBen Goz 					struct kernel_queue *kq,
191364c7f8cfSBen Goz 					struct qcm_process_device *qpd)
191464c7f8cfSBen Goz {
1915efeaed4dSFelix Kuehling 	dqm_lock(dqm);
1916b8cbab04SOded Gabbay 	if (dqm->total_queue_count >= max_num_of_queues_per_device) {
191779775b62SKent Russell 		pr_warn("Can't create new kernel queue because %d queues were already created\n",
1918b8cbab04SOded Gabbay 				dqm->total_queue_count);
1919efeaed4dSFelix Kuehling 		dqm_unlock(dqm);
1920b8cbab04SOded Gabbay 		return -EPERM;
1921b8cbab04SOded Gabbay 	}
1922b8cbab04SOded Gabbay 
1923b8cbab04SOded Gabbay 	/*
1924b8cbab04SOded Gabbay 	 * Unconditionally increment this counter, regardless of the queue's
1925b8cbab04SOded Gabbay 	 * type or whether the queue is active.
1926b8cbab04SOded Gabbay 	 */
1927b8cbab04SOded Gabbay 	dqm->total_queue_count++;
1928b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
1929b8cbab04SOded Gabbay 			dqm->total_queue_count);
1930b8cbab04SOded Gabbay 
193164c7f8cfSBen Goz 	list_add(&kq->list, &qpd->priv_queue_list);
1932ab4d51d4SDavid Yat Sin 	increment_queue_count(dqm, qpd, kq->queue);
193364c7f8cfSBen Goz 	qpd->is_debug = true;
19347cee6a68SJonathan Kim 	execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
19357cee6a68SJonathan Kim 			USE_DEFAULT_GRACE_PERIOD);
1936efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
193764c7f8cfSBen Goz 
193864c7f8cfSBen Goz 	return 0;
193964c7f8cfSBen Goz }
194064c7f8cfSBen Goz 
destroy_kernel_queue_cpsch(struct device_queue_manager * dqm,struct kernel_queue * kq,struct qcm_process_device * qpd)194164c7f8cfSBen Goz static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm,
194264c7f8cfSBen Goz 					struct kernel_queue *kq,
194364c7f8cfSBen Goz 					struct qcm_process_device *qpd)
194464c7f8cfSBen Goz {
1945efeaed4dSFelix Kuehling 	dqm_lock(dqm);
194664c7f8cfSBen Goz 	list_del(&kq->list);
1947ab4d51d4SDavid Yat Sin 	decrement_queue_count(dqm, qpd, kq->queue);
194864c7f8cfSBen Goz 	qpd->is_debug = false;
19497cee6a68SJonathan Kim 	execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
19507cee6a68SJonathan Kim 			USE_DEFAULT_GRACE_PERIOD);
1951b8cbab04SOded Gabbay 	/*
1952b8cbab04SOded Gabbay 	 * Unconditionally decrement this counter, regardless of the queue's
1953b8cbab04SOded Gabbay 	 * type.
1954b8cbab04SOded Gabbay 	 */
19558b58f261SOded Gabbay 	dqm->total_queue_count--;
1956b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
1957b8cbab04SOded Gabbay 			dqm->total_queue_count);
1958efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
195964c7f8cfSBen Goz }
196064c7f8cfSBen 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)196164c7f8cfSBen Goz static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
19622485c12cSDavid Yat Sin 			struct qcm_process_device *qpd,
196342c6c482SDavid Yat Sin 			const struct kfd_criu_queue_priv_data *qd,
19643a9822d7SDavid Yat Sin 			const void *restore_mqd, const void *restore_ctl_stack)
196564c7f8cfSBen Goz {
196664c7f8cfSBen Goz 	int retval;
19678d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
196864c7f8cfSBen Goz 
1969b8cbab04SOded Gabbay 	if (dqm->total_queue_count >= max_num_of_queues_per_device) {
197079775b62SKent Russell 		pr_warn("Can't create new usermode queue because %d queues were already created\n",
1971b8cbab04SOded Gabbay 				dqm->total_queue_count);
197270d488fbSOak Zeng 		retval = -EPERM;
197370d488fbSOak Zeng 		goto out;
1974b8cbab04SOded Gabbay 	}
1975b8cbab04SOded Gabbay 
19761b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
1977e06b71b2SJonathan Kim 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI ||
1978e06b71b2SJonathan Kim 		q->properties.type == KFD_QUEUE_TYPE_SDMA_BY_ENG_ID) {
197938bb4226SOak Zeng 		dqm_lock(dqm);
19802485c12cSDavid Yat Sin 		retval = allocate_sdma_queue(dqm, q, qd ? &qd->sdma_id : NULL);
198138bb4226SOak Zeng 		dqm_unlock(dqm);
1982894a8293SFelix Kuehling 		if (retval)
198370d488fbSOak Zeng 			goto out;
1984e139cd2aSshaoyunl 	}
1985ef568db7SFelix Kuehling 
19865bb6a8faSDavid Yat Sin 	retval = allocate_doorbell(qpd, q, qd ? &qd->doorbell_id : NULL);
1987ef568db7SFelix Kuehling 	if (retval)
1988ef568db7SFelix Kuehling 		goto out_deallocate_sdma_queue;
1989ef568db7SFelix Kuehling 
199070d488fbSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
199170d488fbSOak Zeng 			q->properties.type)];
199270df8273SEric Huang 
1993eec0b4cfSOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
1994eec0b4cfSOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
1995bfd5e378SYong Zhao 		dqm->asic_ops.init_sdma_vm(dqm, q, qpd);
1996373d7080SFelix Kuehling 	q->properties.tba_addr = qpd->tba_addr;
1997373d7080SFelix Kuehling 	q->properties.tma_addr = qpd->tma_addr;
199870d488fbSOak Zeng 	q->mqd_mem_obj = mqd_mgr->allocate_mqd(mqd_mgr->dev, &q->properties);
199970d488fbSOak Zeng 	if (!q->mqd_mem_obj) {
200070d488fbSOak Zeng 		retval = -ENOMEM;
200170d488fbSOak Zeng 		goto out_deallocate_doorbell;
200270d488fbSOak Zeng 	}
200370df8273SEric Huang 
200470df8273SEric Huang 	dqm_lock(dqm);
200570df8273SEric Huang 	/*
200670df8273SEric Huang 	 * Eviction state logic: mark all queues as evicted, even ones
200770df8273SEric Huang 	 * not currently active. Restoring inactive queues later only
200870df8273SEric Huang 	 * updates the is_evicted flag but is a no-op otherwise.
200970df8273SEric Huang 	 */
201070df8273SEric Huang 	q->properties.is_evicted = !!qpd->evicted;
201169a8c3aeSJonathan Kim 	q->properties.is_dbg_wa = qpd->pqm->process->debug_trap_enabled &&
2012cef600e1SJonathan Kim 				  kfd_dbg_has_cwsr_workaround(q->device);
201342c6c482SDavid Yat Sin 
201442c6c482SDavid Yat Sin 	if (qd)
201542c6c482SDavid Yat Sin 		mqd_mgr->restore_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj, &q->gart_mqd_addr,
20163a9822d7SDavid Yat Sin 				     &q->properties, restore_mqd, restore_ctl_stack,
20173a9822d7SDavid Yat Sin 				     qd->ctl_stack_size);
201842c6c482SDavid Yat Sin 	else
20198636e53cSOak Zeng 		mqd_mgr->init_mqd(mqd_mgr, &q->mqd, q->mqd_mem_obj,
20208636e53cSOak Zeng 					&q->gart_mqd_addr, &q->properties);
202189cd9d23SPhilip Yang 
202264c7f8cfSBen Goz 	list_add(&q->list, &qpd->queues_list);
2023bc920fd4SFelix Kuehling 	qpd->queue_count++;
2024f38abc15SYong Zhao 
202564c7f8cfSBen Goz 	if (q->properties.is_active) {
2026ab4d51d4SDavid Yat Sin 		increment_queue_count(dqm, qpd, q);
2027b42902f4SYong Zhao 
20288dc1db31SMukul Joshi 		if (!dqm->dev->kfd->shared_resources.enable_mes)
2029cc009e61SMukul Joshi 			retval = execute_queues_cpsch(dqm,
20307cee6a68SJonathan Kim 					KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD);
2031cc3cb791Sxinhui pan 		else
2032cc009e61SMukul Joshi 			retval = add_queue_mes(dqm, q, qpd);
2033cc009e61SMukul Joshi 		if (retval)
2034cc009e61SMukul Joshi 			goto cleanup_queue;
2035cc009e61SMukul Joshi 	}
203664c7f8cfSBen Goz 
2037b8cbab04SOded Gabbay 	/*
2038b8cbab04SOded Gabbay 	 * Unconditionally increment this counter, regardless of the queue's
2039b8cbab04SOded Gabbay 	 * type or whether the queue is active.
2040b8cbab04SOded Gabbay 	 */
2041b8cbab04SOded Gabbay 	dqm->total_queue_count++;
2042b8cbab04SOded Gabbay 
2043b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
2044b8cbab04SOded Gabbay 			dqm->total_queue_count);
2045b8cbab04SOded Gabbay 
2046efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
204772a01d23SFelix Kuehling 	return retval;
204872a01d23SFelix Kuehling 
2049cc009e61SMukul Joshi cleanup_queue:
2050cc009e61SMukul Joshi 	qpd->queue_count--;
2051cc009e61SMukul Joshi 	list_del(&q->list);
2052cc009e61SMukul Joshi 	if (q->properties.is_active)
2053cc009e61SMukul Joshi 		decrement_queue_count(dqm, qpd, q);
2054cc009e61SMukul Joshi 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
2055cc009e61SMukul Joshi 	dqm_unlock(dqm);
205670d488fbSOak Zeng out_deallocate_doorbell:
205770d488fbSOak Zeng 	deallocate_doorbell(qpd, q);
205872a01d23SFelix Kuehling out_deallocate_sdma_queue:
20591b4670f6SOak Zeng 	if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
206038bb4226SOak Zeng 		q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
206138bb4226SOak Zeng 		dqm_lock(dqm);
20621b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
206338bb4226SOak Zeng 		dqm_unlock(dqm);
206438bb4226SOak Zeng 	}
206570d488fbSOak Zeng out:
206664c7f8cfSBen Goz 	return retval;
206764c7f8cfSBen Goz }
206864c7f8cfSBen Goz 
amdkfd_fence_wait_timeout(struct device_queue_manager * dqm,uint64_t fence_value,unsigned int timeout_ms)206980c74918SAsad Kamal int amdkfd_fence_wait_timeout(struct device_queue_manager *dqm,
2070b010affeSQu Huang 			      uint64_t fence_value,
20718c72c3d7SYong Zhao 			      unsigned int timeout_ms)
207264c7f8cfSBen Goz {
20738c72c3d7SYong Zhao 	unsigned long end_jiffies = msecs_to_jiffies(timeout_ms) + jiffies;
207480c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
2075b6890efbSVictor Zhao 	uint64_t *fence_addr = dqm->fence_addr;
207664c7f8cfSBen Goz 
207764c7f8cfSBen Goz 	while (*fence_addr != fence_value) {
2078e1f6746fSLijo Lazar 		/* Fatal err detected, this response won't come */
2079e1f6746fSLijo Lazar 		if (amdgpu_amdkfd_is_fed(dqm->dev->adev))
2080e1f6746fSLijo Lazar 			return -EIO;
2081e1f6746fSLijo Lazar 
20828c72c3d7SYong Zhao 		if (time_after(jiffies, end_jiffies)) {
208380c74918SAsad Kamal 			dev_err(dev, "qcm fence wait loop timeout expired\n");
20840e9a860cSYong Zhao 			/* In HWS case, this is used to halt the driver thread
20850e9a860cSYong Zhao 			 * in order not to mess up CP states before doing
20860e9a860cSYong Zhao 			 * scandumps for FW debugging.
20870e9a860cSYong Zhao 			 */
20880e9a860cSYong Zhao 			while (halt_if_hws_hang)
20890e9a860cSYong Zhao 				schedule();
20900e9a860cSYong Zhao 
209164c7f8cfSBen Goz 			return -ETIME;
209264c7f8cfSBen Goz 		}
209399331a51SOded Gabbay 		schedule();
209464c7f8cfSBen Goz 	}
209564c7f8cfSBen Goz 
209664c7f8cfSBen Goz 	return 0;
209764c7f8cfSBen Goz }
209864c7f8cfSBen Goz 
2099ac30c783SYong Zhao /* dqm->lock mutex has to be locked before calling this function */
map_queues_cpsch(struct device_queue_manager * dqm)210060a00956SFelix Kuehling static int map_queues_cpsch(struct device_queue_manager *dqm)
210160a00956SFelix Kuehling {
210280c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
210360a00956SFelix Kuehling 	int retval;
210460a00956SFelix Kuehling 
2105234eebe1SAmber Lin 	if (!dqm->sched_running || dqm->sched_halt)
21062c99a547SPhilip Yang 		return 0;
210781b820b3SYong Zhao 	if (dqm->active_queue_count <= 0 || dqm->processes_count <= 0)
210860a00956SFelix Kuehling 		return 0;
210960a00956SFelix Kuehling 	if (dqm->active_runlist)
211060a00956SFelix Kuehling 		return 0;
211160a00956SFelix Kuehling 
21129af5379cSOak Zeng 	retval = pm_send_runlist(&dqm->packet_mgr, &dqm->queues);
211314328aa5SPhilip Cox 	pr_debug("%s sent runlist\n", __func__);
211460a00956SFelix Kuehling 	if (retval) {
211580c74918SAsad Kamal 		dev_err(dev, "failed to execute runlist\n");
211660a00956SFelix Kuehling 		return retval;
211760a00956SFelix Kuehling 	}
211860a00956SFelix Kuehling 	dqm->active_runlist = true;
211960a00956SFelix Kuehling 
212060a00956SFelix Kuehling 	return retval;
212160a00956SFelix Kuehling }
212260a00956SFelix Kuehling 
set_queue_as_reset(struct device_queue_manager * dqm,struct queue * q,struct qcm_process_device * qpd)2123ee0a469cSJonathan Kim static void set_queue_as_reset(struct device_queue_manager *dqm, struct queue *q,
2124ee0a469cSJonathan Kim 			       struct qcm_process_device *qpd)
2125ee0a469cSJonathan Kim {
2126ee0a469cSJonathan Kim 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
2127ee0a469cSJonathan Kim 
21288544374cSXiaogang Chen 	dev_err(dqm->dev->adev->dev, "queue id 0x%0x at pasid %d is reset\n",
21298544374cSXiaogang Chen 		q->properties.queue_id, pdd->process->lead_thread->pid);
2130ee0a469cSJonathan Kim 
2131ee0a469cSJonathan Kim 	pdd->has_reset_queue = true;
2132ee0a469cSJonathan Kim 	if (q->properties.is_active) {
2133ee0a469cSJonathan Kim 		q->properties.is_active = false;
2134ee0a469cSJonathan Kim 		decrement_queue_count(dqm, qpd, q);
2135ee0a469cSJonathan Kim 	}
2136ee0a469cSJonathan Kim }
2137ee0a469cSJonathan Kim 
detect_queue_hang(struct device_queue_manager * dqm)2138ee0a469cSJonathan Kim static int detect_queue_hang(struct device_queue_manager *dqm)
2139ee0a469cSJonathan Kim {
2140ee0a469cSJonathan Kim 	int i;
2141ee0a469cSJonathan Kim 
2142ee0a469cSJonathan Kim 	/* detect should be used only in dqm locked queue reset */
2143ee0a469cSJonathan Kim 	if (WARN_ON(dqm->detect_hang_count > 0))
2144ee0a469cSJonathan Kim 		return 0;
2145ee0a469cSJonathan Kim 
2146ee0a469cSJonathan Kim 	memset(dqm->detect_hang_info, 0, dqm->detect_hang_info_size);
2147ee0a469cSJonathan Kim 
2148ee0a469cSJonathan Kim 	for (i = 0; i < AMDGPU_MAX_QUEUES; ++i) {
2149ee0a469cSJonathan Kim 		uint32_t mec, pipe, queue;
2150ee0a469cSJonathan Kim 		int xcc_id;
2151ee0a469cSJonathan Kim 
2152ee0a469cSJonathan Kim 		mec = (i / dqm->dev->kfd->shared_resources.num_queue_per_pipe)
2153ee0a469cSJonathan Kim 			/ dqm->dev->kfd->shared_resources.num_pipe_per_mec;
2154ee0a469cSJonathan Kim 
2155ee0a469cSJonathan Kim 		if (mec || !test_bit(i, dqm->dev->kfd->shared_resources.cp_queue_bitmap))
2156ee0a469cSJonathan Kim 			continue;
2157ee0a469cSJonathan Kim 
2158ee0a469cSJonathan Kim 		amdgpu_queue_mask_bit_to_mec_queue(dqm->dev->adev, i, &mec, &pipe, &queue);
2159ee0a469cSJonathan Kim 
2160ee0a469cSJonathan Kim 		for_each_inst(xcc_id, dqm->dev->xcc_mask) {
2161ee0a469cSJonathan Kim 			uint64_t queue_addr = dqm->dev->kfd2kgd->hqd_get_pq_addr(
2162ee0a469cSJonathan Kim 						dqm->dev->adev, pipe, queue, xcc_id);
2163ee0a469cSJonathan Kim 			struct dqm_detect_hang_info hang_info;
2164ee0a469cSJonathan Kim 
2165ee0a469cSJonathan Kim 			if (!queue_addr)
2166ee0a469cSJonathan Kim 				continue;
2167ee0a469cSJonathan Kim 
2168ee0a469cSJonathan Kim 			hang_info.pipe_id = pipe;
2169ee0a469cSJonathan Kim 			hang_info.queue_id = queue;
2170ee0a469cSJonathan Kim 			hang_info.xcc_id = xcc_id;
2171ee0a469cSJonathan Kim 			hang_info.queue_address = queue_addr;
2172ee0a469cSJonathan Kim 
2173ee0a469cSJonathan Kim 			dqm->detect_hang_info[dqm->detect_hang_count] = hang_info;
2174ee0a469cSJonathan Kim 			dqm->detect_hang_count++;
2175ee0a469cSJonathan Kim 		}
2176ee0a469cSJonathan Kim 	}
2177ee0a469cSJonathan Kim 
2178ee0a469cSJonathan Kim 	return dqm->detect_hang_count;
2179ee0a469cSJonathan Kim }
2180ee0a469cSJonathan Kim 
find_queue_by_address(struct device_queue_manager * dqm,uint64_t queue_address)2181ee0a469cSJonathan Kim static struct queue *find_queue_by_address(struct device_queue_manager *dqm, uint64_t queue_address)
2182ee0a469cSJonathan Kim {
2183ee0a469cSJonathan Kim 	struct device_process_node *cur;
2184ee0a469cSJonathan Kim 	struct qcm_process_device *qpd;
2185ee0a469cSJonathan Kim 	struct queue *q;
2186ee0a469cSJonathan Kim 
2187ee0a469cSJonathan Kim 	list_for_each_entry(cur, &dqm->queues, list) {
2188ee0a469cSJonathan Kim 		qpd = cur->qpd;
2189ee0a469cSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
2190ee0a469cSJonathan Kim 			if (queue_address == q->properties.queue_address)
2191ee0a469cSJonathan Kim 				return q;
2192ee0a469cSJonathan Kim 		}
2193ee0a469cSJonathan Kim 	}
2194ee0a469cSJonathan Kim 
2195ee0a469cSJonathan Kim 	return NULL;
2196ee0a469cSJonathan Kim }
2197ee0a469cSJonathan Kim 
reset_hung_queues(struct device_queue_manager * dqm)2198bac38ca8SJonathan Kim static int reset_hung_queues(struct device_queue_manager *dqm)
2199ee0a469cSJonathan Kim {
2200ee0a469cSJonathan Kim 	int r = 0, reset_count = 0, i;
2201ee0a469cSJonathan Kim 
2202ee0a469cSJonathan Kim 	if (!dqm->detect_hang_info || dqm->is_hws_hang)
2203ee0a469cSJonathan Kim 		return -EIO;
2204ee0a469cSJonathan Kim 
2205ee0a469cSJonathan Kim 	/* assume dqm locked. */
2206ee0a469cSJonathan Kim 	if (!detect_queue_hang(dqm))
2207ee0a469cSJonathan Kim 		return -ENOTRECOVERABLE;
2208ee0a469cSJonathan Kim 
2209ee0a469cSJonathan Kim 	for (i = 0; i < dqm->detect_hang_count; i++) {
2210ee0a469cSJonathan Kim 		struct dqm_detect_hang_info hang_info = dqm->detect_hang_info[i];
2211ee0a469cSJonathan Kim 		struct queue *q = find_queue_by_address(dqm, hang_info.queue_address);
2212ee0a469cSJonathan Kim 		struct kfd_process_device *pdd;
2213ee0a469cSJonathan Kim 		uint64_t queue_addr = 0;
2214ee0a469cSJonathan Kim 
2215ee0a469cSJonathan Kim 		if (!q) {
2216ee0a469cSJonathan Kim 			r = -ENOTRECOVERABLE;
2217ee0a469cSJonathan Kim 			goto reset_fail;
2218ee0a469cSJonathan Kim 		}
2219ee0a469cSJonathan Kim 
2220ee0a469cSJonathan Kim 		pdd = kfd_get_process_device_data(dqm->dev, q->process);
2221ee0a469cSJonathan Kim 		if (!pdd) {
2222ee0a469cSJonathan Kim 			r = -ENOTRECOVERABLE;
2223ee0a469cSJonathan Kim 			goto reset_fail;
2224ee0a469cSJonathan Kim 		}
2225ee0a469cSJonathan Kim 
2226ee0a469cSJonathan Kim 		queue_addr = dqm->dev->kfd2kgd->hqd_reset(dqm->dev->adev,
2227ee0a469cSJonathan Kim 				hang_info.pipe_id, hang_info.queue_id, hang_info.xcc_id,
2228ee0a469cSJonathan Kim 				KFD_UNMAP_LATENCY_MS);
2229ee0a469cSJonathan Kim 
2230ee0a469cSJonathan Kim 		/* either reset failed or we reset an unexpected queue. */
2231ee0a469cSJonathan Kim 		if (queue_addr != q->properties.queue_address) {
2232ee0a469cSJonathan Kim 			r = -ENOTRECOVERABLE;
2233ee0a469cSJonathan Kim 			goto reset_fail;
2234ee0a469cSJonathan Kim 		}
2235ee0a469cSJonathan Kim 
2236ee0a469cSJonathan Kim 		set_queue_as_reset(dqm, q, &pdd->qpd);
2237ee0a469cSJonathan Kim 		reset_count++;
2238ee0a469cSJonathan Kim 	}
2239ee0a469cSJonathan Kim 
2240ee0a469cSJonathan Kim 	if (reset_count == dqm->detect_hang_count)
2241ee0a469cSJonathan Kim 		kfd_signal_reset_event(dqm->dev);
2242ee0a469cSJonathan Kim 	else
2243ee0a469cSJonathan Kim 		r = -ENOTRECOVERABLE;
2244ee0a469cSJonathan Kim 
2245ee0a469cSJonathan Kim reset_fail:
2246ee0a469cSJonathan Kim 	dqm->detect_hang_count = 0;
2247ee0a469cSJonathan Kim 
2248ee0a469cSJonathan Kim 	return r;
2249ee0a469cSJonathan Kim }
2250ee0a469cSJonathan Kim 
sdma_has_hang(struct device_queue_manager * dqm)2251bac38ca8SJonathan Kim static bool sdma_has_hang(struct device_queue_manager *dqm)
2252bac38ca8SJonathan Kim {
2253bac38ca8SJonathan Kim 	int engine_start = dqm->dev->node_id * get_num_all_sdma_engines(dqm);
2254bac38ca8SJonathan Kim 	int engine_end = engine_start + get_num_all_sdma_engines(dqm);
2255bac38ca8SJonathan Kim 	int num_queues_per_eng =  dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
2256bac38ca8SJonathan Kim 	int i, j;
2257bac38ca8SJonathan Kim 
2258bac38ca8SJonathan Kim 	for (i = engine_start; i < engine_end; i++) {
2259bac38ca8SJonathan Kim 		for (j = 0; j < num_queues_per_eng; j++) {
2260bac38ca8SJonathan Kim 			if (!dqm->dev->kfd2kgd->hqd_sdma_get_doorbell(dqm->dev->adev, i, j))
2261bac38ca8SJonathan Kim 				continue;
2262bac38ca8SJonathan Kim 
2263bac38ca8SJonathan Kim 			return true;
2264bac38ca8SJonathan Kim 		}
2265bac38ca8SJonathan Kim 	}
2266bac38ca8SJonathan Kim 
2267bac38ca8SJonathan Kim 	return false;
2268bac38ca8SJonathan Kim }
2269bac38ca8SJonathan Kim 
set_sdma_queue_as_reset(struct device_queue_manager * dqm,uint32_t doorbell_off)2270bac38ca8SJonathan Kim static bool set_sdma_queue_as_reset(struct device_queue_manager *dqm,
2271bac38ca8SJonathan Kim 				    uint32_t doorbell_off)
2272bac38ca8SJonathan Kim {
2273bac38ca8SJonathan Kim 	struct device_process_node *cur;
2274bac38ca8SJonathan Kim 	struct qcm_process_device *qpd;
2275bac38ca8SJonathan Kim 	struct queue *q;
2276bac38ca8SJonathan Kim 
2277bac38ca8SJonathan Kim 	list_for_each_entry(cur, &dqm->queues, list) {
2278bac38ca8SJonathan Kim 		qpd = cur->qpd;
2279bac38ca8SJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
2280bac38ca8SJonathan Kim 			if ((q->properties.type == KFD_QUEUE_TYPE_SDMA ||
2281bac38ca8SJonathan Kim 			     q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) &&
2282bac38ca8SJonathan Kim 			     q->properties.doorbell_off == doorbell_off) {
2283bac38ca8SJonathan Kim 				set_queue_as_reset(dqm, q, qpd);
2284bac38ca8SJonathan Kim 				return true;
2285bac38ca8SJonathan Kim 			}
2286bac38ca8SJonathan Kim 		}
2287bac38ca8SJonathan Kim 	}
2288bac38ca8SJonathan Kim 
2289bac38ca8SJonathan Kim 	return false;
2290bac38ca8SJonathan Kim }
2291bac38ca8SJonathan Kim 
reset_hung_queues_sdma(struct device_queue_manager * dqm)2292bac38ca8SJonathan Kim static int reset_hung_queues_sdma(struct device_queue_manager *dqm)
2293bac38ca8SJonathan Kim {
2294bac38ca8SJonathan Kim 	int engine_start = dqm->dev->node_id * get_num_all_sdma_engines(dqm);
2295bac38ca8SJonathan Kim 	int engine_end = engine_start + get_num_all_sdma_engines(dqm);
2296bac38ca8SJonathan Kim 	int num_queues_per_eng =  dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
2297bac38ca8SJonathan Kim 	int r = 0, i, j;
2298bac38ca8SJonathan Kim 
2299bac38ca8SJonathan Kim 	if (dqm->is_hws_hang)
2300bac38ca8SJonathan Kim 		return -EIO;
2301bac38ca8SJonathan Kim 
2302bac38ca8SJonathan Kim 	/* Scan for hung HW queues and reset engine. */
2303bac38ca8SJonathan Kim 	dqm->detect_hang_count = 0;
2304bac38ca8SJonathan Kim 	for (i = engine_start; i < engine_end; i++) {
2305bac38ca8SJonathan Kim 		for (j = 0; j < num_queues_per_eng; j++) {
2306bac38ca8SJonathan Kim 			uint32_t doorbell_off =
2307bac38ca8SJonathan Kim 				dqm->dev->kfd2kgd->hqd_sdma_get_doorbell(dqm->dev->adev, i, j);
2308bac38ca8SJonathan Kim 
2309bac38ca8SJonathan Kim 			if (!doorbell_off)
2310bac38ca8SJonathan Kim 				continue;
2311bac38ca8SJonathan Kim 
2312bac38ca8SJonathan Kim 			/* Reset engine and check. */
2313*e02fcf73SAlex Deucher 			if (amdgpu_sdma_reset_engine(dqm->dev->adev, i) ||
2314bac38ca8SJonathan Kim 			    dqm->dev->kfd2kgd->hqd_sdma_get_doorbell(dqm->dev->adev, i, j) ||
2315bac38ca8SJonathan Kim 			    !set_sdma_queue_as_reset(dqm, doorbell_off)) {
2316bac38ca8SJonathan Kim 				r = -ENOTRECOVERABLE;
2317bac38ca8SJonathan Kim 				goto reset_fail;
2318bac38ca8SJonathan Kim 			}
2319bac38ca8SJonathan Kim 
2320bac38ca8SJonathan Kim 			/* Should only expect one queue active per engine */
2321bac38ca8SJonathan Kim 			dqm->detect_hang_count++;
2322bac38ca8SJonathan Kim 			break;
2323bac38ca8SJonathan Kim 		}
2324bac38ca8SJonathan Kim 	}
2325bac38ca8SJonathan Kim 
2326bac38ca8SJonathan Kim 	/* Signal process reset */
2327bac38ca8SJonathan Kim 	if (dqm->detect_hang_count)
2328bac38ca8SJonathan Kim 		kfd_signal_reset_event(dqm->dev);
2329bac38ca8SJonathan Kim 	else
2330bac38ca8SJonathan Kim 		r = -ENOTRECOVERABLE;
2331bac38ca8SJonathan Kim 
2332bac38ca8SJonathan Kim reset_fail:
2333bac38ca8SJonathan Kim 	dqm->detect_hang_count = 0;
2334bac38ca8SJonathan Kim 
2335bac38ca8SJonathan Kim 	return r;
2336bac38ca8SJonathan Kim }
2337bac38ca8SJonathan Kim 
reset_queues_on_hws_hang(struct device_queue_manager * dqm,bool is_sdma)2338bac38ca8SJonathan Kim static int reset_queues_on_hws_hang(struct device_queue_manager *dqm, bool is_sdma)
2339bac38ca8SJonathan Kim {
2340bac38ca8SJonathan Kim 	while (halt_if_hws_hang)
2341bac38ca8SJonathan Kim 		schedule();
2342bac38ca8SJonathan Kim 
2343bac38ca8SJonathan Kim 	if (!amdgpu_gpu_recovery)
2344bac38ca8SJonathan Kim 		return -ENOTRECOVERABLE;
2345bac38ca8SJonathan Kim 
2346bac38ca8SJonathan Kim 	return is_sdma ? reset_hung_queues_sdma(dqm) : reset_hung_queues(dqm);
2347bac38ca8SJonathan Kim }
2348bac38ca8SJonathan Kim 
2349ed962f8dSHarish Kasiviswanathan /* dqm->lock mutex has to be locked before calling this function
2350ed962f8dSHarish Kasiviswanathan  *
2351ed962f8dSHarish Kasiviswanathan  * @grace_period: If USE_DEFAULT_GRACE_PERIOD then default wait time
2352ed962f8dSHarish Kasiviswanathan  *   for context switch latency. Lower values are used by debugger
2353ed962f8dSHarish Kasiviswanathan  *   since context switching are triggered at high frequency.
2354ed962f8dSHarish Kasiviswanathan  *   This is configured by setting CP_IQ_WAIT_TIME2.SCH_WAVE
2355ed962f8dSHarish Kasiviswanathan  *
2356ed962f8dSHarish Kasiviswanathan  */
unmap_queues_cpsch(struct device_queue_manager * dqm,enum kfd_unmap_queues_filter filter,uint32_t filter_param,uint32_t grace_period,bool reset)23577da2bcf8SYong Zhao static int unmap_queues_cpsch(struct device_queue_manager *dqm,
23584465f466SYong Zhao 				enum kfd_unmap_queues_filter filter,
23597cee6a68SJonathan Kim 				uint32_t filter_param,
23607cee6a68SJonathan Kim 				uint32_t grace_period,
23617cee6a68SJonathan Kim 				bool reset)
236264c7f8cfSBen Goz {
236380c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
236451a0f459SOak Zeng 	struct mqd_manager *mqd_mgr;
23651802b042SYunxiang Li 	int retval;
236664c7f8cfSBen Goz 
23672c99a547SPhilip Yang 	if (!dqm->sched_running)
23682c99a547SPhilip Yang 		return 0;
2369991ca8eeSEdward O'Callaghan 	if (!dqm->active_runlist)
23701802b042SYunxiang Li 		return 0;
23711802b042SYunxiang Li 	if (!down_read_trylock(&dqm->dev->adev->reset_domain->sem))
23721802b042SYunxiang Li 		return -EIO;
2373bcea3081SBen Goz 
23747cee6a68SJonathan Kim 	if (grace_period != USE_DEFAULT_GRACE_PERIOD) {
2375ed962f8dSHarish Kasiviswanathan 		retval = pm_config_dequeue_wait_counts(&dqm->packet_mgr,
2376ed962f8dSHarish Kasiviswanathan 				KFD_DEQUEUE_WAIT_SET_SCH_WAVE, grace_period);
23777cee6a68SJonathan Kim 		if (retval)
23781802b042SYunxiang Li 			goto out;
23797cee6a68SJonathan Kim 	}
23807cee6a68SJonathan Kim 
2381d2cb0b21SJonathan Kim 	retval = pm_send_unmap_queue(&dqm->packet_mgr, filter, filter_param, reset);
23824eacc26bSKent Russell 	if (retval)
23831802b042SYunxiang Li 		goto out;
238464c7f8cfSBen Goz 
238564c7f8cfSBen Goz 	*dqm->fence_addr = KFD_FENCE_INIT;
238688344561SVictor Zhao 	mb();
23879af5379cSOak Zeng 	pm_send_query_status(&dqm->packet_mgr, dqm->fence_gpu_addr,
238864c7f8cfSBen Goz 				KFD_FENCE_COMPLETED);
238964c7f8cfSBen Goz 	/* should be timed out */
239080c74918SAsad Kamal 	retval = amdkfd_fence_wait_timeout(dqm, KFD_FENCE_COMPLETED,
239114328aa5SPhilip Cox 					   queue_preemption_timeout_ms);
239209c34e8dSFelix Kuehling 	if (retval) {
239380c74918SAsad Kamal 		dev_err(dev, "The cp might be in an unrecoverable state due to an unsuccessful queues preemption\n");
2394cc009e61SMukul Joshi 		kfd_hws_hang(dqm);
23951802b042SYunxiang Li 		goto out;
239609c34e8dSFelix Kuehling 	}
23979fd3f1bfSFelix Kuehling 
239851a0f459SOak Zeng 	/* In the current MEC firmware implementation, if compute queue
239951a0f459SOak Zeng 	 * doesn't response to the preemption request in time, HIQ will
240051a0f459SOak Zeng 	 * abandon the unmap request without returning any timeout error
240151a0f459SOak Zeng 	 * to driver. Instead, MEC firmware will log the doorbell of the
240251a0f459SOak Zeng 	 * unresponding compute queue to HIQ.MQD.queue_doorbell_id fields.
240351a0f459SOak Zeng 	 * To make sure the queue unmap was successful, driver need to
240451a0f459SOak Zeng 	 * check those fields
240551a0f459SOak Zeng 	 */
240651a0f459SOak Zeng 	mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ];
2407bac38ca8SJonathan Kim 	if (mqd_mgr->check_preemption_failed(mqd_mgr, dqm->packet_mgr.priv_queue->queue->mqd) &&
2408bac38ca8SJonathan Kim 	    reset_queues_on_hws_hang(dqm, false))
2409bac38ca8SJonathan Kim 		goto reset_fail;
2410bac38ca8SJonathan Kim 
2411bac38ca8SJonathan Kim 	/* Check for SDMA hang and attempt SDMA reset */
2412bac38ca8SJonathan Kim 	if (sdma_has_hang(dqm) && reset_queues_on_hws_hang(dqm, true))
2413bac38ca8SJonathan Kim 		goto reset_fail;
241451a0f459SOak Zeng 
24157cee6a68SJonathan Kim 	/* We need to reset the grace period value for this device */
24167cee6a68SJonathan Kim 	if (grace_period != USE_DEFAULT_GRACE_PERIOD) {
2417ed962f8dSHarish Kasiviswanathan 		if (pm_config_dequeue_wait_counts(&dqm->packet_mgr,
2418ed962f8dSHarish Kasiviswanathan 				KFD_DEQUEUE_WAIT_RESET, 0 /* unused */))
241980c74918SAsad Kamal 			dev_err(dev, "Failed to reset grace period\n");
24207cee6a68SJonathan Kim 	}
24217cee6a68SJonathan Kim 
24229af5379cSOak Zeng 	pm_release_ib(&dqm->packet_mgr);
242364c7f8cfSBen Goz 	dqm->active_runlist = false;
24241802b042SYunxiang Li out:
24251802b042SYunxiang Li 	up_read(&dqm->dev->adev->reset_domain->sem);
242664c7f8cfSBen Goz 	return retval;
2427bac38ca8SJonathan Kim 
2428bac38ca8SJonathan Kim reset_fail:
2429bac38ca8SJonathan Kim 	dqm->is_hws_hang = true;
2430bac38ca8SJonathan Kim 	kfd_hws_hang(dqm);
2431bac38ca8SJonathan Kim 	up_read(&dqm->dev->adev->reset_domain->sem);
2432bac38ca8SJonathan Kim 	return -ETIME;
243364c7f8cfSBen Goz }
243464c7f8cfSBen Goz 
2435dec63443STao Zhou /* only for compute queue */
reset_queues_cpsch(struct device_queue_manager * dqm,uint16_t pasid)2436ee0a469cSJonathan Kim static int reset_queues_cpsch(struct device_queue_manager *dqm, uint16_t pasid)
2437dec63443STao Zhou {
2438dec63443STao Zhou 	int retval;
2439dec63443STao Zhou 
2440dec63443STao Zhou 	dqm_lock(dqm);
2441dec63443STao Zhou 
2442dec63443STao Zhou 	retval = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_BY_PASID,
24437cee6a68SJonathan Kim 			pasid, USE_DEFAULT_GRACE_PERIOD, true);
2444dec63443STao Zhou 
2445dec63443STao Zhou 	dqm_unlock(dqm);
2446dec63443STao Zhou 	return retval;
2447dec63443STao Zhou }
2448dec63443STao Zhou 
2449ac30c783SYong 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)2450c4744e24SYong Zhao static int execute_queues_cpsch(struct device_queue_manager *dqm,
2451c4744e24SYong Zhao 				enum kfd_unmap_queues_filter filter,
24527cee6a68SJonathan Kim 				uint32_t filter_param,
24537cee6a68SJonathan Kim 				uint32_t grace_period)
245464c7f8cfSBen Goz {
245564c7f8cfSBen Goz 	int retval;
245664c7f8cfSBen Goz 
24571802b042SYunxiang Li 	if (!down_read_trylock(&dqm->dev->adev->reset_domain->sem))
245873ea648dSShaoyun Liu 		return -EIO;
24597cee6a68SJonathan Kim 	retval = unmap_queues_cpsch(dqm, filter, filter_param, grace_period, false);
24601802b042SYunxiang Li 	if (!retval)
24611802b042SYunxiang Li 		retval = map_queues_cpsch(dqm);
24621802b042SYunxiang Li 	up_read(&dqm->dev->adev->reset_domain->sem);
2463ac30c783SYong Zhao 	return retval;
246464c7f8cfSBen Goz }
246564c7f8cfSBen Goz 
wait_on_destroy_queue(struct device_queue_manager * dqm,struct queue * q)2466a70a93faSJonathan Kim static int wait_on_destroy_queue(struct device_queue_manager *dqm,
2467a70a93faSJonathan Kim 				 struct queue *q)
2468a70a93faSJonathan Kim {
2469a70a93faSJonathan Kim 	struct kfd_process_device *pdd = kfd_get_process_device_data(q->device,
2470a70a93faSJonathan Kim 								q->process);
2471a70a93faSJonathan Kim 	int ret = 0;
2472a70a93faSJonathan Kim 
247388a45aa6SAndrew Martin 	if (WARN_ON(!pdd))
247488a45aa6SAndrew Martin 		return ret;
247588a45aa6SAndrew Martin 
2476a70a93faSJonathan Kim 	if (pdd->qpd.is_debug)
2477a70a93faSJonathan Kim 		return ret;
2478a70a93faSJonathan Kim 
2479a70a93faSJonathan Kim 	q->properties.is_being_destroyed = true;
2480a70a93faSJonathan Kim 
2481a70a93faSJonathan Kim 	if (pdd->process->debug_trap_enabled && q->properties.is_suspended) {
2482a70a93faSJonathan Kim 		dqm_unlock(dqm);
2483a70a93faSJonathan Kim 		mutex_unlock(&q->process->mutex);
2484a70a93faSJonathan Kim 		ret = wait_event_interruptible(dqm->destroy_wait,
2485a70a93faSJonathan Kim 						!q->properties.is_suspended);
2486a70a93faSJonathan Kim 
2487a70a93faSJonathan Kim 		mutex_lock(&q->process->mutex);
2488a70a93faSJonathan Kim 		dqm_lock(dqm);
2489a70a93faSJonathan Kim 	}
2490a70a93faSJonathan Kim 
2491a70a93faSJonathan Kim 	return ret;
2492a70a93faSJonathan Kim }
2493a70a93faSJonathan Kim 
destroy_queue_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd,struct queue * q)249464c7f8cfSBen Goz static int destroy_queue_cpsch(struct device_queue_manager *dqm,
249564c7f8cfSBen Goz 				struct qcm_process_device *qpd,
249664c7f8cfSBen Goz 				struct queue *q)
249764c7f8cfSBen Goz {
249864c7f8cfSBen Goz 	int retval;
24998d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
2500d69fd951SMukul Joshi 	uint64_t sdma_val = 0;
2501d69fd951SMukul Joshi 	struct kfd_process_device *pdd = qpd_to_pdd(qpd);
250280c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
2503d69fd951SMukul Joshi 
2504d69fd951SMukul Joshi 	/* Get the SDMA queue stats */
2505d69fd951SMukul Joshi 	if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) ||
2506d69fd951SMukul Joshi 	    (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
2507818b0324SMukul Joshi 		retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr,
2508d69fd951SMukul Joshi 							&sdma_val);
2509d69fd951SMukul Joshi 		if (retval)
251080c74918SAsad Kamal 			dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n",
2511d69fd951SMukul Joshi 				q->properties.queue_id);
2512d69fd951SMukul Joshi 	}
2513992839adSYair Shachar 
251464c7f8cfSBen Goz 	/* remove queue from list to prevent rescheduling after preemption */
2515efeaed4dSFelix Kuehling 	dqm_lock(dqm);
2516992839adSYair Shachar 
2517a70a93faSJonathan Kim 	retval = wait_on_destroy_queue(dqm, q);
2518a70a93faSJonathan Kim 
2519a70a93faSJonathan Kim 	if (retval) {
2520a70a93faSJonathan Kim 		dqm_unlock(dqm);
2521a70a93faSJonathan Kim 		return retval;
2522a70a93faSJonathan Kim 	}
2523a70a93faSJonathan Kim 
2524992839adSYair Shachar 	if (qpd->is_debug) {
2525992839adSYair Shachar 		/*
2526992839adSYair Shachar 		 * error, currently we do not allow to destroy a queue
2527992839adSYair Shachar 		 * of a currently debugged process
2528992839adSYair Shachar 		 */
2529992839adSYair Shachar 		retval = -EBUSY;
2530992839adSYair Shachar 		goto failed_try_destroy_debugged_queue;
2531992839adSYair Shachar 
2532992839adSYair Shachar 	}
2533992839adSYair Shachar 
2534fdfa090bSOak Zeng 	mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
2535fdfa090bSOak Zeng 			q->properties.type)];
253664c7f8cfSBen Goz 
2537ef568db7SFelix Kuehling 	deallocate_doorbell(qpd, q);
2538ef568db7SFelix Kuehling 
2539d69fd951SMukul Joshi 	if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) ||
2540d69fd951SMukul Joshi 	    (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) {
25411b4670f6SOak Zeng 		deallocate_sdma_queue(dqm, q);
2542d69fd951SMukul Joshi 		pdd->sdma_past_activity_counter += sdma_val;
2543d69fd951SMukul Joshi 	}
2544bcea3081SBen Goz 
25458c07f33eSPhilip Yang 	if (q->properties.is_active) {
25468c07f33eSPhilip Yang 		decrement_queue_count(dqm, qpd, q);
2547101025e9SJonathan Kim 		q->properties.is_active = false;
254880a780abSJonathan Kim 		if (!dqm->dev->kfd->shared_resources.enable_mes) {
25498c07f33eSPhilip Yang 			retval = execute_queues_cpsch(dqm,
25507cee6a68SJonathan Kim 						      KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
25517cee6a68SJonathan Kim 						      USE_DEFAULT_GRACE_PERIOD);
25528c07f33eSPhilip Yang 			if (retval == -ETIME)
25538c07f33eSPhilip Yang 				qpd->reset_wavefronts = true;
25548c07f33eSPhilip Yang 		} else {
25558c07f33eSPhilip Yang 			retval = remove_queue_mes(dqm, q, qpd);
25568c07f33eSPhilip Yang 		}
25578c07f33eSPhilip Yang 	}
2558101025e9SJonathan Kim 	list_del(&q->list);
2559101025e9SJonathan Kim 	qpd->queue_count--;
256064c7f8cfSBen Goz 
2561b8cbab04SOded Gabbay 	/*
2562b8cbab04SOded Gabbay 	 * Unconditionally decrement this counter, regardless of the queue's
2563b8cbab04SOded Gabbay 	 * type
2564b8cbab04SOded Gabbay 	 */
2565b8cbab04SOded Gabbay 	dqm->total_queue_count--;
2566b8cbab04SOded Gabbay 	pr_debug("Total of %d queues are accountable so far\n",
2567b8cbab04SOded Gabbay 			dqm->total_queue_count);
2568b8cbab04SOded Gabbay 
2569efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
257064c7f8cfSBen Goz 
2571a70a93faSJonathan Kim 	/*
2572a70a93faSJonathan Kim 	 * Do free_mqd and raise delete event after dqm_unlock(dqm) to avoid
2573a70a93faSJonathan Kim 	 * circular locking
2574a70a93faSJonathan Kim 	 */
2575a70a93faSJonathan Kim 	kfd_dbg_ev_raise(KFD_EC_MASK(EC_DEVICE_QUEUE_DELETE),
2576a70a93faSJonathan Kim 				qpd->pqm->process, q->device,
2577a70a93faSJonathan Kim 				-1, false, NULL, 0);
2578a70a93faSJonathan Kim 
25798636e53cSOak Zeng 	mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
258089cd9d23SPhilip Yang 
25819e827224SYong Zhao 	return retval;
258264c7f8cfSBen Goz 
2583992839adSYair Shachar failed_try_destroy_debugged_queue:
2584992839adSYair Shachar 
2585efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
258664c7f8cfSBen Goz 	return retval;
258764c7f8cfSBen Goz }
258864c7f8cfSBen 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,u32 misc_process_properties)258964c7f8cfSBen Goz static bool set_cache_memory_policy(struct device_queue_manager *dqm,
259064c7f8cfSBen Goz 				   struct qcm_process_device *qpd,
259164c7f8cfSBen Goz 				   enum cache_policy default_policy,
259264c7f8cfSBen Goz 				   enum cache_policy alternate_policy,
259364c7f8cfSBen Goz 				   void __user *alternate_aperture_base,
2594cf6d949aSHarish Kasiviswanathan 				   uint64_t alternate_aperture_size,
2595cf6d949aSHarish Kasiviswanathan 				   u32 misc_process_properties)
259664c7f8cfSBen Goz {
2597bed4f110SFelix Kuehling 	bool retval = true;
2598bed4f110SFelix Kuehling 
2599bed4f110SFelix Kuehling 	if (!dqm->asic_ops.set_cache_memory_policy)
2600bed4f110SFelix Kuehling 		return retval;
260164c7f8cfSBen Goz 
2602efeaed4dSFelix Kuehling 	dqm_lock(dqm);
260364c7f8cfSBen Goz 
2604bfd5e378SYong Zhao 	retval = dqm->asic_ops.set_cache_memory_policy(
2605a22fc854SBen Goz 			dqm,
2606a22fc854SBen Goz 			qpd,
2607a22fc854SBen Goz 			default_policy,
2608a22fc854SBen Goz 			alternate_policy,
2609a22fc854SBen Goz 			alternate_aperture_base,
2610cf6d949aSHarish Kasiviswanathan 			alternate_aperture_size,
2611cf6d949aSHarish Kasiviswanathan 			misc_process_properties);
261264c7f8cfSBen Goz 
2613289e6850SHarish Kasiviswanathan 	if (retval)
2614289e6850SHarish Kasiviswanathan 		goto out;
2615289e6850SHarish Kasiviswanathan 
2616d146c5a7SFelix Kuehling 	if ((dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0))
261764c7f8cfSBen Goz 		program_sh_mem_settings(dqm, qpd);
261864c7f8cfSBen Goz 
261979775b62SKent Russell 	pr_debug("sh_mem_config: 0x%x, ape1_base: 0x%x, ape1_limit: 0x%x\n",
262064c7f8cfSBen Goz 		qpd->sh_mem_config, qpd->sh_mem_ape1_base,
262164c7f8cfSBen Goz 		qpd->sh_mem_ape1_limit);
262264c7f8cfSBen Goz 
262364c7f8cfSBen Goz out:
2624efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
2625ab7c1648SKent Russell 	return retval;
262664c7f8cfSBen Goz }
262764c7f8cfSBen Goz 
process_termination_nocpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)26289fd3f1bfSFelix Kuehling static int process_termination_nocpsch(struct device_queue_manager *dqm,
26299fd3f1bfSFelix Kuehling 		struct qcm_process_device *qpd)
26309fd3f1bfSFelix Kuehling {
2631a7b2451dSAmber Lin 	struct queue *q;
26329fd3f1bfSFelix Kuehling 	struct device_process_node *cur, *next_dpn;
26339fd3f1bfSFelix Kuehling 	int retval = 0;
263432cce8bcSFelix Kuehling 	bool found = false;
26359fd3f1bfSFelix Kuehling 
2636efeaed4dSFelix Kuehling 	dqm_lock(dqm);
26379fd3f1bfSFelix Kuehling 
26389fd3f1bfSFelix Kuehling 	/* Clear all user mode queues */
2639a7b2451dSAmber Lin 	while (!list_empty(&qpd->queues_list)) {
2640a7b2451dSAmber Lin 		struct mqd_manager *mqd_mgr;
26419fd3f1bfSFelix Kuehling 		int ret;
26429fd3f1bfSFelix Kuehling 
2643a7b2451dSAmber Lin 		q = list_first_entry(&qpd->queues_list, struct queue, list);
2644a7b2451dSAmber Lin 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
2645a7b2451dSAmber Lin 				q->properties.type)];
26469fd3f1bfSFelix Kuehling 		ret = destroy_queue_nocpsch_locked(dqm, qpd, q);
26479fd3f1bfSFelix Kuehling 		if (ret)
26489fd3f1bfSFelix Kuehling 			retval = ret;
2649a7b2451dSAmber Lin 		dqm_unlock(dqm);
2650a7b2451dSAmber Lin 		mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
2651a7b2451dSAmber Lin 		dqm_lock(dqm);
26529fd3f1bfSFelix Kuehling 	}
26539fd3f1bfSFelix Kuehling 
26549fd3f1bfSFelix Kuehling 	/* Unregister process */
26559fd3f1bfSFelix Kuehling 	list_for_each_entry_safe(cur, next_dpn, &dqm->queues, list) {
26569fd3f1bfSFelix Kuehling 		if (qpd == cur->qpd) {
26579fd3f1bfSFelix Kuehling 			list_del(&cur->list);
26589fd3f1bfSFelix Kuehling 			kfree(cur);
26599fd3f1bfSFelix Kuehling 			dqm->processes_count--;
266032cce8bcSFelix Kuehling 			found = true;
26619fd3f1bfSFelix Kuehling 			break;
26629fd3f1bfSFelix Kuehling 		}
26639fd3f1bfSFelix Kuehling 	}
26649fd3f1bfSFelix Kuehling 
2665efeaed4dSFelix Kuehling 	dqm_unlock(dqm);
266632cce8bcSFelix Kuehling 
266732cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
266832cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
266932cce8bcSFelix Kuehling 	 */
267032cce8bcSFelix Kuehling 	if (found)
267132cce8bcSFelix Kuehling 		kfd_dec_compute_active(dqm->dev);
267232cce8bcSFelix Kuehling 
26739fd3f1bfSFelix Kuehling 	return retval;
26749fd3f1bfSFelix Kuehling }
26759fd3f1bfSFelix 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)26765df099e8SJay Cornwall static int get_wave_state(struct device_queue_manager *dqm,
26775df099e8SJay Cornwall 			  struct queue *q,
26785df099e8SJay Cornwall 			  void __user *ctl_stack,
26795df099e8SJay Cornwall 			  u32 *ctl_stack_used_size,
26805df099e8SJay Cornwall 			  u32 *save_area_used_size)
26815df099e8SJay Cornwall {
26824e6c6fc1SYong Zhao 	struct mqd_manager *mqd_mgr;
26835df099e8SJay Cornwall 
26845df099e8SJay Cornwall 	dqm_lock(dqm);
26855df099e8SJay Cornwall 
2686d7c0b047SYong Zhao 	mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_CP];
26875df099e8SJay Cornwall 
268863f6e012SJonathan Kim 	if (q->properties.type != KFD_QUEUE_TYPE_COMPUTE ||
26898dc1db31SMukul Joshi 	    q->properties.is_active || !q->device->kfd->cwsr_enabled ||
269063f6e012SJonathan Kim 	    !mqd_mgr->get_wave_state) {
269163f6e012SJonathan Kim 		dqm_unlock(dqm);
269263f6e012SJonathan Kim 		return -EINVAL;
26935df099e8SJay Cornwall 	}
26945df099e8SJay Cornwall 
26955df099e8SJay Cornwall 	dqm_unlock(dqm);
269663f6e012SJonathan Kim 
269763f6e012SJonathan Kim 	/*
269863f6e012SJonathan Kim 	 * get_wave_state is outside the dqm lock to prevent circular locking
269963f6e012SJonathan Kim 	 * and the queue should be protected against destruction by the process
270063f6e012SJonathan Kim 	 * lock.
270163f6e012SJonathan Kim 	 */
27027fe51e6fSMukul Joshi 	return mqd_mgr->get_wave_state(mqd_mgr, q->mqd, &q->properties,
27037fe51e6fSMukul Joshi 			ctl_stack, ctl_stack_used_size, save_area_used_size);
27045df099e8SJay Cornwall }
27059fd3f1bfSFelix Kuehling 
get_queue_checkpoint_info(struct device_queue_manager * dqm,const struct queue * q,u32 * mqd_size,u32 * ctl_stack_size)270642c6c482SDavid Yat Sin static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
270742c6c482SDavid Yat Sin 			const struct queue *q,
27083a9822d7SDavid Yat Sin 			u32 *mqd_size,
27093a9822d7SDavid Yat Sin 			u32 *ctl_stack_size)
271042c6c482SDavid Yat Sin {
271142c6c482SDavid Yat Sin 	struct mqd_manager *mqd_mgr;
271242c6c482SDavid Yat Sin 	enum KFD_MQD_TYPE mqd_type =
271342c6c482SDavid Yat Sin 			get_mqd_type_from_queue_type(q->properties.type);
271442c6c482SDavid Yat Sin 
271542c6c482SDavid Yat Sin 	dqm_lock(dqm);
271642c6c482SDavid Yat Sin 	mqd_mgr = dqm->mqd_mgrs[mqd_type];
271742c6c482SDavid Yat Sin 	*mqd_size = mqd_mgr->mqd_size;
27183a9822d7SDavid Yat Sin 	*ctl_stack_size = 0;
27193a9822d7SDavid Yat Sin 
27203a9822d7SDavid Yat Sin 	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE && mqd_mgr->get_checkpoint_info)
27213a9822d7SDavid Yat Sin 		mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size);
272242c6c482SDavid Yat Sin 
272342c6c482SDavid Yat Sin 	dqm_unlock(dqm);
272442c6c482SDavid Yat Sin }
272542c6c482SDavid Yat Sin 
checkpoint_mqd(struct device_queue_manager * dqm,const struct queue * q,void * mqd,void * ctl_stack)272642c6c482SDavid Yat Sin static int checkpoint_mqd(struct device_queue_manager *dqm,
272742c6c482SDavid Yat Sin 			  const struct queue *q,
27283a9822d7SDavid Yat Sin 			  void *mqd,
27293a9822d7SDavid Yat Sin 			  void *ctl_stack)
273042c6c482SDavid Yat Sin {
273142c6c482SDavid Yat Sin 	struct mqd_manager *mqd_mgr;
273242c6c482SDavid Yat Sin 	int r = 0;
273342c6c482SDavid Yat Sin 	enum KFD_MQD_TYPE mqd_type =
273442c6c482SDavid Yat Sin 			get_mqd_type_from_queue_type(q->properties.type);
273542c6c482SDavid Yat Sin 
273642c6c482SDavid Yat Sin 	dqm_lock(dqm);
273742c6c482SDavid Yat Sin 
27388dc1db31SMukul Joshi 	if (q->properties.is_active || !q->device->kfd->cwsr_enabled) {
273942c6c482SDavid Yat Sin 		r = -EINVAL;
274042c6c482SDavid Yat Sin 		goto dqm_unlock;
274142c6c482SDavid Yat Sin 	}
274242c6c482SDavid Yat Sin 
274342c6c482SDavid Yat Sin 	mqd_mgr = dqm->mqd_mgrs[mqd_type];
274442c6c482SDavid Yat Sin 	if (!mqd_mgr->checkpoint_mqd) {
274542c6c482SDavid Yat Sin 		r = -EOPNOTSUPP;
274642c6c482SDavid Yat Sin 		goto dqm_unlock;
274742c6c482SDavid Yat Sin 	}
274842c6c482SDavid Yat Sin 
27493a9822d7SDavid Yat Sin 	mqd_mgr->checkpoint_mqd(mqd_mgr, q->mqd, mqd, ctl_stack);
275042c6c482SDavid Yat Sin 
275142c6c482SDavid Yat Sin dqm_unlock:
275242c6c482SDavid Yat Sin 	dqm_unlock(dqm);
275342c6c482SDavid Yat Sin 	return r;
275442c6c482SDavid Yat Sin }
275542c6c482SDavid Yat Sin 
process_termination_cpsch(struct device_queue_manager * dqm,struct qcm_process_device * qpd)27569fd3f1bfSFelix Kuehling static int process_termination_cpsch(struct device_queue_manager *dqm,
27579fd3f1bfSFelix Kuehling 		struct qcm_process_device *qpd)
27589fd3f1bfSFelix Kuehling {
27599fd3f1bfSFelix Kuehling 	int retval;
276056f221b6Sxinhui pan 	struct queue *q;
276180c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
27629fd3f1bfSFelix Kuehling 	struct kernel_queue *kq, *kq_next;
27638d5f3552SYong Zhao 	struct mqd_manager *mqd_mgr;
27649fd3f1bfSFelix Kuehling 	struct device_process_node *cur, *next_dpn;
27659fd3f1bfSFelix Kuehling 	enum kfd_unmap_queues_filter filter =
27669fd3f1bfSFelix Kuehling 		KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES;
276732cce8bcSFelix Kuehling 	bool found = false;
27689fd3f1bfSFelix Kuehling 
27699fd3f1bfSFelix Kuehling 	retval = 0;
27709fd3f1bfSFelix Kuehling 
2771efeaed4dSFelix Kuehling 	dqm_lock(dqm);
27729fd3f1bfSFelix Kuehling 
27739fd3f1bfSFelix Kuehling 	/* Clean all kernel queues */
27749fd3f1bfSFelix Kuehling 	list_for_each_entry_safe(kq, kq_next, &qpd->priv_queue_list, list) {
27759fd3f1bfSFelix Kuehling 		list_del(&kq->list);
2776ab4d51d4SDavid Yat Sin 		decrement_queue_count(dqm, qpd, kq->queue);
27779fd3f1bfSFelix Kuehling 		qpd->is_debug = false;
27789fd3f1bfSFelix Kuehling 		dqm->total_queue_count--;
27799fd3f1bfSFelix Kuehling 		filter = KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES;
27809fd3f1bfSFelix Kuehling 	}
27819fd3f1bfSFelix Kuehling 
27829fd3f1bfSFelix Kuehling 	/* Clear all user mode queues */
27839fd3f1bfSFelix Kuehling 	list_for_each_entry(q, &qpd->queues_list, list) {
2784c7637c95SYong Zhao 		if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
27851b4670f6SOak Zeng 			deallocate_sdma_queue(dqm, q);
2786c7637c95SYong Zhao 		else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
27871b4670f6SOak Zeng 			deallocate_sdma_queue(dqm, q);
27889fd3f1bfSFelix Kuehling 
2789cc009e61SMukul Joshi 		if (q->properties.is_active) {
2790ab4d51d4SDavid Yat Sin 			decrement_queue_count(dqm, qpd, q);
27919fd3f1bfSFelix Kuehling 
27928dc1db31SMukul Joshi 			if (dqm->dev->kfd->shared_resources.enable_mes) {
2793cc009e61SMukul Joshi 				retval = remove_queue_mes(dqm, q, qpd);
2794cc009e61SMukul Joshi 				if (retval)
279580c74918SAsad Kamal 					dev_err(dev, "Failed to remove queue %d\n",
2796cc009e61SMukul Joshi 						q->properties.queue_id);
2797cc009e61SMukul Joshi 			}
2798cc009e61SMukul Joshi 		}
2799cc009e61SMukul Joshi 
28009fd3f1bfSFelix Kuehling 		dqm->total_queue_count--;
28019fd3f1bfSFelix Kuehling 	}
28029fd3f1bfSFelix Kuehling 
28039fd3f1bfSFelix Kuehling 	/* Unregister process */
28049fd3f1bfSFelix Kuehling 	list_for_each_entry_safe(cur, next_dpn, &dqm->queues, list) {
28059fd3f1bfSFelix Kuehling 		if (qpd == cur->qpd) {
28069fd3f1bfSFelix Kuehling 			list_del(&cur->list);
28079fd3f1bfSFelix Kuehling 			kfree(cur);
28089fd3f1bfSFelix Kuehling 			dqm->processes_count--;
280932cce8bcSFelix Kuehling 			found = true;
28109fd3f1bfSFelix Kuehling 			break;
28119fd3f1bfSFelix Kuehling 		}
28129fd3f1bfSFelix Kuehling 	}
28139fd3f1bfSFelix Kuehling 
28148dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
28157cee6a68SJonathan Kim 		retval = execute_queues_cpsch(dqm, filter, 0, USE_DEFAULT_GRACE_PERIOD);
2816cc009e61SMukul Joshi 
28171802b042SYunxiang Li 	if ((retval || qpd->reset_wavefronts) &&
28181802b042SYunxiang Li 	    down_read_trylock(&dqm->dev->adev->reset_domain->sem)) {
28199fd3f1bfSFelix Kuehling 		pr_warn("Resetting wave fronts (cpsch) on dev %p\n", dqm->dev);
28209fd3f1bfSFelix Kuehling 		dbgdev_wave_reset_wavefronts(dqm->dev, qpd->pqm->process);
28219fd3f1bfSFelix Kuehling 		qpd->reset_wavefronts = false;
28221802b042SYunxiang Li 		up_read(&dqm->dev->adev->reset_domain->sem);
28239fd3f1bfSFelix Kuehling 	}
28249fd3f1bfSFelix Kuehling 
282556f221b6Sxinhui pan 	/* Lastly, free mqd resources.
282656f221b6Sxinhui pan 	 * Do free_mqd() after dqm_unlock to avoid circular locking.
282756f221b6Sxinhui pan 	 */
282856f221b6Sxinhui pan 	while (!list_empty(&qpd->queues_list)) {
282956f221b6Sxinhui pan 		q = list_first_entry(&qpd->queues_list, struct queue, list);
283056f221b6Sxinhui pan 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
283156f221b6Sxinhui pan 				q->properties.type)];
283256f221b6Sxinhui pan 		list_del(&q->list);
283356f221b6Sxinhui pan 		qpd->queue_count--;
283456f221b6Sxinhui pan 		dqm_unlock(dqm);
283556f221b6Sxinhui pan 		mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
283656f221b6Sxinhui pan 		dqm_lock(dqm);
283756f221b6Sxinhui pan 	}
283889cd9d23SPhilip Yang 	dqm_unlock(dqm);
283989cd9d23SPhilip Yang 
284032cce8bcSFelix Kuehling 	/* Outside the DQM lock because under the DQM lock we can't do
284132cce8bcSFelix Kuehling 	 * reclaim or take other locks that others hold while reclaiming.
284232cce8bcSFelix Kuehling 	 */
284332cce8bcSFelix Kuehling 	if (found)
284432cce8bcSFelix Kuehling 		kfd_dec_compute_active(dqm->dev);
284532cce8bcSFelix Kuehling 
28469fd3f1bfSFelix Kuehling 	return retval;
28479fd3f1bfSFelix Kuehling }
28489fd3f1bfSFelix Kuehling 
init_mqd_managers(struct device_queue_manager * dqm)2849fdfa090bSOak Zeng static int init_mqd_managers(struct device_queue_manager *dqm)
2850fdfa090bSOak Zeng {
2851fdfa090bSOak Zeng 	int i, j;
285280c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
2853fdfa090bSOak Zeng 	struct mqd_manager *mqd_mgr;
2854fdfa090bSOak Zeng 
2855fdfa090bSOak Zeng 	for (i = 0; i < KFD_MQD_TYPE_MAX; i++) {
2856fdfa090bSOak Zeng 		mqd_mgr = dqm->asic_ops.mqd_manager_init(i, dqm->dev);
2857fdfa090bSOak Zeng 		if (!mqd_mgr) {
285880c74918SAsad Kamal 			dev_err(dev, "mqd manager [%d] initialization failed\n", i);
2859fdfa090bSOak Zeng 			goto out_free;
2860fdfa090bSOak Zeng 		}
2861fdfa090bSOak Zeng 		dqm->mqd_mgrs[i] = mqd_mgr;
2862fdfa090bSOak Zeng 	}
2863fdfa090bSOak Zeng 
2864fdfa090bSOak Zeng 	return 0;
2865fdfa090bSOak Zeng 
2866fdfa090bSOak Zeng out_free:
2867fdfa090bSOak Zeng 	for (j = 0; j < i; j++) {
2868fdfa090bSOak Zeng 		kfree(dqm->mqd_mgrs[j]);
2869fdfa090bSOak Zeng 		dqm->mqd_mgrs[j] = NULL;
2870fdfa090bSOak Zeng 	}
2871fdfa090bSOak Zeng 
2872fdfa090bSOak Zeng 	return -ENOMEM;
2873fdfa090bSOak Zeng }
287411614c36SOak Zeng 
287511614c36SOak Zeng /* Allocate one hiq mqd (HWS) and all SDMA mqd in a continuous trunk*/
allocate_hiq_sdma_mqd(struct device_queue_manager * dqm)287611614c36SOak Zeng static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm)
287711614c36SOak Zeng {
287811614c36SOak Zeng 	int retval;
28798dc1db31SMukul Joshi 	struct kfd_node *dev = dqm->dev;
288011614c36SOak Zeng 	struct kfd_mem_obj *mem_obj = &dqm->hiq_sdma_mqd;
288111614c36SOak Zeng 	uint32_t size = dqm->mqd_mgrs[KFD_MQD_TYPE_SDMA]->mqd_size *
2882c7637c95SYong Zhao 		get_num_all_sdma_engines(dqm) *
28838dc1db31SMukul Joshi 		dev->kfd->device_info.num_sdma_queues_per_engine +
28842f77b9a2SMukul Joshi 		(dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size *
2885c4050ff1SLijo Lazar 		NUM_XCC(dqm->dev->xcc_mask));
288611614c36SOak Zeng 
28876bfc7c7eSGraham Sider 	retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, size,
288811614c36SOak Zeng 		&(mem_obj->gtt_mem), &(mem_obj->gpu_addr),
2889f2cc50ceSEric Huang 		(void *)&(mem_obj->cpu_ptr), false);
289011614c36SOak Zeng 
289111614c36SOak Zeng 	return retval;
289211614c36SOak Zeng }
289311614c36SOak Zeng 
device_queue_manager_init(struct kfd_node * dev)28948dc1db31SMukul Joshi struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev)
289564c7f8cfSBen Goz {
289664c7f8cfSBen Goz 	struct device_queue_manager *dqm;
289764c7f8cfSBen Goz 
289879775b62SKent Russell 	pr_debug("Loading device queue manager\n");
2899a22fc854SBen Goz 
2900dbf56ab1SKent Russell 	dqm = kzalloc(sizeof(*dqm), GFP_KERNEL);
290164c7f8cfSBen Goz 	if (!dqm)
290264c7f8cfSBen Goz 		return NULL;
290364c7f8cfSBen Goz 
29047eb0502aSGraham Sider 	switch (dev->adev->asic_type) {
2905d146c5a7SFelix Kuehling 	/* HWS is not available on Hawaii. */
2906d146c5a7SFelix Kuehling 	case CHIP_HAWAII:
2907d146c5a7SFelix Kuehling 	/* HWS depends on CWSR for timely dequeue. CWSR is not
2908d146c5a7SFelix Kuehling 	 * available on Tonga.
2909d146c5a7SFelix Kuehling 	 *
2910d146c5a7SFelix Kuehling 	 * FIXME: This argument also applies to Kaveri.
2911d146c5a7SFelix Kuehling 	 */
2912d146c5a7SFelix Kuehling 	case CHIP_TONGA:
2913d146c5a7SFelix Kuehling 		dqm->sched_policy = KFD_SCHED_POLICY_NO_HWS;
2914d146c5a7SFelix Kuehling 		break;
2915d146c5a7SFelix Kuehling 	default:
2916d146c5a7SFelix Kuehling 		dqm->sched_policy = sched_policy;
2917d146c5a7SFelix Kuehling 		break;
2918d146c5a7SFelix Kuehling 	}
2919d146c5a7SFelix Kuehling 
292064c7f8cfSBen Goz 	dqm->dev = dev;
2921d146c5a7SFelix Kuehling 	switch (dqm->sched_policy) {
292264c7f8cfSBen Goz 	case KFD_SCHED_POLICY_HWS:
292364c7f8cfSBen Goz 	case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION:
292464c7f8cfSBen Goz 		/* initialize dqm for cp scheduling */
292545c9a5e4SOded Gabbay 		dqm->ops.create_queue = create_queue_cpsch;
292645c9a5e4SOded Gabbay 		dqm->ops.initialize = initialize_cpsch;
292745c9a5e4SOded Gabbay 		dqm->ops.start = start_cpsch;
292845c9a5e4SOded Gabbay 		dqm->ops.stop = stop_cpsch;
2929234eebe1SAmber Lin 		dqm->ops.halt = halt_cpsch;
2930234eebe1SAmber Lin 		dqm->ops.unhalt = unhalt_cpsch;
293145c9a5e4SOded Gabbay 		dqm->ops.destroy_queue = destroy_queue_cpsch;
293245c9a5e4SOded Gabbay 		dqm->ops.update_queue = update_queue;
293358dcd5bfSYong Zhao 		dqm->ops.register_process = register_process;
293458dcd5bfSYong Zhao 		dqm->ops.unregister_process = unregister_process;
293558dcd5bfSYong Zhao 		dqm->ops.uninitialize = uninitialize;
293645c9a5e4SOded Gabbay 		dqm->ops.create_kernel_queue = create_kernel_queue_cpsch;
293745c9a5e4SOded Gabbay 		dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch;
293845c9a5e4SOded Gabbay 		dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
29399fd3f1bfSFelix Kuehling 		dqm->ops.process_termination = process_termination_cpsch;
294026103436SFelix Kuehling 		dqm->ops.evict_process_queues = evict_process_queues_cpsch;
294126103436SFelix Kuehling 		dqm->ops.restore_process_queues = restore_process_queues_cpsch;
29425df099e8SJay Cornwall 		dqm->ops.get_wave_state = get_wave_state;
2943dec63443STao Zhou 		dqm->ops.reset_queues = reset_queues_cpsch;
294442c6c482SDavid Yat Sin 		dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info;
294542c6c482SDavid Yat Sin 		dqm->ops.checkpoint_mqd = checkpoint_mqd;
294664c7f8cfSBen Goz 		break;
294764c7f8cfSBen Goz 	case KFD_SCHED_POLICY_NO_HWS:
294864c7f8cfSBen Goz 		/* initialize dqm for no cp scheduling */
294945c9a5e4SOded Gabbay 		dqm->ops.start = start_nocpsch;
295045c9a5e4SOded Gabbay 		dqm->ops.stop = stop_nocpsch;
295145c9a5e4SOded Gabbay 		dqm->ops.create_queue = create_queue_nocpsch;
295245c9a5e4SOded Gabbay 		dqm->ops.destroy_queue = destroy_queue_nocpsch;
295345c9a5e4SOded Gabbay 		dqm->ops.update_queue = update_queue;
295458dcd5bfSYong Zhao 		dqm->ops.register_process = register_process;
295558dcd5bfSYong Zhao 		dqm->ops.unregister_process = unregister_process;
295645c9a5e4SOded Gabbay 		dqm->ops.initialize = initialize_nocpsch;
295758dcd5bfSYong Zhao 		dqm->ops.uninitialize = uninitialize;
295845c9a5e4SOded Gabbay 		dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
29599fd3f1bfSFelix Kuehling 		dqm->ops.process_termination = process_termination_nocpsch;
296026103436SFelix Kuehling 		dqm->ops.evict_process_queues = evict_process_queues_nocpsch;
296126103436SFelix Kuehling 		dqm->ops.restore_process_queues =
296226103436SFelix Kuehling 			restore_process_queues_nocpsch;
29635df099e8SJay Cornwall 		dqm->ops.get_wave_state = get_wave_state;
296442c6c482SDavid Yat Sin 		dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info;
296542c6c482SDavid Yat Sin 		dqm->ops.checkpoint_mqd = checkpoint_mqd;
296664c7f8cfSBen Goz 		break;
296764c7f8cfSBen Goz 	default:
296880c74918SAsad Kamal 		dev_err(dev->adev->dev, "Invalid scheduling policy %d\n", dqm->sched_policy);
296932fa8219SFelix Kuehling 		goto out_free;
297064c7f8cfSBen Goz 	}
297164c7f8cfSBen Goz 
29727eb0502aSGraham Sider 	switch (dev->adev->asic_type) {
2973a22fc854SBen Goz 	case CHIP_KAVERI:
297497672cbeSFelix Kuehling 	case CHIP_HAWAII:
2975c99a2e7aSAlex Deucher 		device_queue_manager_init_cik(&dqm->asic_ops);
297697672cbeSFelix Kuehling 		break;
297797672cbeSFelix Kuehling 
297899c15019SAlex Deucher 	case CHIP_CARRIZO:
297997672cbeSFelix Kuehling 	case CHIP_TONGA:
298097672cbeSFelix Kuehling 	case CHIP_FIJI:
298197672cbeSFelix Kuehling 	case CHIP_POLARIS10:
298297672cbeSFelix Kuehling 	case CHIP_POLARIS11:
2983846a44d7SGang Ba 	case CHIP_POLARIS12:
2984ed81cd6eSKent Russell 	case CHIP_VEGAM:
2985c99a2e7aSAlex Deucher 		device_queue_manager_init_vi(&dqm->asic_ops);
298697672cbeSFelix Kuehling 		break;
2987bed4f110SFelix Kuehling 
2988e596b903SYong Zhao 	default:
298947fa09b7SDavid Belanger 		if (KFD_GC_VERSION(dev) >= IP_VERSION(12, 0, 0))
299047fa09b7SDavid Belanger 			device_queue_manager_init_v12(&dqm->asic_ops);
299147fa09b7SDavid Belanger 		else if (KFD_GC_VERSION(dev) >= IP_VERSION(11, 0, 0))
2992cc009e61SMukul Joshi 			device_queue_manager_init_v11(&dqm->asic_ops);
2993cc009e61SMukul Joshi 		else if (KFD_GC_VERSION(dev) >= IP_VERSION(10, 1, 1))
299480e28aafSAlex Deucher 			device_queue_manager_init_v10(&dqm->asic_ops);
2995e4804a39SGraham Sider 		else if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 0, 1))
2996e4804a39SGraham Sider 			device_queue_manager_init_v9(&dqm->asic_ops);
2997e4804a39SGraham Sider 		else {
2998e596b903SYong Zhao 			WARN(1, "Unexpected ASIC family %u",
29997eb0502aSGraham Sider 			     dev->adev->asic_type);
3000e596b903SYong Zhao 			goto out_free;
3001a22fc854SBen Goz 		}
3002e4804a39SGraham Sider 	}
3003a22fc854SBen Goz 
3004fdfa090bSOak Zeng 	if (init_mqd_managers(dqm))
3005fdfa090bSOak Zeng 		goto out_free;
3006fdfa090bSOak Zeng 
30078dc1db31SMukul Joshi 	if (!dev->kfd->shared_resources.enable_mes && allocate_hiq_sdma_mqd(dqm)) {
300880c74918SAsad Kamal 		dev_err(dev->adev->dev, "Failed to allocate hiq sdma mqd trunk buffer\n");
300911614c36SOak Zeng 		goto out_free;
301011614c36SOak Zeng 	}
301111614c36SOak Zeng 
3012a70a93faSJonathan Kim 	if (!dqm->ops.initialize(dqm)) {
3013a70a93faSJonathan Kim 		init_waitqueue_head(&dqm->destroy_wait);
301432fa8219SFelix Kuehling 		return dqm;
3015a70a93faSJonathan Kim 	}
301632fa8219SFelix Kuehling 
301732fa8219SFelix Kuehling out_free:
301864c7f8cfSBen Goz 	kfree(dqm);
301964c7f8cfSBen Goz 	return NULL;
302064c7f8cfSBen Goz }
302164c7f8cfSBen Goz 
deallocate_hiq_sdma_mqd(struct kfd_node * dev,struct kfd_mem_obj * mqd)30228dc1db31SMukul Joshi static void deallocate_hiq_sdma_mqd(struct kfd_node *dev,
30237fd5a6fbSYueHaibing 				    struct kfd_mem_obj *mqd)
302411614c36SOak Zeng {
302511614c36SOak Zeng 	WARN(!mqd, "No hiq sdma mqd trunk to free");
302611614c36SOak Zeng 
3027c86ad391SPhilip Yang 	amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem);
302811614c36SOak Zeng }
302911614c36SOak Zeng 
device_queue_manager_uninit(struct device_queue_manager * dqm)303064c7f8cfSBen Goz void device_queue_manager_uninit(struct device_queue_manager *dqm)
303164c7f8cfSBen Goz {
30325e406012SMukul Joshi 	dqm->ops.stop(dqm);
303345c9a5e4SOded Gabbay 	dqm->ops.uninitialize(dqm);
30348dc1db31SMukul Joshi 	if (!dqm->dev->kfd->shared_resources.enable_mes)
303511614c36SOak Zeng 		deallocate_hiq_sdma_mqd(dqm->dev, &dqm->hiq_sdma_mqd);
303664c7f8cfSBen Goz 	kfree(dqm);
303764c7f8cfSBen Goz }
3038851a645eSFelix Kuehling 
kfd_dqm_suspend_bad_queue_mes(struct kfd_node * knode,u32 pasid,u32 doorbell_id)3039eb067d65SMukul Joshi int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbell_id)
3040eb067d65SMukul Joshi {
30418544374cSXiaogang Chen 	struct kfd_process_device *pdd = NULL;
30428544374cSXiaogang Chen 	struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, &pdd);
3043eb067d65SMukul Joshi 	struct device_queue_manager *dqm = knode->dqm;
3044eb067d65SMukul Joshi 	struct device *dev = dqm->dev->adev->dev;
3045eb067d65SMukul Joshi 	struct qcm_process_device *qpd;
3046eb067d65SMukul Joshi 	struct queue *q = NULL;
3047eb067d65SMukul Joshi 	int ret = 0;
3048eb067d65SMukul Joshi 
30498544374cSXiaogang Chen 	if (!pdd)
3050eb067d65SMukul Joshi 		return -EINVAL;
3051eb067d65SMukul Joshi 
3052eb067d65SMukul Joshi 	dqm_lock(dqm);
3053eb067d65SMukul Joshi 
3054eb067d65SMukul Joshi 	if (pdd) {
3055eb067d65SMukul Joshi 		qpd = &pdd->qpd;
3056eb067d65SMukul Joshi 
3057eb067d65SMukul Joshi 		list_for_each_entry(q, &qpd->queues_list, list) {
3058eb067d65SMukul Joshi 			if (q->doorbell_id == doorbell_id && q->properties.is_active) {
3059eb067d65SMukul Joshi 				ret = suspend_all_queues_mes(dqm);
3060eb067d65SMukul Joshi 				if (ret) {
3061eb067d65SMukul Joshi 					dev_err(dev, "Suspending all queues failed");
3062eb067d65SMukul Joshi 					goto out;
3063eb067d65SMukul Joshi 				}
3064eb067d65SMukul Joshi 
3065eb067d65SMukul Joshi 				q->properties.is_evicted = true;
3066eb067d65SMukul Joshi 				q->properties.is_active = false;
3067eb067d65SMukul Joshi 				decrement_queue_count(dqm, qpd, q);
3068eb067d65SMukul Joshi 
3069eb067d65SMukul Joshi 				ret = remove_queue_mes(dqm, q, qpd);
3070eb067d65SMukul Joshi 				if (ret) {
3071eb067d65SMukul Joshi 					dev_err(dev, "Removing bad queue failed");
3072eb067d65SMukul Joshi 					goto out;
3073eb067d65SMukul Joshi 				}
3074eb067d65SMukul Joshi 
3075eb067d65SMukul Joshi 				ret = resume_all_queues_mes(dqm);
3076eb067d65SMukul Joshi 				if (ret)
3077eb067d65SMukul Joshi 					dev_err(dev, "Resuming all queues failed");
3078eb067d65SMukul Joshi 
3079eb067d65SMukul Joshi 				break;
3080eb067d65SMukul Joshi 			}
3081eb067d65SMukul Joshi 		}
3082eb067d65SMukul Joshi 	}
3083eb067d65SMukul Joshi 
3084eb067d65SMukul Joshi out:
3085eb067d65SMukul Joshi 	dqm_unlock(dqm);
30868544374cSXiaogang Chen 	kfd_unref_process(p);
3087eb067d65SMukul Joshi 	return ret;
3088eb067d65SMukul Joshi }
3089eb067d65SMukul Joshi 
kfd_dqm_evict_pasid_mes(struct device_queue_manager * dqm,struct qcm_process_device * qpd)30909a16042fSMukul Joshi static int kfd_dqm_evict_pasid_mes(struct device_queue_manager *dqm,
30919a16042fSMukul Joshi 				   struct qcm_process_device *qpd)
30929a16042fSMukul Joshi {
30939a16042fSMukul Joshi 	struct device *dev = dqm->dev->adev->dev;
30949a16042fSMukul Joshi 	int ret = 0;
30959a16042fSMukul Joshi 
30969a16042fSMukul Joshi 	/* Check if process is already evicted */
30979a16042fSMukul Joshi 	dqm_lock(dqm);
30989a16042fSMukul Joshi 	if (qpd->evicted) {
30999a16042fSMukul Joshi 		/* Increment the evicted count to make sure the
31009a16042fSMukul Joshi 		 * process stays evicted before its terminated.
31019a16042fSMukul Joshi 		 */
31029a16042fSMukul Joshi 		qpd->evicted++;
31039a16042fSMukul Joshi 		dqm_unlock(dqm);
31049a16042fSMukul Joshi 		goto out;
31059a16042fSMukul Joshi 	}
31069a16042fSMukul Joshi 	dqm_unlock(dqm);
31079a16042fSMukul Joshi 
31089a16042fSMukul Joshi 	ret = suspend_all_queues_mes(dqm);
31099a16042fSMukul Joshi 	if (ret) {
31109a16042fSMukul Joshi 		dev_err(dev, "Suspending all queues failed");
31119a16042fSMukul Joshi 		goto out;
31129a16042fSMukul Joshi 	}
31139a16042fSMukul Joshi 
31149a16042fSMukul Joshi 	ret = dqm->ops.evict_process_queues(dqm, qpd);
31159a16042fSMukul Joshi 	if (ret) {
31169a16042fSMukul Joshi 		dev_err(dev, "Evicting process queues failed");
31179a16042fSMukul Joshi 		goto out;
31189a16042fSMukul Joshi 	}
31199a16042fSMukul Joshi 
31209a16042fSMukul Joshi 	ret = resume_all_queues_mes(dqm);
31219a16042fSMukul Joshi 	if (ret)
31229a16042fSMukul Joshi 		dev_err(dev, "Resuming all queues failed");
31239a16042fSMukul Joshi 
31249a16042fSMukul Joshi out:
31259a16042fSMukul Joshi 	return ret;
31269a16042fSMukul Joshi }
31279a16042fSMukul Joshi 
kfd_evict_process_device(struct kfd_process_device * pdd)31288544374cSXiaogang Chen int kfd_evict_process_device(struct kfd_process_device *pdd)
31292640c3faSshaoyunl {
31308544374cSXiaogang Chen 	struct device_queue_manager *dqm;
31318544374cSXiaogang Chen 	struct kfd_process *p;
31322640c3faSshaoyunl 	int ret = 0;
31332640c3faSshaoyunl 
31348544374cSXiaogang Chen 	p = pdd->process;
31358544374cSXiaogang Chen 	dqm = pdd->dev->dqm;
31368544374cSXiaogang Chen 
31378a491bb3SPhilip Cox 	WARN(debug_evictions, "Evicting pid %d", p->lead_thread->pid);
31388544374cSXiaogang Chen 
31399a16042fSMukul Joshi 	if (dqm->dev->kfd->shared_resources.enable_mes)
31409a16042fSMukul Joshi 		ret = kfd_dqm_evict_pasid_mes(dqm, &pdd->qpd);
31419a16042fSMukul Joshi 	else
31422640c3faSshaoyunl 		ret = dqm->ops.evict_process_queues(dqm, &pdd->qpd);
31432640c3faSshaoyunl 
31442640c3faSshaoyunl 	return ret;
31452640c3faSshaoyunl }
31462640c3faSshaoyunl 
reserve_debug_trap_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd)314797ae3c8cSJonathan Kim int reserve_debug_trap_vmid(struct device_queue_manager *dqm,
314897ae3c8cSJonathan Kim 				struct qcm_process_device *qpd)
314997ae3c8cSJonathan Kim {
315097ae3c8cSJonathan Kim 	int r;
315180c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
315297ae3c8cSJonathan Kim 	int updated_vmid_mask;
315397ae3c8cSJonathan Kim 
315497ae3c8cSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
315580c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
315697ae3c8cSJonathan Kim 		return -EINVAL;
315797ae3c8cSJonathan Kim 	}
315897ae3c8cSJonathan Kim 
315997ae3c8cSJonathan Kim 	dqm_lock(dqm);
316097ae3c8cSJonathan Kim 
316197ae3c8cSJonathan Kim 	if (dqm->trap_debug_vmid != 0) {
316280c74918SAsad Kamal 		dev_err(dev, "Trap debug id already reserved\n");
316397ae3c8cSJonathan Kim 		r = -EBUSY;
316497ae3c8cSJonathan Kim 		goto out_unlock;
316597ae3c8cSJonathan Kim 	}
316697ae3c8cSJonathan Kim 
316797ae3c8cSJonathan Kim 	r = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
316897ae3c8cSJonathan Kim 			USE_DEFAULT_GRACE_PERIOD, false);
316997ae3c8cSJonathan Kim 	if (r)
317097ae3c8cSJonathan Kim 		goto out_unlock;
317197ae3c8cSJonathan Kim 
317297ae3c8cSJonathan Kim 	updated_vmid_mask = dqm->dev->kfd->shared_resources.compute_vmid_bitmap;
317397ae3c8cSJonathan Kim 	updated_vmid_mask &= ~(1 << dqm->dev->vm_info.last_vmid_kfd);
317497ae3c8cSJonathan Kim 
317597ae3c8cSJonathan Kim 	dqm->dev->kfd->shared_resources.compute_vmid_bitmap = updated_vmid_mask;
317697ae3c8cSJonathan Kim 	dqm->trap_debug_vmid = dqm->dev->vm_info.last_vmid_kfd;
317797ae3c8cSJonathan Kim 	r = set_sched_resources(dqm);
317897ae3c8cSJonathan Kim 	if (r)
317997ae3c8cSJonathan Kim 		goto out_unlock;
318097ae3c8cSJonathan Kim 
318197ae3c8cSJonathan Kim 	r = map_queues_cpsch(dqm);
318297ae3c8cSJonathan Kim 	if (r)
318397ae3c8cSJonathan Kim 		goto out_unlock;
318497ae3c8cSJonathan Kim 
318597ae3c8cSJonathan Kim 	pr_debug("Reserved VMID for trap debug: %i\n", dqm->trap_debug_vmid);
318697ae3c8cSJonathan Kim 
318797ae3c8cSJonathan Kim out_unlock:
318897ae3c8cSJonathan Kim 	dqm_unlock(dqm);
318997ae3c8cSJonathan Kim 	return r;
319097ae3c8cSJonathan Kim }
319197ae3c8cSJonathan Kim 
319297ae3c8cSJonathan Kim /*
319397ae3c8cSJonathan Kim  * Releases vmid for the trap debugger
319497ae3c8cSJonathan Kim  */
release_debug_trap_vmid(struct device_queue_manager * dqm,struct qcm_process_device * qpd)319597ae3c8cSJonathan Kim int release_debug_trap_vmid(struct device_queue_manager *dqm,
319697ae3c8cSJonathan Kim 			struct qcm_process_device *qpd)
319797ae3c8cSJonathan Kim {
319880c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
319997ae3c8cSJonathan Kim 	int r;
320097ae3c8cSJonathan Kim 	int updated_vmid_mask;
320197ae3c8cSJonathan Kim 	uint32_t trap_debug_vmid;
320297ae3c8cSJonathan Kim 
320397ae3c8cSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
320480c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
320597ae3c8cSJonathan Kim 		return -EINVAL;
320697ae3c8cSJonathan Kim 	}
320797ae3c8cSJonathan Kim 
320897ae3c8cSJonathan Kim 	dqm_lock(dqm);
320997ae3c8cSJonathan Kim 	trap_debug_vmid = dqm->trap_debug_vmid;
321097ae3c8cSJonathan Kim 	if (dqm->trap_debug_vmid == 0) {
321180c74918SAsad Kamal 		dev_err(dev, "Trap debug id is not reserved\n");
321297ae3c8cSJonathan Kim 		r = -EINVAL;
321397ae3c8cSJonathan Kim 		goto out_unlock;
321497ae3c8cSJonathan Kim 	}
321597ae3c8cSJonathan Kim 
321697ae3c8cSJonathan Kim 	r = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0,
321797ae3c8cSJonathan Kim 			USE_DEFAULT_GRACE_PERIOD, false);
321897ae3c8cSJonathan Kim 	if (r)
321997ae3c8cSJonathan Kim 		goto out_unlock;
322097ae3c8cSJonathan Kim 
322197ae3c8cSJonathan Kim 	updated_vmid_mask = dqm->dev->kfd->shared_resources.compute_vmid_bitmap;
322297ae3c8cSJonathan Kim 	updated_vmid_mask |= (1 << dqm->dev->vm_info.last_vmid_kfd);
322397ae3c8cSJonathan Kim 
322497ae3c8cSJonathan Kim 	dqm->dev->kfd->shared_resources.compute_vmid_bitmap = updated_vmid_mask;
322597ae3c8cSJonathan Kim 	dqm->trap_debug_vmid = 0;
322697ae3c8cSJonathan Kim 	r = set_sched_resources(dqm);
322797ae3c8cSJonathan Kim 	if (r)
322897ae3c8cSJonathan Kim 		goto out_unlock;
322997ae3c8cSJonathan Kim 
323097ae3c8cSJonathan Kim 	r = map_queues_cpsch(dqm);
323197ae3c8cSJonathan Kim 	if (r)
323297ae3c8cSJonathan Kim 		goto out_unlock;
323397ae3c8cSJonathan Kim 
323497ae3c8cSJonathan Kim 	pr_debug("Released VMID for trap debug: %i\n", trap_debug_vmid);
323597ae3c8cSJonathan Kim 
323697ae3c8cSJonathan Kim out_unlock:
323797ae3c8cSJonathan Kim 	dqm_unlock(dqm);
323897ae3c8cSJonathan Kim 	return r;
323997ae3c8cSJonathan Kim }
324097ae3c8cSJonathan Kim 
3241a70a93faSJonathan Kim #define QUEUE_NOT_FOUND		-1
3242a70a93faSJonathan Kim /* invalidate queue operation in array */
q_array_invalidate(uint32_t num_queues,uint32_t * queue_ids)3243a70a93faSJonathan Kim static void q_array_invalidate(uint32_t num_queues, uint32_t *queue_ids)
3244a70a93faSJonathan Kim {
3245a70a93faSJonathan Kim 	int i;
3246a70a93faSJonathan Kim 
3247a70a93faSJonathan Kim 	for (i = 0; i < num_queues; i++)
3248a70a93faSJonathan Kim 		queue_ids[i] |= KFD_DBG_QUEUE_INVALID_MASK;
3249a70a93faSJonathan Kim }
3250a70a93faSJonathan Kim 
3251a70a93faSJonathan Kim /* find queue index in array */
q_array_get_index(unsigned int queue_id,uint32_t num_queues,uint32_t * queue_ids)3252a70a93faSJonathan Kim static int q_array_get_index(unsigned int queue_id,
3253a70a93faSJonathan Kim 		uint32_t num_queues,
3254a70a93faSJonathan Kim 		uint32_t *queue_ids)
3255a70a93faSJonathan Kim {
3256a70a93faSJonathan Kim 	int i;
3257a70a93faSJonathan Kim 
3258a70a93faSJonathan Kim 	for (i = 0; i < num_queues; i++)
3259a70a93faSJonathan Kim 		if (queue_id == (queue_ids[i] & ~KFD_DBG_QUEUE_INVALID_MASK))
3260a70a93faSJonathan Kim 			return i;
3261a70a93faSJonathan Kim 
3262a70a93faSJonathan Kim 	return QUEUE_NOT_FOUND;
3263a70a93faSJonathan Kim }
3264a70a93faSJonathan Kim 
3265a70a93faSJonathan Kim struct copy_context_work_handler_workarea {
3266a70a93faSJonathan Kim 	struct work_struct copy_context_work;
3267a70a93faSJonathan Kim 	struct kfd_process *p;
3268a70a93faSJonathan Kim };
3269a70a93faSJonathan Kim 
copy_context_work_handler(struct work_struct * work)3270a70a93faSJonathan Kim static void copy_context_work_handler(struct work_struct *work)
3271a70a93faSJonathan Kim {
3272a70a93faSJonathan Kim 	struct copy_context_work_handler_workarea *workarea;
3273a70a93faSJonathan Kim 	struct mqd_manager *mqd_mgr;
3274a70a93faSJonathan Kim 	struct queue *q;
3275a70a93faSJonathan Kim 	struct mm_struct *mm;
3276a70a93faSJonathan Kim 	struct kfd_process *p;
3277a70a93faSJonathan Kim 	uint32_t tmp_ctl_stack_used_size, tmp_save_area_used_size;
3278a70a93faSJonathan Kim 	int i;
3279a70a93faSJonathan Kim 
3280a70a93faSJonathan Kim 	workarea = container_of(work,
3281a70a93faSJonathan Kim 			struct copy_context_work_handler_workarea,
3282a70a93faSJonathan Kim 			copy_context_work);
3283a70a93faSJonathan Kim 
3284a70a93faSJonathan Kim 	p = workarea->p;
3285a70a93faSJonathan Kim 	mm = get_task_mm(p->lead_thread);
3286a70a93faSJonathan Kim 
3287a70a93faSJonathan Kim 	if (!mm)
3288a70a93faSJonathan Kim 		return;
3289a70a93faSJonathan Kim 
3290a70a93faSJonathan Kim 	kthread_use_mm(mm);
3291a70a93faSJonathan Kim 	for (i = 0; i < p->n_pdds; i++) {
3292a70a93faSJonathan Kim 		struct kfd_process_device *pdd = p->pdds[i];
3293a70a93faSJonathan Kim 		struct device_queue_manager *dqm = pdd->dev->dqm;
3294a70a93faSJonathan Kim 		struct qcm_process_device *qpd = &pdd->qpd;
3295a70a93faSJonathan Kim 
3296a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3297dafc87dcSPhilip Yang 			if (q->properties.type != KFD_QUEUE_TYPE_COMPUTE)
3298dafc87dcSPhilip Yang 				continue;
3299dafc87dcSPhilip Yang 
3300a70a93faSJonathan Kim 			mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_CP];
3301a70a93faSJonathan Kim 
3302a70a93faSJonathan Kim 			/* We ignore the return value from get_wave_state
3303a70a93faSJonathan Kim 			 * because
3304a70a93faSJonathan Kim 			 * i) right now, it always returns 0, and
3305a70a93faSJonathan Kim 			 * ii) if we hit an error, we would continue to the
3306a70a93faSJonathan Kim 			 *      next queue anyway.
3307a70a93faSJonathan Kim 			 */
3308a70a93faSJonathan Kim 			mqd_mgr->get_wave_state(mqd_mgr,
3309a70a93faSJonathan Kim 					q->mqd,
3310a70a93faSJonathan Kim 					&q->properties,
3311a70a93faSJonathan Kim 					(void __user *)	q->properties.ctx_save_restore_area_address,
3312a70a93faSJonathan Kim 					&tmp_ctl_stack_used_size,
3313a70a93faSJonathan Kim 					&tmp_save_area_used_size);
3314a70a93faSJonathan Kim 		}
3315a70a93faSJonathan Kim 	}
3316a70a93faSJonathan Kim 	kthread_unuse_mm(mm);
3317a70a93faSJonathan Kim 	mmput(mm);
3318a70a93faSJonathan Kim }
3319a70a93faSJonathan Kim 
get_queue_ids(uint32_t num_queues,uint32_t * usr_queue_id_array)3320a70a93faSJonathan Kim static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
3321a70a93faSJonathan Kim {
3322a70a93faSJonathan Kim 	size_t array_size = num_queues * sizeof(uint32_t);
3323a70a93faSJonathan Kim 
3324a70a93faSJonathan Kim 	if (!usr_queue_id_array)
3325a70a93faSJonathan Kim 		return NULL;
3326a70a93faSJonathan Kim 
3327bd6040b0SAtul Raut 	return memdup_user(usr_queue_id_array, array_size);
3328a70a93faSJonathan Kim }
3329a70a93faSJonathan Kim 
resume_queues(struct kfd_process * p,uint32_t num_queues,uint32_t * usr_queue_id_array)3330a70a93faSJonathan Kim int resume_queues(struct kfd_process *p,
3331a70a93faSJonathan Kim 		uint32_t num_queues,
3332a70a93faSJonathan Kim 		uint32_t *usr_queue_id_array)
3333a70a93faSJonathan Kim {
3334a70a93faSJonathan Kim 	uint32_t *queue_ids = NULL;
3335a70a93faSJonathan Kim 	int total_resumed = 0;
3336a70a93faSJonathan Kim 	int i;
3337a70a93faSJonathan Kim 
3338a70a93faSJonathan Kim 	if (usr_queue_id_array) {
3339a70a93faSJonathan Kim 		queue_ids = get_queue_ids(num_queues, usr_queue_id_array);
3340a70a93faSJonathan Kim 
3341a70a93faSJonathan Kim 		if (IS_ERR(queue_ids))
3342a70a93faSJonathan Kim 			return PTR_ERR(queue_ids);
3343a70a93faSJonathan Kim 
3344a70a93faSJonathan Kim 		/* mask all queues as invalid.  unmask per successful request */
3345a70a93faSJonathan Kim 		q_array_invalidate(num_queues, queue_ids);
3346a70a93faSJonathan Kim 	}
3347a70a93faSJonathan Kim 
3348a70a93faSJonathan Kim 	for (i = 0; i < p->n_pdds; i++) {
3349a70a93faSJonathan Kim 		struct kfd_process_device *pdd = p->pdds[i];
3350a70a93faSJonathan Kim 		struct device_queue_manager *dqm = pdd->dev->dqm;
335180c74918SAsad Kamal 		struct device *dev = dqm->dev->adev->dev;
3352a70a93faSJonathan Kim 		struct qcm_process_device *qpd = &pdd->qpd;
3353a70a93faSJonathan Kim 		struct queue *q;
3354a70a93faSJonathan Kim 		int r, per_device_resumed = 0;
3355a70a93faSJonathan Kim 
3356a70a93faSJonathan Kim 		dqm_lock(dqm);
3357a70a93faSJonathan Kim 
3358a70a93faSJonathan Kim 		/* unmask queues that resume or already resumed as valid */
3359a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3360a70a93faSJonathan Kim 			int q_idx = QUEUE_NOT_FOUND;
3361a70a93faSJonathan Kim 
3362a70a93faSJonathan Kim 			if (queue_ids)
3363a70a93faSJonathan Kim 				q_idx = q_array_get_index(
3364a70a93faSJonathan Kim 						q->properties.queue_id,
3365a70a93faSJonathan Kim 						num_queues,
3366a70a93faSJonathan Kim 						queue_ids);
3367a70a93faSJonathan Kim 
3368a70a93faSJonathan Kim 			if (!queue_ids || q_idx != QUEUE_NOT_FOUND) {
3369a70a93faSJonathan Kim 				int err = resume_single_queue(dqm, &pdd->qpd, q);
3370a70a93faSJonathan Kim 
3371a70a93faSJonathan Kim 				if (queue_ids) {
3372a70a93faSJonathan Kim 					if (!err) {
3373a70a93faSJonathan Kim 						queue_ids[q_idx] &=
3374a70a93faSJonathan Kim 							~KFD_DBG_QUEUE_INVALID_MASK;
3375a70a93faSJonathan Kim 					} else {
3376a70a93faSJonathan Kim 						queue_ids[q_idx] |=
3377a70a93faSJonathan Kim 							KFD_DBG_QUEUE_ERROR_MASK;
3378a70a93faSJonathan Kim 						break;
3379a70a93faSJonathan Kim 					}
3380a70a93faSJonathan Kim 				}
3381a70a93faSJonathan Kim 
3382a70a93faSJonathan Kim 				if (dqm->dev->kfd->shared_resources.enable_mes) {
3383a70a93faSJonathan Kim 					wake_up_all(&dqm->destroy_wait);
3384a70a93faSJonathan Kim 					if (!err)
3385a70a93faSJonathan Kim 						total_resumed++;
3386a70a93faSJonathan Kim 				} else {
3387a70a93faSJonathan Kim 					per_device_resumed++;
3388a70a93faSJonathan Kim 				}
3389a70a93faSJonathan Kim 			}
3390a70a93faSJonathan Kim 		}
3391a70a93faSJonathan Kim 
3392a70a93faSJonathan Kim 		if (!per_device_resumed) {
3393a70a93faSJonathan Kim 			dqm_unlock(dqm);
3394a70a93faSJonathan Kim 			continue;
3395a70a93faSJonathan Kim 		}
3396a70a93faSJonathan Kim 
3397a70a93faSJonathan Kim 		r = execute_queues_cpsch(dqm,
3398a70a93faSJonathan Kim 					KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES,
3399a70a93faSJonathan Kim 					0,
3400a70a93faSJonathan Kim 					USE_DEFAULT_GRACE_PERIOD);
3401a70a93faSJonathan Kim 		if (r) {
340280c74918SAsad Kamal 			dev_err(dev, "Failed to resume process queues\n");
3403a70a93faSJonathan Kim 			if (queue_ids) {
3404a70a93faSJonathan Kim 				list_for_each_entry(q, &qpd->queues_list, list) {
3405a70a93faSJonathan Kim 					int q_idx = q_array_get_index(
3406a70a93faSJonathan Kim 							q->properties.queue_id,
3407a70a93faSJonathan Kim 							num_queues,
3408a70a93faSJonathan Kim 							queue_ids);
3409a70a93faSJonathan Kim 
3410a70a93faSJonathan Kim 					/* mask queue as error on resume fail */
3411a70a93faSJonathan Kim 					if (q_idx != QUEUE_NOT_FOUND)
3412a70a93faSJonathan Kim 						queue_ids[q_idx] |=
3413a70a93faSJonathan Kim 							KFD_DBG_QUEUE_ERROR_MASK;
3414a70a93faSJonathan Kim 				}
3415a70a93faSJonathan Kim 			}
3416a70a93faSJonathan Kim 		} else {
3417a70a93faSJonathan Kim 			wake_up_all(&dqm->destroy_wait);
3418a70a93faSJonathan Kim 			total_resumed += per_device_resumed;
3419a70a93faSJonathan Kim 		}
3420a70a93faSJonathan Kim 
3421a70a93faSJonathan Kim 		dqm_unlock(dqm);
3422a70a93faSJonathan Kim 	}
3423a70a93faSJonathan Kim 
3424a70a93faSJonathan Kim 	if (queue_ids) {
3425a70a93faSJonathan Kim 		if (copy_to_user((void __user *)usr_queue_id_array, queue_ids,
3426a70a93faSJonathan Kim 				num_queues * sizeof(uint32_t)))
3427a70a93faSJonathan Kim 			pr_err("copy_to_user failed on queue resume\n");
3428a70a93faSJonathan Kim 
3429a70a93faSJonathan Kim 		kfree(queue_ids);
3430a70a93faSJonathan Kim 	}
3431a70a93faSJonathan Kim 
3432a70a93faSJonathan Kim 	return total_resumed;
3433a70a93faSJonathan Kim }
3434a70a93faSJonathan 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)3435a70a93faSJonathan Kim int suspend_queues(struct kfd_process *p,
3436a70a93faSJonathan Kim 			uint32_t num_queues,
3437a70a93faSJonathan Kim 			uint32_t grace_period,
3438a70a93faSJonathan Kim 			uint64_t exception_clear_mask,
3439a70a93faSJonathan Kim 			uint32_t *usr_queue_id_array)
3440a70a93faSJonathan Kim {
3441a70a93faSJonathan Kim 	uint32_t *queue_ids = get_queue_ids(num_queues, usr_queue_id_array);
3442a70a93faSJonathan Kim 	int total_suspended = 0;
3443a70a93faSJonathan Kim 	int i;
3444a70a93faSJonathan Kim 
3445a70a93faSJonathan Kim 	if (IS_ERR(queue_ids))
3446a70a93faSJonathan Kim 		return PTR_ERR(queue_ids);
3447a70a93faSJonathan Kim 
3448a70a93faSJonathan Kim 	/* mask all queues as invalid.  umask on successful request */
3449a70a93faSJonathan Kim 	q_array_invalidate(num_queues, queue_ids);
3450a70a93faSJonathan Kim 
3451a70a93faSJonathan Kim 	for (i = 0; i < p->n_pdds; i++) {
3452a70a93faSJonathan Kim 		struct kfd_process_device *pdd = p->pdds[i];
3453a70a93faSJonathan Kim 		struct device_queue_manager *dqm = pdd->dev->dqm;
345480c74918SAsad Kamal 		struct device *dev = dqm->dev->adev->dev;
3455a70a93faSJonathan Kim 		struct qcm_process_device *qpd = &pdd->qpd;
3456a70a93faSJonathan Kim 		struct queue *q;
3457a70a93faSJonathan Kim 		int r, per_device_suspended = 0;
3458a70a93faSJonathan Kim 
3459a70a93faSJonathan Kim 		mutex_lock(&p->event_mutex);
3460a70a93faSJonathan Kim 		dqm_lock(dqm);
3461a70a93faSJonathan Kim 
3462a70a93faSJonathan Kim 		/* unmask queues that suspend or already suspended */
3463a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3464a70a93faSJonathan Kim 			int q_idx = q_array_get_index(q->properties.queue_id,
3465a70a93faSJonathan Kim 							num_queues,
3466a70a93faSJonathan Kim 							queue_ids);
3467a70a93faSJonathan Kim 
3468a70a93faSJonathan Kim 			if (q_idx != QUEUE_NOT_FOUND) {
3469a70a93faSJonathan Kim 				int err = suspend_single_queue(dqm, pdd, q);
3470a70a93faSJonathan Kim 				bool is_mes = dqm->dev->kfd->shared_resources.enable_mes;
3471a70a93faSJonathan Kim 
3472a70a93faSJonathan Kim 				if (!err) {
3473a70a93faSJonathan Kim 					queue_ids[q_idx] &= ~KFD_DBG_QUEUE_INVALID_MASK;
3474a70a93faSJonathan Kim 					if (exception_clear_mask && is_mes)
3475a70a93faSJonathan Kim 						q->properties.exception_status &=
3476a70a93faSJonathan Kim 							~exception_clear_mask;
3477a70a93faSJonathan Kim 
3478a70a93faSJonathan Kim 					if (is_mes)
3479a70a93faSJonathan Kim 						total_suspended++;
3480a70a93faSJonathan Kim 					else
3481a70a93faSJonathan Kim 						per_device_suspended++;
3482a70a93faSJonathan Kim 				} else if (err != -EBUSY) {
3483a70a93faSJonathan Kim 					r = err;
3484a70a93faSJonathan Kim 					queue_ids[q_idx] |= KFD_DBG_QUEUE_ERROR_MASK;
3485a70a93faSJonathan Kim 					break;
3486a70a93faSJonathan Kim 				}
3487a70a93faSJonathan Kim 			}
3488a70a93faSJonathan Kim 		}
3489a70a93faSJonathan Kim 
3490a70a93faSJonathan Kim 		if (!per_device_suspended) {
3491a70a93faSJonathan Kim 			dqm_unlock(dqm);
3492a70a93faSJonathan Kim 			mutex_unlock(&p->event_mutex);
3493a70a93faSJonathan Kim 			if (total_suspended)
3494a70a93faSJonathan Kim 				amdgpu_amdkfd_debug_mem_fence(dqm->dev->adev);
3495a70a93faSJonathan Kim 			continue;
3496a70a93faSJonathan Kim 		}
3497a70a93faSJonathan Kim 
3498a70a93faSJonathan Kim 		r = execute_queues_cpsch(dqm,
3499a70a93faSJonathan Kim 			KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0,
3500a70a93faSJonathan Kim 			grace_period);
3501a70a93faSJonathan Kim 
3502a70a93faSJonathan Kim 		if (r)
350380c74918SAsad Kamal 			dev_err(dev, "Failed to suspend process queues.\n");
3504a70a93faSJonathan Kim 		else
3505a70a93faSJonathan Kim 			total_suspended += per_device_suspended;
3506a70a93faSJonathan Kim 
3507a70a93faSJonathan Kim 		list_for_each_entry(q, &qpd->queues_list, list) {
3508a70a93faSJonathan Kim 			int q_idx = q_array_get_index(q->properties.queue_id,
3509a70a93faSJonathan Kim 						num_queues, queue_ids);
3510a70a93faSJonathan Kim 
3511a70a93faSJonathan Kim 			if (q_idx == QUEUE_NOT_FOUND)
3512a70a93faSJonathan Kim 				continue;
3513a70a93faSJonathan Kim 
3514a70a93faSJonathan Kim 			/* mask queue as error on suspend fail */
3515a70a93faSJonathan Kim 			if (r)
3516a70a93faSJonathan Kim 				queue_ids[q_idx] |= KFD_DBG_QUEUE_ERROR_MASK;
3517a70a93faSJonathan Kim 			else if (exception_clear_mask)
3518a70a93faSJonathan Kim 				q->properties.exception_status &=
3519a70a93faSJonathan Kim 							~exception_clear_mask;
3520a70a93faSJonathan Kim 		}
3521a70a93faSJonathan Kim 
3522a70a93faSJonathan Kim 		dqm_unlock(dqm);
3523a70a93faSJonathan Kim 		mutex_unlock(&p->event_mutex);
3524a70a93faSJonathan Kim 		amdgpu_device_flush_hdp(dqm->dev->adev, NULL);
3525a70a93faSJonathan Kim 	}
3526a70a93faSJonathan Kim 
3527a70a93faSJonathan Kim 	if (total_suspended) {
3528a70a93faSJonathan Kim 		struct copy_context_work_handler_workarea copy_context_worker;
3529a70a93faSJonathan Kim 
3530a70a93faSJonathan Kim 		INIT_WORK_ONSTACK(
3531a70a93faSJonathan Kim 				&copy_context_worker.copy_context_work,
3532a70a93faSJonathan Kim 				copy_context_work_handler);
3533a70a93faSJonathan Kim 
3534a70a93faSJonathan Kim 		copy_context_worker.p = p;
3535a70a93faSJonathan Kim 
3536a70a93faSJonathan Kim 		schedule_work(&copy_context_worker.copy_context_work);
3537a70a93faSJonathan Kim 
3538a70a93faSJonathan Kim 
3539a70a93faSJonathan Kim 		flush_work(&copy_context_worker.copy_context_work);
3540a70a93faSJonathan Kim 		destroy_work_on_stack(&copy_context_worker.copy_context_work);
3541a70a93faSJonathan Kim 	}
3542a70a93faSJonathan Kim 
3543a70a93faSJonathan Kim 	if (copy_to_user((void __user *)usr_queue_id_array, queue_ids,
3544a70a93faSJonathan Kim 			num_queues * sizeof(uint32_t)))
3545a70a93faSJonathan Kim 		pr_err("copy_to_user failed on queue suspend\n");
3546a70a93faSJonathan Kim 
3547a70a93faSJonathan Kim 	kfree(queue_ids);
3548a70a93faSJonathan Kim 
3549a70a93faSJonathan Kim 	return total_suspended;
3550a70a93faSJonathan Kim }
3551a70a93faSJonathan Kim 
set_queue_type_for_user(struct queue_properties * q_props)3552b17bd5dbSJonathan Kim static uint32_t set_queue_type_for_user(struct queue_properties *q_props)
3553b17bd5dbSJonathan Kim {
3554b17bd5dbSJonathan Kim 	switch (q_props->type) {
3555b17bd5dbSJonathan Kim 	case KFD_QUEUE_TYPE_COMPUTE:
3556b17bd5dbSJonathan Kim 		return q_props->format == KFD_QUEUE_FORMAT_PM4
3557b17bd5dbSJonathan Kim 					? KFD_IOC_QUEUE_TYPE_COMPUTE
3558b17bd5dbSJonathan Kim 					: KFD_IOC_QUEUE_TYPE_COMPUTE_AQL;
3559b17bd5dbSJonathan Kim 	case KFD_QUEUE_TYPE_SDMA:
3560b17bd5dbSJonathan Kim 		return KFD_IOC_QUEUE_TYPE_SDMA;
3561b17bd5dbSJonathan Kim 	case KFD_QUEUE_TYPE_SDMA_XGMI:
3562b17bd5dbSJonathan Kim 		return KFD_IOC_QUEUE_TYPE_SDMA_XGMI;
3563b17bd5dbSJonathan Kim 	default:
3564b17bd5dbSJonathan Kim 		WARN_ONCE(true, "queue type not recognized!");
3565b17bd5dbSJonathan Kim 		return 0xffffffff;
3566b17bd5dbSJonathan Kim 	};
3567b17bd5dbSJonathan Kim }
3568b17bd5dbSJonathan Kim 
set_queue_snapshot_entry(struct queue * q,uint64_t exception_clear_mask,struct kfd_queue_snapshot_entry * qss_entry)3569b17bd5dbSJonathan Kim void set_queue_snapshot_entry(struct queue *q,
3570b17bd5dbSJonathan Kim 			      uint64_t exception_clear_mask,
3571b17bd5dbSJonathan Kim 			      struct kfd_queue_snapshot_entry *qss_entry)
3572b17bd5dbSJonathan Kim {
3573b17bd5dbSJonathan Kim 	qss_entry->ring_base_address = q->properties.queue_address;
3574b17bd5dbSJonathan Kim 	qss_entry->write_pointer_address = (uint64_t)q->properties.write_ptr;
3575b17bd5dbSJonathan Kim 	qss_entry->read_pointer_address = (uint64_t)q->properties.read_ptr;
3576b17bd5dbSJonathan Kim 	qss_entry->ctx_save_restore_address =
3577b17bd5dbSJonathan Kim 				q->properties.ctx_save_restore_area_address;
3578b17bd5dbSJonathan Kim 	qss_entry->ctx_save_restore_area_size =
3579b17bd5dbSJonathan Kim 				q->properties.ctx_save_restore_area_size;
3580b17bd5dbSJonathan Kim 	qss_entry->exception_status = q->properties.exception_status;
3581b17bd5dbSJonathan Kim 	qss_entry->queue_id = q->properties.queue_id;
3582b17bd5dbSJonathan Kim 	qss_entry->gpu_id = q->device->id;
3583b17bd5dbSJonathan Kim 	qss_entry->ring_size = (uint32_t)q->properties.queue_size;
3584b17bd5dbSJonathan Kim 	qss_entry->queue_type = set_queue_type_for_user(&q->properties);
3585b17bd5dbSJonathan Kim 	q->properties.exception_status &= ~exception_clear_mask;
3586b17bd5dbSJonathan Kim }
3587b17bd5dbSJonathan Kim 
debug_lock_and_unmap(struct device_queue_manager * dqm)35880de4ec9aSJonathan Kim int debug_lock_and_unmap(struct device_queue_manager *dqm)
35890de4ec9aSJonathan Kim {
359080c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
35910de4ec9aSJonathan Kim 	int r;
35920de4ec9aSJonathan Kim 
35930de4ec9aSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
359480c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
35950de4ec9aSJonathan Kim 		return -EINVAL;
35960de4ec9aSJonathan Kim 	}
35970de4ec9aSJonathan Kim 
35980de4ec9aSJonathan Kim 	if (!kfd_dbg_is_per_vmid_supported(dqm->dev))
35990de4ec9aSJonathan Kim 		return 0;
36000de4ec9aSJonathan Kim 
36010de4ec9aSJonathan Kim 	dqm_lock(dqm);
36020de4ec9aSJonathan Kim 
36030de4ec9aSJonathan Kim 	r = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0, 0, false);
36040de4ec9aSJonathan Kim 	if (r)
36050de4ec9aSJonathan Kim 		dqm_unlock(dqm);
36060de4ec9aSJonathan Kim 
36070de4ec9aSJonathan Kim 	return r;
36080de4ec9aSJonathan Kim }
36090de4ec9aSJonathan Kim 
debug_map_and_unlock(struct device_queue_manager * dqm)36100de4ec9aSJonathan Kim int debug_map_and_unlock(struct device_queue_manager *dqm)
36110de4ec9aSJonathan Kim {
361280c74918SAsad Kamal 	struct device *dev = dqm->dev->adev->dev;
36130de4ec9aSJonathan Kim 	int r;
36140de4ec9aSJonathan Kim 
36150de4ec9aSJonathan Kim 	if (dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
361680c74918SAsad Kamal 		dev_err(dev, "Unsupported on sched_policy: %i\n", dqm->sched_policy);
36170de4ec9aSJonathan Kim 		return -EINVAL;
36180de4ec9aSJonathan Kim 	}
36190de4ec9aSJonathan Kim 
36200de4ec9aSJonathan Kim 	if (!kfd_dbg_is_per_vmid_supported(dqm->dev))
36210de4ec9aSJonathan Kim 		return 0;
36220de4ec9aSJonathan Kim 
36230de4ec9aSJonathan Kim 	r = map_queues_cpsch(dqm);
36240de4ec9aSJonathan Kim 
36250de4ec9aSJonathan Kim 	dqm_unlock(dqm);
36260de4ec9aSJonathan Kim 
36270de4ec9aSJonathan Kim 	return r;
36280de4ec9aSJonathan Kim }
36290de4ec9aSJonathan Kim 
debug_refresh_runlist(struct device_queue_manager * dqm)36300de4ec9aSJonathan Kim int debug_refresh_runlist(struct device_queue_manager *dqm)
36310de4ec9aSJonathan Kim {
36320de4ec9aSJonathan Kim 	int r = debug_lock_and_unmap(dqm);
36330de4ec9aSJonathan Kim 
36340de4ec9aSJonathan Kim 	if (r)
36350de4ec9aSJonathan Kim 		return r;
36360de4ec9aSJonathan Kim 
36370de4ec9aSJonathan Kim 	return debug_map_and_unlock(dqm);
36380de4ec9aSJonathan Kim }
36390de4ec9aSJonathan Kim 
kfd_dqm_is_queue_in_process(struct device_queue_manager * dqm,struct qcm_process_device * qpd,int doorbell_off,u32 * queue_format)36406ae9e1abSMukul Joshi bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm,
36416ae9e1abSMukul Joshi 				 struct qcm_process_device *qpd,
3642e45b011dSMukul Joshi 				 int doorbell_off, u32 *queue_format)
36436ae9e1abSMukul Joshi {
36446ae9e1abSMukul Joshi 	struct queue *q;
36456ae9e1abSMukul Joshi 	bool r = false;
36466ae9e1abSMukul Joshi 
3647e45b011dSMukul Joshi 	if (!queue_format)
3648e45b011dSMukul Joshi 		return r;
3649e45b011dSMukul Joshi 
36506ae9e1abSMukul Joshi 	dqm_lock(dqm);
36516ae9e1abSMukul Joshi 
36526ae9e1abSMukul Joshi 	list_for_each_entry(q, &qpd->queues_list, list) {
36536ae9e1abSMukul Joshi 		if (q->properties.doorbell_off == doorbell_off) {
3654e45b011dSMukul Joshi 			*queue_format = q->properties.format;
36556ae9e1abSMukul Joshi 			r = true;
36566ae9e1abSMukul Joshi 			goto out;
36576ae9e1abSMukul Joshi 		}
36586ae9e1abSMukul Joshi 	}
36596ae9e1abSMukul Joshi 
36606ae9e1abSMukul Joshi out:
36616ae9e1abSMukul Joshi 	dqm_unlock(dqm);
36626ae9e1abSMukul Joshi 	return r;
36636ae9e1abSMukul Joshi }
3664851a645eSFelix Kuehling #if defined(CONFIG_DEBUG_FS)
3665851a645eSFelix Kuehling 
seq_reg_dump(struct seq_file * m,uint32_t (* dump)[2],uint32_t n_regs)3666851a645eSFelix Kuehling static void seq_reg_dump(struct seq_file *m,
3667851a645eSFelix Kuehling 			 uint32_t (*dump)[2], uint32_t n_regs)
3668851a645eSFelix Kuehling {
3669851a645eSFelix Kuehling 	uint32_t i, count;
3670851a645eSFelix Kuehling 
3671851a645eSFelix Kuehling 	for (i = 0, count = 0; i < n_regs; i++) {
3672851a645eSFelix Kuehling 		if (count == 0 ||
3673851a645eSFelix Kuehling 		    dump[i-1][0] + sizeof(uint32_t) != dump[i][0]) {
3674851a645eSFelix Kuehling 			seq_printf(m, "%s    %08x: %08x",
3675851a645eSFelix Kuehling 				   i ? "\n" : "",
3676851a645eSFelix Kuehling 				   dump[i][0], dump[i][1]);
3677851a645eSFelix Kuehling 			count = 7;
3678851a645eSFelix Kuehling 		} else {
3679851a645eSFelix Kuehling 			seq_printf(m, " %08x", dump[i][1]);
3680851a645eSFelix Kuehling 			count--;
3681851a645eSFelix Kuehling 		}
3682851a645eSFelix Kuehling 	}
3683851a645eSFelix Kuehling 
3684851a645eSFelix Kuehling 	seq_puts(m, "\n");
3685851a645eSFelix Kuehling }
3686851a645eSFelix Kuehling 
dqm_debugfs_hqds(struct seq_file * m,void * data)3687851a645eSFelix Kuehling int dqm_debugfs_hqds(struct seq_file *m, void *data)
3688851a645eSFelix Kuehling {
3689851a645eSFelix Kuehling 	struct device_queue_manager *dqm = data;
3690c4050ff1SLijo Lazar 	uint32_t xcc_mask = dqm->dev->xcc_mask;
3691851a645eSFelix Kuehling 	uint32_t (*dump)[2], n_regs;
3692851a645eSFelix Kuehling 	int pipe, queue;
3693c4050ff1SLijo Lazar 	int r = 0, xcc_id;
3694643e40d4SMukul Joshi 	uint32_t sdma_engine_start;
3695851a645eSFelix Kuehling 
36962c99a547SPhilip Yang 	if (!dqm->sched_running) {
36972243f493SRajneesh Bhardwaj 		seq_puts(m, " Device is stopped\n");
36982c99a547SPhilip Yang 		return 0;
36992c99a547SPhilip Yang 	}
37002c99a547SPhilip Yang 
3701c4050ff1SLijo Lazar 	for_each_inst(xcc_id, xcc_mask) {
3702420185fdSGraham Sider 		r = dqm->dev->kfd2kgd->hqd_dump(dqm->dev->adev,
3703c4050ff1SLijo Lazar 						KFD_CIK_HIQ_PIPE,
3704c4050ff1SLijo Lazar 						KFD_CIK_HIQ_QUEUE, &dump,
3705c4050ff1SLijo Lazar 						&n_regs, xcc_id);
370624f48a42SOak Zeng 		if (!r) {
3707c4050ff1SLijo Lazar 			seq_printf(
3708c4050ff1SLijo Lazar 				m,
3709e2069a7bSMukul Joshi 				"   Inst %d, HIQ on MEC %d Pipe %d Queue %d\n",
3710c4050ff1SLijo Lazar 				xcc_id,
3711c4050ff1SLijo Lazar 				KFD_CIK_HIQ_PIPE / get_pipes_per_mec(dqm) + 1,
371224f48a42SOak Zeng 				KFD_CIK_HIQ_PIPE % get_pipes_per_mec(dqm),
371324f48a42SOak Zeng 				KFD_CIK_HIQ_QUEUE);
371424f48a42SOak Zeng 			seq_reg_dump(m, dump, n_regs);
371524f48a42SOak Zeng 
371624f48a42SOak Zeng 			kfree(dump);
371724f48a42SOak Zeng 		}
371824f48a42SOak Zeng 
3719851a645eSFelix Kuehling 		for (pipe = 0; pipe < get_pipes_per_mec(dqm); pipe++) {
3720851a645eSFelix Kuehling 			int pipe_offset = pipe * get_queues_per_pipe(dqm);
3721851a645eSFelix Kuehling 
3722851a645eSFelix Kuehling 			for (queue = 0; queue < get_queues_per_pipe(dqm); queue++) {
3723851a645eSFelix Kuehling 				if (!test_bit(pipe_offset + queue,
37248dc1db31SMukul Joshi 				      dqm->dev->kfd->shared_resources.cp_queue_bitmap))
3725851a645eSFelix Kuehling 					continue;
3726851a645eSFelix Kuehling 
3727c4050ff1SLijo Lazar 				r = dqm->dev->kfd2kgd->hqd_dump(dqm->dev->adev,
3728c4050ff1SLijo Lazar 								pipe, queue,
3729c4050ff1SLijo Lazar 								&dump, &n_regs,
3730c4050ff1SLijo Lazar 								xcc_id);
3731851a645eSFelix Kuehling 				if (r)
3732851a645eSFelix Kuehling 					break;
3733851a645eSFelix Kuehling 
3734c4050ff1SLijo Lazar 				seq_printf(m,
3735c4050ff1SLijo Lazar 					   " Inst %d,  CP Pipe %d, Queue %d\n",
3736c4050ff1SLijo Lazar 					   xcc_id, pipe, queue);
3737851a645eSFelix Kuehling 				seq_reg_dump(m, dump, n_regs);
3738851a645eSFelix Kuehling 
3739851a645eSFelix Kuehling 				kfree(dump);
3740851a645eSFelix Kuehling 			}
3741851a645eSFelix Kuehling 		}
3742e2069a7bSMukul Joshi 	}
3743851a645eSFelix Kuehling 
3744643e40d4SMukul Joshi 	sdma_engine_start = dqm->dev->node_id * get_num_all_sdma_engines(dqm);
3745643e40d4SMukul Joshi 	for (pipe = sdma_engine_start;
3746643e40d4SMukul Joshi 	     pipe < (sdma_engine_start + get_num_all_sdma_engines(dqm));
3747643e40d4SMukul Joshi 	     pipe++) {
3748d5094189SShaoyun Liu 		for (queue = 0;
37498dc1db31SMukul Joshi 		     queue < dqm->dev->kfd->device_info.num_sdma_queues_per_engine;
3750d5094189SShaoyun Liu 		     queue++) {
3751851a645eSFelix Kuehling 			r = dqm->dev->kfd2kgd->hqd_sdma_dump(
3752420185fdSGraham Sider 				dqm->dev->adev, pipe, queue, &dump, &n_regs);
3753851a645eSFelix Kuehling 			if (r)
3754851a645eSFelix Kuehling 				break;
3755851a645eSFelix Kuehling 
3756851a645eSFelix Kuehling 			seq_printf(m, "  SDMA Engine %d, RLC %d\n",
3757851a645eSFelix Kuehling 				  pipe, queue);
3758851a645eSFelix Kuehling 			seq_reg_dump(m, dump, n_regs);
3759851a645eSFelix Kuehling 
3760851a645eSFelix Kuehling 			kfree(dump);
3761851a645eSFelix Kuehling 		}
3762851a645eSFelix Kuehling 	}
3763851a645eSFelix Kuehling 
3764851a645eSFelix Kuehling 	return r;
3765851a645eSFelix Kuehling }
3766851a645eSFelix Kuehling 
dqm_debugfs_hang_hws(struct device_queue_manager * dqm)37674f942aaeSOak Zeng int dqm_debugfs_hang_hws(struct device_queue_manager *dqm)
3768a29ec470SShaoyun Liu {
3769a29ec470SShaoyun Liu 	int r = 0;
3770a29ec470SShaoyun Liu 
3771a29ec470SShaoyun Liu 	dqm_lock(dqm);
37724f942aaeSOak Zeng 	r = pm_debugfs_hang_hws(&dqm->packet_mgr);
37734f942aaeSOak Zeng 	if (r) {
37744f942aaeSOak Zeng 		dqm_unlock(dqm);
37754f942aaeSOak Zeng 		return r;
37764f942aaeSOak Zeng 	}
3777a29ec470SShaoyun Liu 	dqm->active_runlist = true;
37787cee6a68SJonathan Kim 	r = execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES,
37797cee6a68SJonathan Kim 				0, USE_DEFAULT_GRACE_PERIOD);
3780a29ec470SShaoyun Liu 	dqm_unlock(dqm);
3781a29ec470SShaoyun Liu 
3782a29ec470SShaoyun Liu 	return r;
3783a29ec470SShaoyun Liu }
3784a29ec470SShaoyun Liu 
3785851a645eSFelix Kuehling #endif
3786