162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/firmware.h> 2562306a36Sopenharmony_ci#include <drm/drm_exec.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "amdgpu_mes.h" 2862306a36Sopenharmony_ci#include "amdgpu.h" 2962306a36Sopenharmony_ci#include "soc15_common.h" 3062306a36Sopenharmony_ci#include "amdgpu_mes_ctx.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS 1024 3362306a36Sopenharmony_ci#define AMDGPU_ONE_DOORBELL_SIZE 8 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci return roundup(AMDGPU_ONE_DOORBELL_SIZE * 3862306a36Sopenharmony_ci AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS, 3962306a36Sopenharmony_ci PAGE_SIZE); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic int amdgpu_mes_kernel_doorbell_get(struct amdgpu_device *adev, 4362306a36Sopenharmony_ci struct amdgpu_mes_process *process, 4462306a36Sopenharmony_ci int ip_type, uint64_t *doorbell_index) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci unsigned int offset, found; 4762306a36Sopenharmony_ci struct amdgpu_mes *mes = &adev->mes; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (ip_type == AMDGPU_RING_TYPE_SDMA) 5062306a36Sopenharmony_ci offset = adev->doorbell_index.sdma_engine[0]; 5162306a36Sopenharmony_ci else 5262306a36Sopenharmony_ci offset = 0; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci found = find_next_zero_bit(mes->doorbell_bitmap, mes->num_mes_dbs, offset); 5562306a36Sopenharmony_ci if (found >= mes->num_mes_dbs) { 5662306a36Sopenharmony_ci DRM_WARN("No doorbell available\n"); 5762306a36Sopenharmony_ci return -ENOSPC; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci set_bit(found, mes->doorbell_bitmap); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Get the absolute doorbell index on BAR */ 6362306a36Sopenharmony_ci *doorbell_index = mes->db_start_dw_offset + found * 2; 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void amdgpu_mes_kernel_doorbell_free(struct amdgpu_device *adev, 6862306a36Sopenharmony_ci struct amdgpu_mes_process *process, 6962306a36Sopenharmony_ci uint32_t doorbell_index) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci unsigned int old, rel_index; 7262306a36Sopenharmony_ci struct amdgpu_mes *mes = &adev->mes; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Find the relative index of the doorbell in this object */ 7562306a36Sopenharmony_ci rel_index = (doorbell_index - mes->db_start_dw_offset) / 2; 7662306a36Sopenharmony_ci old = test_and_clear_bit(rel_index, mes->doorbell_bitmap); 7762306a36Sopenharmony_ci WARN_ON(!old); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int amdgpu_mes_doorbell_init(struct amdgpu_device *adev) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci struct amdgpu_mes *mes = &adev->mes; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Bitmap for dynamic allocation of kernel doorbells */ 8662306a36Sopenharmony_ci mes->doorbell_bitmap = bitmap_zalloc(PAGE_SIZE / sizeof(u32), GFP_KERNEL); 8762306a36Sopenharmony_ci if (!mes->doorbell_bitmap) { 8862306a36Sopenharmony_ci DRM_ERROR("Failed to allocate MES doorbell bitmap\n"); 8962306a36Sopenharmony_ci return -ENOMEM; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mes->num_mes_dbs = PAGE_SIZE / AMDGPU_ONE_DOORBELL_SIZE; 9362306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MES_PRIORITY_NUM_LEVELS; i++) { 9462306a36Sopenharmony_ci adev->mes.aggregated_doorbells[i] = mes->db_start_dw_offset + i * 2; 9562306a36Sopenharmony_ci set_bit(i, mes->doorbell_bitmap); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void amdgpu_mes_doorbell_free(struct amdgpu_device *adev) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci bitmap_free(adev->mes.doorbell_bitmap); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciint amdgpu_mes_init(struct amdgpu_device *adev) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci int i, r; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci adev->mes.adev = adev; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci idr_init(&adev->mes.pasid_idr); 11362306a36Sopenharmony_ci idr_init(&adev->mes.gang_id_idr); 11462306a36Sopenharmony_ci idr_init(&adev->mes.queue_id_idr); 11562306a36Sopenharmony_ci ida_init(&adev->mes.doorbell_ida); 11662306a36Sopenharmony_ci spin_lock_init(&adev->mes.queue_id_lock); 11762306a36Sopenharmony_ci spin_lock_init(&adev->mes.ring_lock); 11862306a36Sopenharmony_ci mutex_init(&adev->mes.mutex_hidden); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci adev->mes.total_max_queue = AMDGPU_FENCE_MES_QUEUE_ID_MASK; 12162306a36Sopenharmony_ci adev->mes.vmid_mask_mmhub = 0xffffff00; 12262306a36Sopenharmony_ci adev->mes.vmid_mask_gfxhub = 0xffffff00; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MES_MAX_COMPUTE_PIPES; i++) { 12562306a36Sopenharmony_ci /* use only 1st MEC pipes */ 12662306a36Sopenharmony_ci if (i >= 4) 12762306a36Sopenharmony_ci continue; 12862306a36Sopenharmony_ci adev->mes.compute_hqd_mask[i] = 0xc; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++) 13262306a36Sopenharmony_ci adev->mes.gfx_hqd_mask[i] = i ? 0 : 0xfffffffe; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++) { 13562306a36Sopenharmony_ci if (adev->ip_versions[SDMA0_HWIP][0] < IP_VERSION(6, 0, 0)) 13662306a36Sopenharmony_ci adev->mes.sdma_hqd_mask[i] = i ? 0 : 0x3fc; 13762306a36Sopenharmony_ci /* zero sdma_hqd_mask for non-existent engine */ 13862306a36Sopenharmony_ci else if (adev->sdma.num_instances == 1) 13962306a36Sopenharmony_ci adev->mes.sdma_hqd_mask[i] = i ? 0 : 0xfc; 14062306a36Sopenharmony_ci else 14162306a36Sopenharmony_ci adev->mes.sdma_hqd_mask[i] = 0xfc; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci r = amdgpu_device_wb_get(adev, &adev->mes.sch_ctx_offs); 14562306a36Sopenharmony_ci if (r) { 14662306a36Sopenharmony_ci dev_err(adev->dev, 14762306a36Sopenharmony_ci "(%d) ring trail_fence_offs wb alloc failed\n", r); 14862306a36Sopenharmony_ci goto error_ids; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci adev->mes.sch_ctx_gpu_addr = 15162306a36Sopenharmony_ci adev->wb.gpu_addr + (adev->mes.sch_ctx_offs * 4); 15262306a36Sopenharmony_ci adev->mes.sch_ctx_ptr = 15362306a36Sopenharmony_ci (uint64_t *)&adev->wb.wb[adev->mes.sch_ctx_offs]; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci r = amdgpu_device_wb_get(adev, &adev->mes.query_status_fence_offs); 15662306a36Sopenharmony_ci if (r) { 15762306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); 15862306a36Sopenharmony_ci dev_err(adev->dev, 15962306a36Sopenharmony_ci "(%d) query_status_fence_offs wb alloc failed\n", r); 16062306a36Sopenharmony_ci goto error_ids; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci adev->mes.query_status_fence_gpu_addr = 16362306a36Sopenharmony_ci adev->wb.gpu_addr + (adev->mes.query_status_fence_offs * 4); 16462306a36Sopenharmony_ci adev->mes.query_status_fence_ptr = 16562306a36Sopenharmony_ci (uint64_t *)&adev->wb.wb[adev->mes.query_status_fence_offs]; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci r = amdgpu_device_wb_get(adev, &adev->mes.read_val_offs); 16862306a36Sopenharmony_ci if (r) { 16962306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); 17062306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs); 17162306a36Sopenharmony_ci dev_err(adev->dev, 17262306a36Sopenharmony_ci "(%d) read_val_offs alloc failed\n", r); 17362306a36Sopenharmony_ci goto error_ids; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci adev->mes.read_val_gpu_addr = 17662306a36Sopenharmony_ci adev->wb.gpu_addr + (adev->mes.read_val_offs * 4); 17762306a36Sopenharmony_ci adev->mes.read_val_ptr = 17862306a36Sopenharmony_ci (uint32_t *)&adev->wb.wb[adev->mes.read_val_offs]; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci r = amdgpu_mes_doorbell_init(adev); 18162306a36Sopenharmony_ci if (r) 18262306a36Sopenharmony_ci goto error; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cierror: 18762306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); 18862306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs); 18962306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.read_val_offs); 19062306a36Sopenharmony_cierror_ids: 19162306a36Sopenharmony_ci idr_destroy(&adev->mes.pasid_idr); 19262306a36Sopenharmony_ci idr_destroy(&adev->mes.gang_id_idr); 19362306a36Sopenharmony_ci idr_destroy(&adev->mes.queue_id_idr); 19462306a36Sopenharmony_ci ida_destroy(&adev->mes.doorbell_ida); 19562306a36Sopenharmony_ci mutex_destroy(&adev->mes.mutex_hidden); 19662306a36Sopenharmony_ci return r; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid amdgpu_mes_fini(struct amdgpu_device *adev) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); 20262306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs); 20362306a36Sopenharmony_ci amdgpu_device_wb_free(adev, adev->mes.read_val_offs); 20462306a36Sopenharmony_ci amdgpu_mes_doorbell_free(adev); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci idr_destroy(&adev->mes.pasid_idr); 20762306a36Sopenharmony_ci idr_destroy(&adev->mes.gang_id_idr); 20862306a36Sopenharmony_ci idr_destroy(&adev->mes.queue_id_idr); 20962306a36Sopenharmony_ci ida_destroy(&adev->mes.doorbell_ida); 21062306a36Sopenharmony_ci mutex_destroy(&adev->mes.mutex_hidden); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic void amdgpu_mes_queue_free_mqd(struct amdgpu_mes_queue *q) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci amdgpu_bo_free_kernel(&q->mqd_obj, 21662306a36Sopenharmony_ci &q->mqd_gpu_addr, 21762306a36Sopenharmony_ci &q->mqd_cpu_ptr); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciint amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, 22162306a36Sopenharmony_ci struct amdgpu_vm *vm) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct amdgpu_mes_process *process; 22462306a36Sopenharmony_ci int r; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* allocate the mes process buffer */ 22762306a36Sopenharmony_ci process = kzalloc(sizeof(struct amdgpu_mes_process), GFP_KERNEL); 22862306a36Sopenharmony_ci if (!process) { 22962306a36Sopenharmony_ci DRM_ERROR("no more memory to create mes process\n"); 23062306a36Sopenharmony_ci return -ENOMEM; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* allocate the process context bo and map it */ 23462306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_PROC_CTX_SIZE, PAGE_SIZE, 23562306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 23662306a36Sopenharmony_ci &process->proc_ctx_bo, 23762306a36Sopenharmony_ci &process->proc_ctx_gpu_addr, 23862306a36Sopenharmony_ci &process->proc_ctx_cpu_ptr); 23962306a36Sopenharmony_ci if (r) { 24062306a36Sopenharmony_ci DRM_ERROR("failed to allocate process context bo\n"); 24162306a36Sopenharmony_ci goto clean_up_memory; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci memset(process->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* 24662306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 24762306a36Sopenharmony_ci * lock dependencies. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* add the mes process to idr list */ 25262306a36Sopenharmony_ci r = idr_alloc(&adev->mes.pasid_idr, process, pasid, pasid + 1, 25362306a36Sopenharmony_ci GFP_KERNEL); 25462306a36Sopenharmony_ci if (r < 0) { 25562306a36Sopenharmony_ci DRM_ERROR("failed to lock pasid=%d\n", pasid); 25662306a36Sopenharmony_ci goto clean_up_ctx; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci INIT_LIST_HEAD(&process->gang_list); 26062306a36Sopenharmony_ci process->vm = vm; 26162306a36Sopenharmony_ci process->pasid = pasid; 26262306a36Sopenharmony_ci process->process_quantum = adev->mes.default_process_quantum; 26362306a36Sopenharmony_ci process->pd_gpu_addr = amdgpu_bo_gpu_offset(vm->root.bo); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ciclean_up_ctx: 26962306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 27062306a36Sopenharmony_ci amdgpu_bo_free_kernel(&process->proc_ctx_bo, 27162306a36Sopenharmony_ci &process->proc_ctx_gpu_addr, 27262306a36Sopenharmony_ci &process->proc_ctx_cpu_ptr); 27362306a36Sopenharmony_ciclean_up_memory: 27462306a36Sopenharmony_ci kfree(process); 27562306a36Sopenharmony_ci return r; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_civoid amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct amdgpu_mes_process *process; 28162306a36Sopenharmony_ci struct amdgpu_mes_gang *gang, *tmp1; 28262306a36Sopenharmony_ci struct amdgpu_mes_queue *queue, *tmp2; 28362306a36Sopenharmony_ci struct mes_remove_queue_input queue_input; 28462306a36Sopenharmony_ci unsigned long flags; 28562306a36Sopenharmony_ci int r; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* 28862306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 28962306a36Sopenharmony_ci * lock dependencies. 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci process = idr_find(&adev->mes.pasid_idr, pasid); 29462306a36Sopenharmony_ci if (!process) { 29562306a36Sopenharmony_ci DRM_WARN("pasid %d doesn't exist\n", pasid); 29662306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 29762306a36Sopenharmony_ci return; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Remove all queues from hardware */ 30162306a36Sopenharmony_ci list_for_each_entry_safe(gang, tmp1, &process->gang_list, list) { 30262306a36Sopenharmony_ci list_for_each_entry_safe(queue, tmp2, &gang->queue_list, list) { 30362306a36Sopenharmony_ci spin_lock_irqsave(&adev->mes.queue_id_lock, flags); 30462306a36Sopenharmony_ci idr_remove(&adev->mes.queue_id_idr, queue->queue_id); 30562306a36Sopenharmony_ci spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci queue_input.doorbell_offset = queue->doorbell_off; 30862306a36Sopenharmony_ci queue_input.gang_context_addr = gang->gang_ctx_gpu_addr; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci r = adev->mes.funcs->remove_hw_queue(&adev->mes, 31162306a36Sopenharmony_ci &queue_input); 31262306a36Sopenharmony_ci if (r) 31362306a36Sopenharmony_ci DRM_WARN("failed to remove hardware queue\n"); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci idr_remove(&adev->mes.gang_id_idr, gang->gang_id); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci idr_remove(&adev->mes.pasid_idr, pasid); 32062306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* free all memory allocated by the process */ 32362306a36Sopenharmony_ci list_for_each_entry_safe(gang, tmp1, &process->gang_list, list) { 32462306a36Sopenharmony_ci /* free all queues in the gang */ 32562306a36Sopenharmony_ci list_for_each_entry_safe(queue, tmp2, &gang->queue_list, list) { 32662306a36Sopenharmony_ci amdgpu_mes_queue_free_mqd(queue); 32762306a36Sopenharmony_ci list_del(&queue->list); 32862306a36Sopenharmony_ci kfree(queue); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci amdgpu_bo_free_kernel(&gang->gang_ctx_bo, 33162306a36Sopenharmony_ci &gang->gang_ctx_gpu_addr, 33262306a36Sopenharmony_ci &gang->gang_ctx_cpu_ptr); 33362306a36Sopenharmony_ci list_del(&gang->list); 33462306a36Sopenharmony_ci kfree(gang); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci amdgpu_bo_free_kernel(&process->proc_ctx_bo, 33862306a36Sopenharmony_ci &process->proc_ctx_gpu_addr, 33962306a36Sopenharmony_ci &process->proc_ctx_cpu_ptr); 34062306a36Sopenharmony_ci kfree(process); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciint amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, 34462306a36Sopenharmony_ci struct amdgpu_mes_gang_properties *gprops, 34562306a36Sopenharmony_ci int *gang_id) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct amdgpu_mes_process *process; 34862306a36Sopenharmony_ci struct amdgpu_mes_gang *gang; 34962306a36Sopenharmony_ci int r; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* allocate the mes gang buffer */ 35262306a36Sopenharmony_ci gang = kzalloc(sizeof(struct amdgpu_mes_gang), GFP_KERNEL); 35362306a36Sopenharmony_ci if (!gang) { 35462306a36Sopenharmony_ci return -ENOMEM; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* allocate the gang context bo and map it to cpu space */ 35862306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_GANG_CTX_SIZE, PAGE_SIZE, 35962306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 36062306a36Sopenharmony_ci &gang->gang_ctx_bo, 36162306a36Sopenharmony_ci &gang->gang_ctx_gpu_addr, 36262306a36Sopenharmony_ci &gang->gang_ctx_cpu_ptr); 36362306a36Sopenharmony_ci if (r) { 36462306a36Sopenharmony_ci DRM_ERROR("failed to allocate process context bo\n"); 36562306a36Sopenharmony_ci goto clean_up_mem; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci memset(gang->gang_ctx_cpu_ptr, 0, AMDGPU_MES_GANG_CTX_SIZE); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 37162306a36Sopenharmony_ci * lock dependencies. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci process = idr_find(&adev->mes.pasid_idr, pasid); 37662306a36Sopenharmony_ci if (!process) { 37762306a36Sopenharmony_ci DRM_ERROR("pasid %d doesn't exist\n", pasid); 37862306a36Sopenharmony_ci r = -EINVAL; 37962306a36Sopenharmony_ci goto clean_up_ctx; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* add the mes gang to idr list */ 38362306a36Sopenharmony_ci r = idr_alloc(&adev->mes.gang_id_idr, gang, 1, 0, 38462306a36Sopenharmony_ci GFP_KERNEL); 38562306a36Sopenharmony_ci if (r < 0) { 38662306a36Sopenharmony_ci DRM_ERROR("failed to allocate idr for gang\n"); 38762306a36Sopenharmony_ci goto clean_up_ctx; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci gang->gang_id = r; 39162306a36Sopenharmony_ci *gang_id = r; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci INIT_LIST_HEAD(&gang->queue_list); 39462306a36Sopenharmony_ci gang->process = process; 39562306a36Sopenharmony_ci gang->priority = gprops->priority; 39662306a36Sopenharmony_ci gang->gang_quantum = gprops->gang_quantum ? 39762306a36Sopenharmony_ci gprops->gang_quantum : adev->mes.default_gang_quantum; 39862306a36Sopenharmony_ci gang->global_priority_level = gprops->global_priority_level; 39962306a36Sopenharmony_ci gang->inprocess_gang_priority = gprops->inprocess_gang_priority; 40062306a36Sopenharmony_ci list_add_tail(&gang->list, &process->gang_list); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ciclean_up_ctx: 40662306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 40762306a36Sopenharmony_ci amdgpu_bo_free_kernel(&gang->gang_ctx_bo, 40862306a36Sopenharmony_ci &gang->gang_ctx_gpu_addr, 40962306a36Sopenharmony_ci &gang->gang_ctx_cpu_ptr); 41062306a36Sopenharmony_ciclean_up_mem: 41162306a36Sopenharmony_ci kfree(gang); 41262306a36Sopenharmony_ci return r; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ciint amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct amdgpu_mes_gang *gang; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 42162306a36Sopenharmony_ci * lock dependencies. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci gang = idr_find(&adev->mes.gang_id_idr, gang_id); 42662306a36Sopenharmony_ci if (!gang) { 42762306a36Sopenharmony_ci DRM_ERROR("gang id %d doesn't exist\n", gang_id); 42862306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 42962306a36Sopenharmony_ci return -EINVAL; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (!list_empty(&gang->queue_list)) { 43362306a36Sopenharmony_ci DRM_ERROR("queue list is not empty\n"); 43462306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 43562306a36Sopenharmony_ci return -EBUSY; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci idr_remove(&adev->mes.gang_id_idr, gang->gang_id); 43962306a36Sopenharmony_ci list_del(&gang->list); 44062306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci amdgpu_bo_free_kernel(&gang->gang_ctx_bo, 44362306a36Sopenharmony_ci &gang->gang_ctx_gpu_addr, 44462306a36Sopenharmony_ci &gang->gang_ctx_cpu_ptr); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci kfree(gang); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ciint amdgpu_mes_suspend(struct amdgpu_device *adev) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct idr *idp; 45462306a36Sopenharmony_ci struct amdgpu_mes_process *process; 45562306a36Sopenharmony_ci struct amdgpu_mes_gang *gang; 45662306a36Sopenharmony_ci struct mes_suspend_gang_input input; 45762306a36Sopenharmony_ci int r, pasid; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* 46062306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 46162306a36Sopenharmony_ci * lock dependencies. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci idp = &adev->mes.pasid_idr; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci idr_for_each_entry(idp, process, pasid) { 46862306a36Sopenharmony_ci list_for_each_entry(gang, &process->gang_list, list) { 46962306a36Sopenharmony_ci r = adev->mes.funcs->suspend_gang(&adev->mes, &input); 47062306a36Sopenharmony_ci if (r) 47162306a36Sopenharmony_ci DRM_ERROR("failed to suspend pasid %d gangid %d", 47262306a36Sopenharmony_ci pasid, gang->gang_id); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ciint amdgpu_mes_resume(struct amdgpu_device *adev) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct idr *idp; 48362306a36Sopenharmony_ci struct amdgpu_mes_process *process; 48462306a36Sopenharmony_ci struct amdgpu_mes_gang *gang; 48562306a36Sopenharmony_ci struct mes_resume_gang_input input; 48662306a36Sopenharmony_ci int r, pasid; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* 48962306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 49062306a36Sopenharmony_ci * lock dependencies. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci idp = &adev->mes.pasid_idr; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci idr_for_each_entry(idp, process, pasid) { 49762306a36Sopenharmony_ci list_for_each_entry(gang, &process->gang_list, list) { 49862306a36Sopenharmony_ci r = adev->mes.funcs->resume_gang(&adev->mes, &input); 49962306a36Sopenharmony_ci if (r) 50062306a36Sopenharmony_ci DRM_ERROR("failed to resume pasid %d gangid %d", 50162306a36Sopenharmony_ci pasid, gang->gang_id); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int amdgpu_mes_queue_alloc_mqd(struct amdgpu_device *adev, 51062306a36Sopenharmony_ci struct amdgpu_mes_queue *q, 51162306a36Sopenharmony_ci struct amdgpu_mes_queue_properties *p) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct amdgpu_mqd *mqd_mgr = &adev->mqds[p->queue_type]; 51462306a36Sopenharmony_ci u32 mqd_size = mqd_mgr->mqd_size; 51562306a36Sopenharmony_ci int r; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE, 51862306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 51962306a36Sopenharmony_ci &q->mqd_obj, 52062306a36Sopenharmony_ci &q->mqd_gpu_addr, &q->mqd_cpu_ptr); 52162306a36Sopenharmony_ci if (r) { 52262306a36Sopenharmony_ci dev_warn(adev->dev, "failed to create queue mqd bo (%d)", r); 52362306a36Sopenharmony_ci return r; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci memset(q->mqd_cpu_ptr, 0, mqd_size); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci r = amdgpu_bo_reserve(q->mqd_obj, false); 52862306a36Sopenharmony_ci if (unlikely(r != 0)) 52962306a36Sopenharmony_ci goto clean_up; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciclean_up: 53462306a36Sopenharmony_ci amdgpu_bo_free_kernel(&q->mqd_obj, 53562306a36Sopenharmony_ci &q->mqd_gpu_addr, 53662306a36Sopenharmony_ci &q->mqd_cpu_ptr); 53762306a36Sopenharmony_ci return r; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev, 54162306a36Sopenharmony_ci struct amdgpu_mes_queue *q, 54262306a36Sopenharmony_ci struct amdgpu_mes_queue_properties *p) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct amdgpu_mqd *mqd_mgr = &adev->mqds[p->queue_type]; 54562306a36Sopenharmony_ci struct amdgpu_mqd_prop mqd_prop = {0}; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci mqd_prop.mqd_gpu_addr = q->mqd_gpu_addr; 54862306a36Sopenharmony_ci mqd_prop.hqd_base_gpu_addr = p->hqd_base_gpu_addr; 54962306a36Sopenharmony_ci mqd_prop.rptr_gpu_addr = p->rptr_gpu_addr; 55062306a36Sopenharmony_ci mqd_prop.wptr_gpu_addr = p->wptr_gpu_addr; 55162306a36Sopenharmony_ci mqd_prop.queue_size = p->queue_size; 55262306a36Sopenharmony_ci mqd_prop.use_doorbell = true; 55362306a36Sopenharmony_ci mqd_prop.doorbell_index = p->doorbell_off; 55462306a36Sopenharmony_ci mqd_prop.eop_gpu_addr = p->eop_gpu_addr; 55562306a36Sopenharmony_ci mqd_prop.hqd_pipe_priority = p->hqd_pipe_priority; 55662306a36Sopenharmony_ci mqd_prop.hqd_queue_priority = p->hqd_queue_priority; 55762306a36Sopenharmony_ci mqd_prop.hqd_active = false; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (p->queue_type == AMDGPU_RING_TYPE_GFX || 56062306a36Sopenharmony_ci p->queue_type == AMDGPU_RING_TYPE_COMPUTE) { 56162306a36Sopenharmony_ci mutex_lock(&adev->srbm_mutex); 56262306a36Sopenharmony_ci amdgpu_gfx_select_me_pipe_q(adev, p->ring->me, p->ring->pipe, 0, 0, 0); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci mqd_mgr->init_mqd(adev, q->mqd_cpu_ptr, &mqd_prop); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (p->queue_type == AMDGPU_RING_TYPE_GFX || 56862306a36Sopenharmony_ci p->queue_type == AMDGPU_RING_TYPE_COMPUTE) { 56962306a36Sopenharmony_ci amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0, 0); 57062306a36Sopenharmony_ci mutex_unlock(&adev->srbm_mutex); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci amdgpu_bo_unreserve(q->mqd_obj); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ciint amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, 57762306a36Sopenharmony_ci struct amdgpu_mes_queue_properties *qprops, 57862306a36Sopenharmony_ci int *queue_id) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct amdgpu_mes_queue *queue; 58162306a36Sopenharmony_ci struct amdgpu_mes_gang *gang; 58262306a36Sopenharmony_ci struct mes_add_queue_input queue_input; 58362306a36Sopenharmony_ci unsigned long flags; 58462306a36Sopenharmony_ci int r; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci memset(&queue_input, 0, sizeof(struct mes_add_queue_input)); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* allocate the mes queue buffer */ 58962306a36Sopenharmony_ci queue = kzalloc(sizeof(struct amdgpu_mes_queue), GFP_KERNEL); 59062306a36Sopenharmony_ci if (!queue) { 59162306a36Sopenharmony_ci DRM_ERROR("Failed to allocate memory for queue\n"); 59262306a36Sopenharmony_ci return -ENOMEM; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Allocate the queue mqd */ 59662306a36Sopenharmony_ci r = amdgpu_mes_queue_alloc_mqd(adev, queue, qprops); 59762306a36Sopenharmony_ci if (r) 59862306a36Sopenharmony_ci goto clean_up_memory; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* 60162306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 60262306a36Sopenharmony_ci * lock dependencies. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci gang = idr_find(&adev->mes.gang_id_idr, gang_id); 60762306a36Sopenharmony_ci if (!gang) { 60862306a36Sopenharmony_ci DRM_ERROR("gang id %d doesn't exist\n", gang_id); 60962306a36Sopenharmony_ci r = -EINVAL; 61062306a36Sopenharmony_ci goto clean_up_mqd; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* add the mes gang to idr list */ 61462306a36Sopenharmony_ci spin_lock_irqsave(&adev->mes.queue_id_lock, flags); 61562306a36Sopenharmony_ci r = idr_alloc(&adev->mes.queue_id_idr, queue, 1, 0, 61662306a36Sopenharmony_ci GFP_ATOMIC); 61762306a36Sopenharmony_ci if (r < 0) { 61862306a36Sopenharmony_ci spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); 61962306a36Sopenharmony_ci goto clean_up_mqd; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); 62262306a36Sopenharmony_ci *queue_id = queue->queue_id = r; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* allocate a doorbell index for the queue */ 62562306a36Sopenharmony_ci r = amdgpu_mes_kernel_doorbell_get(adev, gang->process, 62662306a36Sopenharmony_ci qprops->queue_type, 62762306a36Sopenharmony_ci &qprops->doorbell_off); 62862306a36Sopenharmony_ci if (r) 62962306a36Sopenharmony_ci goto clean_up_queue_id; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* initialize the queue mqd */ 63262306a36Sopenharmony_ci amdgpu_mes_queue_init_mqd(adev, queue, qprops); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* add hw queue to mes */ 63562306a36Sopenharmony_ci queue_input.process_id = gang->process->pasid; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci queue_input.page_table_base_addr = 63862306a36Sopenharmony_ci adev->vm_manager.vram_base_offset + gang->process->pd_gpu_addr - 63962306a36Sopenharmony_ci adev->gmc.vram_start; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci queue_input.process_va_start = 0; 64262306a36Sopenharmony_ci queue_input.process_va_end = 64362306a36Sopenharmony_ci (adev->vm_manager.max_pfn - 1) << AMDGPU_GPU_PAGE_SHIFT; 64462306a36Sopenharmony_ci queue_input.process_quantum = gang->process->process_quantum; 64562306a36Sopenharmony_ci queue_input.process_context_addr = gang->process->proc_ctx_gpu_addr; 64662306a36Sopenharmony_ci queue_input.gang_quantum = gang->gang_quantum; 64762306a36Sopenharmony_ci queue_input.gang_context_addr = gang->gang_ctx_gpu_addr; 64862306a36Sopenharmony_ci queue_input.inprocess_gang_priority = gang->inprocess_gang_priority; 64962306a36Sopenharmony_ci queue_input.gang_global_priority_level = gang->global_priority_level; 65062306a36Sopenharmony_ci queue_input.doorbell_offset = qprops->doorbell_off; 65162306a36Sopenharmony_ci queue_input.mqd_addr = queue->mqd_gpu_addr; 65262306a36Sopenharmony_ci queue_input.wptr_addr = qprops->wptr_gpu_addr; 65362306a36Sopenharmony_ci queue_input.wptr_mc_addr = qprops->wptr_mc_addr; 65462306a36Sopenharmony_ci queue_input.queue_type = qprops->queue_type; 65562306a36Sopenharmony_ci queue_input.paging = qprops->paging; 65662306a36Sopenharmony_ci queue_input.is_kfd_process = 0; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci r = adev->mes.funcs->add_hw_queue(&adev->mes, &queue_input); 65962306a36Sopenharmony_ci if (r) { 66062306a36Sopenharmony_ci DRM_ERROR("failed to add hardware queue to MES, doorbell=0x%llx\n", 66162306a36Sopenharmony_ci qprops->doorbell_off); 66262306a36Sopenharmony_ci goto clean_up_doorbell; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci DRM_DEBUG("MES hw queue was added, pasid=%d, gang id=%d, " 66662306a36Sopenharmony_ci "queue type=%d, doorbell=0x%llx\n", 66762306a36Sopenharmony_ci gang->process->pasid, gang_id, qprops->queue_type, 66862306a36Sopenharmony_ci qprops->doorbell_off); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci queue->ring = qprops->ring; 67162306a36Sopenharmony_ci queue->doorbell_off = qprops->doorbell_off; 67262306a36Sopenharmony_ci queue->wptr_gpu_addr = qprops->wptr_gpu_addr; 67362306a36Sopenharmony_ci queue->queue_type = qprops->queue_type; 67462306a36Sopenharmony_ci queue->paging = qprops->paging; 67562306a36Sopenharmony_ci queue->gang = gang; 67662306a36Sopenharmony_ci queue->ring->mqd_ptr = queue->mqd_cpu_ptr; 67762306a36Sopenharmony_ci list_add_tail(&queue->list, &gang->queue_list); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ciclean_up_doorbell: 68362306a36Sopenharmony_ci amdgpu_mes_kernel_doorbell_free(adev, gang->process, 68462306a36Sopenharmony_ci qprops->doorbell_off); 68562306a36Sopenharmony_ciclean_up_queue_id: 68662306a36Sopenharmony_ci spin_lock_irqsave(&adev->mes.queue_id_lock, flags); 68762306a36Sopenharmony_ci idr_remove(&adev->mes.queue_id_idr, queue->queue_id); 68862306a36Sopenharmony_ci spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); 68962306a36Sopenharmony_ciclean_up_mqd: 69062306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 69162306a36Sopenharmony_ci amdgpu_mes_queue_free_mqd(queue); 69262306a36Sopenharmony_ciclean_up_memory: 69362306a36Sopenharmony_ci kfree(queue); 69462306a36Sopenharmony_ci return r; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ciint amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci unsigned long flags; 70062306a36Sopenharmony_ci struct amdgpu_mes_queue *queue; 70162306a36Sopenharmony_ci struct amdgpu_mes_gang *gang; 70262306a36Sopenharmony_ci struct mes_remove_queue_input queue_input; 70362306a36Sopenharmony_ci int r; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 70762306a36Sopenharmony_ci * lock dependencies. 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* remove the mes gang from idr list */ 71262306a36Sopenharmony_ci spin_lock_irqsave(&adev->mes.queue_id_lock, flags); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci queue = idr_find(&adev->mes.queue_id_idr, queue_id); 71562306a36Sopenharmony_ci if (!queue) { 71662306a36Sopenharmony_ci spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); 71762306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 71862306a36Sopenharmony_ci DRM_ERROR("queue id %d doesn't exist\n", queue_id); 71962306a36Sopenharmony_ci return -EINVAL; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci idr_remove(&adev->mes.queue_id_idr, queue_id); 72362306a36Sopenharmony_ci spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci DRM_DEBUG("try to remove queue, doorbell off = 0x%llx\n", 72662306a36Sopenharmony_ci queue->doorbell_off); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci gang = queue->gang; 72962306a36Sopenharmony_ci queue_input.doorbell_offset = queue->doorbell_off; 73062306a36Sopenharmony_ci queue_input.gang_context_addr = gang->gang_ctx_gpu_addr; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input); 73362306a36Sopenharmony_ci if (r) 73462306a36Sopenharmony_ci DRM_ERROR("failed to remove hardware queue, queue id = %d\n", 73562306a36Sopenharmony_ci queue_id); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci list_del(&queue->list); 73862306a36Sopenharmony_ci amdgpu_mes_kernel_doorbell_free(adev, gang->process, 73962306a36Sopenharmony_ci queue->doorbell_off); 74062306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci amdgpu_mes_queue_free_mqd(queue); 74362306a36Sopenharmony_ci kfree(queue); 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ciint amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev, 74862306a36Sopenharmony_ci struct amdgpu_ring *ring, 74962306a36Sopenharmony_ci enum amdgpu_unmap_queues_action action, 75062306a36Sopenharmony_ci u64 gpu_addr, u64 seq) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct mes_unmap_legacy_queue_input queue_input; 75362306a36Sopenharmony_ci int r; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci queue_input.action = action; 75662306a36Sopenharmony_ci queue_input.queue_type = ring->funcs->type; 75762306a36Sopenharmony_ci queue_input.doorbell_offset = ring->doorbell_index; 75862306a36Sopenharmony_ci queue_input.pipe_id = ring->pipe; 75962306a36Sopenharmony_ci queue_input.queue_id = ring->queue; 76062306a36Sopenharmony_ci queue_input.trail_fence_addr = gpu_addr; 76162306a36Sopenharmony_ci queue_input.trail_fence_data = seq; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci r = adev->mes.funcs->unmap_legacy_queue(&adev->mes, &queue_input); 76462306a36Sopenharmony_ci if (r) 76562306a36Sopenharmony_ci DRM_ERROR("failed to unmap legacy queue\n"); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci return r; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ciuint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct mes_misc_op_input op_input; 77362306a36Sopenharmony_ci int r, val = 0; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci op_input.op = MES_MISC_OP_READ_REG; 77662306a36Sopenharmony_ci op_input.read_reg.reg_offset = reg; 77762306a36Sopenharmony_ci op_input.read_reg.buffer_addr = adev->mes.read_val_gpu_addr; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (!adev->mes.funcs->misc_op) { 78062306a36Sopenharmony_ci DRM_ERROR("mes rreg is not supported!\n"); 78162306a36Sopenharmony_ci goto error; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci r = adev->mes.funcs->misc_op(&adev->mes, &op_input); 78562306a36Sopenharmony_ci if (r) 78662306a36Sopenharmony_ci DRM_ERROR("failed to read reg (0x%x)\n", reg); 78762306a36Sopenharmony_ci else 78862306a36Sopenharmony_ci val = *(adev->mes.read_val_ptr); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cierror: 79162306a36Sopenharmony_ci return val; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ciint amdgpu_mes_wreg(struct amdgpu_device *adev, 79562306a36Sopenharmony_ci uint32_t reg, uint32_t val) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci struct mes_misc_op_input op_input; 79862306a36Sopenharmony_ci int r; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci op_input.op = MES_MISC_OP_WRITE_REG; 80162306a36Sopenharmony_ci op_input.write_reg.reg_offset = reg; 80262306a36Sopenharmony_ci op_input.write_reg.reg_value = val; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (!adev->mes.funcs->misc_op) { 80562306a36Sopenharmony_ci DRM_ERROR("mes wreg is not supported!\n"); 80662306a36Sopenharmony_ci r = -EINVAL; 80762306a36Sopenharmony_ci goto error; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci r = adev->mes.funcs->misc_op(&adev->mes, &op_input); 81162306a36Sopenharmony_ci if (r) 81262306a36Sopenharmony_ci DRM_ERROR("failed to write reg (0x%x)\n", reg); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cierror: 81562306a36Sopenharmony_ci return r; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ciint amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev, 81962306a36Sopenharmony_ci uint32_t reg0, uint32_t reg1, 82062306a36Sopenharmony_ci uint32_t ref, uint32_t mask) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct mes_misc_op_input op_input; 82362306a36Sopenharmony_ci int r; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci op_input.op = MES_MISC_OP_WRM_REG_WR_WAIT; 82662306a36Sopenharmony_ci op_input.wrm_reg.reg0 = reg0; 82762306a36Sopenharmony_ci op_input.wrm_reg.reg1 = reg1; 82862306a36Sopenharmony_ci op_input.wrm_reg.ref = ref; 82962306a36Sopenharmony_ci op_input.wrm_reg.mask = mask; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (!adev->mes.funcs->misc_op) { 83262306a36Sopenharmony_ci DRM_ERROR("mes reg_write_reg_wait is not supported!\n"); 83362306a36Sopenharmony_ci r = -EINVAL; 83462306a36Sopenharmony_ci goto error; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci r = adev->mes.funcs->misc_op(&adev->mes, &op_input); 83862306a36Sopenharmony_ci if (r) 83962306a36Sopenharmony_ci DRM_ERROR("failed to reg_write_reg_wait\n"); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cierror: 84262306a36Sopenharmony_ci return r; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ciint amdgpu_mes_reg_wait(struct amdgpu_device *adev, uint32_t reg, 84662306a36Sopenharmony_ci uint32_t val, uint32_t mask) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct mes_misc_op_input op_input; 84962306a36Sopenharmony_ci int r; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci op_input.op = MES_MISC_OP_WRM_REG_WAIT; 85262306a36Sopenharmony_ci op_input.wrm_reg.reg0 = reg; 85362306a36Sopenharmony_ci op_input.wrm_reg.ref = val; 85462306a36Sopenharmony_ci op_input.wrm_reg.mask = mask; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (!adev->mes.funcs->misc_op) { 85762306a36Sopenharmony_ci DRM_ERROR("mes reg wait is not supported!\n"); 85862306a36Sopenharmony_ci r = -EINVAL; 85962306a36Sopenharmony_ci goto error; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci r = adev->mes.funcs->misc_op(&adev->mes, &op_input); 86362306a36Sopenharmony_ci if (r) 86462306a36Sopenharmony_ci DRM_ERROR("failed to reg_write_reg_wait\n"); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cierror: 86762306a36Sopenharmony_ci return r; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ciint amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, 87162306a36Sopenharmony_ci uint64_t process_context_addr, 87262306a36Sopenharmony_ci uint32_t spi_gdbg_per_vmid_cntl, 87362306a36Sopenharmony_ci const uint32_t *tcp_watch_cntl, 87462306a36Sopenharmony_ci uint32_t flags, 87562306a36Sopenharmony_ci bool trap_en) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci struct mes_misc_op_input op_input = {0}; 87862306a36Sopenharmony_ci int r; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (!adev->mes.funcs->misc_op) { 88162306a36Sopenharmony_ci DRM_ERROR("mes set shader debugger is not supported!\n"); 88262306a36Sopenharmony_ci return -EINVAL; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER; 88662306a36Sopenharmony_ci op_input.set_shader_debugger.process_context_addr = process_context_addr; 88762306a36Sopenharmony_ci op_input.set_shader_debugger.flags.u32all = flags; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* use amdgpu mes_flush_shader_debugger instead */ 89062306a36Sopenharmony_ci if (op_input.set_shader_debugger.flags.process_ctx_flush) 89162306a36Sopenharmony_ci return -EINVAL; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci op_input.set_shader_debugger.spi_gdbg_per_vmid_cntl = spi_gdbg_per_vmid_cntl; 89462306a36Sopenharmony_ci memcpy(op_input.set_shader_debugger.tcp_watch_cntl, tcp_watch_cntl, 89562306a36Sopenharmony_ci sizeof(op_input.set_shader_debugger.tcp_watch_cntl)); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (((adev->mes.sched_version & AMDGPU_MES_API_VERSION_MASK) >> 89862306a36Sopenharmony_ci AMDGPU_MES_API_VERSION_SHIFT) >= 14) 89962306a36Sopenharmony_ci op_input.set_shader_debugger.trap_en = trap_en; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci r = adev->mes.funcs->misc_op(&adev->mes, &op_input); 90462306a36Sopenharmony_ci if (r) 90562306a36Sopenharmony_ci DRM_ERROR("failed to set_shader_debugger\n"); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci return r; 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ciint amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev, 91362306a36Sopenharmony_ci uint64_t process_context_addr) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct mes_misc_op_input op_input = {0}; 91662306a36Sopenharmony_ci int r; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (!adev->mes.funcs->misc_op) { 91962306a36Sopenharmony_ci DRM_ERROR("mes flush shader debugger is not supported!\n"); 92062306a36Sopenharmony_ci return -EINVAL; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER; 92462306a36Sopenharmony_ci op_input.set_shader_debugger.process_context_addr = process_context_addr; 92562306a36Sopenharmony_ci op_input.set_shader_debugger.flags.process_ctx_flush = true; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci r = adev->mes.funcs->misc_op(&adev->mes, &op_input); 93062306a36Sopenharmony_ci if (r) 93162306a36Sopenharmony_ci DRM_ERROR("failed to set_shader_debugger\n"); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci return r; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic void 93962306a36Sopenharmony_ciamdgpu_mes_ring_to_queue_props(struct amdgpu_device *adev, 94062306a36Sopenharmony_ci struct amdgpu_ring *ring, 94162306a36Sopenharmony_ci struct amdgpu_mes_queue_properties *props) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci props->queue_type = ring->funcs->type; 94462306a36Sopenharmony_ci props->hqd_base_gpu_addr = ring->gpu_addr; 94562306a36Sopenharmony_ci props->rptr_gpu_addr = ring->rptr_gpu_addr; 94662306a36Sopenharmony_ci props->wptr_gpu_addr = ring->wptr_gpu_addr; 94762306a36Sopenharmony_ci props->wptr_mc_addr = 94862306a36Sopenharmony_ci ring->mes_ctx->meta_data_mc_addr + ring->wptr_offs; 94962306a36Sopenharmony_ci props->queue_size = ring->ring_size; 95062306a36Sopenharmony_ci props->eop_gpu_addr = ring->eop_gpu_addr; 95162306a36Sopenharmony_ci props->hqd_pipe_priority = AMDGPU_GFX_PIPE_PRIO_NORMAL; 95262306a36Sopenharmony_ci props->hqd_queue_priority = AMDGPU_GFX_QUEUE_PRIORITY_MINIMUM; 95362306a36Sopenharmony_ci props->paging = false; 95462306a36Sopenharmony_ci props->ring = ring; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci#define DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(_eng) \ 95862306a36Sopenharmony_cido { \ 95962306a36Sopenharmony_ci if (id_offs < AMDGPU_MES_CTX_MAX_OFFS) \ 96062306a36Sopenharmony_ci return offsetof(struct amdgpu_mes_ctx_meta_data, \ 96162306a36Sopenharmony_ci _eng[ring->idx].slots[id_offs]); \ 96262306a36Sopenharmony_ci else if (id_offs == AMDGPU_MES_CTX_RING_OFFS) \ 96362306a36Sopenharmony_ci return offsetof(struct amdgpu_mes_ctx_meta_data, \ 96462306a36Sopenharmony_ci _eng[ring->idx].ring); \ 96562306a36Sopenharmony_ci else if (id_offs == AMDGPU_MES_CTX_IB_OFFS) \ 96662306a36Sopenharmony_ci return offsetof(struct amdgpu_mes_ctx_meta_data, \ 96762306a36Sopenharmony_ci _eng[ring->idx].ib); \ 96862306a36Sopenharmony_ci else if (id_offs == AMDGPU_MES_CTX_PADDING_OFFS) \ 96962306a36Sopenharmony_ci return offsetof(struct amdgpu_mes_ctx_meta_data, \ 97062306a36Sopenharmony_ci _eng[ring->idx].padding); \ 97162306a36Sopenharmony_ci} while(0) 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ciint amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci switch (ring->funcs->type) { 97662306a36Sopenharmony_ci case AMDGPU_RING_TYPE_GFX: 97762306a36Sopenharmony_ci DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(gfx); 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci case AMDGPU_RING_TYPE_COMPUTE: 98062306a36Sopenharmony_ci DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(compute); 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci case AMDGPU_RING_TYPE_SDMA: 98362306a36Sopenharmony_ci DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(sdma); 98462306a36Sopenharmony_ci break; 98562306a36Sopenharmony_ci default: 98662306a36Sopenharmony_ci break; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci WARN_ON(1); 99062306a36Sopenharmony_ci return -EINVAL; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ciint amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, 99462306a36Sopenharmony_ci int queue_type, int idx, 99562306a36Sopenharmony_ci struct amdgpu_mes_ctx_data *ctx_data, 99662306a36Sopenharmony_ci struct amdgpu_ring **out) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci struct amdgpu_ring *ring; 99962306a36Sopenharmony_ci struct amdgpu_mes_gang *gang; 100062306a36Sopenharmony_ci struct amdgpu_mes_queue_properties qprops = {0}; 100162306a36Sopenharmony_ci int r, queue_id, pasid; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* 100462306a36Sopenharmony_ci * Avoid taking any other locks under MES lock to avoid circular 100562306a36Sopenharmony_ci * lock dependencies. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci amdgpu_mes_lock(&adev->mes); 100862306a36Sopenharmony_ci gang = idr_find(&adev->mes.gang_id_idr, gang_id); 100962306a36Sopenharmony_ci if (!gang) { 101062306a36Sopenharmony_ci DRM_ERROR("gang id %d doesn't exist\n", gang_id); 101162306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 101262306a36Sopenharmony_ci return -EINVAL; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci pasid = gang->process->pasid; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci ring = kzalloc(sizeof(struct amdgpu_ring), GFP_KERNEL); 101762306a36Sopenharmony_ci if (!ring) { 101862306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 101962306a36Sopenharmony_ci return -ENOMEM; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci ring->ring_obj = NULL; 102362306a36Sopenharmony_ci ring->use_doorbell = true; 102462306a36Sopenharmony_ci ring->is_mes_queue = true; 102562306a36Sopenharmony_ci ring->mes_ctx = ctx_data; 102662306a36Sopenharmony_ci ring->idx = idx; 102762306a36Sopenharmony_ci ring->no_scheduler = true; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (queue_type == AMDGPU_RING_TYPE_COMPUTE) { 103062306a36Sopenharmony_ci int offset = offsetof(struct amdgpu_mes_ctx_meta_data, 103162306a36Sopenharmony_ci compute[ring->idx].mec_hpd); 103262306a36Sopenharmony_ci ring->eop_gpu_addr = 103362306a36Sopenharmony_ci amdgpu_mes_ctx_get_offs_gpu_addr(ring, offset); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci switch (queue_type) { 103762306a36Sopenharmony_ci case AMDGPU_RING_TYPE_GFX: 103862306a36Sopenharmony_ci ring->funcs = adev->gfx.gfx_ring[0].funcs; 103962306a36Sopenharmony_ci ring->me = adev->gfx.gfx_ring[0].me; 104062306a36Sopenharmony_ci ring->pipe = adev->gfx.gfx_ring[0].pipe; 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci case AMDGPU_RING_TYPE_COMPUTE: 104362306a36Sopenharmony_ci ring->funcs = adev->gfx.compute_ring[0].funcs; 104462306a36Sopenharmony_ci ring->me = adev->gfx.compute_ring[0].me; 104562306a36Sopenharmony_ci ring->pipe = adev->gfx.compute_ring[0].pipe; 104662306a36Sopenharmony_ci break; 104762306a36Sopenharmony_ci case AMDGPU_RING_TYPE_SDMA: 104862306a36Sopenharmony_ci ring->funcs = adev->sdma.instance[0].ring.funcs; 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci default: 105162306a36Sopenharmony_ci BUG(); 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci r = amdgpu_ring_init(adev, ring, 1024, NULL, 0, 105562306a36Sopenharmony_ci AMDGPU_RING_PRIO_DEFAULT, NULL); 105662306a36Sopenharmony_ci if (r) 105762306a36Sopenharmony_ci goto clean_up_memory; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci amdgpu_mes_ring_to_queue_props(adev, ring, &qprops); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci dma_fence_wait(gang->process->vm->last_update, false); 106262306a36Sopenharmony_ci dma_fence_wait(ctx_data->meta_data_va->last_pt_update, false); 106362306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci r = amdgpu_mes_add_hw_queue(adev, gang_id, &qprops, &queue_id); 106662306a36Sopenharmony_ci if (r) 106762306a36Sopenharmony_ci goto clean_up_ring; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci ring->hw_queue_id = queue_id; 107062306a36Sopenharmony_ci ring->doorbell_index = qprops.doorbell_off; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (queue_type == AMDGPU_RING_TYPE_GFX) 107362306a36Sopenharmony_ci sprintf(ring->name, "gfx_%d.%d.%d", pasid, gang_id, queue_id); 107462306a36Sopenharmony_ci else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) 107562306a36Sopenharmony_ci sprintf(ring->name, "compute_%d.%d.%d", pasid, gang_id, 107662306a36Sopenharmony_ci queue_id); 107762306a36Sopenharmony_ci else if (queue_type == AMDGPU_RING_TYPE_SDMA) 107862306a36Sopenharmony_ci sprintf(ring->name, "sdma_%d.%d.%d", pasid, gang_id, 107962306a36Sopenharmony_ci queue_id); 108062306a36Sopenharmony_ci else 108162306a36Sopenharmony_ci BUG(); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci *out = ring; 108462306a36Sopenharmony_ci return 0; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ciclean_up_ring: 108762306a36Sopenharmony_ci amdgpu_ring_fini(ring); 108862306a36Sopenharmony_ciclean_up_memory: 108962306a36Sopenharmony_ci kfree(ring); 109062306a36Sopenharmony_ci amdgpu_mes_unlock(&adev->mes); 109162306a36Sopenharmony_ci return r; 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_civoid amdgpu_mes_remove_ring(struct amdgpu_device *adev, 109562306a36Sopenharmony_ci struct amdgpu_ring *ring) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci if (!ring) 109862306a36Sopenharmony_ci return; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci amdgpu_mes_remove_hw_queue(adev, ring->hw_queue_id); 110162306a36Sopenharmony_ci amdgpu_ring_fini(ring); 110262306a36Sopenharmony_ci kfree(ring); 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ciuint32_t amdgpu_mes_get_aggregated_doorbell_index(struct amdgpu_device *adev, 110662306a36Sopenharmony_ci enum amdgpu_mes_priority_level prio) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci return adev->mes.aggregated_doorbells[prio]; 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ciint amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device *adev, 111262306a36Sopenharmony_ci struct amdgpu_mes_ctx_data *ctx_data) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci int r; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, 111762306a36Sopenharmony_ci sizeof(struct amdgpu_mes_ctx_meta_data), 111862306a36Sopenharmony_ci PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, 111962306a36Sopenharmony_ci &ctx_data->meta_data_obj, 112062306a36Sopenharmony_ci &ctx_data->meta_data_mc_addr, 112162306a36Sopenharmony_ci &ctx_data->meta_data_ptr); 112262306a36Sopenharmony_ci if (r) { 112362306a36Sopenharmony_ci dev_warn(adev->dev, "(%d) create CTX bo failed\n", r); 112462306a36Sopenharmony_ci return r; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci if (!ctx_data->meta_data_obj) 112862306a36Sopenharmony_ci return -ENOMEM; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci memset(ctx_data->meta_data_ptr, 0, 113162306a36Sopenharmony_ci sizeof(struct amdgpu_mes_ctx_meta_data)); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_civoid amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci if (ctx_data->meta_data_obj) 113962306a36Sopenharmony_ci amdgpu_bo_free_kernel(&ctx_data->meta_data_obj, 114062306a36Sopenharmony_ci &ctx_data->meta_data_mc_addr, 114162306a36Sopenharmony_ci &ctx_data->meta_data_ptr); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ciint amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev, 114562306a36Sopenharmony_ci struct amdgpu_vm *vm, 114662306a36Sopenharmony_ci struct amdgpu_mes_ctx_data *ctx_data) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct amdgpu_bo_va *bo_va; 114962306a36Sopenharmony_ci struct amdgpu_sync sync; 115062306a36Sopenharmony_ci struct drm_exec exec; 115162306a36Sopenharmony_ci int r; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci amdgpu_sync_create(&sync); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci drm_exec_init(&exec, 0); 115662306a36Sopenharmony_ci drm_exec_until_all_locked(&exec) { 115762306a36Sopenharmony_ci r = drm_exec_lock_obj(&exec, 115862306a36Sopenharmony_ci &ctx_data->meta_data_obj->tbo.base); 115962306a36Sopenharmony_ci drm_exec_retry_on_contention(&exec); 116062306a36Sopenharmony_ci if (unlikely(r)) 116162306a36Sopenharmony_ci goto error_fini_exec; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci r = amdgpu_vm_lock_pd(vm, &exec, 0); 116462306a36Sopenharmony_ci drm_exec_retry_on_contention(&exec); 116562306a36Sopenharmony_ci if (unlikely(r)) 116662306a36Sopenharmony_ci goto error_fini_exec; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci bo_va = amdgpu_vm_bo_add(adev, vm, ctx_data->meta_data_obj); 117062306a36Sopenharmony_ci if (!bo_va) { 117162306a36Sopenharmony_ci DRM_ERROR("failed to create bo_va for meta data BO\n"); 117262306a36Sopenharmony_ci r = -ENOMEM; 117362306a36Sopenharmony_ci goto error_fini_exec; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci r = amdgpu_vm_bo_map(adev, bo_va, ctx_data->meta_data_gpu_addr, 0, 117762306a36Sopenharmony_ci sizeof(struct amdgpu_mes_ctx_meta_data), 117862306a36Sopenharmony_ci AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | 117962306a36Sopenharmony_ci AMDGPU_PTE_EXECUTABLE); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (r) { 118262306a36Sopenharmony_ci DRM_ERROR("failed to do bo_map on meta data, err=%d\n", r); 118362306a36Sopenharmony_ci goto error_del_bo_va; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci r = amdgpu_vm_bo_update(adev, bo_va, false); 118762306a36Sopenharmony_ci if (r) { 118862306a36Sopenharmony_ci DRM_ERROR("failed to do vm_bo_update on meta data\n"); 118962306a36Sopenharmony_ci goto error_del_bo_va; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci amdgpu_sync_fence(&sync, bo_va->last_pt_update); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci r = amdgpu_vm_update_pdes(adev, vm, false); 119462306a36Sopenharmony_ci if (r) { 119562306a36Sopenharmony_ci DRM_ERROR("failed to update pdes on meta data\n"); 119662306a36Sopenharmony_ci goto error_del_bo_va; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci amdgpu_sync_fence(&sync, vm->last_update); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci amdgpu_sync_wait(&sync, false); 120162306a36Sopenharmony_ci drm_exec_fini(&exec); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci amdgpu_sync_free(&sync); 120462306a36Sopenharmony_ci ctx_data->meta_data_va = bo_va; 120562306a36Sopenharmony_ci return 0; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cierror_del_bo_va: 120862306a36Sopenharmony_ci amdgpu_vm_bo_del(adev, bo_va); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cierror_fini_exec: 121162306a36Sopenharmony_ci drm_exec_fini(&exec); 121262306a36Sopenharmony_ci amdgpu_sync_free(&sync); 121362306a36Sopenharmony_ci return r; 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ciint amdgpu_mes_ctx_unmap_meta_data(struct amdgpu_device *adev, 121762306a36Sopenharmony_ci struct amdgpu_mes_ctx_data *ctx_data) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct amdgpu_bo_va *bo_va = ctx_data->meta_data_va; 122062306a36Sopenharmony_ci struct amdgpu_bo *bo = ctx_data->meta_data_obj; 122162306a36Sopenharmony_ci struct amdgpu_vm *vm = bo_va->base.vm; 122262306a36Sopenharmony_ci struct dma_fence *fence; 122362306a36Sopenharmony_ci struct drm_exec exec; 122462306a36Sopenharmony_ci long r; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci drm_exec_init(&exec, 0); 122762306a36Sopenharmony_ci drm_exec_until_all_locked(&exec) { 122862306a36Sopenharmony_ci r = drm_exec_lock_obj(&exec, 122962306a36Sopenharmony_ci &ctx_data->meta_data_obj->tbo.base); 123062306a36Sopenharmony_ci drm_exec_retry_on_contention(&exec); 123162306a36Sopenharmony_ci if (unlikely(r)) 123262306a36Sopenharmony_ci goto out_unlock; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci r = amdgpu_vm_lock_pd(vm, &exec, 0); 123562306a36Sopenharmony_ci drm_exec_retry_on_contention(&exec); 123662306a36Sopenharmony_ci if (unlikely(r)) 123762306a36Sopenharmony_ci goto out_unlock; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci amdgpu_vm_bo_del(adev, bo_va); 124162306a36Sopenharmony_ci if (!amdgpu_vm_ready(vm)) 124262306a36Sopenharmony_ci goto out_unlock; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci r = dma_resv_get_singleton(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP, 124562306a36Sopenharmony_ci &fence); 124662306a36Sopenharmony_ci if (r) 124762306a36Sopenharmony_ci goto out_unlock; 124862306a36Sopenharmony_ci if (fence) { 124962306a36Sopenharmony_ci amdgpu_bo_fence(bo, fence, true); 125062306a36Sopenharmony_ci fence = NULL; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci r = amdgpu_vm_clear_freed(adev, vm, &fence); 125462306a36Sopenharmony_ci if (r || !fence) 125562306a36Sopenharmony_ci goto out_unlock; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci dma_fence_wait(fence, false); 125862306a36Sopenharmony_ci amdgpu_bo_fence(bo, fence, true); 125962306a36Sopenharmony_ci dma_fence_put(fence); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ciout_unlock: 126262306a36Sopenharmony_ci if (unlikely(r < 0)) 126362306a36Sopenharmony_ci dev_err(adev->dev, "failed to clear page tables (%ld)\n", r); 126462306a36Sopenharmony_ci drm_exec_fini(&exec); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return r; 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cistatic int amdgpu_mes_test_create_gang_and_queues(struct amdgpu_device *adev, 127062306a36Sopenharmony_ci int pasid, int *gang_id, 127162306a36Sopenharmony_ci int queue_type, int num_queue, 127262306a36Sopenharmony_ci struct amdgpu_ring **added_rings, 127362306a36Sopenharmony_ci struct amdgpu_mes_ctx_data *ctx_data) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci struct amdgpu_ring *ring; 127662306a36Sopenharmony_ci struct amdgpu_mes_gang_properties gprops = {0}; 127762306a36Sopenharmony_ci int r, j; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* create a gang for the process */ 128062306a36Sopenharmony_ci gprops.priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; 128162306a36Sopenharmony_ci gprops.gang_quantum = adev->mes.default_gang_quantum; 128262306a36Sopenharmony_ci gprops.inprocess_gang_priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; 128362306a36Sopenharmony_ci gprops.priority_level = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; 128462306a36Sopenharmony_ci gprops.global_priority_level = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci r = amdgpu_mes_add_gang(adev, pasid, &gprops, gang_id); 128762306a36Sopenharmony_ci if (r) { 128862306a36Sopenharmony_ci DRM_ERROR("failed to add gang\n"); 128962306a36Sopenharmony_ci return r; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* create queues for the gang */ 129362306a36Sopenharmony_ci for (j = 0; j < num_queue; j++) { 129462306a36Sopenharmony_ci r = amdgpu_mes_add_ring(adev, *gang_id, queue_type, j, 129562306a36Sopenharmony_ci ctx_data, &ring); 129662306a36Sopenharmony_ci if (r) { 129762306a36Sopenharmony_ci DRM_ERROR("failed to add ring\n"); 129862306a36Sopenharmony_ci break; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci DRM_INFO("ring %s was added\n", ring->name); 130262306a36Sopenharmony_ci added_rings[j] = ring; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci return 0; 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic int amdgpu_mes_test_queues(struct amdgpu_ring **added_rings) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci struct amdgpu_ring *ring; 131162306a36Sopenharmony_ci int i, r; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MES_CTX_MAX_RINGS; i++) { 131462306a36Sopenharmony_ci ring = added_rings[i]; 131562306a36Sopenharmony_ci if (!ring) 131662306a36Sopenharmony_ci continue; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci r = amdgpu_ring_test_helper(ring); 131962306a36Sopenharmony_ci if (r) 132062306a36Sopenharmony_ci return r; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci r = amdgpu_ring_test_ib(ring, 1000 * 10); 132362306a36Sopenharmony_ci if (r) { 132462306a36Sopenharmony_ci DRM_DEV_ERROR(ring->adev->dev, 132562306a36Sopenharmony_ci "ring %s ib test failed (%d)\n", 132662306a36Sopenharmony_ci ring->name, r); 132762306a36Sopenharmony_ci return r; 132862306a36Sopenharmony_ci } else 132962306a36Sopenharmony_ci DRM_INFO("ring %s ib test pass\n", ring->name); 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci return 0; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ciint amdgpu_mes_self_test(struct amdgpu_device *adev) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci struct amdgpu_vm *vm = NULL; 133862306a36Sopenharmony_ci struct amdgpu_mes_ctx_data ctx_data = {0}; 133962306a36Sopenharmony_ci struct amdgpu_ring *added_rings[AMDGPU_MES_CTX_MAX_RINGS] = { NULL }; 134062306a36Sopenharmony_ci int gang_ids[3] = {0}; 134162306a36Sopenharmony_ci int queue_types[][2] = { { AMDGPU_RING_TYPE_GFX, 1 }, 134262306a36Sopenharmony_ci { AMDGPU_RING_TYPE_COMPUTE, 1 }, 134362306a36Sopenharmony_ci { AMDGPU_RING_TYPE_SDMA, 1} }; 134462306a36Sopenharmony_ci int i, r, pasid, k = 0; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci pasid = amdgpu_pasid_alloc(16); 134762306a36Sopenharmony_ci if (pasid < 0) { 134862306a36Sopenharmony_ci dev_warn(adev->dev, "No more PASIDs available!"); 134962306a36Sopenharmony_ci pasid = 0; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci vm = kzalloc(sizeof(*vm), GFP_KERNEL); 135362306a36Sopenharmony_ci if (!vm) { 135462306a36Sopenharmony_ci r = -ENOMEM; 135562306a36Sopenharmony_ci goto error_pasid; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci r = amdgpu_vm_init(adev, vm, -1); 135962306a36Sopenharmony_ci if (r) { 136062306a36Sopenharmony_ci DRM_ERROR("failed to initialize vm\n"); 136162306a36Sopenharmony_ci goto error_pasid; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci r = amdgpu_mes_ctx_alloc_meta_data(adev, &ctx_data); 136562306a36Sopenharmony_ci if (r) { 136662306a36Sopenharmony_ci DRM_ERROR("failed to alloc ctx meta data\n"); 136762306a36Sopenharmony_ci goto error_fini; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci ctx_data.meta_data_gpu_addr = AMDGPU_VA_RESERVED_SIZE; 137162306a36Sopenharmony_ci r = amdgpu_mes_ctx_map_meta_data(adev, vm, &ctx_data); 137262306a36Sopenharmony_ci if (r) { 137362306a36Sopenharmony_ci DRM_ERROR("failed to map ctx meta data\n"); 137462306a36Sopenharmony_ci goto error_vm; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci r = amdgpu_mes_create_process(adev, pasid, vm); 137862306a36Sopenharmony_ci if (r) { 137962306a36Sopenharmony_ci DRM_ERROR("failed to create MES process\n"); 138062306a36Sopenharmony_ci goto error_vm; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(queue_types); i++) { 138462306a36Sopenharmony_ci /* On GFX v10.3, fw hasn't supported to map sdma queue. */ 138562306a36Sopenharmony_ci if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0) && 138662306a36Sopenharmony_ci adev->ip_versions[GC_HWIP][0] < IP_VERSION(11, 0, 0) && 138762306a36Sopenharmony_ci queue_types[i][0] == AMDGPU_RING_TYPE_SDMA) 138862306a36Sopenharmony_ci continue; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci r = amdgpu_mes_test_create_gang_and_queues(adev, pasid, 139162306a36Sopenharmony_ci &gang_ids[i], 139262306a36Sopenharmony_ci queue_types[i][0], 139362306a36Sopenharmony_ci queue_types[i][1], 139462306a36Sopenharmony_ci &added_rings[k], 139562306a36Sopenharmony_ci &ctx_data); 139662306a36Sopenharmony_ci if (r) 139762306a36Sopenharmony_ci goto error_queues; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci k += queue_types[i][1]; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci /* start ring test and ib test for MES queues */ 140362306a36Sopenharmony_ci amdgpu_mes_test_queues(added_rings); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cierror_queues: 140662306a36Sopenharmony_ci /* remove all queues */ 140762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(added_rings); i++) { 140862306a36Sopenharmony_ci if (!added_rings[i]) 140962306a36Sopenharmony_ci continue; 141062306a36Sopenharmony_ci amdgpu_mes_remove_ring(adev, added_rings[i]); 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gang_ids); i++) { 141462306a36Sopenharmony_ci if (!gang_ids[i]) 141562306a36Sopenharmony_ci continue; 141662306a36Sopenharmony_ci amdgpu_mes_remove_gang(adev, gang_ids[i]); 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci amdgpu_mes_destroy_process(adev, pasid); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_cierror_vm: 142262306a36Sopenharmony_ci amdgpu_mes_ctx_unmap_meta_data(adev, &ctx_data); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_cierror_fini: 142562306a36Sopenharmony_ci amdgpu_vm_fini(adev, vm); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_cierror_pasid: 142862306a36Sopenharmony_ci if (pasid) 142962306a36Sopenharmony_ci amdgpu_pasid_free(pasid); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci amdgpu_mes_ctx_free_meta_data(&ctx_data); 143262306a36Sopenharmony_ci kfree(vm); 143362306a36Sopenharmony_ci return 0; 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ciint amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci const struct mes_firmware_header_v1_0 *mes_hdr; 143962306a36Sopenharmony_ci struct amdgpu_firmware_info *info; 144062306a36Sopenharmony_ci char ucode_prefix[30]; 144162306a36Sopenharmony_ci char fw_name[40]; 144262306a36Sopenharmony_ci bool need_retry = false; 144362306a36Sopenharmony_ci int r; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, 144662306a36Sopenharmony_ci sizeof(ucode_prefix)); 144762306a36Sopenharmony_ci if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(11, 0, 0)) { 144862306a36Sopenharmony_ci snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin", 144962306a36Sopenharmony_ci ucode_prefix, 145062306a36Sopenharmony_ci pipe == AMDGPU_MES_SCHED_PIPE ? "_2" : "1"); 145162306a36Sopenharmony_ci need_retry = true; 145262306a36Sopenharmony_ci } else { 145362306a36Sopenharmony_ci snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin", 145462306a36Sopenharmony_ci ucode_prefix, 145562306a36Sopenharmony_ci pipe == AMDGPU_MES_SCHED_PIPE ? "" : "1"); 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], fw_name); 145962306a36Sopenharmony_ci if (r && need_retry && pipe == AMDGPU_MES_SCHED_PIPE) { 146062306a36Sopenharmony_ci snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin", 146162306a36Sopenharmony_ci ucode_prefix); 146262306a36Sopenharmony_ci DRM_INFO("try to fall back to %s\n", fw_name); 146362306a36Sopenharmony_ci r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], 146462306a36Sopenharmony_ci fw_name); 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if (r) 146862306a36Sopenharmony_ci goto out; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci mes_hdr = (const struct mes_firmware_header_v1_0 *) 147162306a36Sopenharmony_ci adev->mes.fw[pipe]->data; 147262306a36Sopenharmony_ci adev->mes.uc_start_addr[pipe] = 147362306a36Sopenharmony_ci le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) | 147462306a36Sopenharmony_ci ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32); 147562306a36Sopenharmony_ci adev->mes.data_start_addr[pipe] = 147662306a36Sopenharmony_ci le32_to_cpu(mes_hdr->mes_data_start_addr_lo) | 147762306a36Sopenharmony_ci ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 148062306a36Sopenharmony_ci int ucode, ucode_data; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci if (pipe == AMDGPU_MES_SCHED_PIPE) { 148362306a36Sopenharmony_ci ucode = AMDGPU_UCODE_ID_CP_MES; 148462306a36Sopenharmony_ci ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA; 148562306a36Sopenharmony_ci } else { 148662306a36Sopenharmony_ci ucode = AMDGPU_UCODE_ID_CP_MES1; 148762306a36Sopenharmony_ci ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA; 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci info = &adev->firmware.ucode[ucode]; 149162306a36Sopenharmony_ci info->ucode_id = ucode; 149262306a36Sopenharmony_ci info->fw = adev->mes.fw[pipe]; 149362306a36Sopenharmony_ci adev->firmware.fw_size += 149462306a36Sopenharmony_ci ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes), 149562306a36Sopenharmony_ci PAGE_SIZE); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci info = &adev->firmware.ucode[ucode_data]; 149862306a36Sopenharmony_ci info->ucode_id = ucode_data; 149962306a36Sopenharmony_ci info->fw = adev->mes.fw[pipe]; 150062306a36Sopenharmony_ci adev->firmware.fw_size += 150162306a36Sopenharmony_ci ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes), 150262306a36Sopenharmony_ci PAGE_SIZE); 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci return 0; 150662306a36Sopenharmony_ciout: 150762306a36Sopenharmony_ci amdgpu_ucode_release(&adev->mes.fw[pipe]); 150862306a36Sopenharmony_ci return r; 150962306a36Sopenharmony_ci} 1510