1d87f36a0SRajneesh Bhardwaj // SPDX-License-Identifier: GPL-2.0 OR MIT
245102048SBen Goz /*
3d87f36a0SRajneesh Bhardwaj * Copyright 2014-2022 Advanced Micro Devices, Inc.
445102048SBen Goz *
545102048SBen Goz * Permission is hereby granted, free of charge, to any person obtaining a
645102048SBen Goz * copy of this software and associated documentation files (the "Software"),
745102048SBen Goz * to deal in the Software without restriction, including without limitation
845102048SBen Goz * the rights to use, copy, modify, merge, publish, distribute, sublicense,
945102048SBen Goz * and/or sell copies of the Software, and to permit persons to whom the
1045102048SBen Goz * Software is furnished to do so, subject to the following conditions:
1145102048SBen Goz *
1245102048SBen Goz * The above copyright notice and this permission notice shall be included in
1345102048SBen Goz * all copies or substantial portions of the Software.
1445102048SBen Goz *
1545102048SBen Goz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1645102048SBen Goz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1745102048SBen Goz * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1845102048SBen Goz * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1945102048SBen Goz * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2045102048SBen Goz * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2145102048SBen Goz * OTHER DEALINGS IN THE SOFTWARE.
2245102048SBen Goz *
2345102048SBen Goz */
2445102048SBen Goz
2545102048SBen Goz #include <linux/slab.h>
2645102048SBen Goz #include <linux/list.h>
2745102048SBen Goz #include "kfd_device_queue_manager.h"
2845102048SBen Goz #include "kfd_priv.h"
2945102048SBen Goz #include "kfd_kernel_queue.h"
30eb82da1dSOak Zeng #include "amdgpu_amdkfd.h"
31d225960cSYunxiang Li #include "amdgpu_reset.h"
3245102048SBen Goz
get_queue_by_qid(struct process_queue_manager * pqm,unsigned int qid)3345102048SBen Goz static inline struct process_queue_node *get_queue_by_qid(
3445102048SBen Goz struct process_queue_manager *pqm, unsigned int qid)
3545102048SBen Goz {
3645102048SBen Goz struct process_queue_node *pqn;
3745102048SBen Goz
3845102048SBen Goz list_for_each_entry(pqn, &pqm->queues, process_queue_list) {
39ab7c1648SKent Russell if ((pqn->q && pqn->q->properties.queue_id == qid) ||
40ab7c1648SKent Russell (pqn->kq && pqn->kq->queue->properties.queue_id == qid))
4145102048SBen Goz return pqn;
4245102048SBen Goz }
4345102048SBen Goz
4445102048SBen Goz return NULL;
4545102048SBen Goz }
4645102048SBen Goz
assign_queue_slot_by_qid(struct process_queue_manager * pqm,unsigned int qid)478668dfc3SDavid Yat Sin static int assign_queue_slot_by_qid(struct process_queue_manager *pqm,
488668dfc3SDavid Yat Sin unsigned int qid)
498668dfc3SDavid Yat Sin {
508668dfc3SDavid Yat Sin if (qid >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
518668dfc3SDavid Yat Sin return -EINVAL;
528668dfc3SDavid Yat Sin
538668dfc3SDavid Yat Sin if (__test_and_set_bit(qid, pqm->queue_slot_bitmap)) {
548668dfc3SDavid Yat Sin pr_err("Cannot create new queue because requested qid(%u) is in use\n", qid);
558668dfc3SDavid Yat Sin return -ENOSPC;
568668dfc3SDavid Yat Sin }
578668dfc3SDavid Yat Sin
588668dfc3SDavid Yat Sin return 0;
598668dfc3SDavid Yat Sin }
608668dfc3SDavid Yat Sin
find_available_queue_slot(struct process_queue_manager * pqm,unsigned int * qid)6145102048SBen Goz static int find_available_queue_slot(struct process_queue_manager *pqm,
6245102048SBen Goz unsigned int *qid)
6345102048SBen Goz {
6445102048SBen Goz unsigned long found;
6545102048SBen Goz
6645102048SBen Goz found = find_first_zero_bit(pqm->queue_slot_bitmap,
67b8cbab04SOded Gabbay KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
6845102048SBen Goz
6979775b62SKent Russell pr_debug("The new slot id %lu\n", found);
7045102048SBen Goz
71b8cbab04SOded Gabbay if (found >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) {
728544374cSXiaogang Chen pr_info("Cannot open more queues for process with pid %d\n",
738544374cSXiaogang Chen pqm->process->lead_thread->pid);
7445102048SBen Goz return -ENOMEM;
7545102048SBen Goz }
7645102048SBen Goz
7745102048SBen Goz set_bit(found, pqm->queue_slot_bitmap);
7845102048SBen Goz *qid = found;
7945102048SBen Goz
8045102048SBen Goz return 0;
8145102048SBen Goz }
8245102048SBen Goz
kfd_process_dequeue_from_device(struct kfd_process_device * pdd)839fd3f1bfSFelix Kuehling void kfd_process_dequeue_from_device(struct kfd_process_device *pdd)
849fd3f1bfSFelix Kuehling {
858dc1db31SMukul Joshi struct kfd_node *dev = pdd->dev;
869fd3f1bfSFelix Kuehling
879fd3f1bfSFelix Kuehling if (pdd->already_dequeued)
889fd3f1bfSFelix Kuehling return;
899078a5bfSPrike Liang /* The MES context flush needs to filter out the case which the
909078a5bfSPrike Liang * KFD process is created without setting up the MES context and
919078a5bfSPrike Liang * queue for creating a compute queue.
929078a5bfSPrike Liang */
939fd3f1bfSFelix Kuehling dev->dqm->ops.process_termination(dev->dqm, &pdd->qpd);
949078a5bfSPrike Liang if (dev->kfd->shared_resources.enable_mes && !!pdd->proc_ctx_gpu_addr &&
95d225960cSYunxiang Li down_read_trylock(&dev->adev->reset_domain->sem)) {
96d225960cSYunxiang Li amdgpu_mes_flush_shader_debugger(dev->adev,
97d225960cSYunxiang Li pdd->proc_ctx_gpu_addr);
98d225960cSYunxiang Li up_read(&dev->adev->reset_domain->sem);
99d225960cSYunxiang Li }
1009fd3f1bfSFelix Kuehling pdd->already_dequeued = true;
1019fd3f1bfSFelix Kuehling }
1029fd3f1bfSFelix Kuehling
pqm_set_gws(struct process_queue_manager * pqm,unsigned int qid,void * gws)103eb82da1dSOak Zeng int pqm_set_gws(struct process_queue_manager *pqm, unsigned int qid,
104eb82da1dSOak Zeng void *gws)
105eb82da1dSOak Zeng {
106e3de58f8SRajneesh Bhardwaj struct mqd_update_info minfo = {0};
1078dc1db31SMukul Joshi struct kfd_node *dev = NULL;
108eb82da1dSOak Zeng struct process_queue_node *pqn;
109eb82da1dSOak Zeng struct kfd_process_device *pdd;
110eb82da1dSOak Zeng struct kgd_mem *mem = NULL;
111eb82da1dSOak Zeng int ret;
112eb82da1dSOak Zeng
113eb82da1dSOak Zeng pqn = get_queue_by_qid(pqm, qid);
114eb82da1dSOak Zeng if (!pqn) {
115eb82da1dSOak Zeng pr_err("Queue id does not match any known queue\n");
116eb82da1dSOak Zeng return -EINVAL;
117eb82da1dSOak Zeng }
118eb82da1dSOak Zeng
119eb82da1dSOak Zeng if (pqn->q)
120eb82da1dSOak Zeng dev = pqn->q->device;
121eb82da1dSOak Zeng if (WARN_ON(!dev))
122eb82da1dSOak Zeng return -ENODEV;
123eb82da1dSOak Zeng
124eb82da1dSOak Zeng pdd = kfd_get_process_device_data(dev, pqm->process);
125eb82da1dSOak Zeng if (!pdd) {
126eb82da1dSOak Zeng pr_err("Process device data doesn't exist\n");
127eb82da1dSOak Zeng return -EINVAL;
128eb82da1dSOak Zeng }
129eb82da1dSOak Zeng
130eb82da1dSOak Zeng /* Only allow one queue per process can have GWS assigned */
131eb82da1dSOak Zeng if (gws && pdd->qpd.num_gws)
132443e902eSOak Zeng return -EBUSY;
133eb82da1dSOak Zeng
134eb82da1dSOak Zeng if (!gws && pdd->qpd.num_gws == 0)
135eb82da1dSOak Zeng return -EINVAL;
136eb82da1dSOak Zeng
13771985559SAlex Sierra if ((KFD_GC_VERSION(dev) != IP_VERSION(9, 4, 3) &&
1385f571c61SHawking Zhang KFD_GC_VERSION(dev) != IP_VERSION(9, 4, 4) &&
13971985559SAlex Sierra KFD_GC_VERSION(dev) != IP_VERSION(9, 5, 0)) &&
1405f571c61SHawking Zhang !dev->kfd->shared_resources.enable_mes) {
141eb82da1dSOak Zeng if (gws)
142eb82da1dSOak Zeng ret = amdgpu_amdkfd_add_gws_to_process(pdd->process->kgd_process_info,
143eb82da1dSOak Zeng gws, &mem);
144eb82da1dSOak Zeng else
145eb82da1dSOak Zeng ret = amdgpu_amdkfd_remove_gws_from_process(pdd->process->kgd_process_info,
146eb82da1dSOak Zeng pqn->q->gws);
147eb82da1dSOak Zeng if (unlikely(ret))
148eb82da1dSOak Zeng return ret;
149eb82da1dSOak Zeng pqn->q->gws = mem;
150fc133accSMukul Joshi } else {
151fc133accSMukul Joshi /*
152fc133accSMukul Joshi * Intentionally set GWS to a non-NULL value
1537a1c5c67SJonathan Kim * for devices that do not use GWS for global wave
1547a1c5c67SJonathan Kim * synchronization but require the formality
1557a1c5c67SJonathan Kim * of setting GWS for cooperative groups.
156fc133accSMukul Joshi */
157fc133accSMukul Joshi pqn->q->gws = gws ? ERR_PTR(-ENOMEM) : NULL;
158fc133accSMukul Joshi }
159fc133accSMukul Joshi
16002274fc0SGraham Sider pdd->qpd.num_gws = gws ? dev->adev->gds.gws_size : 0;
161e3de58f8SRajneesh Bhardwaj minfo.update_flag = gws ? UPDATE_FLAG_IS_GWS : 0;
162eb82da1dSOak Zeng
163eb82da1dSOak Zeng return pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
164e3de58f8SRajneesh Bhardwaj pqn->q, &minfo);
165eb82da1dSOak Zeng }
166eb82da1dSOak Zeng
kfd_process_dequeue_from_all_devices(struct kfd_process * p)1679fd3f1bfSFelix Kuehling void kfd_process_dequeue_from_all_devices(struct kfd_process *p)
1689fd3f1bfSFelix Kuehling {
1696ae27841SAlex Sierra int i;
1709fd3f1bfSFelix Kuehling
1716ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++)
1726ae27841SAlex Sierra kfd_process_dequeue_from_device(p->pdds[i]);
1739fd3f1bfSFelix Kuehling }
1749fd3f1bfSFelix Kuehling
pqm_init(struct process_queue_manager * pqm,struct kfd_process * p)17545102048SBen Goz int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p)
17645102048SBen Goz {
17745102048SBen Goz INIT_LIST_HEAD(&pqm->queues);
178b9dd6fbdSChristophe JAILLET pqm->queue_slot_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
179b9dd6fbdSChristophe JAILLET GFP_KERNEL);
1804eacc26bSKent Russell if (!pqm->queue_slot_bitmap)
18145102048SBen Goz return -ENOMEM;
18245102048SBen Goz pqm->process = p;
18345102048SBen Goz
18445102048SBen Goz return 0;
18545102048SBen Goz }
18645102048SBen Goz
pqm_clean_queue_resource(struct process_queue_manager * pqm,struct process_queue_node * pqn)187d581ceabSZhenGuo Yin static void pqm_clean_queue_resource(struct process_queue_manager *pqm,
188d581ceabSZhenGuo Yin struct process_queue_node *pqn)
189d581ceabSZhenGuo Yin {
190d581ceabSZhenGuo Yin struct kfd_node *dev;
191d581ceabSZhenGuo Yin struct kfd_process_device *pdd;
192d581ceabSZhenGuo Yin
193d581ceabSZhenGuo Yin dev = pqn->q->device;
194d581ceabSZhenGuo Yin
195d581ceabSZhenGuo Yin pdd = kfd_get_process_device_data(dev, pqm->process);
196d581ceabSZhenGuo Yin if (!pdd) {
197d581ceabSZhenGuo Yin pr_err("Process device data doesn't exist\n");
198d581ceabSZhenGuo Yin return;
199d581ceabSZhenGuo Yin }
200d581ceabSZhenGuo Yin
201d581ceabSZhenGuo Yin if (pqn->q->gws) {
202d581ceabSZhenGuo Yin if (KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 3) &&
2035f571c61SHawking Zhang KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 4) &&
20471985559SAlex Sierra KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 5, 0) &&
205d581ceabSZhenGuo Yin !dev->kfd->shared_resources.enable_mes)
206d581ceabSZhenGuo Yin amdgpu_amdkfd_remove_gws_from_process(
207d581ceabSZhenGuo Yin pqm->process->kgd_process_info, pqn->q->gws);
208d581ceabSZhenGuo Yin pdd->qpd.num_gws = 0;
209d581ceabSZhenGuo Yin }
210d581ceabSZhenGuo Yin
211d581ceabSZhenGuo Yin if (dev->kfd->shared_resources.enable_mes) {
212c86ad391SPhilip Yang amdgpu_amdkfd_free_gtt_mem(dev->adev, &pqn->q->gang_ctx_bo);
213fb910658SPhilip Yang amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&pqn->q->wptr_bo_gart);
214d581ceabSZhenGuo Yin }
215d581ceabSZhenGuo Yin }
216d581ceabSZhenGuo Yin
pqm_uninit(struct process_queue_manager * pqm)21745102048SBen Goz void pqm_uninit(struct process_queue_manager *pqm)
21845102048SBen Goz {
21945102048SBen Goz struct process_queue_node *pqn, *next;
22045102048SBen Goz
22145102048SBen Goz list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) {
222fb910658SPhilip Yang if (pqn->q) {
223a592bb19SAndrew Martin struct kfd_process_device *pdd = kfd_get_process_device_data(pqn->q->device,
224a592bb19SAndrew Martin pqm->process);
225a592bb19SAndrew Martin if (pdd) {
226a1fc9f58SPhilip Yang kfd_queue_unref_bo_vas(pdd, &pqn->q->properties);
227fb910658SPhilip Yang kfd_queue_release_buffers(pdd, &pqn->q->properties);
228a592bb19SAndrew Martin } else {
229a592bb19SAndrew Martin WARN_ON(!pdd);
230a592bb19SAndrew Martin }
231d581ceabSZhenGuo Yin pqm_clean_queue_resource(pqm, pqn);
232fb910658SPhilip Yang }
233d581ceabSZhenGuo Yin
234dcdb4d90SPhilip Yang kfd_procfs_del_queue(pqn->q);
2359fd3f1bfSFelix Kuehling uninit_queue(pqn->q);
2369fd3f1bfSFelix Kuehling list_del(&pqn->process_queue_list);
2379fd3f1bfSFelix Kuehling kfree(pqn);
2389fd3f1bfSFelix Kuehling }
23945102048SBen Goz
240b9dd6fbdSChristophe JAILLET bitmap_free(pqm->queue_slot_bitmap);
24145102048SBen Goz pqm->queue_slot_bitmap = NULL;
24245102048SBen Goz }
24345102048SBen Goz
init_user_queue(struct process_queue_manager * pqm,struct kfd_node * dev,struct queue ** q,struct queue_properties * q_properties,unsigned int qid)2442d030d3eSYong Zhao static int init_user_queue(struct process_queue_manager *pqm,
2458dc1db31SMukul Joshi struct kfd_node *dev, struct queue **q,
24645102048SBen Goz struct queue_properties *q_properties,
247bc4688aeSLang Yu unsigned int qid)
24845102048SBen Goz {
24945102048SBen Goz int retval;
25045102048SBen Goz
25145102048SBen Goz /* Doorbell initialized in user space*/
25245102048SBen Goz q_properties->doorbell_ptr = NULL;
253a70a93faSJonathan Kim q_properties->exception_status = KFD_EC_MASK(EC_QUEUE_NEW);
25445102048SBen Goz
25545102048SBen Goz /* let DQM handle it*/
25645102048SBen Goz q_properties->vmid = 0;
25745102048SBen Goz q_properties->queue_id = qid;
25845102048SBen Goz
259e88a614cSEdward O'Callaghan retval = init_queue(q, q_properties);
26045102048SBen Goz if (retval != 0)
261ab7c1648SKent Russell return retval;
26245102048SBen Goz
26345102048SBen Goz (*q)->device = dev;
26445102048SBen Goz (*q)->process = pqm->process;
26545102048SBen Goz
2668dc1db31SMukul Joshi if (dev->kfd->shared_resources.enable_mes) {
267cc009e61SMukul Joshi retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev,
268cc009e61SMukul Joshi AMDGPU_MES_GANG_CTX_SIZE,
269cc009e61SMukul Joshi &(*q)->gang_ctx_bo,
270cc009e61SMukul Joshi &(*q)->gang_ctx_gpu_addr,
271cc009e61SMukul Joshi &(*q)->gang_ctx_cpu_ptr,
272cc009e61SMukul Joshi false);
273cc009e61SMukul Joshi if (retval) {
274cc009e61SMukul Joshi pr_err("failed to allocate gang context bo\n");
275cc009e61SMukul Joshi goto cleanup;
276cc009e61SMukul Joshi }
277cc009e61SMukul Joshi memset((*q)->gang_ctx_cpu_ptr, 0, AMDGPU_MES_GANG_CTX_SIZE);
278fb910658SPhilip Yang
279fb910658SPhilip Yang /* Starting with GFX11, wptr BOs must be mapped to GART for MES to determine work
280fb910658SPhilip Yang * on unmapped queues for usermode queue oversubscription (no aggregated doorbell)
281fb910658SPhilip Yang */
282fb910658SPhilip Yang if (((dev->adev->mes.sched_version & AMDGPU_MES_API_VERSION_MASK)
283fb910658SPhilip Yang >> AMDGPU_MES_API_VERSION_SHIFT) >= 2) {
284fb910658SPhilip Yang if (dev->adev != amdgpu_ttm_adev(q_properties->wptr_bo->tbo.bdev)) {
285fb910658SPhilip Yang pr_err("Queue memory allocated to wrong device\n");
286fb910658SPhilip Yang retval = -EINVAL;
287fb910658SPhilip Yang goto free_gang_ctx_bo;
288fb910658SPhilip Yang }
289fb910658SPhilip Yang
290fb910658SPhilip Yang retval = amdgpu_amdkfd_map_gtt_bo_to_gart(q_properties->wptr_bo,
291fb910658SPhilip Yang &(*q)->wptr_bo_gart);
292fb910658SPhilip Yang if (retval) {
293fb910658SPhilip Yang pr_err("Failed to map wptr bo to GART\n");
294fb910658SPhilip Yang goto free_gang_ctx_bo;
295fb910658SPhilip Yang }
296fb910658SPhilip Yang }
297cc009e61SMukul Joshi }
29845102048SBen Goz
299cc009e61SMukul Joshi pr_debug("PQM After init queue");
300cc009e61SMukul Joshi return 0;
301cc009e61SMukul Joshi
302fb910658SPhilip Yang free_gang_ctx_bo:
303a33f7f96SZhu Lingshan amdgpu_amdkfd_free_gtt_mem(dev->adev, &(*q)->gang_ctx_bo);
304cc009e61SMukul Joshi cleanup:
305cc009e61SMukul Joshi uninit_queue(*q);
3060b255ab7SChia-I Wu *q = NULL;
30745102048SBen Goz return retval;
30845102048SBen Goz }
30945102048SBen Goz
pqm_create_queue(struct process_queue_manager * pqm,struct kfd_node * dev,struct queue_properties * properties,unsigned int * qid,const struct kfd_criu_queue_priv_data * q_data,const void * restore_mqd,const void * restore_ctl_stack,uint32_t * p_doorbell_offset_in_process)31045102048SBen Goz int pqm_create_queue(struct process_queue_manager *pqm,
3118dc1db31SMukul Joshi struct kfd_node *dev,
31245102048SBen Goz struct queue_properties *properties,
313e47a8b52SYong Zhao unsigned int *qid,
3148668dfc3SDavid Yat Sin const struct kfd_criu_queue_priv_data *q_data,
31542c6c482SDavid Yat Sin const void *restore_mqd,
3163a9822d7SDavid Yat Sin const void *restore_ctl_stack,
317e47a8b52SYong Zhao uint32_t *p_doorbell_offset_in_process)
31845102048SBen Goz {
31945102048SBen Goz int retval;
32045102048SBen Goz struct kfd_process_device *pdd;
32145102048SBen Goz struct queue *q;
32245102048SBen Goz struct process_queue_node *pqn;
32345102048SBen Goz struct kernel_queue *kq;
324e6f791b1SYong Zhao enum kfd_queue_type type = properties->type;
32536c2d7ebSFelix Kuehling unsigned int max_queues = 127; /* HWS limit */
32645102048SBen Goz
3273697b9bdSMukul Joshi /*
32871985559SAlex Sierra * On GFX 9.4.3/9.5.0, increase the number of queues that
32971985559SAlex Sierra * can be created to 255. No HWS limit on GFX 9.4.3/9.5.0.
3303697b9bdSMukul Joshi */
3315f571c61SHawking Zhang if (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 3) ||
33271985559SAlex Sierra KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 4) ||
33371985559SAlex Sierra KFD_GC_VERSION(dev) == IP_VERSION(9, 5, 0))
3343697b9bdSMukul Joshi max_queues = 255;
3353697b9bdSMukul Joshi
33645102048SBen Goz q = NULL;
33745102048SBen Goz kq = NULL;
33845102048SBen Goz
339093c7d8cSAlexey Skidanov pdd = kfd_get_process_device_data(dev, pqm->process);
340093c7d8cSAlexey Skidanov if (!pdd) {
341093c7d8cSAlexey Skidanov pr_err("Process device data doesn't exist\n");
342093c7d8cSAlexey Skidanov return -1;
343093c7d8cSAlexey Skidanov }
34445102048SBen Goz
345992839adSYair Shachar /*
346992839adSYair Shachar * for debug process, verify that it is within the static queues limit
347992839adSYair Shachar * currently limit is set to half of the total avail HQD slots
348992839adSYair Shachar * If we are just about to create DIQ, the is_debug flag is not set yet
349992839adSYair Shachar * Hence we also check the type as well
350992839adSYair Shachar */
35136c2d7ebSFelix Kuehling if ((pdd->qpd.is_debug) || (type == KFD_QUEUE_TYPE_DIQ))
3528dc1db31SMukul Joshi max_queues = dev->kfd->device_info.max_no_of_hqd/2;
35336c2d7ebSFelix Kuehling
35436c2d7ebSFelix Kuehling if (pdd->qpd.queue_count >= max_queues)
355ab7c1648SKent Russell return -ENOSPC;
356992839adSYair Shachar
3578668dfc3SDavid Yat Sin if (q_data) {
3588668dfc3SDavid Yat Sin retval = assign_queue_slot_by_qid(pqm, q_data->q_id);
3598668dfc3SDavid Yat Sin *qid = q_data->q_id;
3608668dfc3SDavid Yat Sin } else
36145102048SBen Goz retval = find_available_queue_slot(pqm, qid);
3628668dfc3SDavid Yat Sin
36345102048SBen Goz if (retval != 0)
36445102048SBen Goz return retval;
36545102048SBen Goz
366fddc4502SSrinivasan Shanmugam /* Register process if this is the first queue */
3675a29ad6bSBen Goz if (list_empty(&pdd->qpd.queues_list) &&
368b20cd0dfSFelix Kuehling list_empty(&pdd->qpd.priv_queue_list))
36945c9a5e4SOded Gabbay dev->dqm->ops.register_process(dev->dqm, &pdd->qpd);
37045102048SBen Goz
371fddc4502SSrinivasan Shanmugam /* Allocate proc_ctx_bo only if MES is enabled and this is the first queue */
372fddc4502SSrinivasan Shanmugam if (!pdd->proc_ctx_cpu_ptr && dev->kfd->shared_resources.enable_mes) {
373fddc4502SSrinivasan Shanmugam retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev,
374fddc4502SSrinivasan Shanmugam AMDGPU_MES_PROC_CTX_SIZE,
375fddc4502SSrinivasan Shanmugam &pdd->proc_ctx_bo,
376fddc4502SSrinivasan Shanmugam &pdd->proc_ctx_gpu_addr,
377fddc4502SSrinivasan Shanmugam &pdd->proc_ctx_cpu_ptr,
378fddc4502SSrinivasan Shanmugam false);
379fddc4502SSrinivasan Shanmugam if (retval) {
380fddc4502SSrinivasan Shanmugam dev_err(dev->adev->dev, "failed to allocate process context bo\n");
381fddc4502SSrinivasan Shanmugam return retval;
382fddc4502SSrinivasan Shanmugam }
383fddc4502SSrinivasan Shanmugam memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE);
384fddc4502SSrinivasan Shanmugam }
385fddc4502SSrinivasan Shanmugam
386dbf56ab1SKent Russell pqn = kzalloc(sizeof(*pqn), GFP_KERNEL);
38745102048SBen Goz if (!pqn) {
38845102048SBen Goz retval = -ENOMEM;
38945102048SBen Goz goto err_allocate_pqn;
39045102048SBen Goz }
39145102048SBen Goz
39245102048SBen Goz switch (type) {
393bcea3081SBen Goz case KFD_QUEUE_TYPE_SDMA:
3941b4670f6SOak Zeng case KFD_QUEUE_TYPE_SDMA_XGMI:
395e06b71b2SJonathan Kim case KFD_QUEUE_TYPE_SDMA_BY_ENG_ID:
396c7637c95SYong Zhao /* SDMA queues are always allocated statically no matter
397c7637c95SYong Zhao * which scheduler mode is used. We also do not need to
398c7637c95SYong Zhao * check whether a SDMA queue can be allocated here, because
399c7637c95SYong Zhao * allocate_sdma_queue() in create_queue() has the
400c7637c95SYong Zhao * corresponding check logic.
401c7637c95SYong Zhao */
402bc4688aeSLang Yu retval = init_user_queue(pqm, dev, &q, properties, *qid);
4038c946b89SFelix Kuehling if (retval != 0)
4048c946b89SFelix Kuehling goto err_create_queue;
4058c946b89SFelix Kuehling pqn->q = q;
4068c946b89SFelix Kuehling pqn->kq = NULL;
4073a9822d7SDavid Yat Sin retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd, q_data,
4083a9822d7SDavid Yat Sin restore_mqd, restore_ctl_stack);
4098c946b89SFelix Kuehling print_queue(q);
4108c946b89SFelix Kuehling break;
4118c946b89SFelix Kuehling
41245102048SBen Goz case KFD_QUEUE_TYPE_COMPUTE:
41345102048SBen Goz /* check if there is over subscription */
414d146c5a7SFelix Kuehling if ((dev->dqm->sched_policy ==
415d146c5a7SFelix Kuehling KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
41644008d7aSYong Zhao ((dev->dqm->processes_count >= dev->vm_info.vmid_num_kfd) ||
417e6945304SYong Zhao (dev->dqm->active_queue_count >= get_cp_queues_num(dev->dqm)))) {
418e7016d8eSYong Zhao pr_debug("Over-subscription is not allowed when amdkfd.sched_policy == 1\n");
41945102048SBen Goz retval = -EPERM;
42045102048SBen Goz goto err_create_queue;
42145102048SBen Goz }
42245102048SBen Goz
423bc4688aeSLang Yu retval = init_user_queue(pqm, dev, &q, properties, *qid);
42445102048SBen Goz if (retval != 0)
42545102048SBen Goz goto err_create_queue;
42645102048SBen Goz pqn->q = q;
42745102048SBen Goz pqn->kq = NULL;
4283a9822d7SDavid Yat Sin retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd, q_data,
4293a9822d7SDavid Yat Sin restore_mqd, restore_ctl_stack);
43045102048SBen Goz print_queue(q);
43145102048SBen Goz break;
43245102048SBen Goz case KFD_QUEUE_TYPE_DIQ:
43345102048SBen Goz kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_DIQ);
4344eacc26bSKent Russell if (!kq) {
435e048a0b2SDan Carpenter retval = -ENOMEM;
43645102048SBen Goz goto err_create_queue;
43745102048SBen Goz }
43845102048SBen Goz kq->queue->properties.queue_id = *qid;
43945102048SBen Goz pqn->kq = kq;
44045102048SBen Goz pqn->q = NULL;
44112fb1ad7SJonathan Kim retval = kfd_process_drain_interrupts(pdd);
44212fb1ad7SJonathan Kim if (retval)
44312fb1ad7SJonathan Kim break;
44412fb1ad7SJonathan Kim
44545c9a5e4SOded Gabbay retval = dev->dqm->ops.create_kernel_queue(dev->dqm,
44645c9a5e4SOded Gabbay kq, &pdd->qpd);
44745102048SBen Goz break;
44845102048SBen Goz default:
44932fa8219SFelix Kuehling WARN(1, "Invalid queue type %d", type);
45032fa8219SFelix Kuehling retval = -EINVAL;
45145102048SBen Goz }
45245102048SBen Goz
45345102048SBen Goz if (retval != 0) {
4548544374cSXiaogang Chen pr_err("process pid %d DQM create queue type %d failed. ret %d\n",
4558544374cSXiaogang Chen pqm->process->lead_thread->pid, type, retval);
45645102048SBen Goz goto err_create_queue;
45745102048SBen Goz }
45845102048SBen Goz
4592105a15aSShashank Sharma if (q && p_doorbell_offset_in_process) {
460ef568db7SFelix Kuehling /* Return the doorbell offset within the doorbell page
461ef568db7SFelix Kuehling * to the caller so it can be passed up to user mode
462ef568db7SFelix Kuehling * (in bytes).
4632105a15aSShashank Sharma * relative doorbell index = Absolute doorbell index -
4642105a15aSShashank Sharma * absolute index of first doorbell in the page.
465ef568db7SFelix Kuehling */
4662105a15aSShashank Sharma uint32_t first_db_index = amdgpu_doorbell_index_on_bar(pdd->dev->adev,
4672105a15aSShashank Sharma pdd->qpd.proc_doorbells,
468367a0af4SArvind Yadav 0,
469367a0af4SArvind Yadav pdd->dev->kfd->device_info.doorbell_size);
4702105a15aSShashank Sharma
4712105a15aSShashank Sharma *p_doorbell_offset_in_process = (q->properties.doorbell_off
4722105a15aSShashank Sharma - first_db_index) * sizeof(uint32_t);
4732105a15aSShashank Sharma }
474ef568db7SFelix Kuehling
47579775b62SKent Russell pr_debug("PQM After DQM create queue\n");
47645102048SBen Goz
47745102048SBen Goz list_add(&pqn->process_queue_list, &pqm->queues);
47845102048SBen Goz
47945102048SBen Goz if (q) {
48079775b62SKent Russell pr_debug("PQM done creating queue\n");
4816d220a7eSAmber Lin kfd_procfs_add_queue(q);
482e6f791b1SYong Zhao print_queue_properties(&q->properties);
48345102048SBen Goz }
48445102048SBen Goz
48545102048SBen Goz return retval;
48645102048SBen Goz
48745102048SBen Goz err_create_queue:
48866f28b9aSYong Zhao uninit_queue(q);
48966f28b9aSYong Zhao if (kq)
4901802b042SYunxiang Li kernel_queue_uninit(kq);
49145102048SBen Goz kfree(pqn);
49245102048SBen Goz err_allocate_pqn:
493f046bfdfSBen Goz /* check if queues list is empty unregister process from device */
49445102048SBen Goz clear_bit(*qid, pqm->queue_slot_bitmap);
4955a29ad6bSBen Goz if (list_empty(&pdd->qpd.queues_list) &&
4965a29ad6bSBen Goz list_empty(&pdd->qpd.priv_queue_list))
497b3869b17SDave Airlie dev->dqm->ops.unregister_process(dev->dqm, &pdd->qpd);
49845102048SBen Goz return retval;
49945102048SBen Goz }
50045102048SBen Goz
pqm_destroy_queue(struct process_queue_manager * pqm,unsigned int qid)50145102048SBen Goz int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
50245102048SBen Goz {
50345102048SBen Goz struct process_queue_node *pqn;
50445102048SBen Goz struct kfd_process_device *pdd;
50545102048SBen Goz struct device_queue_manager *dqm;
5068dc1db31SMukul Joshi struct kfd_node *dev;
50745102048SBen Goz int retval;
50845102048SBen Goz
50945102048SBen Goz dqm = NULL;
51045102048SBen Goz
51145102048SBen Goz retval = 0;
51245102048SBen Goz
51345102048SBen Goz pqn = get_queue_by_qid(pqm, qid);
5144eacc26bSKent Russell if (!pqn) {
51579775b62SKent Russell pr_err("Queue id does not match any known queue\n");
51645102048SBen Goz return -EINVAL;
51745102048SBen Goz }
51845102048SBen Goz
51945102048SBen Goz dev = NULL;
52045102048SBen Goz if (pqn->kq)
52145102048SBen Goz dev = pqn->kq->dev;
52245102048SBen Goz if (pqn->q)
52345102048SBen Goz dev = pqn->q->device;
52432fa8219SFelix Kuehling if (WARN_ON(!dev))
52532fa8219SFelix Kuehling return -ENODEV;
52645102048SBen Goz
527093c7d8cSAlexey Skidanov pdd = kfd_get_process_device_data(dev, pqm->process);
528093c7d8cSAlexey Skidanov if (!pdd) {
529093c7d8cSAlexey Skidanov pr_err("Process device data doesn't exist\n");
530093c7d8cSAlexey Skidanov return -1;
531093c7d8cSAlexey Skidanov }
53245102048SBen Goz
53345102048SBen Goz if (pqn->kq) {
53445102048SBen Goz /* destroy kernel queue (DIQ) */
53545102048SBen Goz dqm = pqn->kq->dev->dqm;
53645c9a5e4SOded Gabbay dqm->ops.destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
5371802b042SYunxiang Li kernel_queue_uninit(pqn->kq);
53845102048SBen Goz }
53945102048SBen Goz
54045102048SBen Goz if (pqn->q) {
541a1fc9f58SPhilip Yang retval = kfd_queue_unref_bo_vas(pdd, &pqn->q->properties);
542fb910658SPhilip Yang if (retval)
543fb910658SPhilip Yang goto err_destroy_queue;
544fb910658SPhilip Yang
54545102048SBen Goz dqm = pqn->q->device->dqm;
54645c9a5e4SOded Gabbay retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q);
5473c0b4280SPhilip Yang if (retval) {
5486027b1bfSYong Zhao pr_err("Pasid 0x%x destroy queue %d failed, ret %d\n",
5498544374cSXiaogang Chen pdd->pasid,
5502533f074SShaoyun Liu pqn->q->properties.queue_id, retval);
551*7919b4caSPhilip Yang if (retval != -ETIME && retval != -EIO)
5523c0b4280SPhilip Yang goto err_destroy_queue;
5533c0b4280SPhilip Yang }
55421d1d724SKent Russell kfd_procfs_del_queue(pqn->q);
555a1fc9f58SPhilip Yang kfd_queue_release_buffers(pdd, &pqn->q->properties);
556d581ceabSZhenGuo Yin pqm_clean_queue_resource(pqm, pqn);
55745102048SBen Goz uninit_queue(pqn->q);
55845102048SBen Goz }
55945102048SBen Goz
56045102048SBen Goz list_del(&pqn->process_queue_list);
56145102048SBen Goz kfree(pqn);
56245102048SBen Goz clear_bit(qid, pqm->queue_slot_bitmap);
56345102048SBen Goz
5645a29ad6bSBen Goz if (list_empty(&pdd->qpd.queues_list) &&
5655a29ad6bSBen Goz list_empty(&pdd->qpd.priv_queue_list))
56645c9a5e4SOded Gabbay dqm->ops.unregister_process(dqm, &pdd->qpd);
56745102048SBen Goz
5683c0b4280SPhilip Yang err_destroy_queue:
56945102048SBen Goz return retval;
57045102048SBen Goz }
57145102048SBen Goz
pqm_update_queue_properties(struct process_queue_manager * pqm,unsigned int qid,struct queue_properties * p)5727c695a2cSLang Yu int pqm_update_queue_properties(struct process_queue_manager *pqm,
5737c695a2cSLang Yu unsigned int qid, struct queue_properties *p)
57445102048SBen Goz {
57545102048SBen Goz int retval;
57645102048SBen Goz struct process_queue_node *pqn;
57745102048SBen Goz
57845102048SBen Goz pqn = get_queue_by_qid(pqm, qid);
579305cd109SPhilip Yang if (!pqn || !pqn->q) {
58079775b62SKent Russell pr_debug("No queue %d exists for update operation\n", qid);
581b9dce23dSOded Gabbay return -EFAULT;
582b9dce23dSOded Gabbay }
58345102048SBen Goz
584305cd109SPhilip Yang /*
585305cd109SPhilip Yang * Update with NULL ring address is used to disable the queue
586305cd109SPhilip Yang */
587305cd109SPhilip Yang if (p->queue_address && p->queue_size) {
588305cd109SPhilip Yang struct kfd_process_device *pdd;
589305cd109SPhilip Yang struct amdgpu_vm *vm;
590305cd109SPhilip Yang struct queue *q = pqn->q;
591305cd109SPhilip Yang int err;
592305cd109SPhilip Yang
593305cd109SPhilip Yang pdd = kfd_get_process_device_data(q->device, q->process);
594305cd109SPhilip Yang if (!pdd)
595305cd109SPhilip Yang return -ENODEV;
596305cd109SPhilip Yang vm = drm_priv_to_vm(pdd->drm_priv);
597305cd109SPhilip Yang err = amdgpu_bo_reserve(vm->root.bo, false);
598305cd109SPhilip Yang if (err)
599305cd109SPhilip Yang return err;
600305cd109SPhilip Yang
601305cd109SPhilip Yang if (kfd_queue_buffer_get(vm, (void *)p->queue_address, &p->ring_bo,
602305cd109SPhilip Yang p->queue_size)) {
603305cd109SPhilip Yang pr_debug("ring buf 0x%llx size 0x%llx not mapped on GPU\n",
604305cd109SPhilip Yang p->queue_address, p->queue_size);
605305cd109SPhilip Yang return -EFAULT;
606305cd109SPhilip Yang }
607305cd109SPhilip Yang
608a1fc9f58SPhilip Yang kfd_queue_unref_bo_va(vm, &pqn->q->properties.ring_bo);
609a1fc9f58SPhilip Yang kfd_queue_buffer_put(&pqn->q->properties.ring_bo);
610305cd109SPhilip Yang amdgpu_bo_unreserve(vm->root.bo);
611305cd109SPhilip Yang
612305cd109SPhilip Yang pqn->q->properties.ring_bo = p->ring_bo;
613305cd109SPhilip Yang }
614305cd109SPhilip Yang
61545102048SBen Goz pqn->q->properties.queue_address = p->queue_address;
61645102048SBen Goz pqn->q->properties.queue_size = p->queue_size;
61745102048SBen Goz pqn->q->properties.queue_percent = p->queue_percent;
61845102048SBen Goz pqn->q->properties.priority = p->priority;
6193c8bdb51SMukul Joshi pqn->q->properties.pm4_target_xcc = p->pm4_target_xcc;
62045102048SBen Goz
62145c9a5e4SOded Gabbay retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
622c6e559ebSLang Yu pqn->q, NULL);
62345102048SBen Goz if (retval != 0)
62445102048SBen Goz return retval;
62545102048SBen Goz
62645102048SBen Goz return 0;
62745102048SBen Goz }
62845102048SBen Goz
pqm_update_mqd(struct process_queue_manager * pqm,unsigned int qid,struct mqd_update_info * minfo)6297c695a2cSLang Yu int pqm_update_mqd(struct process_queue_manager *pqm,
6307c695a2cSLang Yu unsigned int qid, struct mqd_update_info *minfo)
63139e7f331SFelix Kuehling {
63239e7f331SFelix Kuehling int retval;
63339e7f331SFelix Kuehling struct process_queue_node *pqn;
63439e7f331SFelix Kuehling
63539e7f331SFelix Kuehling pqn = get_queue_by_qid(pqm, qid);
63639e7f331SFelix Kuehling if (!pqn) {
63739e7f331SFelix Kuehling pr_debug("No queue %d exists for update operation\n", qid);
63839e7f331SFelix Kuehling return -EFAULT;
63939e7f331SFelix Kuehling }
64039e7f331SFelix Kuehling
64169a8c3aeSJonathan Kim /* CUs are masked for debugger requirements so deny user mask */
64269a8c3aeSJonathan Kim if (pqn->q->properties.is_dbg_wa && minfo && minfo->cu_mask.ptr)
64369a8c3aeSJonathan Kim return -EBUSY;
64469a8c3aeSJonathan Kim
645cff35798SJonathan Kim /* ASICs that have WGPs must enforce pairwise enabled mask checks. */
64669a8c3aeSJonathan Kim if (minfo && minfo->cu_mask.ptr &&
647cff35798SJonathan Kim KFD_GC_VERSION(pqn->q->device) >= IP_VERSION(10, 0, 0)) {
648cff35798SJonathan Kim int i;
649cff35798SJonathan Kim
650cff35798SJonathan Kim for (i = 0; i < minfo->cu_mask.count; i += 2) {
651cff35798SJonathan Kim uint32_t cu_pair = (minfo->cu_mask.ptr[i / 32] >> (i % 32)) & 0x3;
652cff35798SJonathan Kim
653cff35798SJonathan Kim if (cu_pair && cu_pair != 0x3) {
654cff35798SJonathan Kim pr_debug("CUs must be adjacent pairwise enabled.\n");
655cff35798SJonathan Kim return -EINVAL;
656cff35798SJonathan Kim }
657cff35798SJonathan Kim }
658cff35798SJonathan Kim }
659cff35798SJonathan Kim
66039e7f331SFelix Kuehling retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
6617c695a2cSLang Yu pqn->q, minfo);
66239e7f331SFelix Kuehling if (retval != 0)
66339e7f331SFelix Kuehling return retval;
66439e7f331SFelix Kuehling
66569a8c3aeSJonathan Kim if (minfo && minfo->cu_mask.ptr)
66669a8c3aeSJonathan Kim pqn->q->properties.is_user_cu_masked = true;
66769a8c3aeSJonathan Kim
66839e7f331SFelix Kuehling return 0;
66939e7f331SFelix Kuehling }
67039e7f331SFelix Kuehling
pqm_get_user_queue(struct process_queue_manager * pqm,unsigned int qid)6715bb4b78bSOak Zeng struct queue *pqm_get_user_queue(struct process_queue_manager *pqm,
6725bb4b78bSOak Zeng unsigned int qid)
6735bb4b78bSOak Zeng {
6745bb4b78bSOak Zeng struct process_queue_node *pqn;
6755bb4b78bSOak Zeng
6765bb4b78bSOak Zeng pqn = get_queue_by_qid(pqm, qid);
6775bb4b78bSOak Zeng return pqn ? pqn->q : NULL;
6785bb4b78bSOak Zeng }
6795bb4b78bSOak Zeng
pqm_get_wave_state(struct process_queue_manager * pqm,unsigned int qid,void __user * ctl_stack,u32 * ctl_stack_used_size,u32 * save_area_used_size)6805df099e8SJay Cornwall int pqm_get_wave_state(struct process_queue_manager *pqm,
6815df099e8SJay Cornwall unsigned int qid,
6825df099e8SJay Cornwall void __user *ctl_stack,
6835df099e8SJay Cornwall u32 *ctl_stack_used_size,
6845df099e8SJay Cornwall u32 *save_area_used_size)
6855df099e8SJay Cornwall {
6865df099e8SJay Cornwall struct process_queue_node *pqn;
6875df099e8SJay Cornwall
6885df099e8SJay Cornwall pqn = get_queue_by_qid(pqm, qid);
6895df099e8SJay Cornwall if (!pqn) {
6905df099e8SJay Cornwall pr_debug("amdkfd: No queue %d exists for operation\n",
6915df099e8SJay Cornwall qid);
6925df099e8SJay Cornwall return -EFAULT;
6935df099e8SJay Cornwall }
6945df099e8SJay Cornwall
6955df099e8SJay Cornwall return pqn->q->device->dqm->ops.get_wave_state(pqn->q->device->dqm,
6965df099e8SJay Cornwall pqn->q,
6975df099e8SJay Cornwall ctl_stack,
6985df099e8SJay Cornwall ctl_stack_used_size,
6995df099e8SJay Cornwall save_area_used_size);
7005df099e8SJay Cornwall }
7015df099e8SJay Cornwall
pqm_get_queue_snapshot(struct process_queue_manager * pqm,uint64_t exception_clear_mask,void __user * buf,int * num_qss_entries,uint32_t * entry_size)702b17bd5dbSJonathan Kim int pqm_get_queue_snapshot(struct process_queue_manager *pqm,
703b17bd5dbSJonathan Kim uint64_t exception_clear_mask,
704b17bd5dbSJonathan Kim void __user *buf,
705b17bd5dbSJonathan Kim int *num_qss_entries,
706b17bd5dbSJonathan Kim uint32_t *entry_size)
707b17bd5dbSJonathan Kim {
708b17bd5dbSJonathan Kim struct process_queue_node *pqn;
709b17bd5dbSJonathan Kim struct kfd_queue_snapshot_entry src;
710b17bd5dbSJonathan Kim uint32_t tmp_entry_size = *entry_size, tmp_qss_entries = *num_qss_entries;
711b17bd5dbSJonathan Kim int r = 0;
712b17bd5dbSJonathan Kim
713b17bd5dbSJonathan Kim *num_qss_entries = 0;
714b17bd5dbSJonathan Kim if (!(*entry_size))
715b17bd5dbSJonathan Kim return -EINVAL;
716b17bd5dbSJonathan Kim
717b17bd5dbSJonathan Kim *entry_size = min_t(size_t, *entry_size, sizeof(struct kfd_queue_snapshot_entry));
718b17bd5dbSJonathan Kim mutex_lock(&pqm->process->event_mutex);
719b17bd5dbSJonathan Kim
720b17bd5dbSJonathan Kim memset(&src, 0, sizeof(src));
721b17bd5dbSJonathan Kim
722b17bd5dbSJonathan Kim list_for_each_entry(pqn, &pqm->queues, process_queue_list) {
723b17bd5dbSJonathan Kim if (!pqn->q)
724b17bd5dbSJonathan Kim continue;
725b17bd5dbSJonathan Kim
726b17bd5dbSJonathan Kim if (*num_qss_entries < tmp_qss_entries) {
727b17bd5dbSJonathan Kim set_queue_snapshot_entry(pqn->q, exception_clear_mask, &src);
728b17bd5dbSJonathan Kim
729b17bd5dbSJonathan Kim if (copy_to_user(buf, &src, *entry_size)) {
730b17bd5dbSJonathan Kim r = -EFAULT;
731b17bd5dbSJonathan Kim break;
732b17bd5dbSJonathan Kim }
733b17bd5dbSJonathan Kim buf += tmp_entry_size;
734b17bd5dbSJonathan Kim }
735b17bd5dbSJonathan Kim *num_qss_entries += 1;
736b17bd5dbSJonathan Kim }
737b17bd5dbSJonathan Kim
738b17bd5dbSJonathan Kim mutex_unlock(&pqm->process->event_mutex);
739b17bd5dbSJonathan Kim return r;
740b17bd5dbSJonathan Kim }
741b17bd5dbSJonathan Kim
get_queue_data_sizes(struct kfd_process_device * pdd,struct queue * q,uint32_t * mqd_size,uint32_t * ctl_stack_size)7423a9822d7SDavid Yat Sin static int get_queue_data_sizes(struct kfd_process_device *pdd,
7433a9822d7SDavid Yat Sin struct queue *q,
7443a9822d7SDavid Yat Sin uint32_t *mqd_size,
7453a9822d7SDavid Yat Sin uint32_t *ctl_stack_size)
74642c6c482SDavid Yat Sin {
74742c6c482SDavid Yat Sin int ret;
74842c6c482SDavid Yat Sin
7493a9822d7SDavid Yat Sin ret = pqm_get_queue_checkpoint_info(&pdd->process->pqm,
7503a9822d7SDavid Yat Sin q->properties.queue_id,
7513a9822d7SDavid Yat Sin mqd_size,
7523a9822d7SDavid Yat Sin ctl_stack_size);
75342c6c482SDavid Yat Sin if (ret)
75442c6c482SDavid Yat Sin pr_err("Failed to get queue dump info (%d)\n", ret);
75542c6c482SDavid Yat Sin
75642c6c482SDavid Yat Sin return ret;
75742c6c482SDavid Yat Sin }
75842c6c482SDavid Yat Sin
kfd_process_get_queue_info(struct kfd_process * p,uint32_t * num_queues,uint64_t * priv_data_sizes)759626f7b31SDavid Yat Sin int kfd_process_get_queue_info(struct kfd_process *p,
760626f7b31SDavid Yat Sin uint32_t *num_queues,
761626f7b31SDavid Yat Sin uint64_t *priv_data_sizes)
762626f7b31SDavid Yat Sin {
76342c6c482SDavid Yat Sin uint32_t extra_data_sizes = 0;
764626f7b31SDavid Yat Sin struct queue *q;
765626f7b31SDavid Yat Sin int i;
76642c6c482SDavid Yat Sin int ret;
767626f7b31SDavid Yat Sin
768626f7b31SDavid Yat Sin *num_queues = 0;
769626f7b31SDavid Yat Sin
770626f7b31SDavid Yat Sin /* Run over all PDDs of the process */
771626f7b31SDavid Yat Sin for (i = 0; i < p->n_pdds; i++) {
772626f7b31SDavid Yat Sin struct kfd_process_device *pdd = p->pdds[i];
773626f7b31SDavid Yat Sin
774626f7b31SDavid Yat Sin list_for_each_entry(q, &pdd->qpd.queues_list, list) {
775626f7b31SDavid Yat Sin if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||
776626f7b31SDavid Yat Sin q->properties.type == KFD_QUEUE_TYPE_SDMA ||
777626f7b31SDavid Yat Sin q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) {
7783a9822d7SDavid Yat Sin uint32_t mqd_size, ctl_stack_size;
7793a9822d7SDavid Yat Sin
780626f7b31SDavid Yat Sin *num_queues = *num_queues + 1;
78142c6c482SDavid Yat Sin
7823a9822d7SDavid Yat Sin ret = get_queue_data_sizes(pdd, q, &mqd_size, &ctl_stack_size);
78342c6c482SDavid Yat Sin if (ret)
78442c6c482SDavid Yat Sin return ret;
78542c6c482SDavid Yat Sin
7863a9822d7SDavid Yat Sin extra_data_sizes += mqd_size + ctl_stack_size;
787626f7b31SDavid Yat Sin } else {
788626f7b31SDavid Yat Sin pr_err("Unsupported queue type (%d)\n", q->properties.type);
789626f7b31SDavid Yat Sin return -EOPNOTSUPP;
790626f7b31SDavid Yat Sin }
791626f7b31SDavid Yat Sin }
792626f7b31SDavid Yat Sin }
79342c6c482SDavid Yat Sin *priv_data_sizes = extra_data_sizes +
79442c6c482SDavid Yat Sin (*num_queues * sizeof(struct kfd_criu_queue_priv_data));
795626f7b31SDavid Yat Sin
796626f7b31SDavid Yat Sin return 0;
797626f7b31SDavid Yat Sin }
798626f7b31SDavid Yat Sin
pqm_checkpoint_mqd(struct process_queue_manager * pqm,unsigned int qid,void * mqd,void * ctl_stack)7993a9822d7SDavid Yat Sin static int pqm_checkpoint_mqd(struct process_queue_manager *pqm,
8003a9822d7SDavid Yat Sin unsigned int qid,
8013a9822d7SDavid Yat Sin void *mqd,
8023a9822d7SDavid Yat Sin void *ctl_stack)
80342c6c482SDavid Yat Sin {
80442c6c482SDavid Yat Sin struct process_queue_node *pqn;
80542c6c482SDavid Yat Sin
80642c6c482SDavid Yat Sin pqn = get_queue_by_qid(pqm, qid);
80742c6c482SDavid Yat Sin if (!pqn) {
80842c6c482SDavid Yat Sin pr_debug("amdkfd: No queue %d exists for operation\n", qid);
80942c6c482SDavid Yat Sin return -EFAULT;
81042c6c482SDavid Yat Sin }
81142c6c482SDavid Yat Sin
81242c6c482SDavid Yat Sin if (!pqn->q->device->dqm->ops.checkpoint_mqd) {
81342c6c482SDavid Yat Sin pr_err("amdkfd: queue dumping not supported on this device\n");
81442c6c482SDavid Yat Sin return -EOPNOTSUPP;
81542c6c482SDavid Yat Sin }
81642c6c482SDavid Yat Sin
8173a9822d7SDavid Yat Sin return pqn->q->device->dqm->ops.checkpoint_mqd(pqn->q->device->dqm,
8183a9822d7SDavid Yat Sin pqn->q, mqd, ctl_stack);
81942c6c482SDavid Yat Sin }
82042c6c482SDavid Yat Sin
criu_checkpoint_queue(struct kfd_process_device * pdd,struct queue * q,struct kfd_criu_queue_priv_data * q_data)82142c6c482SDavid Yat Sin static int criu_checkpoint_queue(struct kfd_process_device *pdd,
822626f7b31SDavid Yat Sin struct queue *q,
823626f7b31SDavid Yat Sin struct kfd_criu_queue_priv_data *q_data)
824626f7b31SDavid Yat Sin {
8253a9822d7SDavid Yat Sin uint8_t *mqd, *ctl_stack;
82642c6c482SDavid Yat Sin int ret;
82742c6c482SDavid Yat Sin
82842c6c482SDavid Yat Sin mqd = (void *)(q_data + 1);
8293a9822d7SDavid Yat Sin ctl_stack = mqd + q_data->mqd_size;
83042c6c482SDavid Yat Sin
831bef153b7SDavid Yat Sin q_data->gpu_id = pdd->user_gpu_id;
832626f7b31SDavid Yat Sin q_data->type = q->properties.type;
833626f7b31SDavid Yat Sin q_data->format = q->properties.format;
834626f7b31SDavid Yat Sin q_data->q_id = q->properties.queue_id;
835626f7b31SDavid Yat Sin q_data->q_address = q->properties.queue_address;
836626f7b31SDavid Yat Sin q_data->q_size = q->properties.queue_size;
837626f7b31SDavid Yat Sin q_data->priority = q->properties.priority;
838626f7b31SDavid Yat Sin q_data->q_percent = q->properties.queue_percent;
839626f7b31SDavid Yat Sin q_data->read_ptr_addr = (uint64_t)q->properties.read_ptr;
840626f7b31SDavid Yat Sin q_data->write_ptr_addr = (uint64_t)q->properties.write_ptr;
841626f7b31SDavid Yat Sin q_data->doorbell_id = q->doorbell_id;
842626f7b31SDavid Yat Sin
843626f7b31SDavid Yat Sin q_data->sdma_id = q->sdma_id;
844626f7b31SDavid Yat Sin
845626f7b31SDavid Yat Sin q_data->eop_ring_buffer_address =
846626f7b31SDavid Yat Sin q->properties.eop_ring_buffer_address;
847626f7b31SDavid Yat Sin
848626f7b31SDavid Yat Sin q_data->eop_ring_buffer_size = q->properties.eop_ring_buffer_size;
849626f7b31SDavid Yat Sin
850626f7b31SDavid Yat Sin q_data->ctx_save_restore_area_address =
851626f7b31SDavid Yat Sin q->properties.ctx_save_restore_area_address;
852626f7b31SDavid Yat Sin
853626f7b31SDavid Yat Sin q_data->ctx_save_restore_area_size =
854626f7b31SDavid Yat Sin q->properties.ctx_save_restore_area_size;
855626f7b31SDavid Yat Sin
856747eea07SDavid Yat Sin q_data->gws = !!q->gws;
857747eea07SDavid Yat Sin
8583a9822d7SDavid Yat Sin ret = pqm_checkpoint_mqd(&pdd->process->pqm, q->properties.queue_id, mqd, ctl_stack);
85942c6c482SDavid Yat Sin if (ret) {
86042c6c482SDavid Yat Sin pr_err("Failed checkpoint queue_mqd (%d)\n", ret);
86142c6c482SDavid Yat Sin return ret;
86242c6c482SDavid Yat Sin }
86342c6c482SDavid Yat Sin
864626f7b31SDavid Yat Sin pr_debug("Dumping Queue: gpu_id:%x queue_id:%u\n", q_data->gpu_id, q_data->q_id);
86542c6c482SDavid Yat Sin return ret;
866626f7b31SDavid Yat Sin }
867626f7b31SDavid Yat Sin
criu_checkpoint_queues_device(struct kfd_process_device * pdd,uint8_t __user * user_priv,unsigned int * q_index,uint64_t * queues_priv_data_offset)8688668dfc3SDavid Yat Sin static int criu_checkpoint_queues_device(struct kfd_process_device *pdd,
869626f7b31SDavid Yat Sin uint8_t __user *user_priv,
870626f7b31SDavid Yat Sin unsigned int *q_index,
871626f7b31SDavid Yat Sin uint64_t *queues_priv_data_offset)
872626f7b31SDavid Yat Sin {
87342c6c482SDavid Yat Sin unsigned int q_private_data_size = 0;
87442c6c482SDavid Yat Sin uint8_t *q_private_data = NULL; /* Local buffer to store individual queue private data */
875626f7b31SDavid Yat Sin struct queue *q;
876626f7b31SDavid Yat Sin int ret = 0;
877626f7b31SDavid Yat Sin
878626f7b31SDavid Yat Sin list_for_each_entry(q, &pdd->qpd.queues_list, list) {
87942c6c482SDavid Yat Sin struct kfd_criu_queue_priv_data *q_data;
88042c6c482SDavid Yat Sin uint64_t q_data_size;
88142c6c482SDavid Yat Sin uint32_t mqd_size;
8823a9822d7SDavid Yat Sin uint32_t ctl_stack_size;
88342c6c482SDavid Yat Sin
884626f7b31SDavid Yat Sin if (q->properties.type != KFD_QUEUE_TYPE_COMPUTE &&
885626f7b31SDavid Yat Sin q->properties.type != KFD_QUEUE_TYPE_SDMA &&
886626f7b31SDavid Yat Sin q->properties.type != KFD_QUEUE_TYPE_SDMA_XGMI) {
887626f7b31SDavid Yat Sin
888626f7b31SDavid Yat Sin pr_err("Unsupported queue type (%d)\n", q->properties.type);
889626f7b31SDavid Yat Sin ret = -EOPNOTSUPP;
890626f7b31SDavid Yat Sin break;
891626f7b31SDavid Yat Sin }
892626f7b31SDavid Yat Sin
8933a9822d7SDavid Yat Sin ret = get_queue_data_sizes(pdd, q, &mqd_size, &ctl_stack_size);
89442c6c482SDavid Yat Sin if (ret)
89542c6c482SDavid Yat Sin break;
89642c6c482SDavid Yat Sin
8973a9822d7SDavid Yat Sin q_data_size = sizeof(*q_data) + mqd_size + ctl_stack_size;
89842c6c482SDavid Yat Sin
89942c6c482SDavid Yat Sin /* Increase local buffer space if needed */
90042c6c482SDavid Yat Sin if (q_private_data_size < q_data_size) {
90142c6c482SDavid Yat Sin kfree(q_private_data);
90242c6c482SDavid Yat Sin
90342c6c482SDavid Yat Sin q_private_data = kzalloc(q_data_size, GFP_KERNEL);
90442c6c482SDavid Yat Sin if (!q_private_data) {
90542c6c482SDavid Yat Sin ret = -ENOMEM;
90642c6c482SDavid Yat Sin break;
90742c6c482SDavid Yat Sin }
90842c6c482SDavid Yat Sin q_private_data_size = q_data_size;
90942c6c482SDavid Yat Sin }
91042c6c482SDavid Yat Sin
91142c6c482SDavid Yat Sin q_data = (struct kfd_criu_queue_priv_data *)q_private_data;
91242c6c482SDavid Yat Sin
9133a9822d7SDavid Yat Sin /* data stored in this order: priv_data, mqd, ctl_stack */
91442c6c482SDavid Yat Sin q_data->mqd_size = mqd_size;
9153a9822d7SDavid Yat Sin q_data->ctl_stack_size = ctl_stack_size;
91642c6c482SDavid Yat Sin
91742c6c482SDavid Yat Sin ret = criu_checkpoint_queue(pdd, q, q_data);
91842c6c482SDavid Yat Sin if (ret)
91942c6c482SDavid Yat Sin break;
92042c6c482SDavid Yat Sin
9218668dfc3SDavid Yat Sin q_data->object_type = KFD_CRIU_OBJECT_TYPE_QUEUE;
922626f7b31SDavid Yat Sin
92342c6c482SDavid Yat Sin ret = copy_to_user(user_priv + *queues_priv_data_offset,
92442c6c482SDavid Yat Sin q_data, q_data_size);
925626f7b31SDavid Yat Sin if (ret) {
926626f7b31SDavid Yat Sin ret = -EFAULT;
927626f7b31SDavid Yat Sin break;
928626f7b31SDavid Yat Sin }
92942c6c482SDavid Yat Sin *queues_priv_data_offset += q_data_size;
930626f7b31SDavid Yat Sin *q_index = *q_index + 1;
931626f7b31SDavid Yat Sin }
932626f7b31SDavid Yat Sin
93342c6c482SDavid Yat Sin kfree(q_private_data);
934626f7b31SDavid Yat Sin
935626f7b31SDavid Yat Sin return ret;
936626f7b31SDavid Yat Sin }
937626f7b31SDavid Yat Sin
kfd_criu_checkpoint_queues(struct kfd_process * p,uint8_t __user * user_priv_data,uint64_t * priv_data_offset)938626f7b31SDavid Yat Sin int kfd_criu_checkpoint_queues(struct kfd_process *p,
939626f7b31SDavid Yat Sin uint8_t __user *user_priv_data,
940626f7b31SDavid Yat Sin uint64_t *priv_data_offset)
941626f7b31SDavid Yat Sin {
942626f7b31SDavid Yat Sin int ret = 0, pdd_index, q_index = 0;
943626f7b31SDavid Yat Sin
944626f7b31SDavid Yat Sin for (pdd_index = 0; pdd_index < p->n_pdds; pdd_index++) {
945626f7b31SDavid Yat Sin struct kfd_process_device *pdd = p->pdds[pdd_index];
946626f7b31SDavid Yat Sin
947626f7b31SDavid Yat Sin /*
9488668dfc3SDavid Yat Sin * criu_checkpoint_queues_device will copy data to user and update q_index and
949626f7b31SDavid Yat Sin * queues_priv_data_offset
950626f7b31SDavid Yat Sin */
9518668dfc3SDavid Yat Sin ret = criu_checkpoint_queues_device(pdd, user_priv_data, &q_index,
9528668dfc3SDavid Yat Sin priv_data_offset);
9538668dfc3SDavid Yat Sin
954626f7b31SDavid Yat Sin if (ret)
955626f7b31SDavid Yat Sin break;
956626f7b31SDavid Yat Sin }
957626f7b31SDavid Yat Sin
958626f7b31SDavid Yat Sin return ret;
959626f7b31SDavid Yat Sin }
960626f7b31SDavid Yat Sin
set_queue_properties_from_criu(struct queue_properties * qp,struct kfd_criu_queue_priv_data * q_data)961626f7b31SDavid Yat Sin static void set_queue_properties_from_criu(struct queue_properties *qp,
962626f7b31SDavid Yat Sin struct kfd_criu_queue_priv_data *q_data)
963626f7b31SDavid Yat Sin {
964626f7b31SDavid Yat Sin qp->is_interop = false;
965626f7b31SDavid Yat Sin qp->queue_percent = q_data->q_percent;
966626f7b31SDavid Yat Sin qp->priority = q_data->priority;
967626f7b31SDavid Yat Sin qp->queue_address = q_data->q_address;
968626f7b31SDavid Yat Sin qp->queue_size = q_data->q_size;
969626f7b31SDavid Yat Sin qp->read_ptr = (uint32_t *) q_data->read_ptr_addr;
970626f7b31SDavid Yat Sin qp->write_ptr = (uint32_t *) q_data->write_ptr_addr;
971626f7b31SDavid Yat Sin qp->eop_ring_buffer_address = q_data->eop_ring_buffer_address;
972626f7b31SDavid Yat Sin qp->eop_ring_buffer_size = q_data->eop_ring_buffer_size;
973626f7b31SDavid Yat Sin qp->ctx_save_restore_area_address = q_data->ctx_save_restore_area_address;
974626f7b31SDavid Yat Sin qp->ctx_save_restore_area_size = q_data->ctx_save_restore_area_size;
975626f7b31SDavid Yat Sin qp->ctl_stack_size = q_data->ctl_stack_size;
976626f7b31SDavid Yat Sin qp->type = q_data->type;
977626f7b31SDavid Yat Sin qp->format = q_data->format;
978626f7b31SDavid Yat Sin }
979626f7b31SDavid Yat Sin
kfd_criu_restore_queue(struct kfd_process * p,uint8_t __user * user_priv_ptr,uint64_t * priv_data_offset,uint64_t max_priv_data_size)980626f7b31SDavid Yat Sin int kfd_criu_restore_queue(struct kfd_process *p,
981626f7b31SDavid Yat Sin uint8_t __user *user_priv_ptr,
982626f7b31SDavid Yat Sin uint64_t *priv_data_offset,
983626f7b31SDavid Yat Sin uint64_t max_priv_data_size)
984626f7b31SDavid Yat Sin {
9853a9822d7SDavid Yat Sin uint8_t *mqd, *ctl_stack, *q_extra_data = NULL;
986626f7b31SDavid Yat Sin struct kfd_criu_queue_priv_data *q_data;
987626f7b31SDavid Yat Sin struct kfd_process_device *pdd;
98842c6c482SDavid Yat Sin uint64_t q_extra_data_size;
989626f7b31SDavid Yat Sin struct queue_properties qp;
990626f7b31SDavid Yat Sin unsigned int queue_id;
991626f7b31SDavid Yat Sin int ret = 0;
992626f7b31SDavid Yat Sin
993626f7b31SDavid Yat Sin if (*priv_data_offset + sizeof(*q_data) > max_priv_data_size)
994626f7b31SDavid Yat Sin return -EINVAL;
995626f7b31SDavid Yat Sin
996626f7b31SDavid Yat Sin q_data = kmalloc(sizeof(*q_data), GFP_KERNEL);
997626f7b31SDavid Yat Sin if (!q_data)
998626f7b31SDavid Yat Sin return -ENOMEM;
999626f7b31SDavid Yat Sin
1000626f7b31SDavid Yat Sin ret = copy_from_user(q_data, user_priv_ptr + *priv_data_offset, sizeof(*q_data));
1001626f7b31SDavid Yat Sin if (ret) {
1002626f7b31SDavid Yat Sin ret = -EFAULT;
1003626f7b31SDavid Yat Sin goto exit;
1004626f7b31SDavid Yat Sin }
1005626f7b31SDavid Yat Sin
1006626f7b31SDavid Yat Sin *priv_data_offset += sizeof(*q_data);
10078f7519b2SDavid Yat Sin q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size;
100842c6c482SDavid Yat Sin
100942c6c482SDavid Yat Sin if (*priv_data_offset + q_extra_data_size > max_priv_data_size) {
101042c6c482SDavid Yat Sin ret = -EINVAL;
101142c6c482SDavid Yat Sin goto exit;
101242c6c482SDavid Yat Sin }
101342c6c482SDavid Yat Sin
101442c6c482SDavid Yat Sin q_extra_data = kmalloc(q_extra_data_size, GFP_KERNEL);
101542c6c482SDavid Yat Sin if (!q_extra_data) {
101642c6c482SDavid Yat Sin ret = -ENOMEM;
101742c6c482SDavid Yat Sin goto exit;
101842c6c482SDavid Yat Sin }
101942c6c482SDavid Yat Sin
102042c6c482SDavid Yat Sin ret = copy_from_user(q_extra_data, user_priv_ptr + *priv_data_offset, q_extra_data_size);
102142c6c482SDavid Yat Sin if (ret) {
102242c6c482SDavid Yat Sin ret = -EFAULT;
102342c6c482SDavid Yat Sin goto exit;
102442c6c482SDavid Yat Sin }
102542c6c482SDavid Yat Sin
102642c6c482SDavid Yat Sin *priv_data_offset += q_extra_data_size;
1027626f7b31SDavid Yat Sin
1028bef153b7SDavid Yat Sin pdd = kfd_process_device_data_by_id(p, q_data->gpu_id);
1029626f7b31SDavid Yat Sin if (!pdd) {
1030626f7b31SDavid Yat Sin pr_err("Failed to get pdd\n");
1031bef153b7SDavid Yat Sin ret = -EINVAL;
1032bef153b7SDavid Yat Sin goto exit;
1033626f7b31SDavid Yat Sin }
1034a4a3798fSRajneesh Bhardwaj
10353a9822d7SDavid Yat Sin /* data stored in this order: mqd, ctl_stack */
103642c6c482SDavid Yat Sin mqd = q_extra_data;
10373a9822d7SDavid Yat Sin ctl_stack = mqd + q_data->mqd_size;
1038626f7b31SDavid Yat Sin
1039626f7b31SDavid Yat Sin memset(&qp, 0, sizeof(qp));
1040626f7b31SDavid Yat Sin set_queue_properties_from_criu(&qp, q_data);
1041626f7b31SDavid Yat Sin
1042626f7b31SDavid Yat Sin print_queue_properties(&qp);
1043626f7b31SDavid Yat Sin
1044bc4688aeSLang Yu ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL);
1045626f7b31SDavid Yat Sin if (ret) {
1046626f7b31SDavid Yat Sin pr_err("Failed to create new queue err:%d\n", ret);
1047747eea07SDavid Yat Sin goto exit;
1048626f7b31SDavid Yat Sin }
1049626f7b31SDavid Yat Sin
1050747eea07SDavid Yat Sin if (q_data->gws)
1051747eea07SDavid Yat Sin ret = pqm_set_gws(&p->pqm, q_data->q_id, pdd->dev->gws);
1052747eea07SDavid Yat Sin
1053626f7b31SDavid Yat Sin exit:
1054626f7b31SDavid Yat Sin if (ret)
1055747eea07SDavid Yat Sin pr_err("Failed to restore queue (%d)\n", ret);
1056626f7b31SDavid Yat Sin else
1057626f7b31SDavid Yat Sin pr_debug("Queue id %d was restored successfully\n", queue_id);
1058626f7b31SDavid Yat Sin
1059626f7b31SDavid Yat Sin kfree(q_data);
1060aa47fe8dSJesse Zhang kfree(q_extra_data);
1061626f7b31SDavid Yat Sin
1062626f7b31SDavid Yat Sin return ret;
1063626f7b31SDavid Yat Sin }
1064626f7b31SDavid Yat Sin
pqm_get_queue_checkpoint_info(struct process_queue_manager * pqm,unsigned int qid,uint32_t * mqd_size,uint32_t * ctl_stack_size)106542c6c482SDavid Yat Sin int pqm_get_queue_checkpoint_info(struct process_queue_manager *pqm,
106642c6c482SDavid Yat Sin unsigned int qid,
10673a9822d7SDavid Yat Sin uint32_t *mqd_size,
10683a9822d7SDavid Yat Sin uint32_t *ctl_stack_size)
106942c6c482SDavid Yat Sin {
107042c6c482SDavid Yat Sin struct process_queue_node *pqn;
107142c6c482SDavid Yat Sin
107242c6c482SDavid Yat Sin pqn = get_queue_by_qid(pqm, qid);
107342c6c482SDavid Yat Sin if (!pqn) {
107442c6c482SDavid Yat Sin pr_debug("amdkfd: No queue %d exists for operation\n", qid);
107542c6c482SDavid Yat Sin return -EFAULT;
107642c6c482SDavid Yat Sin }
107742c6c482SDavid Yat Sin
107842c6c482SDavid Yat Sin if (!pqn->q->device->dqm->ops.get_queue_checkpoint_info) {
107942c6c482SDavid Yat Sin pr_err("amdkfd: queue dumping not supported on this device\n");
108042c6c482SDavid Yat Sin return -EOPNOTSUPP;
108142c6c482SDavid Yat Sin }
108242c6c482SDavid Yat Sin
10833a9822d7SDavid Yat Sin pqn->q->device->dqm->ops.get_queue_checkpoint_info(pqn->q->device->dqm,
10843a9822d7SDavid Yat Sin pqn->q, mqd_size,
10853a9822d7SDavid Yat Sin ctl_stack_size);
108642c6c482SDavid Yat Sin return 0;
108742c6c482SDavid Yat Sin }
108842c6c482SDavid Yat Sin
1089851a645eSFelix Kuehling #if defined(CONFIG_DEBUG_FS)
109045102048SBen Goz
pqm_debugfs_mqds(struct seq_file * m,void * data)1091851a645eSFelix Kuehling int pqm_debugfs_mqds(struct seq_file *m, void *data)
1092851a645eSFelix Kuehling {
1093851a645eSFelix Kuehling struct process_queue_manager *pqm = data;
1094851a645eSFelix Kuehling struct process_queue_node *pqn;
1095851a645eSFelix Kuehling struct queue *q;
1096851a645eSFelix Kuehling enum KFD_MQD_TYPE mqd_type;
10978d5f3552SYong Zhao struct mqd_manager *mqd_mgr;
10982f77b9a2SMukul Joshi int r = 0, xcc, num_xccs = 1;
10992f77b9a2SMukul Joshi void *mqd;
11002f77b9a2SMukul Joshi uint64_t size = 0;
1101851a645eSFelix Kuehling
1102851a645eSFelix Kuehling list_for_each_entry(pqn, &pqm->queues, process_queue_list) {
1103851a645eSFelix Kuehling if (pqn->q) {
1104851a645eSFelix Kuehling q = pqn->q;
1105851a645eSFelix Kuehling switch (q->properties.type) {
1106851a645eSFelix Kuehling case KFD_QUEUE_TYPE_SDMA:
11071b4670f6SOak Zeng case KFD_QUEUE_TYPE_SDMA_XGMI:
1108851a645eSFelix Kuehling seq_printf(m, " SDMA queue on device %x\n",
1109851a645eSFelix Kuehling q->device->id);
1110851a645eSFelix Kuehling mqd_type = KFD_MQD_TYPE_SDMA;
1111851a645eSFelix Kuehling break;
1112851a645eSFelix Kuehling case KFD_QUEUE_TYPE_COMPUTE:
1113851a645eSFelix Kuehling seq_printf(m, " Compute queue on device %x\n",
1114851a645eSFelix Kuehling q->device->id);
1115851a645eSFelix Kuehling mqd_type = KFD_MQD_TYPE_CP;
1116c4050ff1SLijo Lazar num_xccs = NUM_XCC(q->device->xcc_mask);
1117851a645eSFelix Kuehling break;
1118851a645eSFelix Kuehling default:
1119851a645eSFelix Kuehling seq_printf(m,
1120851a645eSFelix Kuehling " Bad user queue type %d on device %x\n",
1121851a645eSFelix Kuehling q->properties.type, q->device->id);
1122851a645eSFelix Kuehling continue;
1123851a645eSFelix Kuehling }
1124fdfa090bSOak Zeng mqd_mgr = q->device->dqm->mqd_mgrs[mqd_type];
11252f77b9a2SMukul Joshi size = mqd_mgr->mqd_stride(mqd_mgr,
11262f77b9a2SMukul Joshi &q->properties);
1127851a645eSFelix Kuehling } else if (pqn->kq) {
1128851a645eSFelix Kuehling q = pqn->kq->queue;
11298d5f3552SYong Zhao mqd_mgr = pqn->kq->mqd_mgr;
1130851a645eSFelix Kuehling switch (q->properties.type) {
1131851a645eSFelix Kuehling case KFD_QUEUE_TYPE_DIQ:
1132851a645eSFelix Kuehling seq_printf(m, " DIQ on device %x\n",
1133851a645eSFelix Kuehling pqn->kq->dev->id);
1134851a645eSFelix Kuehling break;
1135851a645eSFelix Kuehling default:
1136851a645eSFelix Kuehling seq_printf(m,
1137851a645eSFelix Kuehling " Bad kernel queue type %d on device %x\n",
1138851a645eSFelix Kuehling q->properties.type,
1139851a645eSFelix Kuehling pqn->kq->dev->id);
1140851a645eSFelix Kuehling continue;
1141851a645eSFelix Kuehling }
1142851a645eSFelix Kuehling } else {
1143851a645eSFelix Kuehling seq_printf(m,
1144851a645eSFelix Kuehling " Weird: Queue node with neither kernel nor user queue\n");
1145851a645eSFelix Kuehling continue;
1146851a645eSFelix Kuehling }
1147851a645eSFelix Kuehling
11482f77b9a2SMukul Joshi for (xcc = 0; xcc < num_xccs; xcc++) {
11492f77b9a2SMukul Joshi mqd = q->mqd + size * xcc;
11502f77b9a2SMukul Joshi r = mqd_mgr->debugfs_show_mqd(m, mqd);
1151851a645eSFelix Kuehling if (r != 0)
1152851a645eSFelix Kuehling break;
1153851a645eSFelix Kuehling }
11542f77b9a2SMukul Joshi }
1155851a645eSFelix Kuehling
1156851a645eSFelix Kuehling return r;
1157851a645eSFelix Kuehling }
1158851a645eSFelix Kuehling
1159851a645eSFelix Kuehling #endif
1160