From 32de57e9ef59b6f646849a8bd615b7c978a4fa6d Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Mon, 11 Apr 2022 16:46:13 -0400 Subject: drm/amdgpu/mes: manage mes doorbell allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is used to manage the doorbell allocation of mes processes and queues. Driver calls into process doorbell allocation to get the slice doorbell for the process, then the doorbell for a queue is allocated from the process doorbell slice. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 133 ++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c new file mode 100644 index 000000000000..1c591cb45fd9 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -0,0 +1,133 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "amdgpu_mes.h" +#include "amdgpu.h" +#include "soc15_common.h" +#include "amdgpu_mes_ctx.h" + +#define AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS 1024 +#define AMDGPU_ONE_DOORBELL_SIZE 8 + +static int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev) +{ + return roundup(AMDGPU_ONE_DOORBELL_SIZE * + AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS, + PAGE_SIZE); +} + +static int amdgpu_mes_alloc_process_doorbells(struct amdgpu_device *adev, + struct amdgpu_mes_process *process) +{ + int r = ida_simple_get(&adev->mes.doorbell_ida, 2, + adev->mes.max_doorbell_slices, + GFP_KERNEL); + if (r > 0) + process->doorbell_index = r; + + return r; +} + +static void amdgpu_mes_free_process_doorbells(struct amdgpu_device *adev, + struct amdgpu_mes_process *process) +{ + if (process->doorbell_index) + ida_simple_remove(&adev->mes.doorbell_ida, + process->doorbell_index); +} + +static int amdgpu_mes_queue_doorbell_get(struct amdgpu_device *adev, + struct amdgpu_mes_process *process, + int ip_type, uint64_t *doorbell_index) +{ + unsigned int offset, found; + + if (ip_type == AMDGPU_RING_TYPE_SDMA) { + offset = adev->doorbell_index.sdma_engine[0]; + found = find_next_zero_bit(process->doorbell_bitmap, + AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS, + offset); + } else { + found = find_first_zero_bit(process->doorbell_bitmap, + AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS); + } + + if (found >= AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS) { + DRM_WARN("No doorbell available\n"); + return -ENOSPC; + } + + set_bit(found, process->doorbell_bitmap); + + *doorbell_index = + (process->doorbell_index * + amdgpu_mes_doorbell_process_slice(adev)) / sizeof(u32) + + found * 2; + + return 0; +} + +static void amdgpu_mes_queue_doorbell_free(struct amdgpu_device *adev, + struct amdgpu_mes_process *process, + uint32_t doorbell_index) +{ + unsigned int old, doorbell_id; + + doorbell_id = doorbell_index - + (process->doorbell_index * + amdgpu_mes_doorbell_process_slice(adev)) / sizeof(u32); + doorbell_id /= 2; + + old = test_and_clear_bit(doorbell_id, process->doorbell_bitmap); + WARN_ON(!old); +} + +static int amdgpu_mes_doorbell_init(struct amdgpu_device *adev) +{ + size_t doorbell_start_offset; + size_t doorbell_aperture_size; + size_t doorbell_process_limit; + + doorbell_start_offset = (adev->doorbell_index.max_assignment+1) * sizeof(u32); + doorbell_start_offset = + roundup(doorbell_start_offset, + amdgpu_mes_doorbell_process_slice(adev)); + + doorbell_aperture_size = adev->doorbell.size; + doorbell_aperture_size = + rounddown(doorbell_aperture_size, + amdgpu_mes_doorbell_process_slice(adev)); + + if (doorbell_aperture_size > doorbell_start_offset) + doorbell_process_limit = + (doorbell_aperture_size - doorbell_start_offset) / + amdgpu_mes_doorbell_process_slice(adev); + else + return -ENOSPC; + + adev->mes.doorbell_id_offset = doorbell_start_offset / sizeof(u32); + adev->mes.max_doorbell_slices = doorbell_process_limit; + + DRM_INFO("max_doorbell_slices=%ld\n", doorbell_process_limit); + return 0; +} -- cgit From b04c1d64685ecc45f68c6e3667d662cf8633d027 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 14:50:01 +0800 Subject: drm/amdgpu/mes: initialize/finalize common mes structure v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize/finalize common mes structure. v2: add mutex_init for adev->mes.mutex Cc: Le Ma Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 72 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 4 ++ 2 files changed, 76 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 1c591cb45fd9..90c400564540 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -131,3 +131,75 @@ static int amdgpu_mes_doorbell_init(struct amdgpu_device *adev) DRM_INFO("max_doorbell_slices=%ld\n", doorbell_process_limit); return 0; } + +int amdgpu_mes_init(struct amdgpu_device *adev) +{ + int i, r; + + adev->mes.adev = adev; + + idr_init(&adev->mes.pasid_idr); + idr_init(&adev->mes.gang_id_idr); + idr_init(&adev->mes.queue_id_idr); + ida_init(&adev->mes.doorbell_ida); + spin_lock_init(&adev->mes.queue_id_lock); + mutex_init(&adev->mes.mutex); + + adev->mes.total_max_queue = AMDGPU_FENCE_MES_QUEUE_ID_MASK; + adev->mes.vmid_mask_mmhub = 0xffffff00; + adev->mes.vmid_mask_gfxhub = 0xffffff00; + + for (i = 0; i < AMDGPU_MES_MAX_COMPUTE_PIPES; i++) { + /* use only 1st MEC pipes */ + if (i >= 4) + continue; + adev->mes.compute_hqd_mask[i] = 0xc; + } + + for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++) + adev->mes.gfx_hqd_mask[i] = i ? 0 : 0xfffffffe; + + for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++) + adev->mes.sdma_hqd_mask[i] = i ? 0 : 0x3fc; + + for (i = 0; i < AMDGPU_MES_PRIORITY_NUM_LEVELS; i++) + adev->mes.agreegated_doorbells[i] = 0xffffffff; + + r = amdgpu_device_wb_get(adev, &adev->mes.sch_ctx_offs); + if (r) { + dev_err(adev->dev, + "(%d) ring trail_fence_offs wb alloc failed\n", r); + goto error_ids; + } + adev->mes.sch_ctx_gpu_addr = + adev->wb.gpu_addr + (adev->mes.sch_ctx_offs * 4); + adev->mes.sch_ctx_ptr = + (uint64_t *)&adev->wb.wb[adev->mes.sch_ctx_offs]; + + r = amdgpu_mes_doorbell_init(adev); + if (r) + goto error; + + return 0; + +error: + amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); +error_ids: + idr_destroy(&adev->mes.pasid_idr); + idr_destroy(&adev->mes.gang_id_idr); + idr_destroy(&adev->mes.queue_id_idr); + ida_destroy(&adev->mes.doorbell_ida); + mutex_destroy(&adev->mes.mutex); + return r; +} + +void amdgpu_mes_fini(struct amdgpu_device *adev) +{ + amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); + + idr_destroy(&adev->mes.pasid_idr); + idr_destroy(&adev->mes.gang_id_idr); + idr_destroy(&adev->mes.queue_id_idr); + ida_destroy(&adev->mes.doorbell_ida); + mutex_destroy(&adev->mes.mutex); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 35a6bb2b4be8..45c0a246b618 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -208,6 +208,10 @@ struct amdgpu_mes_funcs { struct mes_resume_gang_input *input); }; + #define amdgpu_mes_kiq_hw_init(adev) (adev)->mes.kiq_hw_init((adev)) +int amdgpu_mes_init(struct amdgpu_device *adev); +void amdgpu_mes_fini(struct amdgpu_device *adev); + #endif /* __AMDGPU_MES_H__ */ -- cgit From 0bf478f01abf1c35fd706081c4686fd0250eb559 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Sat, 28 Mar 2020 15:32:27 +0800 Subject: drm/amdgpu/mes: relocate status_fence slot allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the status_fence slot allocation from ip specific function to general mes function. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 11 +++++++++++ drivers/gpu/drm/amd/amdgpu/mes_v10_1.c | 33 --------------------------------- 2 files changed, 11 insertions(+), 33 deletions(-) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 90c400564540..a988c232b4a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -176,6 +176,17 @@ int amdgpu_mes_init(struct amdgpu_device *adev) adev->mes.sch_ctx_ptr = (uint64_t *)&adev->wb.wb[adev->mes.sch_ctx_offs]; + r = amdgpu_device_wb_get(adev, &adev->mes.query_status_fence_offs); + if (r) { + dev_err(adev->dev, + "(%d) query_status_fence_offs wb alloc failed\n", r); + return r; + } + adev->mes.query_status_fence_gpu_addr = + adev->wb.gpu_addr + (adev->mes.query_status_fence_offs * 4); + adev->mes.query_status_fence_ptr = + (uint64_t *)&adev->wb.wb[adev->mes.query_status_fence_offs]; + r = amdgpu_mes_doorbell_init(adev); if (r) goto error; diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c index fecf3f26bf7c..d77242e0360e 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c @@ -606,35 +606,6 @@ static int mes_v10_1_allocate_eop_buf(struct amdgpu_device *adev, return 0; } -static int mes_v10_1_allocate_mem_slots(struct amdgpu_device *adev) -{ - int r; - - r = amdgpu_device_wb_get(adev, &adev->mes.sch_ctx_offs); - if (r) { - dev_err(adev->dev, - "(%d) mes sch_ctx_offs wb alloc failed\n", r); - return r; - } - adev->mes.sch_ctx_gpu_addr = - adev->wb.gpu_addr + (adev->mes.sch_ctx_offs * 4); - adev->mes.sch_ctx_ptr = - (uint64_t *)&adev->wb.wb[adev->mes.sch_ctx_offs]; - - r = amdgpu_device_wb_get(adev, &adev->mes.query_status_fence_offs); - if (r) { - dev_err(adev->dev, - "(%d) query_status_fence_offs wb alloc failed\n", r); - return r; - } - adev->mes.query_status_fence_gpu_addr = - adev->wb.gpu_addr + (adev->mes.query_status_fence_offs * 4); - adev->mes.query_status_fence_ptr = - (uint64_t *)&adev->wb.wb[adev->mes.query_status_fence_offs]; - - return 0; -} - static int mes_v10_1_mqd_init(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; @@ -991,10 +962,6 @@ static int mes_v10_1_sw_init(void *handle) if (r) return r; - r = mes_v10_1_allocate_mem_slots(adev); - if (r) - return r; - return 0; } -- cgit From 48dcd2b751d3e3f4a46447263817b3b4b15c2328 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 15:03:16 +0800 Subject: drm/amdgpu/mes: implement creating mes process v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a mes process which contains process-related resources, like vm, doorbell bitmap, process ctx bo and etc. v2: move the simple variable to the end Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 77 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 3 ++ 2 files changed, 80 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index a988c232b4a3..55005a594be1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -214,3 +214,80 @@ void amdgpu_mes_fini(struct amdgpu_device *adev) ida_destroy(&adev->mes.doorbell_ida); mutex_destroy(&adev->mes.mutex); } + +int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, + struct amdgpu_vm *vm) +{ + struct amdgpu_mes_process *process; + int r; + + mutex_lock(&adev->mes.mutex); + + /* allocate the mes process buffer */ + process = kzalloc(sizeof(struct amdgpu_mes_process), GFP_KERNEL); + if (!process) { + DRM_ERROR("no more memory to create mes process\n"); + mutex_unlock(&adev->mes.mutex); + return -ENOMEM; + } + + process->doorbell_bitmap = + kzalloc(DIV_ROUND_UP(AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS, + BITS_PER_BYTE), GFP_KERNEL); + if (!process->doorbell_bitmap) { + DRM_ERROR("failed to allocate doorbell bitmap\n"); + kfree(process); + mutex_unlock(&adev->mes.mutex); + return -ENOMEM; + } + + /* add the mes process to idr list */ + r = idr_alloc(&adev->mes.pasid_idr, process, pasid, pasid + 1, + GFP_KERNEL); + if (r < 0) { + DRM_ERROR("failed to lock pasid=%d\n", pasid); + goto clean_up_memory; + } + + /* allocate the process context bo and map it */ + r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_PROC_CTX_SIZE, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, + &process->proc_ctx_bo, + &process->proc_ctx_gpu_addr, + &process->proc_ctx_cpu_ptr); + if (r) { + DRM_ERROR("failed to allocate process context bo\n"); + goto clean_up_pasid; + } + memset(process->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); + + /* allocate the starting doorbell index of the process */ + r = amdgpu_mes_alloc_process_doorbells(adev, process); + if (r < 0) { + DRM_ERROR("failed to allocate doorbell for process\n"); + goto clean_up_ctx; + } + + DRM_DEBUG("process doorbell index = %d\n", process->doorbell_index); + + INIT_LIST_HEAD(&process->gang_list); + process->vm = vm; + process->pasid = pasid; + process->process_quantum = adev->mes.default_process_quantum; + process->pd_gpu_addr = amdgpu_bo_gpu_offset(vm->root.bo); + + mutex_unlock(&adev->mes.mutex); + return 0; + +clean_up_ctx: + amdgpu_bo_free_kernel(&process->proc_ctx_bo, + &process->proc_ctx_gpu_addr, + &process->proc_ctx_cpu_ptr); +clean_up_pasid: + idr_remove(&adev->mes.pasid_idr, pasid); +clean_up_memory: + kfree(process->doorbell_bitmap); + kfree(process); + mutex_unlock(&adev->mes.mutex); + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 45c0a246b618..455f0cb8ebf5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -214,4 +214,7 @@ struct amdgpu_mes_funcs { int amdgpu_mes_init(struct amdgpu_device *adev); void amdgpu_mes_fini(struct amdgpu_device *adev); +int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, + struct amdgpu_vm *vm); + #endif /* __AMDGPU_MES_H__ */ -- cgit From 063a38d6628e7c91e808cab8f83384c51cb5c853 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 15:10:55 +0800 Subject: drm/amdgpu/mes: implement destroying mes process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Destroy the mes process, which free resources of the process. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 58 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 1 + 2 files changed, 59 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 55005a594be1..05e27636ce20 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -291,3 +291,61 @@ clean_up_memory: mutex_unlock(&adev->mes.mutex); return r; } + +void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid) +{ + struct amdgpu_mes_process *process; + struct amdgpu_mes_gang *gang, *tmp1; + struct amdgpu_mes_queue *queue, *tmp2; + struct mes_remove_queue_input queue_input; + unsigned long flags; + int r; + + mutex_lock(&adev->mes.mutex); + + process = idr_find(&adev->mes.pasid_idr, pasid); + if (!process) { + DRM_WARN("pasid %d doesn't exist\n", pasid); + mutex_unlock(&adev->mes.mutex); + return; + } + + /* free all gangs in the process */ + list_for_each_entry_safe(gang, tmp1, &process->gang_list, list) { + /* free all queues in the gang */ + list_for_each_entry_safe(queue, tmp2, &gang->queue_list, list) { + spin_lock_irqsave(&adev->mes.queue_id_lock, flags); + idr_remove(&adev->mes.queue_id_idr, queue->queue_id); + spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); + + queue_input.doorbell_offset = queue->doorbell_off; + queue_input.gang_context_addr = gang->gang_ctx_gpu_addr; + + r = adev->mes.funcs->remove_hw_queue(&adev->mes, + &queue_input); + if (r) + DRM_WARN("failed to remove hardware queue\n"); + + list_del(&queue->list); + kfree(queue); + } + + idr_remove(&adev->mes.gang_id_idr, gang->gang_id); + amdgpu_bo_free_kernel(&gang->gang_ctx_bo, + &gang->gang_ctx_gpu_addr, + &gang->gang_ctx_cpu_ptr); + list_del(&gang->list); + kfree(gang); + } + + amdgpu_mes_free_process_doorbells(adev, process); + + idr_remove(&adev->mes.pasid_idr, pasid); + amdgpu_bo_free_kernel(&process->proc_ctx_bo, + &process->proc_ctx_gpu_addr, + &process->proc_ctx_cpu_ptr); + kfree(process->doorbell_bitmap); + kfree(process); + + mutex_unlock(&adev->mes.mutex); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 455f0cb8ebf5..6f44a81066b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -216,5 +216,6 @@ void amdgpu_mes_fini(struct amdgpu_device *adev); int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, struct amdgpu_vm *vm); +void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid); #endif /* __AMDGPU_MES_H__ */ -- cgit From 5d0f619f723d0caa909e99c875a0c813588a0d68 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 15:27:48 +0800 Subject: drm/amdgpu/mes: implement adding mes gang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gang is a group of the same type queue, which is the scheduling unit of mes hardware scheduler. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 67 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 12 ++++++ 2 files changed, 79 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 05e27636ce20..74385e4b45c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -349,3 +349,70 @@ void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid) mutex_unlock(&adev->mes.mutex); } + +int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, + struct amdgpu_mes_gang_properties *gprops, + int *gang_id) +{ + struct amdgpu_mes_process *process; + struct amdgpu_mes_gang *gang; + int r; + + mutex_lock(&adev->mes.mutex); + + process = idr_find(&adev->mes.pasid_idr, pasid); + if (!process) { + DRM_ERROR("pasid %d doesn't exist\n", pasid); + mutex_unlock(&adev->mes.mutex); + return -EINVAL; + } + + /* allocate the mes gang buffer */ + gang = kzalloc(sizeof(struct amdgpu_mes_gang), GFP_KERNEL); + if (!gang) { + mutex_unlock(&adev->mes.mutex); + return -ENOMEM; + } + + /* add the mes gang to idr list */ + r = idr_alloc(&adev->mes.gang_id_idr, gang, 1, 0, + GFP_KERNEL); + if (r < 0) { + kfree(gang); + mutex_unlock(&adev->mes.mutex); + return r; + } + + gang->gang_id = r; + *gang_id = r; + + /* allocate the gang context bo and map it to cpu space */ + r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_GANG_CTX_SIZE, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, + &gang->gang_ctx_bo, + &gang->gang_ctx_gpu_addr, + &gang->gang_ctx_cpu_ptr); + if (r) { + DRM_ERROR("failed to allocate process context bo\n"); + goto clean_up; + } + memset(gang->gang_ctx_cpu_ptr, 0, AMDGPU_MES_GANG_CTX_SIZE); + + INIT_LIST_HEAD(&gang->queue_list); + gang->process = process; + gang->priority = gprops->priority; + gang->gang_quantum = gprops->gang_quantum ? + gprops->gang_quantum : adev->mes.default_gang_quantum; + gang->global_priority_level = gprops->global_priority_level; + gang->inprocess_gang_priority = gprops->inprocess_gang_priority; + list_add_tail(&gang->list, &process->gang_list); + + mutex_unlock(&adev->mes.mutex); + return 0; + +clean_up: + idr_remove(&adev->mes.gang_id_idr, gang->gang_id); + kfree(gang); + mutex_unlock(&adev->mes.mutex); + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 6f44a81066b6..92139e362478 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -159,6 +159,14 @@ struct amdgpu_mes_queue { struct amdgpu_ring *ring; }; +struct amdgpu_mes_gang_properties { + uint32_t priority; + uint32_t gang_quantum; + uint32_t inprocess_gang_priority; + uint32_t priority_level; + int global_priority_level; +}; + struct mes_add_queue_input { uint32_t process_id; uint64_t page_table_base_addr; @@ -218,4 +226,8 @@ int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, struct amdgpu_vm *vm); void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid); +int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, + struct amdgpu_mes_gang_properties *gprops, + int *gang_id); + #endif /* __AMDGPU_MES_H__ */ -- cgit From b0306e584004b20d406d8111cb8922b7bb8d8840 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Thu, 24 Mar 2022 11:35:29 +0800 Subject: drm/amdgpu/mes: implement removing mes gang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Free the mes gang and its resources. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 30 ++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 1 + 2 files changed, 31 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 74385e4b45c4..07ddf7bf6a3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -416,3 +416,33 @@ clean_up: mutex_unlock(&adev->mes.mutex); return r; } + +int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id) +{ + struct amdgpu_mes_gang *gang; + + mutex_lock(&adev->mes.mutex); + + gang = idr_find(&adev->mes.gang_id_idr, gang_id); + if (!gang) { + DRM_ERROR("gang id %d doesn't exist\n", gang_id); + mutex_unlock(&adev->mes.mutex); + return -EINVAL; + } + + if (!list_empty(&gang->queue_list)) { + DRM_ERROR("queue list is not empty\n"); + mutex_unlock(&adev->mes.mutex); + return -EBUSY; + } + + idr_remove(&adev->mes.gang_id_idr, gang->gang_id); + amdgpu_bo_free_kernel(&gang->gang_ctx_bo, + &gang->gang_ctx_gpu_addr, + &gang->gang_ctx_cpu_ptr); + list_del(&gang->list); + kfree(gang); + + mutex_unlock(&adev->mes.mutex); + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 92139e362478..a24394fa6ee9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -229,5 +229,6 @@ void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid); int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, struct amdgpu_mes_gang_properties *gprops, int *gang_id); +int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id); #endif /* __AMDGPU_MES_H__ */ -- cgit From c8bb10572ca3a03aa0a11d0ba2d87c205f140883 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 16:41:56 +0800 Subject: drm/amdgpu/mes: implement suspending all gangs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement suspending all gangs. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 2 ++ 2 files changed, 27 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 07ddf7bf6a3b..e64f2a4b5a3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -446,3 +446,28 @@ int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id) mutex_unlock(&adev->mes.mutex); return 0; } + +int amdgpu_mes_suspend(struct amdgpu_device *adev) +{ + struct idr *idp; + struct amdgpu_mes_process *process; + struct amdgpu_mes_gang *gang; + struct mes_suspend_gang_input input; + int r, pasid; + + mutex_lock(&adev->mes.mutex); + + idp = &adev->mes.pasid_idr; + + idr_for_each_entry(idp, process, pasid) { + list_for_each_entry(gang, &process->gang_list, list) { + r = adev->mes.funcs->suspend_gang(&adev->mes, &input); + if (r) + DRM_ERROR("failed to suspend pasid %d gangid %d", + pasid, gang->gang_id); + } + } + + mutex_unlock(&adev->mes.mutex); + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index a24394fa6ee9..8c26528b06ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -231,4 +231,6 @@ int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, int *gang_id); int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id); +int amdgpu_mes_suspend(struct amdgpu_device *adev); + #endif /* __AMDGPU_MES_H__ */ -- cgit From ea756bd5cc675b8dfb2be4069c620302200ecc2f Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 16:43:28 +0800 Subject: drm/amdgpu/mes: implement resuming all gangs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement resuming all gangs. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 1 + 2 files changed, 26 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index e64f2a4b5a3b..b58af81f04a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -471,3 +471,28 @@ int amdgpu_mes_suspend(struct amdgpu_device *adev) mutex_unlock(&adev->mes.mutex); return 0; } + +int amdgpu_mes_resume(struct amdgpu_device *adev) +{ + struct idr *idp; + struct amdgpu_mes_process *process; + struct amdgpu_mes_gang *gang; + struct mes_resume_gang_input input; + int r, pasid; + + mutex_lock(&adev->mes.mutex); + + idp = &adev->mes.pasid_idr; + + idr_for_each_entry(idp, process, pasid) { + list_for_each_entry(gang, &process->gang_list, list) { + r = adev->mes.funcs->resume_gang(&adev->mes, &input); + if (r) + DRM_ERROR("failed to resume pasid %d gangid %d", + pasid, gang->gang_id); + } + } + + mutex_unlock(&adev->mes.mutex); + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 8c26528b06ff..c7fddb24ce51 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -232,5 +232,6 @@ int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id); int amdgpu_mes_suspend(struct amdgpu_device *adev); +int amdgpu_mes_resume(struct amdgpu_device *adev); #endif /* __AMDGPU_MES_H__ */ -- cgit From 5fa963d0fc358766adb6c12f0eafe81b2735fc17 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Wed, 1 Jul 2020 14:58:46 +0800 Subject: drm/amdgpu/mes: initialize mqd from queue properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper function to initialize mqd from queue properties. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index b58af81f04a3..2cd2fa76b5c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -496,3 +496,57 @@ int amdgpu_mes_resume(struct amdgpu_device *adev) mutex_unlock(&adev->mes.mutex); return 0; } + +static int amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev, + struct amdgpu_mes_queue *q, + struct amdgpu_mes_queue_properties *p) +{ + struct amdgpu_mqd *mqd_mgr = &adev->mqds[p->queue_type]; + u32 mqd_size = mqd_mgr->mqd_size; + struct amdgpu_mqd_prop mqd_prop = {0}; + int r; + + r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, + &q->mqd_obj, + &q->mqd_gpu_addr, &q->mqd_cpu_ptr); + if (r) { + dev_warn(adev->dev, "failed to create queue mqd bo (%d)", r); + return r; + } + memset(q->mqd_cpu_ptr, 0, mqd_size); + + mqd_prop.mqd_gpu_addr = q->mqd_gpu_addr; + mqd_prop.hqd_base_gpu_addr = p->hqd_base_gpu_addr; + mqd_prop.rptr_gpu_addr = p->rptr_gpu_addr; + mqd_prop.wptr_gpu_addr = p->wptr_gpu_addr; + mqd_prop.queue_size = p->queue_size; + mqd_prop.use_doorbell = true; + mqd_prop.doorbell_index = p->doorbell_off; + mqd_prop.eop_gpu_addr = p->eop_gpu_addr; + mqd_prop.hqd_pipe_priority = p->hqd_pipe_priority; + mqd_prop.hqd_queue_priority = p->hqd_queue_priority; + mqd_prop.hqd_active = false; + + r = amdgpu_bo_reserve(q->mqd_obj, false); + if (unlikely(r != 0)) + goto clean_up; + + mqd_mgr->init_mqd(adev, q->mqd_cpu_ptr, &mqd_prop); + + amdgpu_bo_unreserve(q->mqd_obj); + return 0; + +clean_up: + amdgpu_bo_free_kernel(&q->mqd_obj, + &q->mqd_gpu_addr, + &q->mqd_cpu_ptr); + return r; +} + +static void amdgpu_mes_queue_free_mqd(struct amdgpu_mes_queue *q) +{ + amdgpu_bo_free_kernel(&q->mqd_obj, + &q->mqd_gpu_addr, + &q->mqd_cpu_ptr); +} -- cgit From be5609de15aab00a5154979c0112fd9c31051f75 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 16:58:55 +0800 Subject: drm/amdgpu/mes: implement adding mes queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allocate related resources for the queue and add it to mes for scheduling. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 105 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 19 ++++++ 2 files changed, 124 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 2cd2fa76b5c8..9f059c32c6c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -550,3 +550,108 @@ static void amdgpu_mes_queue_free_mqd(struct amdgpu_mes_queue *q) &q->mqd_gpu_addr, &q->mqd_cpu_ptr); } + +int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, + struct amdgpu_mes_queue_properties *qprops, + int *queue_id) +{ + struct amdgpu_mes_queue *queue; + struct amdgpu_mes_gang *gang; + struct mes_add_queue_input queue_input; + unsigned long flags; + int r; + + mutex_lock(&adev->mes.mutex); + + gang = idr_find(&adev->mes.gang_id_idr, gang_id); + if (!gang) { + DRM_ERROR("gang id %d doesn't exist\n", gang_id); + mutex_unlock(&adev->mes.mutex); + return -EINVAL; + } + + /* allocate the mes queue buffer */ + queue = kzalloc(sizeof(struct amdgpu_mes_queue), GFP_KERNEL); + if (!queue) { + mutex_unlock(&adev->mes.mutex); + return -ENOMEM; + } + + /* add the mes gang to idr list */ + spin_lock_irqsave(&adev->mes.queue_id_lock, flags); + r = idr_alloc(&adev->mes.queue_id_idr, queue, 1, 0, + GFP_ATOMIC); + if (r < 0) { + spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); + goto clean_up_memory; + } + spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); + *queue_id = queue->queue_id = r; + + /* allocate a doorbell index for the queue */ + r = amdgpu_mes_queue_doorbell_get(adev, gang->process, + qprops->queue_type, + &qprops->doorbell_off); + if (r) + goto clean_up_queue_id; + + /* initialize the queue mqd */ + r = amdgpu_mes_queue_init_mqd(adev, queue, qprops); + if (r) + goto clean_up_doorbell; + + /* add hw queue to mes */ + queue_input.process_id = gang->process->pasid; + queue_input.page_table_base_addr = gang->process->pd_gpu_addr; + queue_input.process_va_start = 0; + queue_input.process_va_end = + (adev->vm_manager.max_pfn - 1) << AMDGPU_GPU_PAGE_SHIFT; + queue_input.process_quantum = gang->process->process_quantum; + queue_input.process_context_addr = gang->process->proc_ctx_gpu_addr; + queue_input.gang_quantum = gang->gang_quantum; + queue_input.gang_context_addr = gang->gang_ctx_gpu_addr; + queue_input.inprocess_gang_priority = gang->inprocess_gang_priority; + queue_input.gang_global_priority_level = gang->global_priority_level; + queue_input.doorbell_offset = qprops->doorbell_off; + queue_input.mqd_addr = queue->mqd_gpu_addr; + queue_input.wptr_addr = qprops->wptr_gpu_addr; + queue_input.queue_type = qprops->queue_type; + queue_input.paging = qprops->paging; + + r = adev->mes.funcs->add_hw_queue(&adev->mes, &queue_input); + if (r) { + DRM_ERROR("failed to add hardware queue to MES, doorbell=0x%llx\n", + qprops->doorbell_off); + goto clean_up_mqd; + } + + DRM_DEBUG("MES hw queue was added, pasid=%d, gang id=%d, " + "queue type=%d, doorbell=0x%llx\n", + gang->process->pasid, gang_id, qprops->queue_type, + qprops->doorbell_off); + + queue->ring = qprops->ring; + queue->doorbell_off = qprops->doorbell_off; + queue->wptr_gpu_addr = qprops->wptr_gpu_addr; + queue->queue_type = qprops->queue_type; + queue->paging = qprops->paging; + queue->gang = gang; + list_add_tail(&queue->list, &gang->queue_list); + + mutex_unlock(&adev->mes.mutex); + return 0; + +clean_up_mqd: + amdgpu_mes_queue_free_mqd(queue); +clean_up_doorbell: + amdgpu_mes_queue_doorbell_free(adev, gang->process, + qprops->doorbell_off); +clean_up_queue_id: + spin_lock_irqsave(&adev->mes.queue_id_lock, flags); + idr_remove(&adev->mes.queue_id_idr, queue->queue_id); + spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); +clean_up_memory: + kfree(queue); + mutex_unlock(&adev->mes.mutex); + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index c7fddb24ce51..bae91b01ec6d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -159,6 +159,21 @@ struct amdgpu_mes_queue { struct amdgpu_ring *ring; }; +struct amdgpu_mes_queue_properties { + int queue_type; + uint64_t hqd_base_gpu_addr; + uint64_t rptr_gpu_addr; + uint64_t wptr_gpu_addr; + uint32_t queue_size; + uint64_t eop_gpu_addr; + uint32_t hqd_pipe_priority; + uint32_t hqd_queue_priority; + bool paging; + struct amdgpu_ring *ring; + /* out */ + uint64_t doorbell_off; +}; + struct amdgpu_mes_gang_properties { uint32_t priority; uint32_t gang_quantum; @@ -234,4 +249,8 @@ int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id); int amdgpu_mes_suspend(struct amdgpu_device *adev); int amdgpu_mes_resume(struct amdgpu_device *adev); +int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, + struct amdgpu_mes_queue_properties *qprops, + int *queue_id); + #endif /* __AMDGPU_MES_H__ */ -- cgit From bcc4e1e1d43d6fe7cd8e6892e01572ee8ba78cba Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 17:08:40 +0800 Subject: drm/amdgpu/mes: implement removing mes queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the MES queue from MES scheduling and free its resources. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 45 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 1 + 2 files changed, 46 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 9f059c32c6c2..df0e542bd687 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -655,3 +655,48 @@ clean_up_memory: mutex_unlock(&adev->mes.mutex); return r; } + +int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id) +{ + unsigned long flags; + struct amdgpu_mes_queue *queue; + struct amdgpu_mes_gang *gang; + struct mes_remove_queue_input queue_input; + int r; + + mutex_lock(&adev->mes.mutex); + + /* remove the mes gang from idr list */ + spin_lock_irqsave(&adev->mes.queue_id_lock, flags); + + queue = idr_find(&adev->mes.queue_id_idr, queue_id); + if (!queue) { + spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); + mutex_unlock(&adev->mes.mutex); + DRM_ERROR("queue id %d doesn't exist\n", queue_id); + return -EINVAL; + } + + idr_remove(&adev->mes.queue_id_idr, queue_id); + spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); + + DRM_DEBUG("try to remove queue, doorbell off = 0x%llx\n", + queue->doorbell_off); + + gang = queue->gang; + queue_input.doorbell_offset = queue->doorbell_off; + queue_input.gang_context_addr = gang->gang_ctx_gpu_addr; + + r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input); + if (r) + DRM_ERROR("failed to remove hardware queue, queue id = %d\n", + queue_id); + + amdgpu_mes_queue_free_mqd(queue); + list_del(&queue->list); + amdgpu_mes_queue_doorbell_free(adev, gang->process, + queue->doorbell_off); + kfree(queue); + mutex_unlock(&adev->mes.mutex); + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index bae91b01ec6d..1174c8d359ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -252,5 +252,6 @@ int amdgpu_mes_resume(struct amdgpu_device *adev); int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, struct amdgpu_mes_queue_properties *qprops, int *queue_id); +int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id); #endif /* __AMDGPU_MES_H__ */ -- cgit From 1a27aacb6ed7422eb9c47e03d3355d201c35f224 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 17:16:28 +0800 Subject: drm/amdgpu/mes: add helper function to convert ring to queue property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the helper function to convert ring to queue property. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index df0e542bd687..8cb74d0d0a1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -700,3 +700,20 @@ int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id) mutex_unlock(&adev->mes.mutex); return 0; } + +static void +amdgpu_mes_ring_to_queue_props(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + struct amdgpu_mes_queue_properties *props) +{ + props->queue_type = ring->funcs->type; + props->hqd_base_gpu_addr = ring->gpu_addr; + props->rptr_gpu_addr = ring->rptr_gpu_addr; + props->wptr_gpu_addr = ring->wptr_gpu_addr; + props->queue_size = ring->ring_size; + props->eop_gpu_addr = ring->eop_gpu_addr; + props->hqd_pipe_priority = AMDGPU_GFX_PIPE_PRIO_NORMAL; + props->hqd_queue_priority = AMDGPU_GFX_QUEUE_PRIORITY_MINIMUM; + props->paging = false; + props->ring = ring; +} -- cgit From 11ec5b3605db3a136c1a0fde0d78883f6361d666 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 17:42:01 +0800 Subject: drm/amdgpu/mes: add helper function to get the ctx meta data offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the helper function to get the corresponding ctx meta data offset. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 36 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 3 ++- 2 files changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 8cb74d0d0a1f..4e99adcfbb0e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -717,3 +717,39 @@ amdgpu_mes_ring_to_queue_props(struct amdgpu_device *adev, props->paging = false; props->ring = ring; } + +#define DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(_eng) \ +do { \ + if (id_offs < AMDGPU_MES_CTX_MAX_OFFS) \ + return offsetof(struct amdgpu_mes_ctx_meta_data, \ + _eng[ring->idx].slots[id_offs]); \ + else if (id_offs == AMDGPU_MES_CTX_RING_OFFS) \ + return offsetof(struct amdgpu_mes_ctx_meta_data, \ + _eng[ring->idx].ring); \ + else if (id_offs == AMDGPU_MES_CTX_IB_OFFS) \ + return offsetof(struct amdgpu_mes_ctx_meta_data, \ + _eng[ring->idx].ib); \ + else if (id_offs == AMDGPU_MES_CTX_PADDING_OFFS) \ + return offsetof(struct amdgpu_mes_ctx_meta_data, \ + _eng[ring->idx].padding); \ +} while(0) + +int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs) +{ + switch (ring->funcs->type) { + case AMDGPU_RING_TYPE_GFX: + DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(gfx); + break; + case AMDGPU_RING_TYPE_COMPUTE: + DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(compute); + break; + case AMDGPU_RING_TYPE_SDMA: + DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(sdma); + break; + default: + break; + } + + WARN_ON(1); + return -EINVAL; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 1174c8d359ba..4c88e92b196f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -231,9 +231,10 @@ struct amdgpu_mes_funcs { struct mes_resume_gang_input *input); }; - #define amdgpu_mes_kiq_hw_init(adev) (adev)->mes.kiq_hw_init((adev)) +int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs); + int amdgpu_mes_init(struct amdgpu_device *adev); void amdgpu_mes_fini(struct amdgpu_device *adev); -- cgit From d0c423b64765a5060aa56e6df147c45ac696b5dd Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 17:30:00 +0800 Subject: drm/amdgpu/mes: use ring for kernel queue submission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ring as the front end for kernel queue submission. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 93 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 5 ++ 2 files changed, 98 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 4e99adcfbb0e..827391fcb2a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -753,3 +753,96 @@ int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs) WARN_ON(1); return -EINVAL; } + +int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, + int queue_type, int idx, + struct amdgpu_mes_ctx_data *ctx_data, + struct amdgpu_ring **out) +{ + struct amdgpu_ring *ring; + struct amdgpu_mes_gang *gang; + struct amdgpu_mes_queue_properties qprops = {0}; + int r, queue_id, pasid; + + mutex_lock(&adev->mes.mutex); + gang = idr_find(&adev->mes.gang_id_idr, gang_id); + if (!gang) { + DRM_ERROR("gang id %d doesn't exist\n", gang_id); + mutex_unlock(&adev->mes.mutex); + return -EINVAL; + } + pasid = gang->process->pasid; + + ring = kzalloc(sizeof(struct amdgpu_ring), GFP_KERNEL); + if (!ring) { + mutex_unlock(&adev->mes.mutex); + return -ENOMEM; + } + + ring->ring_obj = NULL; + ring->use_doorbell = true; + ring->is_mes_queue = true; + ring->mes_ctx = ctx_data; + ring->idx = idx; + ring->no_scheduler = true; + + if (queue_type == AMDGPU_RING_TYPE_COMPUTE) { + int offset = offsetof(struct amdgpu_mes_ctx_meta_data, + compute[ring->idx].mec_hpd); + ring->eop_gpu_addr = + amdgpu_mes_ctx_get_offs_gpu_addr(ring, offset); + } + + switch (queue_type) { + case AMDGPU_RING_TYPE_GFX: + ring->funcs = adev->gfx.gfx_ring[0].funcs; + break; + case AMDGPU_RING_TYPE_COMPUTE: + ring->funcs = adev->gfx.compute_ring[0].funcs; + break; + case AMDGPU_RING_TYPE_SDMA: + ring->funcs = adev->sdma.instance[0].ring.funcs; + break; + default: + BUG(); + } + + r = amdgpu_ring_init(adev, ring, 1024, NULL, 0, + AMDGPU_RING_PRIO_DEFAULT, NULL); + if (r) + goto clean_up_memory; + + amdgpu_mes_ring_to_queue_props(adev, ring, &qprops); + + dma_fence_wait(gang->process->vm->last_update, false); + dma_fence_wait(ctx_data->meta_data_va->last_pt_update, false); + mutex_unlock(&adev->mes.mutex); + + r = amdgpu_mes_add_hw_queue(adev, gang_id, &qprops, &queue_id); + if (r) + goto clean_up_ring; + + ring->hw_queue_id = queue_id; + ring->doorbell_index = qprops.doorbell_off; + + if (queue_type == AMDGPU_RING_TYPE_GFX) + sprintf(ring->name, "gfx_%d.%d.%d", pasid, gang_id, queue_id); + else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) + sprintf(ring->name, "compute_%d.%d.%d", pasid, gang_id, + queue_id); + else if (queue_type == AMDGPU_RING_TYPE_SDMA) + sprintf(ring->name, "sdma_%d.%d.%d", pasid, gang_id, + queue_id); + else + BUG(); + + *out = ring; + return 0; + +clean_up_ring: + amdgpu_ring_fini(ring); +clean_up_memory: + kfree(ring); + mutex_unlock(&adev->mes.mutex); + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 4c88e92b196f..287f4e633677 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -255,4 +255,9 @@ int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, int *queue_id); int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id); +int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, + int queue_type, int idx, + struct amdgpu_mes_ctx_data *ctx_data, + struct amdgpu_ring **out); + #endif /* __AMDGPU_MES_H__ */ -- cgit From 9cc654c8ceb6561dc7f646a142535737932a0309 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 18:04:36 +0800 Subject: drm/amdgpu/mes: implement removing mes ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the mes ring and its resources. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 11 +++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 2 ++ 2 files changed, 13 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 827391fcb2a3..fa43a7e3c9ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -846,3 +846,14 @@ clean_up_memory: mutex_unlock(&adev->mes.mutex); return r; } + +void amdgpu_mes_remove_ring(struct amdgpu_device *adev, + struct amdgpu_ring *ring) +{ + if (!ring) + return; + + amdgpu_mes_remove_hw_queue(adev, ring->hw_queue_id); + amdgpu_ring_fini(ring); + kfree(ring); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 287f4e633677..b68719823195 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -259,5 +259,7 @@ int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, int queue_type, int idx, struct amdgpu_mes_ctx_data *ctx_data, struct amdgpu_ring **out); +void amdgpu_mes_remove_ring(struct amdgpu_device *adev, + struct amdgpu_ring *ring); #endif /* __AMDGPU_MES_H__ */ -- cgit From e3652b0976f383dea912607a404e974632b019b1 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 18:11:15 +0800 Subject: drm/amdgpu/mes: add helper functions to alloc/free ctx metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the helper functions to allocate/free context metadata. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 4 ++++ 2 files changed, 29 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index fa43a7e3c9ab..6c01581e3a7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -857,3 +857,28 @@ void amdgpu_mes_remove_ring(struct amdgpu_device *adev, amdgpu_ring_fini(ring); kfree(ring); } + +int amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device *adev, + struct amdgpu_mes_ctx_data *ctx_data) +{ + int r; + + r = amdgpu_bo_create_kernel(adev, + sizeof(struct amdgpu_mes_ctx_meta_data), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, + &ctx_data->meta_data_obj, NULL, + &ctx_data->meta_data_ptr); + if (!ctx_data->meta_data_obj) + return -ENOMEM; + + memset(ctx_data->meta_data_ptr, 0, + sizeof(struct amdgpu_mes_ctx_meta_data)); + + return 0; +} + +void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data) +{ + if (ctx_data->meta_data_obj) + amdgpu_bo_free_kernel(&ctx_data->meta_data_obj, NULL, NULL); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index b68719823195..828d52cdc297 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -262,4 +262,8 @@ int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, void amdgpu_mes_remove_ring(struct amdgpu_device *adev, struct amdgpu_ring *ring); +int amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device *adev, + struct amdgpu_mes_ctx_data *ctx_data); +void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data); + #endif /* __AMDGPU_MES_H__ */ -- cgit From a22f760a02f80d140147de4b504bd7531b268e62 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 21:36:43 +0800 Subject: drm/amdgpu/mes: map ctx metadata for mes self test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map ctx metadata for mes self test. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 6c01581e3a7b..b440b36dd98a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -882,3 +882,40 @@ void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data) if (ctx_data->meta_data_obj) amdgpu_bo_free_kernel(&ctx_data->meta_data_obj, NULL, NULL); } + +static int amdgpu_mes_test_map_ctx_meta_data(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + struct amdgpu_mes_ctx_data *ctx_data) +{ + struct amdgpu_bo_va *meta_data_va = NULL; + uint64_t meta_data_addr = AMDGPU_VA_RESERVED_SIZE; + int r; + + r = amdgpu_map_static_csa(adev, vm, ctx_data->meta_data_obj, + &meta_data_va, meta_data_addr, + sizeof(struct amdgpu_mes_ctx_meta_data)); + if (r) + return r; + + r = amdgpu_vm_bo_update(adev, meta_data_va, false); + if (r) + goto error; + + r = amdgpu_vm_update_pdes(adev, vm, false); + if (r) + goto error; + + dma_fence_wait(vm->last_update, false); + dma_fence_wait(meta_data_va->last_pt_update, false); + + ctx_data->meta_data_gpu_addr = meta_data_addr; + ctx_data->meta_data_va = meta_data_va; + + return 0; + +error: + BUG_ON(amdgpu_bo_reserve(ctx_data->meta_data_obj, true)); + amdgpu_vm_bo_rmv(adev, meta_data_va); + amdgpu_bo_unreserve(ctx_data->meta_data_obj); + return r; +} -- cgit From f1d93c9c2722a2fc25cdb93b5f99da7252cae6c1 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 27 Mar 2020 21:38:42 +0800 Subject: drm/amdgpu/mes: create gang and queues for mes self test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create gang and queues for mes self test. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index b440b36dd98a..027f3aae6025 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -919,3 +919,42 @@ error: amdgpu_bo_unreserve(ctx_data->meta_data_obj); return r; } + +static int amdgpu_mes_test_create_gang_and_queues(struct amdgpu_device *adev, + int pasid, int *gang_id, + int queue_type, int num_queue, + struct amdgpu_ring **added_rings, + struct amdgpu_mes_ctx_data *ctx_data) +{ + struct amdgpu_ring *ring; + struct amdgpu_mes_gang_properties gprops = {0}; + int r, j; + + /* create a gang for the process */ + gprops.priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; + gprops.gang_quantum = adev->mes.default_gang_quantum; + gprops.inprocess_gang_priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; + gprops.priority_level = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; + gprops.global_priority_level = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; + + r = amdgpu_mes_add_gang(adev, pasid, &gprops, gang_id); + if (r) { + DRM_ERROR("failed to add gang\n"); + return r; + } + + /* create queues for the gang */ + for (j = 0; j < num_queue; j++) { + r = amdgpu_mes_add_ring(adev, *gang_id, queue_type, j, + ctx_data, &ring); + if (r) { + DRM_ERROR("failed to add ring\n"); + break; + } + + DRM_INFO("ring %s was added\n", ring->name); + added_rings[j] = ring; + } + + return 0; +} -- cgit From cdb7476d9692c84ba204e0b4172998506b41f270 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Sat, 28 Mar 2020 00:18:26 +0800 Subject: drm/amdgpu/mes: add ring/ib test for mes self test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run the ring test and ib test for mes self test. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 027f3aae6025..e2b1da08ab64 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -958,3 +958,35 @@ static int amdgpu_mes_test_create_gang_and_queues(struct amdgpu_device *adev, return 0; } + +static int amdgpu_mes_test_queues(struct amdgpu_ring **added_rings) +{ + struct amdgpu_ring *ring; + int i, r; + + for (i = 0; i < AMDGPU_MES_CTX_MAX_RINGS; i++) { + ring = added_rings[i]; + if (!ring) + continue; + + r = amdgpu_ring_test_ring(ring); + if (r) { + DRM_DEV_ERROR(ring->adev->dev, + "ring %s test failed (%d)\n", + ring->name, r); + return r; + } else + DRM_INFO("ring %s test pass\n", ring->name); + + r = amdgpu_ring_test_ib(ring, 1000 * 10); + if (r) { + DRM_DEV_ERROR(ring->adev->dev, + "ring %s ib test failed (%d)\n", + ring->name, r); + return r; + } else + DRM_INFO("ring %s ib test pass\n", ring->name); + } + + return 0; +} -- cgit From 6624d161039734e58fd1f045a5d821d3907f47ab Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Sat, 28 Mar 2020 00:23:34 +0800 Subject: drm/amdgpu/mes: implement mes self test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add mes self test to verify its fundamental functionality by running ring test and ib test of mes kernel queue. Signed-off-by: Jack Xiao Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 97 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 2 + 2 files changed, 99 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index e2b1da08ab64..c9516b3aa6d9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -990,3 +990,100 @@ static int amdgpu_mes_test_queues(struct amdgpu_ring **added_rings) return 0; } + +int amdgpu_mes_self_test(struct amdgpu_device *adev) +{ + struct amdgpu_vm *vm = NULL; + struct amdgpu_mes_ctx_data ctx_data = {0}; + struct amdgpu_ring *added_rings[AMDGPU_MES_CTX_MAX_RINGS] = { NULL }; + int gang_ids[3] = {0}; + int queue_types[][2] = { { AMDGPU_RING_TYPE_GFX, + AMDGPU_MES_CTX_MAX_GFX_RINGS}, + { AMDGPU_RING_TYPE_COMPUTE, + AMDGPU_MES_CTX_MAX_COMPUTE_RINGS}, + { AMDGPU_RING_TYPE_SDMA, + AMDGPU_MES_CTX_MAX_SDMA_RINGS } }; + int i, r, pasid, k = 0; + + pasid = amdgpu_pasid_alloc(16); + if (pasid < 0) { + dev_warn(adev->dev, "No more PASIDs available!"); + pasid = 0; + } + + vm = kzalloc(sizeof(*vm), GFP_KERNEL); + if (!vm) { + r = -ENOMEM; + goto error_pasid; + } + + r = amdgpu_vm_init(adev, vm); + if (r) { + DRM_ERROR("failed to initialize vm\n"); + goto error_pasid; + } + + r = amdgpu_mes_ctx_alloc_meta_data(adev, &ctx_data); + if (r) { + DRM_ERROR("failed to alloc ctx meta data\n"); + goto error_pasid; + } + + r = amdgpu_mes_test_map_ctx_meta_data(adev, vm, &ctx_data); + if (r) { + DRM_ERROR("failed to map ctx meta data\n"); + goto error_vm; + } + + r = amdgpu_mes_create_process(adev, pasid, vm); + if (r) { + DRM_ERROR("failed to create MES process\n"); + goto error_vm; + } + + for (i = 0; i < ARRAY_SIZE(queue_types); i++) { + r = amdgpu_mes_test_create_gang_and_queues(adev, pasid, + &gang_ids[i], + queue_types[i][0], + queue_types[i][1], + &added_rings[k], + &ctx_data); + if (r) + goto error_queues; + + k += queue_types[i][1]; + } + + /* start ring test and ib test for MES queues */ + amdgpu_mes_test_queues(added_rings); + +error_queues: + /* remove all queues */ + for (i = 0; i < ARRAY_SIZE(added_rings); i++) { + if (!added_rings[i]) + continue; + amdgpu_mes_remove_ring(adev, added_rings[i]); + } + + for (i = 0; i < ARRAY_SIZE(gang_ids); i++) { + if (!gang_ids[i]) + continue; + amdgpu_mes_remove_gang(adev, gang_ids[i]); + } + + amdgpu_mes_destroy_process(adev, pasid); + +error_vm: + BUG_ON(amdgpu_bo_reserve(ctx_data.meta_data_obj, true)); + amdgpu_vm_bo_rmv(adev, ctx_data.meta_data_va); + amdgpu_bo_unreserve(ctx_data.meta_data_obj); + amdgpu_vm_fini(adev, vm); + +error_pasid: + if (pasid) + amdgpu_pasid_free(pasid); + + amdgpu_mes_ctx_free_meta_data(&ctx_data); + kfree(vm); + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 828d52cdc297..ad593e32255e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -266,4 +266,6 @@ int amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device *adev, struct amdgpu_mes_ctx_data *ctx_data); void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data); +int amdgpu_mes_self_test(struct amdgpu_device *adev); + #endif /* __AMDGPU_MES_H__ */ -- cgit From 7c18b40e220a6213f3e63e89b761ef3ba056815e Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Fri, 25 Feb 2022 17:46:25 +0800 Subject: drm/amdgpu/mes: fix vm csa update issue Need reserve VM buffers before update VM csa. v2: rebase fixes Signed-off-by: Jack Xiao Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 81 ++++++++++++++++++++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 3 ++ 2 files changed, 62 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index c9516b3aa6d9..51a6f309ef22 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -883,40 +883,76 @@ void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data) amdgpu_bo_free_kernel(&ctx_data->meta_data_obj, NULL, NULL); } -static int amdgpu_mes_test_map_ctx_meta_data(struct amdgpu_device *adev, - struct amdgpu_vm *vm, - struct amdgpu_mes_ctx_data *ctx_data) +int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + struct amdgpu_mes_ctx_data *ctx_data) { - struct amdgpu_bo_va *meta_data_va = NULL; - uint64_t meta_data_addr = AMDGPU_VA_RESERVED_SIZE; + struct amdgpu_bo_va *bo_va; + struct ww_acquire_ctx ticket; + struct list_head list; + struct amdgpu_bo_list_entry pd; + struct ttm_validate_buffer csa_tv; + struct amdgpu_sync sync; int r; - r = amdgpu_map_static_csa(adev, vm, ctx_data->meta_data_obj, - &meta_data_va, meta_data_addr, - sizeof(struct amdgpu_mes_ctx_meta_data)); - if (r) + amdgpu_sync_create(&sync); + INIT_LIST_HEAD(&list); + INIT_LIST_HEAD(&csa_tv.head); + + csa_tv.bo = &ctx_data->meta_data_obj->tbo; + csa_tv.num_shared = 1; + + list_add(&csa_tv.head, &list); + amdgpu_vm_get_pd_bo(vm, &list, &pd); + + r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL); + if (r) { + DRM_ERROR("failed to reserve meta data BO: err=%d\n", r); return r; + } - r = amdgpu_vm_bo_update(adev, meta_data_va, false); - if (r) + bo_va = amdgpu_vm_bo_add(adev, vm, ctx_data->meta_data_obj); + if (!bo_va) { + ttm_eu_backoff_reservation(&ticket, &list); + DRM_ERROR("failed to create bo_va for meta data BO\n"); + return -ENOMEM; + } + + r = amdgpu_vm_bo_map(adev, bo_va, ctx_data->meta_data_gpu_addr, 0, + sizeof(struct amdgpu_mes_ctx_meta_data), + AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | + AMDGPU_PTE_EXECUTABLE); + + if (r) { + DRM_ERROR("failed to do bo_map on meta data, err=%d\n", r); goto error; + } - r = amdgpu_vm_update_pdes(adev, vm, false); - if (r) + r = amdgpu_vm_bo_update(adev, bo_va, false); + if (r) { + DRM_ERROR("failed to do vm_bo_update on meta data\n"); goto error; + } + amdgpu_sync_fence(&sync, bo_va->last_pt_update); - dma_fence_wait(vm->last_update, false); - dma_fence_wait(meta_data_va->last_pt_update, false); + r = amdgpu_vm_update_pdes(adev, vm, false); + if (r) { + DRM_ERROR("failed to update pdes on meta data\n"); + goto error; + } + amdgpu_sync_fence(&sync, vm->last_update); - ctx_data->meta_data_gpu_addr = meta_data_addr; - ctx_data->meta_data_va = meta_data_va; + amdgpu_sync_wait(&sync, false); + ttm_eu_backoff_reservation(&ticket, &list); + amdgpu_sync_free(&sync); + ctx_data->meta_data_va = bo_va; return 0; error: - BUG_ON(amdgpu_bo_reserve(ctx_data->meta_data_obj, true)); - amdgpu_vm_bo_rmv(adev, meta_data_va); - amdgpu_bo_unreserve(ctx_data->meta_data_obj); + amdgpu_vm_bo_del(adev, bo_va); + ttm_eu_backoff_reservation(&ticket, &list); + amdgpu_sync_free(&sync); return r; } @@ -1029,7 +1065,8 @@ int amdgpu_mes_self_test(struct amdgpu_device *adev) goto error_pasid; } - r = amdgpu_mes_test_map_ctx_meta_data(adev, vm, &ctx_data); + ctx_data.meta_data_gpu_addr = AMDGPU_VA_RESERVED_SIZE; + r = amdgpu_mes_ctx_map_meta_data(adev, vm, &ctx_data); if (r) { DRM_ERROR("failed to map ctx meta data\n"); goto error_vm; @@ -1075,7 +1112,7 @@ error_queues: error_vm: BUG_ON(amdgpu_bo_reserve(ctx_data.meta_data_obj, true)); - amdgpu_vm_bo_rmv(adev, ctx_data.meta_data_va); + amdgpu_vm_bo_del(adev, ctx_data.meta_data_va); amdgpu_bo_unreserve(ctx_data.meta_data_obj); amdgpu_vm_fini(adev, vm); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index ad593e32255e..781b57c30725 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -265,6 +265,9 @@ void amdgpu_mes_remove_ring(struct amdgpu_device *adev, int amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device *adev, struct amdgpu_mes_ctx_data *ctx_data); void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data); +int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + struct amdgpu_mes_ctx_data *ctx_data); int amdgpu_mes_self_test(struct amdgpu_device *adev); -- cgit From da1c0338f035e51ba718bf446a82121e973f7d1f Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Wed, 26 May 2021 14:00:11 +0800 Subject: drm/amdgpu/mes: disable mes sdma queue test Disable mes sdma queue test on sienna cichlid+, for fw hasn't supported to map sdma queue. The test can be enabled if fw supports. Signed-off-by: Jack Xiao Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 51a6f309ef22..e23c864aca11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -1079,6 +1079,11 @@ int amdgpu_mes_self_test(struct amdgpu_device *adev) } for (i = 0; i < ARRAY_SIZE(queue_types); i++) { + /* On sienna cichlid+, fw hasn't supported to map sdma queue. */ + if (adev->asic_type >= CHIP_SIENNA_CICHLID && + i == AMDGPU_RING_TYPE_SDMA) + continue; + r = amdgpu_mes_test_create_gang_and_queues(adev, pasid, &gang_ids[i], queue_types[i][0], -- cgit From 464913c0dd3bc5f05befa62a38e0f5327736c95f Mon Sep 17 00:00:00 2001 From: Mukul Joshi Date: Wed, 2 Sep 2020 15:34:04 -0400 Subject: drm/amdgpu/mes: Update the doorbell function signatures Update the function signatures for process doorbell allocations with MES enabled to make them more generic. KFD would need to access these functions to allocate/free doorbells when MES is enabled. Signed-off-by: Mukul Joshi Acked-by: Oak Zeng Reviewed-by: Felix Kuehling Reviewed-by: Jack Xiao Reviewed-by: Harish Kasiviswanathan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 37 ++++++++++++++++++++------------- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 9 ++++++++ 2 files changed, 31 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index e23c864aca11..5be30bf68b0c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -29,31 +29,40 @@ #define AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS 1024 #define AMDGPU_ONE_DOORBELL_SIZE 8 -static int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev) +int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev) { return roundup(AMDGPU_ONE_DOORBELL_SIZE * AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS, PAGE_SIZE); } -static int amdgpu_mes_alloc_process_doorbells(struct amdgpu_device *adev, - struct amdgpu_mes_process *process) +int amdgpu_mes_alloc_process_doorbells(struct amdgpu_device *adev, + unsigned int *doorbell_index) { int r = ida_simple_get(&adev->mes.doorbell_ida, 2, adev->mes.max_doorbell_slices, GFP_KERNEL); if (r > 0) - process->doorbell_index = r; + *doorbell_index = r; return r; } -static void amdgpu_mes_free_process_doorbells(struct amdgpu_device *adev, - struct amdgpu_mes_process *process) +void amdgpu_mes_free_process_doorbells(struct amdgpu_device *adev, + unsigned int doorbell_index) { - if (process->doorbell_index) - ida_simple_remove(&adev->mes.doorbell_ida, - process->doorbell_index); + if (doorbell_index) + ida_simple_remove(&adev->mes.doorbell_ida, doorbell_index); +} + +unsigned int amdgpu_mes_get_doorbell_dw_offset_in_bar( + struct amdgpu_device *adev, + uint32_t doorbell_index, + unsigned int doorbell_id) +{ + return ((doorbell_index * + amdgpu_mes_doorbell_process_slice(adev)) / sizeof(u32) + + doorbell_id * 2); } static int amdgpu_mes_queue_doorbell_get(struct amdgpu_device *adev, @@ -79,10 +88,8 @@ static int amdgpu_mes_queue_doorbell_get(struct amdgpu_device *adev, set_bit(found, process->doorbell_bitmap); - *doorbell_index = - (process->doorbell_index * - amdgpu_mes_doorbell_process_slice(adev)) / sizeof(u32) + - found * 2; + *doorbell_index = amdgpu_mes_get_doorbell_dw_offset_in_bar(adev, + process->doorbell_index, found); return 0; } @@ -262,7 +269,7 @@ int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, memset(process->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); /* allocate the starting doorbell index of the process */ - r = amdgpu_mes_alloc_process_doorbells(adev, process); + r = amdgpu_mes_alloc_process_doorbells(adev, &process->doorbell_index); if (r < 0) { DRM_ERROR("failed to allocate doorbell for process\n"); goto clean_up_ctx; @@ -338,7 +345,7 @@ void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid) kfree(gang); } - amdgpu_mes_free_process_doorbells(adev, process); + amdgpu_mes_free_process_doorbells(adev, process->doorbell_index); idr_remove(&adev->mes.pasid_idr, pasid); amdgpu_bo_free_kernel(&process->proc_ctx_bo, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 781b57c30725..548015bb6ee7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -271,4 +271,13 @@ int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev, int amdgpu_mes_self_test(struct amdgpu_device *adev); +int amdgpu_mes_alloc_process_doorbells(struct amdgpu_device *adev, + unsigned int *doorbell_index); +void amdgpu_mes_free_process_doorbells(struct amdgpu_device *adev, + unsigned int doorbell_index); +unsigned int amdgpu_mes_get_doorbell_dw_offset_in_bar( + struct amdgpu_device *adev, + uint32_t doorbell_index, + unsigned int doorbell_id); +int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev); #endif /* __AMDGPU_MES_H__ */ -- cgit From 18ee4ce63e0f32cc63dcadb1062e7a3446ead338 Mon Sep 17 00:00:00 2001 From: Jack Xiao Date: Wed, 13 Apr 2022 14:30:37 -0400 Subject: drm/amdgpu: add mes unmap legacy queue routine For mes kiq has been taken over by mes sched, drv can't directly use mes kiq to unmap queues. drv has to use mes sched api to unmap legacy queue. Signed-off-by: Jack Xiao Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 8 +- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 335 +++++++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 85 ++++- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 6 + drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 7 +- drivers/gpu/drm/amd/amdgpu/mes_api_def.h | 443 ----------------------- drivers/gpu/drm/amd/amdgpu/mes_v10_1.c | 69 +++- drivers/gpu/drm/amd/include/mes_api_def.h | 570 ++++++++++++++++++++++++++++++ 8 files changed, 949 insertions(+), 574 deletions(-) delete mode 100644 drivers/gpu/drm/amd/amdgpu/mes_api_def.h create mode 100644 drivers/gpu/drm/amd/include/mes_api_def.h (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 40df1e04d682..5d6b04fc6206 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -367,7 +367,7 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, /* create MQD for KIQ */ ring = &adev->gfx.kiq.ring; - if (!ring->mqd_obj) { + if (!adev->enable_mes_kiq && !ring->mqd_obj) { /* originaly the KIQ MQD is put in GTT domain, but for SRIOV VRAM domain is a must * otherwise hypervisor trigger SAVE_VF fail after driver unloaded which mean MQD * deallocated and gart_unbind, to strict diverage we decide to use VRAM domain for @@ -464,7 +464,7 @@ int amdgpu_gfx_disable_kcq(struct amdgpu_device *adev) { struct amdgpu_kiq *kiq = &adev->gfx.kiq; struct amdgpu_ring *kiq_ring = &kiq->ring; - int i, r; + int i, r = 0; if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues) return -EINVAL; @@ -479,7 +479,9 @@ int amdgpu_gfx_disable_kcq(struct amdgpu_device *adev) for (i = 0; i < adev->gfx.num_compute_rings; i++) kiq->pmf->kiq_unmap_queues(kiq_ring, &adev->gfx.compute_ring[i], RESET_QUEUES, 0, 0); - r = amdgpu_ring_test_helper(kiq_ring); + + if (adev->gfx.kiq.ring.sched.ready) + r = amdgpu_ring_test_helper(kiq_ring); spin_unlock(&adev->gfx.kiq.ring_lock); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 5be30bf68b0c..72bafba1c470 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -150,7 +150,7 @@ int amdgpu_mes_init(struct amdgpu_device *adev) idr_init(&adev->mes.queue_id_idr); ida_init(&adev->mes.doorbell_ida); spin_lock_init(&adev->mes.queue_id_lock); - mutex_init(&adev->mes.mutex); + mutex_init(&adev->mes.mutex_hidden); adev->mes.total_max_queue = AMDGPU_FENCE_MES_QUEUE_ID_MASK; adev->mes.vmid_mask_mmhub = 0xffffff00; @@ -166,8 +166,12 @@ int amdgpu_mes_init(struct amdgpu_device *adev) for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++) adev->mes.gfx_hqd_mask[i] = i ? 0 : 0xfffffffe; - for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++) - adev->mes.sdma_hqd_mask[i] = i ? 0 : 0x3fc; + for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++) { + if (adev->ip_versions[SDMA0_HWIP][0] < IP_VERSION(6, 0, 0)) + adev->mes.sdma_hqd_mask[i] = i ? 0 : 0x3fc; + else + adev->mes.sdma_hqd_mask[i] = 0xfc; + } for (i = 0; i < AMDGPU_MES_PRIORITY_NUM_LEVELS; i++) adev->mes.agreegated_doorbells[i] = 0xffffffff; @@ -207,7 +211,7 @@ error_ids: idr_destroy(&adev->mes.gang_id_idr); idr_destroy(&adev->mes.queue_id_idr); ida_destroy(&adev->mes.doorbell_ida); - mutex_destroy(&adev->mes.mutex); + mutex_destroy(&adev->mes.mutex_hidden); return r; } @@ -219,7 +223,14 @@ void amdgpu_mes_fini(struct amdgpu_device *adev) idr_destroy(&adev->mes.gang_id_idr); idr_destroy(&adev->mes.queue_id_idr); ida_destroy(&adev->mes.doorbell_ida); - mutex_destroy(&adev->mes.mutex); + mutex_destroy(&adev->mes.mutex_hidden); +} + +static void amdgpu_mes_queue_free_mqd(struct amdgpu_mes_queue *q) +{ + amdgpu_bo_free_kernel(&q->mqd_obj, + &q->mqd_gpu_addr, + &q->mqd_cpu_ptr); } int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, @@ -228,13 +239,10 @@ int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, struct amdgpu_mes_process *process; int r; - mutex_lock(&adev->mes.mutex); - /* allocate the mes process buffer */ process = kzalloc(sizeof(struct amdgpu_mes_process), GFP_KERNEL); if (!process) { DRM_ERROR("no more memory to create mes process\n"); - mutex_unlock(&adev->mes.mutex); return -ENOMEM; } @@ -244,18 +252,9 @@ int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, if (!process->doorbell_bitmap) { DRM_ERROR("failed to allocate doorbell bitmap\n"); kfree(process); - mutex_unlock(&adev->mes.mutex); return -ENOMEM; } - /* add the mes process to idr list */ - r = idr_alloc(&adev->mes.pasid_idr, process, pasid, pasid + 1, - GFP_KERNEL); - if (r < 0) { - DRM_ERROR("failed to lock pasid=%d\n", pasid); - goto clean_up_memory; - } - /* allocate the process context bo and map it */ r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_PROC_CTX_SIZE, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, @@ -264,15 +263,29 @@ int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, &process->proc_ctx_cpu_ptr); if (r) { DRM_ERROR("failed to allocate process context bo\n"); - goto clean_up_pasid; + goto clean_up_memory; } memset(process->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); + + /* add the mes process to idr list */ + r = idr_alloc(&adev->mes.pasid_idr, process, pasid, pasid + 1, + GFP_KERNEL); + if (r < 0) { + DRM_ERROR("failed to lock pasid=%d\n", pasid); + goto clean_up_ctx; + } + /* allocate the starting doorbell index of the process */ r = amdgpu_mes_alloc_process_doorbells(adev, &process->doorbell_index); if (r < 0) { DRM_ERROR("failed to allocate doorbell for process\n"); - goto clean_up_ctx; + goto clean_up_pasid; } DRM_DEBUG("process doorbell index = %d\n", process->doorbell_index); @@ -283,19 +296,19 @@ int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid, process->process_quantum = adev->mes.default_process_quantum; process->pd_gpu_addr = amdgpu_bo_gpu_offset(vm->root.bo); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return 0; +clean_up_pasid: + idr_remove(&adev->mes.pasid_idr, pasid); + amdgpu_mes_unlock(&adev->mes); clean_up_ctx: amdgpu_bo_free_kernel(&process->proc_ctx_bo, &process->proc_ctx_gpu_addr, &process->proc_ctx_cpu_ptr); -clean_up_pasid: - idr_remove(&adev->mes.pasid_idr, pasid); clean_up_memory: kfree(process->doorbell_bitmap); kfree(process); - mutex_unlock(&adev->mes.mutex); return r; } @@ -308,18 +321,21 @@ void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid) unsigned long flags; int r; - mutex_lock(&adev->mes.mutex); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); process = idr_find(&adev->mes.pasid_idr, pasid); if (!process) { DRM_WARN("pasid %d doesn't exist\n", pasid); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return; } - /* free all gangs in the process */ + /* Remove all queues from hardware */ list_for_each_entry_safe(gang, tmp1, &process->gang_list, list) { - /* free all queues in the gang */ list_for_each_entry_safe(queue, tmp2, &gang->queue_list, list) { spin_lock_irqsave(&adev->mes.queue_id_lock, flags); idr_remove(&adev->mes.queue_id_idr, queue->queue_id); @@ -332,29 +348,35 @@ void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid) &queue_input); if (r) DRM_WARN("failed to remove hardware queue\n"); + } + + idr_remove(&adev->mes.gang_id_idr, gang->gang_id); + } + amdgpu_mes_free_process_doorbells(adev, process->doorbell_index); + idr_remove(&adev->mes.pasid_idr, pasid); + amdgpu_mes_unlock(&adev->mes); + + /* free all memory allocated by the process */ + list_for_each_entry_safe(gang, tmp1, &process->gang_list, list) { + /* free all queues in the gang */ + list_for_each_entry_safe(queue, tmp2, &gang->queue_list, list) { + amdgpu_mes_queue_free_mqd(queue); list_del(&queue->list); kfree(queue); } - - idr_remove(&adev->mes.gang_id_idr, gang->gang_id); amdgpu_bo_free_kernel(&gang->gang_ctx_bo, &gang->gang_ctx_gpu_addr, &gang->gang_ctx_cpu_ptr); list_del(&gang->list); kfree(gang); - } - amdgpu_mes_free_process_doorbells(adev, process->doorbell_index); - - idr_remove(&adev->mes.pasid_idr, pasid); + } amdgpu_bo_free_kernel(&process->proc_ctx_bo, &process->proc_ctx_gpu_addr, &process->proc_ctx_cpu_ptr); kfree(process->doorbell_bitmap); kfree(process); - - mutex_unlock(&adev->mes.mutex); } int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, @@ -365,34 +387,12 @@ int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, struct amdgpu_mes_gang *gang; int r; - mutex_lock(&adev->mes.mutex); - - process = idr_find(&adev->mes.pasid_idr, pasid); - if (!process) { - DRM_ERROR("pasid %d doesn't exist\n", pasid); - mutex_unlock(&adev->mes.mutex); - return -EINVAL; - } - /* allocate the mes gang buffer */ gang = kzalloc(sizeof(struct amdgpu_mes_gang), GFP_KERNEL); if (!gang) { - mutex_unlock(&adev->mes.mutex); return -ENOMEM; } - /* add the mes gang to idr list */ - r = idr_alloc(&adev->mes.gang_id_idr, gang, 1, 0, - GFP_KERNEL); - if (r < 0) { - kfree(gang); - mutex_unlock(&adev->mes.mutex); - return r; - } - - gang->gang_id = r; - *gang_id = r; - /* allocate the gang context bo and map it to cpu space */ r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_GANG_CTX_SIZE, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, @@ -401,10 +401,34 @@ int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, &gang->gang_ctx_cpu_ptr); if (r) { DRM_ERROR("failed to allocate process context bo\n"); - goto clean_up; + goto clean_up_mem; } memset(gang->gang_ctx_cpu_ptr, 0, AMDGPU_MES_GANG_CTX_SIZE); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); + + process = idr_find(&adev->mes.pasid_idr, pasid); + if (!process) { + DRM_ERROR("pasid %d doesn't exist\n", pasid); + r = -EINVAL; + goto clean_up_ctx; + } + + /* add the mes gang to idr list */ + r = idr_alloc(&adev->mes.gang_id_idr, gang, 1, 0, + GFP_KERNEL); + if (r < 0) { + DRM_ERROR("failed to allocate idr for gang\n"); + goto clean_up_ctx; + } + + gang->gang_id = r; + *gang_id = r; + INIT_LIST_HEAD(&gang->queue_list); gang->process = process; gang->priority = gprops->priority; @@ -414,13 +438,16 @@ int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid, gang->inprocess_gang_priority = gprops->inprocess_gang_priority; list_add_tail(&gang->list, &process->gang_list); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return 0; -clean_up: - idr_remove(&adev->mes.gang_id_idr, gang->gang_id); +clean_up_ctx: + amdgpu_mes_unlock(&adev->mes); + amdgpu_bo_free_kernel(&gang->gang_ctx_bo, + &gang->gang_ctx_gpu_addr, + &gang->gang_ctx_cpu_ptr); +clean_up_mem: kfree(gang); - mutex_unlock(&adev->mes.mutex); return r; } @@ -428,29 +455,35 @@ int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id) { struct amdgpu_mes_gang *gang; - mutex_lock(&adev->mes.mutex); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); gang = idr_find(&adev->mes.gang_id_idr, gang_id); if (!gang) { DRM_ERROR("gang id %d doesn't exist\n", gang_id); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return -EINVAL; } if (!list_empty(&gang->queue_list)) { DRM_ERROR("queue list is not empty\n"); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return -EBUSY; } idr_remove(&adev->mes.gang_id_idr, gang->gang_id); + list_del(&gang->list); + amdgpu_mes_unlock(&adev->mes); + amdgpu_bo_free_kernel(&gang->gang_ctx_bo, &gang->gang_ctx_gpu_addr, &gang->gang_ctx_cpu_ptr); - list_del(&gang->list); + kfree(gang); - mutex_unlock(&adev->mes.mutex); return 0; } @@ -462,7 +495,11 @@ int amdgpu_mes_suspend(struct amdgpu_device *adev) struct mes_suspend_gang_input input; int r, pasid; - mutex_lock(&adev->mes.mutex); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); idp = &adev->mes.pasid_idr; @@ -475,7 +512,7 @@ int amdgpu_mes_suspend(struct amdgpu_device *adev) } } - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return 0; } @@ -487,7 +524,11 @@ int amdgpu_mes_resume(struct amdgpu_device *adev) struct mes_resume_gang_input input; int r, pasid; - mutex_lock(&adev->mes.mutex); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); idp = &adev->mes.pasid_idr; @@ -500,17 +541,16 @@ int amdgpu_mes_resume(struct amdgpu_device *adev) } } - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return 0; } -static int amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev, +static int amdgpu_mes_queue_alloc_mqd(struct amdgpu_device *adev, struct amdgpu_mes_queue *q, struct amdgpu_mes_queue_properties *p) { struct amdgpu_mqd *mqd_mgr = &adev->mqds[p->queue_type]; u32 mqd_size = mqd_mgr->mqd_size; - struct amdgpu_mqd_prop mqd_prop = {0}; int r; r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE, @@ -523,6 +563,26 @@ static int amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev, } memset(q->mqd_cpu_ptr, 0, mqd_size); + r = amdgpu_bo_reserve(q->mqd_obj, false); + if (unlikely(r != 0)) + goto clean_up; + + return 0; + +clean_up: + amdgpu_bo_free_kernel(&q->mqd_obj, + &q->mqd_gpu_addr, + &q->mqd_cpu_ptr); + return r; +} + +static void amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev, + struct amdgpu_mes_queue *q, + struct amdgpu_mes_queue_properties *p) +{ + struct amdgpu_mqd *mqd_mgr = &adev->mqds[p->queue_type]; + struct amdgpu_mqd_prop mqd_prop = {0}; + mqd_prop.mqd_gpu_addr = q->mqd_gpu_addr; mqd_prop.hqd_base_gpu_addr = p->hqd_base_gpu_addr; mqd_prop.rptr_gpu_addr = p->rptr_gpu_addr; @@ -535,27 +595,9 @@ static int amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev, mqd_prop.hqd_queue_priority = p->hqd_queue_priority; mqd_prop.hqd_active = false; - r = amdgpu_bo_reserve(q->mqd_obj, false); - if (unlikely(r != 0)) - goto clean_up; - mqd_mgr->init_mqd(adev, q->mqd_cpu_ptr, &mqd_prop); amdgpu_bo_unreserve(q->mqd_obj); - return 0; - -clean_up: - amdgpu_bo_free_kernel(&q->mqd_obj, - &q->mqd_gpu_addr, - &q->mqd_cpu_ptr); - return r; -} - -static void amdgpu_mes_queue_free_mqd(struct amdgpu_mes_queue *q) -{ - amdgpu_bo_free_kernel(&q->mqd_obj, - &q->mqd_gpu_addr, - &q->mqd_cpu_ptr); } int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, @@ -568,29 +610,38 @@ int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, unsigned long flags; int r; - mutex_lock(&adev->mes.mutex); - - gang = idr_find(&adev->mes.gang_id_idr, gang_id); - if (!gang) { - DRM_ERROR("gang id %d doesn't exist\n", gang_id); - mutex_unlock(&adev->mes.mutex); - return -EINVAL; - } - /* allocate the mes queue buffer */ queue = kzalloc(sizeof(struct amdgpu_mes_queue), GFP_KERNEL); if (!queue) { - mutex_unlock(&adev->mes.mutex); + DRM_ERROR("Failed to allocate memory for queue\n"); return -ENOMEM; } + /* Allocate the queue mqd */ + r = amdgpu_mes_queue_alloc_mqd(adev, queue, qprops); + if (r) + goto clean_up_memory; + + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); + + gang = idr_find(&adev->mes.gang_id_idr, gang_id); + if (!gang) { + DRM_ERROR("gang id %d doesn't exist\n", gang_id); + r = -EINVAL; + goto clean_up_mqd; + } + /* add the mes gang to idr list */ spin_lock_irqsave(&adev->mes.queue_id_lock, flags); r = idr_alloc(&adev->mes.queue_id_idr, queue, 1, 0, GFP_ATOMIC); if (r < 0) { spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); - goto clean_up_memory; + goto clean_up_mqd; } spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); *queue_id = queue->queue_id = r; @@ -603,13 +654,15 @@ int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, goto clean_up_queue_id; /* initialize the queue mqd */ - r = amdgpu_mes_queue_init_mqd(adev, queue, qprops); - if (r) - goto clean_up_doorbell; + amdgpu_mes_queue_init_mqd(adev, queue, qprops); /* add hw queue to mes */ queue_input.process_id = gang->process->pasid; - queue_input.page_table_base_addr = gang->process->pd_gpu_addr; + + queue_input.page_table_base_addr = + adev->vm_manager.vram_base_offset + gang->process->pd_gpu_addr - + adev->gmc.vram_start; + queue_input.process_va_start = 0; queue_input.process_va_end = (adev->vm_manager.max_pfn - 1) << AMDGPU_GPU_PAGE_SHIFT; @@ -629,7 +682,7 @@ int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, if (r) { DRM_ERROR("failed to add hardware queue to MES, doorbell=0x%llx\n", qprops->doorbell_off); - goto clean_up_mqd; + goto clean_up_doorbell; } DRM_DEBUG("MES hw queue was added, pasid=%d, gang id=%d, " @@ -645,11 +698,9 @@ int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, queue->gang = gang; list_add_tail(&queue->list, &gang->queue_list); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return 0; -clean_up_mqd: - amdgpu_mes_queue_free_mqd(queue); clean_up_doorbell: amdgpu_mes_queue_doorbell_free(adev, gang->process, qprops->doorbell_off); @@ -657,9 +708,11 @@ clean_up_queue_id: spin_lock_irqsave(&adev->mes.queue_id_lock, flags); idr_remove(&adev->mes.queue_id_idr, queue->queue_id); spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); +clean_up_mqd: + amdgpu_mes_unlock(&adev->mes); + amdgpu_mes_queue_free_mqd(queue); clean_up_memory: kfree(queue); - mutex_unlock(&adev->mes.mutex); return r; } @@ -671,7 +724,11 @@ int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id) struct mes_remove_queue_input queue_input; int r; - mutex_lock(&adev->mes.mutex); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); /* remove the mes gang from idr list */ spin_lock_irqsave(&adev->mes.queue_id_lock, flags); @@ -679,7 +736,7 @@ int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id) queue = idr_find(&adev->mes.queue_id_idr, queue_id); if (!queue) { spin_unlock_irqrestore(&adev->mes.queue_id_lock, flags); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); DRM_ERROR("queue id %d doesn't exist\n", queue_id); return -EINVAL; } @@ -699,15 +756,42 @@ int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id) DRM_ERROR("failed to remove hardware queue, queue id = %d\n", queue_id); - amdgpu_mes_queue_free_mqd(queue); list_del(&queue->list); amdgpu_mes_queue_doorbell_free(adev, gang->process, queue->doorbell_off); + amdgpu_mes_unlock(&adev->mes); + + amdgpu_mes_queue_free_mqd(queue); kfree(queue); - mutex_unlock(&adev->mes.mutex); return 0; } +int amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + enum amdgpu_unmap_queues_action action, + u64 gpu_addr, u64 seq) +{ + struct mes_unmap_legacy_queue_input queue_input; + int r; + + amdgpu_mes_lock(&adev->mes); + + queue_input.action = action; + queue_input.queue_type = ring->funcs->type; + queue_input.doorbell_offset = ring->doorbell_index; + queue_input.pipe_id = ring->pipe; + queue_input.queue_id = ring->queue; + queue_input.trail_fence_addr = gpu_addr; + queue_input.trail_fence_data = seq; + + r = adev->mes.funcs->unmap_legacy_queue(&adev->mes, &queue_input); + if (r) + DRM_ERROR("failed to unmap legacy queue\n"); + + amdgpu_mes_unlock(&adev->mes); + return r; +} + static void amdgpu_mes_ring_to_queue_props(struct amdgpu_device *adev, struct amdgpu_ring *ring, @@ -771,18 +855,22 @@ int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, struct amdgpu_mes_queue_properties qprops = {0}; int r, queue_id, pasid; - mutex_lock(&adev->mes.mutex); + /* + * Avoid taking any other locks under MES lock to avoid circular + * lock dependencies. + */ + amdgpu_mes_lock(&adev->mes); gang = idr_find(&adev->mes.gang_id_idr, gang_id); if (!gang) { DRM_ERROR("gang id %d doesn't exist\n", gang_id); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return -EINVAL; } pasid = gang->process->pasid; ring = kzalloc(sizeof(struct amdgpu_ring), GFP_KERNEL); if (!ring) { - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return -ENOMEM; } @@ -823,7 +911,7 @@ int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, dma_fence_wait(gang->process->vm->last_update, false); dma_fence_wait(ctx_data->meta_data_va->last_pt_update, false); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); r = amdgpu_mes_add_hw_queue(adev, gang_id, &qprops, &queue_id); if (r) @@ -850,7 +938,7 @@ clean_up_ring: amdgpu_ring_fini(ring); clean_up_memory: kfree(ring); - mutex_unlock(&adev->mes.mutex); + amdgpu_mes_unlock(&adev->mes); return r; } @@ -1086,9 +1174,10 @@ int amdgpu_mes_self_test(struct amdgpu_device *adev) } for (i = 0; i < ARRAY_SIZE(queue_types); i++) { - /* On sienna cichlid+, fw hasn't supported to map sdma queue. */ - if (adev->asic_type >= CHIP_SIENNA_CICHLID && - i == AMDGPU_RING_TYPE_SDMA) + /* On GFX v10.3, fw hasn't supported to map sdma queue. */ + if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0) && + adev->ip_versions[GC_HWIP][0] < IP_VERSION(11, 0, 0) && + queue_types[i][0] == AMDGPU_RING_TYPE_SDMA) continue; r = amdgpu_mes_test_create_gang_and_queues(adev, pasid, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 548015bb6ee7..25590b301f25 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -56,7 +56,7 @@ enum admgpu_mes_pipe { struct amdgpu_mes { struct amdgpu_device *adev; - struct mutex mutex; + struct mutex mutex_hidden; struct idr pasid_idr; struct idr gang_id_idr; @@ -109,9 +109,11 @@ struct amdgpu_mes { uint32_t query_status_fence_offs; uint64_t query_status_fence_gpu_addr; uint64_t *query_status_fence_ptr; + uint32_t saved_flags; /* initialize kiq pipe */ int (*kiq_hw_init)(struct amdgpu_device *adev); + int (*kiq_hw_fini)(struct amdgpu_device *adev); /* ip specific functions */ const struct amdgpu_mes_funcs *funcs; @@ -198,6 +200,10 @@ struct mes_add_queue_input { uint64_t wptr_addr; uint32_t queue_type; uint32_t paging; + uint32_t gws_base; + uint32_t gws_size; + uint64_t tba_addr; + uint64_t tma_addr; }; struct mes_remove_queue_input { @@ -205,6 +211,16 @@ struct mes_remove_queue_input { uint64_t gang_context_addr; }; +struct mes_unmap_legacy_queue_input { + enum amdgpu_unmap_queues_action action; + uint32_t queue_type; + uint32_t doorbell_offset; + uint32_t pipe_id; + uint32_t queue_id; + uint64_t trail_fence_addr; + uint64_t trail_fence_data; +}; + struct mes_suspend_gang_input { bool suspend_all_gangs; uint64_t gang_context_addr; @@ -224,6 +240,9 @@ struct amdgpu_mes_funcs { int (*remove_hw_queue)(struct amdgpu_mes *mes, struct mes_remove_queue_input *input); + int (*unmap_legacy_queue)(struct amdgpu_mes *mes, + struct mes_unmap_legacy_queue_input *input); + int (*suspend_gang)(struct amdgpu_mes *mes, struct mes_suspend_gang_input *input); @@ -232,6 +251,7 @@ struct amdgpu_mes_funcs { }; #define amdgpu_mes_kiq_hw_init(adev) (adev)->mes.kiq_hw_init((adev)) +#define amdgpu_mes_kiq_hw_fini(adev) (adev)->mes.kiq_hw_fini((adev)) int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs); @@ -255,6 +275,11 @@ int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id, int *queue_id); int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id); +int amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + enum amdgpu_unmap_queues_action action, + u64 gpu_addr, u64 seq); + int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, int queue_type, int idx, struct amdgpu_mes_ctx_data *ctx_data, @@ -280,4 +305,62 @@ unsigned int amdgpu_mes_get_doorbell_dw_offset_in_bar( uint32_t doorbell_index, unsigned int doorbell_id); int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev); + +/* + * MES lock can be taken in MMU notifiers. + * + * A bit more detail about why to set no-FS reclaim with MES lock: + * + * The purpose of the MMU notifier is to stop GPU access to memory so + * that the Linux VM subsystem can move pages around safely. This is + * done by preempting user mode queues for the affected process. When + * MES is used, MES lock needs to be taken to preempt the queues. + * + * The MMU notifier callback entry point in the driver is + * amdgpu_mn_invalidate_range_start_hsa. The relevant call chain from + * there is: + * amdgpu_amdkfd_evict_userptr -> kgd2kfd_quiesce_mm -> + * kfd_process_evict_queues -> pdd->dev->dqm->ops.evict_process_queues + * + * The last part of the chain is a function pointer where we take the + * MES lock. + * + * The problem with taking locks in the MMU notifier is, that MMU + * notifiers can be called in reclaim-FS context. That's where the + * kernel frees up pages to make room for new page allocations under + * memory pressure. While we are running in reclaim-FS context, we must + * not trigger another memory reclaim operation because that would + * recursively reenter the reclaim code and cause a deadlock. The + * memalloc_nofs_save/restore calls guarantee that. + * + * In addition we also need to avoid lock dependencies on other locks taken + * under the MES lock, for example reservation locks. Here is a possible + * scenario of a deadlock: + * Thread A: takes and holds reservation lock | triggers reclaim-FS | + * MMU notifier | blocks trying to take MES lock + * Thread B: takes and holds MES lock | blocks trying to take reservation lock + * + * In this scenario Thread B gets involved in a deadlock even without + * triggering a reclaim-FS operation itself. + * To fix this and break the lock dependency chain you'd need to either: + * 1. protect reservation locks with memalloc_nofs_save/restore, or + * 2. avoid taking reservation locks under the MES lock. + * + * Reservation locks are taken all over the kernel in different subsystems, we + * have no control over them and their lock dependencies.So the only workable + * solution is to avoid taking other locks under the MES lock. + * As a result, make sure no reclaim-FS happens while holding this lock anywhere + * to prevent deadlocks when an MMU notifier runs in reclaim-FS context. + */ +static inline void amdgpu_mes_lock(struct amdgpu_mes *mes) +{ + mutex_lock(&mes->mutex_hidden); + mes->saved_flags = memalloc_noreclaim_save(); +} + +static inline void amdgpu_mes_unlock(struct amdgpu_mes *mes) +{ + memalloc_noreclaim_restore(mes->saved_flags); + mutex_unlock(&mes->mutex_hidden); +} #endif /* __AMDGPU_MES_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 9042e0b480ce..3c4f2a94ad9f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3551,8 +3551,14 @@ static void gfx10_kiq_unmap_queues(struct amdgpu_ring *kiq_ring, enum amdgpu_unmap_queues_action action, u64 gpu_addr, u64 seq) { + struct amdgpu_device *adev = kiq_ring->adev; uint32_t eng_sel = ring->funcs->type == AMDGPU_RING_TYPE_GFX ? 4 : 0; + if (!adev->gfx.kiq.ring.sched.ready) { + amdgpu_mes_unmap_legacy_queue(adev, ring, action, gpu_addr, seq); + return; + } + amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_UNMAP_QUEUES, 4)); amdgpu_ring_write(kiq_ring, /* Q_sel: 0, vmid: 0, engine: 0, num_Q: 1 */ PACKET3_UNMAP_QUEUES_ACTION(action) | diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index b80b5f70ecf1..61db2a378008 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -274,7 +274,7 @@ static void gmc_v11_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, /* For SRIOV run time, driver shouldn't access the register through MMIO * Directly use kiq to do the vm invalidation instead */ - if (adev->gfx.kiq.ring.sched.ready && + if (adev->gfx.kiq.ring.sched.ready && !adev->enable_mes && (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) { struct amdgpu_vmhub *hub = &adev->vmhub[vmhub]; const unsigned eng = 17; @@ -411,6 +411,10 @@ static void gmc_v11_0_emit_pasid_mapping(struct amdgpu_ring *ring, unsigned vmid struct amdgpu_device *adev = ring->adev; uint32_t reg; + /* MES fw manages IH_VMID_x_LUT updating */ + if (ring->is_mes_queue) + return; + if (ring->funcs->vmhub == AMDGPU_GFXHUB_0) reg = SOC15_REG_OFFSET(OSSSYS, 0, regIH_VMID_0_LUT) + vmid; else @@ -803,6 +807,7 @@ static int gmc_v11_0_gart_enable(struct amdgpu_device *adev) } amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); + r = adev->mmhub.funcs->gart_enable(adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/mes_api_def.h b/drivers/gpu/drm/amd/amdgpu/mes_api_def.h deleted file mode 100644 index 3f4fca5fd1da..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/mes_api_def.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright 2019 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __MES_API_DEF_H__ -#define __MES_API_DEF_H__ - -#pragma pack(push, 4) - -#define MES_API_VERSION 1 - -/* Driver submits one API(cmd) as a single Frame and this command size is same - * for all API to ease the debugging and parsing of ring buffer. - */ -enum { API_FRAME_SIZE_IN_DWORDS = 64 }; - -/* To avoid command in scheduler context to be overwritten whenenver mutilple - * interrupts come in, this creates another queue. - */ -enum { API_NUMBER_OF_COMMAND_MAX = 32 }; - -enum MES_API_TYPE { - MES_API_TYPE_SCHEDULER = 1, - MES_API_TYPE_MAX -}; - -enum MES_SCH_API_OPCODE { - MES_SCH_API_SET_HW_RSRC = 0, - MES_SCH_API_SET_SCHEDULING_CONFIG = 1, /* agreegated db, quantums, etc */ - MES_SCH_API_ADD_QUEUE = 2, - MES_SCH_API_REMOVE_QUEUE = 3, - MES_SCH_API_PERFORM_YIELD = 4, - MES_SCH_API_SET_GANG_PRIORITY_LEVEL = 5, - MES_SCH_API_SUSPEND = 6, - MES_SCH_API_RESUME = 7, - MES_SCH_API_RESET = 8, - MES_SCH_API_SET_LOG_BUFFER = 9, - MES_SCH_API_CHANGE_GANG_PRORITY = 10, - MES_SCH_API_QUERY_SCHEDULER_STATUS = 11, - MES_SCH_API_PROGRAM_GDS = 12, - MES_SCH_API_SET_DEBUG_VMID = 13, - MES_SCH_API_MISC = 14, - MES_SCH_API_MAX = 0xFF -}; - -union MES_API_HEADER { - struct { - uint32_t type : 4; /* 0 - Invalid; 1 - Scheduling; 2 - TBD */ - uint32_t opcode : 8; - uint32_t dwsize : 8; /* including header */ - uint32_t reserved : 12; - }; - - uint32_t u32All; -}; - -enum MES_AMD_PRIORITY_LEVEL { - AMD_PRIORITY_LEVEL_LOW = 0, - AMD_PRIORITY_LEVEL_NORMAL = 1, - AMD_PRIORITY_LEVEL_MEDIUM = 2, - AMD_PRIORITY_LEVEL_HIGH = 3, - AMD_PRIORITY_LEVEL_REALTIME = 4, - AMD_PRIORITY_NUM_LEVELS -}; - -enum MES_QUEUE_TYPE { - MES_QUEUE_TYPE_GFX, - MES_QUEUE_TYPE_COMPUTE, - MES_QUEUE_TYPE_SDMA, - MES_QUEUE_TYPE_MAX, -}; - -struct MES_API_STATUS { - uint64_t api_completion_fence_addr; - uint64_t api_completion_fence_value; -}; - -enum { MAX_COMPUTE_PIPES = 8 }; -enum { MAX_GFX_PIPES = 2 }; -enum { MAX_SDMA_PIPES = 2 }; - -enum { MAX_COMPUTE_HQD_PER_PIPE = 8 }; -enum { MAX_GFX_HQD_PER_PIPE = 8 }; -enum { MAX_SDMA_HQD_PER_PIPE = 10 }; - -enum { MAX_QUEUES_IN_A_GANG = 8 }; - -enum VM_HUB_TYPE { - VM_HUB_TYPE_GC = 0, - VM_HUB_TYPE_MM = 1, - VM_HUB_TYPE_MAX, -}; - -enum { VMID_INVALID = 0xffff }; - -enum { MAX_VMID_GCHUB = 16 }; -enum { MAX_VMID_MMHUB = 16 }; - -enum MES_LOG_OPERATION { - MES_LOG_OPERATION_CONTEXT_STATE_CHANGE = 0 -}; - -enum MES_LOG_CONTEXT_STATE { - MES_LOG_CONTEXT_STATE_IDLE = 0, - MES_LOG_CONTEXT_STATE_RUNNING = 1, - MES_LOG_CONTEXT_STATE_READY = 2, - MES_LOG_CONTEXT_STATE_READY_STANDBY = 3, -}; - -struct MES_LOG_CONTEXT_STATE_CHANGE { - void *h_context; - enum MES_LOG_CONTEXT_STATE new_context_state; -}; - -struct MES_LOG_ENTRY_HEADER { - uint32_t first_free_entry_index; - uint32_t wraparound_count; - uint64_t number_of_entries; - uint64_t reserved[2]; -}; - -struct MES_LOG_ENTRY_DATA { - uint64_t gpu_time_stamp; - uint32_t operation_type; /* operation_type is of MES_LOG_OPERATION type */ - uint32_t reserved_operation_type_bits; - union { - struct MES_LOG_CONTEXT_STATE_CHANGE context_state_change; - uint64_t reserved_operation_data[2]; - }; -}; - -struct MES_LOG_BUFFER { - struct MES_LOG_ENTRY_HEADER header; - struct MES_LOG_ENTRY_DATA entries[1]; -}; - -union MESAPI_SET_HW_RESOURCES { - struct { - union MES_API_HEADER header; - uint32_t vmid_mask_mmhub; - uint32_t vmid_mask_gfxhub; - uint32_t gds_size; - uint32_t paging_vmid; - uint32_t compute_hqd_mask[MAX_COMPUTE_PIPES]; - uint32_t gfx_hqd_mask[MAX_GFX_PIPES]; - uint32_t sdma_hqd_mask[MAX_SDMA_PIPES]; - uint32_t agreegated_doorbells[AMD_PRIORITY_NUM_LEVELS]; - uint64_t g_sch_ctx_gpu_mc_ptr; - uint64_t query_status_fence_gpu_mc_ptr; - struct MES_API_STATUS api_status; - union { - struct { - uint32_t disable_reset : 1; - uint32_t reserved : 31; - }; - uint32_t uint32_t_all; - }; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__ADD_QUEUE { - struct { - union MES_API_HEADER header; - uint32_t process_id; - uint64_t page_table_base_addr; - uint64_t process_va_start; - uint64_t process_va_end; - uint64_t process_quantum; - uint64_t process_context_addr; - uint64_t gang_quantum; - uint64_t gang_context_addr; - uint32_t inprocess_gang_priority; - enum MES_AMD_PRIORITY_LEVEL gang_global_priority_level; - uint32_t doorbell_offset; - uint64_t mqd_addr; - uint64_t wptr_addr; - enum MES_QUEUE_TYPE queue_type; - uint32_t gds_base; - uint32_t gds_size; - uint32_t gws_base; - uint32_t gws_size; - uint32_t oa_mask; - - struct { - uint32_t paging : 1; - uint32_t debug_vmid : 4; - uint32_t program_gds : 1; - uint32_t is_gang_suspended : 1; - uint32_t is_tmz_queue : 1; - uint32_t reserved : 24; - }; - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__REMOVE_QUEUE { - struct { - union MES_API_HEADER header; - uint32_t doorbell_offset; - uint64_t gang_context_addr; - - struct { - uint32_t unmap_legacy_gfx_queue : 1; - uint32_t reserved : 31; - }; - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__SET_SCHEDULING_CONFIG { - struct { - union MES_API_HEADER header; - /* Grace period when preempting another priority band for this - * priority band. The value for idle priority band is ignored, - * as it never preempts other bands. - */ - uint64_t grace_period_other_levels[AMD_PRIORITY_NUM_LEVELS]; - /* Default quantum for scheduling across processes within - * a priority band. - */ - uint64_t process_quantum_for_level[AMD_PRIORITY_NUM_LEVELS]; - /* Default grace period for processes that preempt each other - * within a priority band. - */ - uint64_t process_grace_period_same_level[AMD_PRIORITY_NUM_LEVELS]; - /* For normal level this field specifies the target GPU - * percentage in situations when it's starved by the high level. - * Valid values are between 0 and 50, with the default being 10. - */ - uint32_t normal_yield_percent; - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__PERFORM_YIELD { - struct { - union MES_API_HEADER header; - uint32_t dummy; - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__CHANGE_GANG_PRIORITY_LEVEL { - struct { - union MES_API_HEADER header; - uint32_t inprocess_gang_priority; - enum MES_AMD_PRIORITY_LEVEL gang_global_priority_level; - uint64_t gang_quantum; - uint64_t gang_context_addr; - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__SUSPEND { - struct { - union MES_API_HEADER header; - /* false - suspend all gangs; true - specific gang */ - struct { - uint32_t suspend_all_gangs : 1; - uint32_t reserved : 31; - }; - /* gang_context_addr is valid only if suspend_all = false */ - uint64_t gang_context_addr; - - uint64_t suspend_fence_addr; - uint32_t suspend_fence_value; - - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__RESUME { - struct { - union MES_API_HEADER header; - /* false - resume all gangs; true - specified gang */ - struct { - uint32_t resume_all_gangs : 1; - uint32_t reserved : 31; - }; - /* valid only if resume_all_gangs = false */ - uint64_t gang_context_addr; - - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__RESET { - struct { - union MES_API_HEADER header; - - struct { - uint32_t reset_queue : 1; - uint32_t reserved : 31; - }; - - uint64_t gang_context_addr; - uint32_t doorbell_offset; /* valid only if reset_queue = true */ - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__SET_LOGGING_BUFFER { - struct { - union MES_API_HEADER header; - /* There are separate log buffers for each queue type */ - enum MES_QUEUE_TYPE log_type; - /* Log buffer GPU Address */ - uint64_t logging_buffer_addr; - /* number of entries in the log buffer */ - uint32_t number_of_entries; - /* Entry index at which CPU interrupt needs to be signalled */ - uint32_t interrupt_entry; - - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__QUERY_MES_STATUS { - struct { - union MES_API_HEADER header; - bool mes_healthy; /* 0 - not healthy, 1 - healthy */ - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__PROGRAM_GDS { - struct { - union MES_API_HEADER header; - uint64_t process_context_addr; - uint32_t gds_base; - uint32_t gds_size; - uint32_t gws_base; - uint32_t gws_size; - uint32_t oa_mask; - struct MES_API_STATUS api_status; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -union MESAPI__SET_DEBUG_VMID { - struct { - union MES_API_HEADER header; - struct MES_API_STATUS api_status; - union { - struct { - uint32_t use_gds : 1; - uint32_t reserved : 31; - } flags; - uint32_t u32All; - }; - uint32_t reserved; - uint32_t debug_vmid; - uint64_t process_context_addr; - uint64_t page_table_base_addr; - uint64_t process_va_start; - uint64_t process_va_end; - uint32_t gds_base; - uint32_t gds_size; - uint32_t gws_base; - uint32_t gws_size; - uint32_t oa_mask; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -enum MESAPI_MISC_OPCODE { - MESAPI_MISC__MODIFY_REG, - MESAPI_MISC__MAX, -}; - -enum MODIFY_REG_SUBCODE { - MODIFY_REG__OVERWRITE, - MODIFY_REG__RMW_OR, - MODIFY_REG__RMW_AND, - MODIFY_REG__MAX, -}; - -enum { MISC_DATA_MAX_SIZE_IN_DWORDS = 20 }; - -union MESAPI__MISC { - struct { - union MES_API_HEADER header; - enum MESAPI_MISC_OPCODE opcode; - struct MES_API_STATUS api_status; - - union { - struct { - enum MODIFY_REG_SUBCODE subcode; - uint32_t reg_offset; - uint32_t reg_value; - } modify_reg; - uint32_t data[MISC_DATA_MAX_SIZE_IN_DWORDS]; - }; - }; - - uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; -}; - -#pragma pack(pop) -#endif diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c index 622aa17b18e7..030a92b3a0da 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c @@ -133,6 +133,8 @@ static int mes_v10_1_add_hw_queue(struct amdgpu_mes *mes, { struct amdgpu_device *adev = mes->adev; union MESAPI__ADD_QUEUE mes_add_queue_pkt; + struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_GFXHUB_0]; + uint32_t vm_cntx_cntl = hub->vm_cntx_cntl; memset(&mes_add_queue_pkt, 0, sizeof(mes_add_queue_pkt)); @@ -141,8 +143,7 @@ static int mes_v10_1_add_hw_queue(struct amdgpu_mes *mes, mes_add_queue_pkt.header.dwsize = API_FRAME_SIZE_IN_DWORDS; mes_add_queue_pkt.process_id = input->process_id; - mes_add_queue_pkt.page_table_base_addr = - input->page_table_base_addr - adev->gmc.vram_start; + mes_add_queue_pkt.page_table_base_addr = input->page_table_base_addr; mes_add_queue_pkt.process_va_start = input->process_va_start; mes_add_queue_pkt.process_va_end = input->process_va_end; mes_add_queue_pkt.process_quantum = input->process_quantum; @@ -159,6 +160,10 @@ static int mes_v10_1_add_hw_queue(struct amdgpu_mes *mes, mes_add_queue_pkt.queue_type = convert_to_mes_queue_type(input->queue_type); mes_add_queue_pkt.paging = input->paging; + mes_add_queue_pkt.vm_context_cntl = vm_cntx_cntl; + mes_add_queue_pkt.gws_base = input->gws_base; + mes_add_queue_pkt.gws_size = input->gws_size; + mes_add_queue_pkt.trap_handler_addr = input->tba_addr; mes_add_queue_pkt.api_status.api_completion_fence_addr = mes->ring.fence_drv.gpu_addr; @@ -192,6 +197,44 @@ static int mes_v10_1_remove_hw_queue(struct amdgpu_mes *mes, &mes_remove_queue_pkt, sizeof(mes_remove_queue_pkt)); } +static int mes_v10_1_unmap_legacy_queue(struct amdgpu_mes *mes, + struct mes_unmap_legacy_queue_input *input) +{ + union MESAPI__REMOVE_QUEUE mes_remove_queue_pkt; + + memset(&mes_remove_queue_pkt, 0, sizeof(mes_remove_queue_pkt)); + + mes_remove_queue_pkt.header.type = MES_API_TYPE_SCHEDULER; + mes_remove_queue_pkt.header.opcode = MES_SCH_API_REMOVE_QUEUE; + mes_remove_queue_pkt.header.dwsize = API_FRAME_SIZE_IN_DWORDS; + + mes_remove_queue_pkt.doorbell_offset = input->doorbell_offset; + mes_remove_queue_pkt.gang_context_addr = 0; + + mes_remove_queue_pkt.pipe_id = input->pipe_id; + mes_remove_queue_pkt.queue_id = input->queue_id; + + if (input->action == PREEMPT_QUEUES_NO_UNMAP) { + mes_remove_queue_pkt.preempt_legacy_gfx_queue = 1; + mes_remove_queue_pkt.tf_addr = input->trail_fence_addr; + mes_remove_queue_pkt.tf_data = + lower_32_bits(input->trail_fence_data); + } else { + if (input->queue_type == AMDGPU_RING_TYPE_GFX) + mes_remove_queue_pkt.unmap_legacy_gfx_queue = 1; + else + mes_remove_queue_pkt.unmap_kiq_utility_queue = 1; + } + + mes_remove_queue_pkt.api_status.api_completion_fence_addr = + mes->ring.fence_drv.gpu_addr; + mes_remove_queue_pkt.api_status.api_completion_fence_value = + ++mes->ring.fence_drv.sync_seq; + + return mes_v10_1_submit_pkt_and_poll_completion(mes, + &mes_remove_queue_pkt, sizeof(mes_remove_queue_pkt)); +} + static int mes_v10_1_suspend_gang(struct amdgpu_mes *mes, struct mes_suspend_gang_input *input) { @@ -254,9 +297,21 @@ static int mes_v10_1_set_hw_resources(struct amdgpu_mes *mes) mes_set_hw_res_pkt.sdma_hqd_mask[i] = mes->sdma_hqd_mask[i]; for (i = 0; i < AMD_PRIORITY_NUM_LEVELS; i++) - mes_set_hw_res_pkt.agreegated_doorbells[i] = + mes_set_hw_res_pkt.aggregated_doorbells[i] = mes->agreegated_doorbells[i]; + for (i = 0; i < 5; i++) { + mes_set_hw_res_pkt.gc_base[i] = adev->reg_offset[GC_HWIP][0][i]; + mes_set_hw_res_pkt.mmhub_base[i] = + adev->reg_offset[MMHUB_HWIP][0][i]; + mes_set_hw_res_pkt.osssys_base[i] = + adev->reg_offset[OSSSYS_HWIP][0][i]; + } + + mes_set_hw_res_pkt.disable_reset = 1; + mes_set_hw_res_pkt.disable_mes_log = 1; + mes_set_hw_res_pkt.use_different_vmid_compute = 1; + mes_set_hw_res_pkt.api_status.api_completion_fence_addr = mes->ring.fence_drv.gpu_addr; mes_set_hw_res_pkt.api_status.api_completion_fence_value = @@ -269,6 +324,7 @@ static int mes_v10_1_set_hw_resources(struct amdgpu_mes *mes) static const struct amdgpu_mes_funcs mes_v10_1_funcs = { .add_hw_queue = mes_v10_1_add_hw_queue, .remove_hw_queue = mes_v10_1_remove_hw_queue, + .unmap_legacy_queue = mes_v10_1_unmap_legacy_queue, .suspend_gang = mes_v10_1_suspend_gang, .resume_gang = mes_v10_1_resume_gang, }; @@ -1097,6 +1153,13 @@ static int mes_v10_1_hw_init(void *handle) goto failure; } + /* + * Disable KIQ ring usage from the driver once MES is enabled. + * MES uses KIQ ring exclusively so driver cannot access KIQ ring + * with MES enabled. + */ + adev->gfx.kiq.ring.sched.ready = false; + return 0; failure: diff --git a/drivers/gpu/drm/amd/include/mes_api_def.h b/drivers/gpu/drm/amd/include/mes_api_def.h new file mode 100644 index 000000000000..b2a8503feec0 --- /dev/null +++ b/drivers/gpu/drm/amd/include/mes_api_def.h @@ -0,0 +1,570 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __MES_API_DEF_H__ +#define __MES_API_DEF_H__ + +#pragma pack(push, 4) + +#define MES_API_VERSION 1 + +/* Driver submits one API(cmd) as a single Frame and this command size is same + * for all API to ease the debugging and parsing of ring buffer. + */ +enum { API_FRAME_SIZE_IN_DWORDS = 64 }; + +/* To avoid command in scheduler context to be overwritten whenenver mutilple + * interrupts come in, this creates another queue. + */ +enum { API_NUMBER_OF_COMMAND_MAX = 32 }; + +enum MES_API_TYPE { + MES_API_TYPE_SCHEDULER = 1, + MES_API_TYPE_MAX +}; + +enum MES_SCH_API_OPCODE { + MES_SCH_API_SET_HW_RSRC = 0, + MES_SCH_API_SET_SCHEDULING_CONFIG = 1, /* agreegated db, quantums, etc */ + MES_SCH_API_ADD_QUEUE = 2, + MES_SCH_API_REMOVE_QUEUE = 3, + MES_SCH_API_PERFORM_YIELD = 4, + MES_SCH_API_SET_GANG_PRIORITY_LEVEL = 5, + MES_SCH_API_SUSPEND = 6, + MES_SCH_API_RESUME = 7, + MES_SCH_API_RESET = 8, + MES_SCH_API_SET_LOG_BUFFER = 9, + MES_SCH_API_CHANGE_GANG_PRORITY = 10, + MES_SCH_API_QUERY_SCHEDULER_STATUS = 11, + MES_SCH_API_PROGRAM_GDS = 12, + MES_SCH_API_SET_DEBUG_VMID = 13, + MES_SCH_API_MISC = 14, + MES_SCH_API_UPDATE_ROOT_PAGE_TABLE = 15, + MES_SCH_API_AMD_LOG = 16, + MES_SCH_API_MAX = 0xFF +}; + +union MES_API_HEADER { + struct { + uint32_t type : 4; /* 0 - Invalid; 1 - Scheduling; 2 - TBD */ + uint32_t opcode : 8; + uint32_t dwsize : 8; /* including header */ + uint32_t reserved : 12; + }; + + uint32_t u32All; +}; + +enum MES_AMD_PRIORITY_LEVEL { + AMD_PRIORITY_LEVEL_LOW = 0, + AMD_PRIORITY_LEVEL_NORMAL = 1, + AMD_PRIORITY_LEVEL_MEDIUM = 2, + AMD_PRIORITY_LEVEL_HIGH = 3, + AMD_PRIORITY_LEVEL_REALTIME = 4, + AMD_PRIORITY_NUM_LEVELS +}; + +enum MES_QUEUE_TYPE { + MES_QUEUE_TYPE_GFX, + MES_QUEUE_TYPE_COMPUTE, + MES_QUEUE_TYPE_SDMA, + MES_QUEUE_TYPE_MAX, +}; + +struct MES_API_STATUS { + uint64_t api_completion_fence_addr; + uint64_t api_completion_fence_value; +}; + +enum { MAX_COMPUTE_PIPES = 8 }; +enum { MAX_GFX_PIPES = 2 }; +enum { MAX_SDMA_PIPES = 2 }; + +enum { MAX_COMPUTE_HQD_PER_PIPE = 8 }; +enum { MAX_GFX_HQD_PER_PIPE = 8 }; +enum { MAX_SDMA_HQD_PER_PIPE = 10 }; + +enum { MAX_QUEUES_IN_A_GANG = 8 }; + +enum VM_HUB_TYPE { + VM_HUB_TYPE_GC = 0, + VM_HUB_TYPE_MM = 1, + VM_HUB_TYPE_MAX, +}; + +enum { VMID_INVALID = 0xffff }; + +enum { MAX_VMID_GCHUB = 16 }; +enum { MAX_VMID_MMHUB = 16 }; + +enum MES_LOG_OPERATION { + MES_LOG_OPERATION_CONTEXT_STATE_CHANGE = 0, + MES_LOG_OPERATION_QUEUE_NEW_WORK = 1, + MES_LOG_OPERATION_QUEUE_UNWAIT_SYNC_OBJECT = 2, + MES_LOG_OPERATION_QUEUE_NO_MORE_WORK = 3, + MES_LOG_OPERATION_QUEUE_WAIT_SYNC_OBJECT = 4, + MES_LOG_OPERATION_QUEUE_INVALID = 0xF, +}; + +enum MES_LOG_CONTEXT_STATE { + MES_LOG_CONTEXT_STATE_IDLE = 0, + MES_LOG_CONTEXT_STATE_RUNNING = 1, + MES_LOG_CONTEXT_STATE_READY = 2, + MES_LOG_CONTEXT_STATE_READY_STANDBY = 3, + MES_LOG_CONTEXT_STATE_INVALID = 0xF, +}; + +struct MES_LOG_CONTEXT_STATE_CHANGE { + void *h_context; + enum MES_LOG_CONTEXT_STATE new_context_state; +}; + +struct MES_LOG_QUEUE_NEW_WORK { + uint64_t h_queue; + uint64_t reserved; +}; + +struct MES_LOG_QUEUE_UNWAIT_SYNC_OBJECT { + uint64_t h_queue; + uint64_t h_sync_object; +}; + +struct MES_LOG_QUEUE_NO_MORE_WORK { + uint64_t h_queue; + uint64_t reserved; +}; + +struct MES_LOG_QUEUE_WAIT_SYNC_OBJECT { + uint64_t h_queue; + uint64_t h_sync_object; +}; + +struct MES_LOG_ENTRY_HEADER { + uint32_t first_free_entry_index; + uint32_t wraparound_count; + uint64_t number_of_entries; + uint64_t reserved[2]; +}; + +struct MES_LOG_ENTRY_DATA { + uint64_t gpu_time_stamp; + uint32_t operation_type; /* operation_type is of MES_LOG_OPERATION type */ + uint32_t reserved_operation_type_bits; + union { + struct MES_LOG_CONTEXT_STATE_CHANGE context_state_change; + struct MES_LOG_QUEUE_NEW_WORK queue_new_work; + struct MES_LOG_QUEUE_UNWAIT_SYNC_OBJECT queue_unwait_sync_object; + struct MES_LOG_QUEUE_NO_MORE_WORK queue_no_more_work; + struct MES_LOG_QUEUE_WAIT_SYNC_OBJECT queue_wait_sync_object; + uint64_t all[2]; + }; +}; + +struct MES_LOG_BUFFER { + struct MES_LOG_ENTRY_HEADER header; + struct MES_LOG_ENTRY_DATA entries[1]; +}; + +enum MES_SWIP_TO_HWIP_DEF { + MES_MAX_HWIP_SEGMENT = 6, +}; + +union MESAPI_SET_HW_RESOURCES { + struct { + union MES_API_HEADER header; + uint32_t vmid_mask_mmhub; + uint32_t vmid_mask_gfxhub; + uint32_t gds_size; + uint32_t paging_vmid; + uint32_t compute_hqd_mask[MAX_COMPUTE_PIPES]; + uint32_t gfx_hqd_mask[MAX_GFX_PIPES]; + uint32_t sdma_hqd_mask[MAX_SDMA_PIPES]; + uint32_t aggregated_doorbells[AMD_PRIORITY_NUM_LEVELS]; + uint64_t g_sch_ctx_gpu_mc_ptr; + uint64_t query_status_fence_gpu_mc_ptr; + uint32_t gc_base[MES_MAX_HWIP_SEGMENT]; + uint32_t mmhub_base[MES_MAX_HWIP_SEGMENT]; + uint32_t osssys_base[MES_MAX_HWIP_SEGMENT]; + struct MES_API_STATUS api_status; + union { + struct { + uint32_t disable_reset : 1; + uint32_t use_different_vmid_compute : 1; + uint32_t disable_mes_log : 1; + uint32_t apply_mmhub_pgvm_invalidate_ack_loss_wa : 1; + uint32_t apply_grbm_remote_register_dummy_read_wa : 1; + uint32_t second_gfx_pipe_enabled : 1; + uint32_t enable_level_process_quantum_check : 1; + uint32_t apply_cwsr_program_all_vmid_sq_shader_tba_registers_wa : 1; + uint32_t enable_mqd_active_poll : 1; + uint32_t disable_timer_int : 1; + uint32_t reserved : 22; + }; + uint32_t uint32_t_all; + }; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__ADD_QUEUE { + struct { + union MES_API_HEADER header; + uint32_t process_id; + uint64_t page_table_base_addr; + uint64_t process_va_start; + uint64_t process_va_end; + uint64_t process_quantum; + uint64_t process_context_addr; + uint64_t gang_quantum; + uint64_t gang_context_addr; + uint32_t inprocess_gang_priority; + enum MES_AMD_PRIORITY_LEVEL gang_global_priority_level; + uint32_t doorbell_offset; + uint64_t mqd_addr; + uint64_t wptr_addr; + uint64_t h_context; + uint64_t h_queue; + enum MES_QUEUE_TYPE queue_type; + uint32_t gds_base; + uint32_t gds_size; + uint32_t gws_base; + uint32_t gws_size; + uint32_t oa_mask; + uint64_t trap_handler_addr; + uint32_t vm_context_cntl; + + struct { + uint32_t paging : 1; + uint32_t debug_vmid : 4; + uint32_t program_gds : 1; + uint32_t is_gang_suspended : 1; + uint32_t is_tmz_queue : 1; + uint32_t map_kiq_utility_queue : 1; + uint32_t reserved : 23; + }; + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__REMOVE_QUEUE { + struct { + union MES_API_HEADER header; + uint32_t doorbell_offset; + uint64_t gang_context_addr; + + struct { + uint32_t unmap_legacy_gfx_queue : 1; + uint32_t unmap_kiq_utility_queue : 1; + uint32_t preempt_legacy_gfx_queue : 1; + uint32_t reserved : 29; + }; + struct MES_API_STATUS api_status; + + uint32_t pipe_id; + uint32_t queue_id; + + uint64_t tf_addr; + uint32_t tf_data; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__SET_SCHEDULING_CONFIG { + struct { + union MES_API_HEADER header; + /* Grace period when preempting another priority band for this + * priority band. The value for idle priority band is ignored, + * as it never preempts other bands. + */ + uint64_t grace_period_other_levels[AMD_PRIORITY_NUM_LEVELS]; + /* Default quantum for scheduling across processes within + * a priority band. + */ + uint64_t process_quantum_for_level[AMD_PRIORITY_NUM_LEVELS]; + /* Default grace period for processes that preempt each other + * within a priority band. + */ + uint64_t process_grace_period_same_level[AMD_PRIORITY_NUM_LEVELS]; + /* For normal level this field specifies the target GPU + * percentage in situations when it's starved by the high level. + * Valid values are between 0 and 50, with the default being 10. + */ + uint32_t normal_yield_percent; + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__PERFORM_YIELD { + struct { + union MES_API_HEADER header; + uint32_t dummy; + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__CHANGE_GANG_PRIORITY_LEVEL { + struct { + union MES_API_HEADER header; + uint32_t inprocess_gang_priority; + enum MES_AMD_PRIORITY_LEVEL gang_global_priority_level; + uint64_t gang_quantum; + uint64_t gang_context_addr; + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__SUSPEND { + struct { + union MES_API_HEADER header; + /* false - suspend all gangs; true - specific gang */ + struct { + uint32_t suspend_all_gangs : 1; + uint32_t reserved : 31; + }; + /* gang_context_addr is valid only if suspend_all = false */ + uint64_t gang_context_addr; + + uint64_t suspend_fence_addr; + uint32_t suspend_fence_value; + + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__RESUME { + struct { + union MES_API_HEADER header; + /* false - resume all gangs; true - specified gang */ + struct { + uint32_t resume_all_gangs : 1; + uint32_t reserved : 31; + }; + /* valid only if resume_all_gangs = false */ + uint64_t gang_context_addr; + + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__RESET { + struct { + union MES_API_HEADER header; + + struct { + /* Only reset the queue given by doorbell_offset (not entire gang) */ + uint32_t reset_queue_only : 1; + /* Hang detection first then reset any queues that are hung */ + uint32_t hang_detect_then_reset : 1; + /* Only do hang detection (no reset) */ + uint32_t hang_detect_only : 1; + /* Rest HP and LP kernel queues not managed by MES */ + uint32_t reset_legacy_gfx : 1; + uint32_t reserved : 28; + }; + + uint64_t gang_context_addr; + + /* valid only if reset_queue_only = true */ + uint32_t doorbell_offset; + + /* valid only if hang_detect_then_reset = true */ + uint64_t doorbell_offset_addr; + enum MES_QUEUE_TYPE queue_type; + + /* valid only if reset_legacy_gfx = true */ + uint32_t pipe_id_lp; + uint32_t queue_id_lp; + uint32_t vmid_id_lp; + uint64_t mqd_mc_addr_lp; + uint32_t doorbell_offset_lp; + uint64_t wptr_addr_lp; + + uint32_t pipe_id_hp; + uint32_t queue_id_hp; + uint32_t vmid_id_hp; + uint64_t mqd_mc_addr_hp; + uint32_t doorbell_offset_hp; + uint64_t wptr_addr_hp; + + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__SET_LOGGING_BUFFER { + struct { + union MES_API_HEADER header; + /* There are separate log buffers for each queue type */ + enum MES_QUEUE_TYPE log_type; + /* Log buffer GPU Address */ + uint64_t logging_buffer_addr; + /* number of entries in the log buffer */ + uint32_t number_of_entries; + /* Entry index at which CPU interrupt needs to be signalled */ + uint32_t interrupt_entry; + + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__QUERY_MES_STATUS { + struct { + union MES_API_HEADER header; + bool mes_healthy; /* 0 - not healthy, 1 - healthy */ + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__PROGRAM_GDS { + struct { + union MES_API_HEADER header; + uint64_t process_context_addr; + uint32_t gds_base; + uint32_t gds_size; + uint32_t gws_base; + uint32_t gws_size; + uint32_t oa_mask; + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__SET_DEBUG_VMID { + struct { + union MES_API_HEADER header; + struct MES_API_STATUS api_status; + union { + struct { + uint32_t use_gds : 1; + uint32_t reserved : 31; + } flags; + uint32_t u32All; + }; + uint32_t reserved; + uint32_t debug_vmid; + uint64_t process_context_addr; + uint64_t page_table_base_addr; + uint64_t process_va_start; + uint64_t process_va_end; + uint32_t gds_base; + uint32_t gds_size; + uint32_t gws_base; + uint32_t gws_size; + uint32_t oa_mask; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +enum MESAPI_MISC_OPCODE { + MESAPI_MISC__MODIFY_REG, + MESAPI_MISC__INV_GART, + MESAPI_MISC__QUERY_STATUS, + MESAPI_MISC__MAX, +}; + +enum MODIFY_REG_SUBCODE { + MODIFY_REG__OVERWRITE, + MODIFY_REG__RMW_OR, + MODIFY_REG__RMW_AND, + MODIFY_REG__MAX, +}; + +enum { MISC_DATA_MAX_SIZE_IN_DWORDS = 20 }; + +struct MODIFY_REG { + enum MODIFY_REG_SUBCODE subcode; + uint32_t reg_offset; + uint32_t reg_value; +}; + +struct INV_GART { + uint64_t inv_range_va_start; + uint64_t inv_range_size; +}; + +struct QUERY_STATUS { + uint32_t context_id; +}; + +union MESAPI__MISC { + struct { + union MES_API_HEADER header; + enum MESAPI_MISC_OPCODE opcode; + struct MES_API_STATUS api_status; + + union { + struct MODIFY_REG modify_reg; + struct INV_GART inv_gart; + struct QUERY_STATUS query_status; + uint32_t data[MISC_DATA_MAX_SIZE_IN_DWORDS]; + }; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI__UPDATE_ROOT_PAGE_TABLE { + struct { + union MES_API_HEADER header; + uint64_t page_table_base_addr; + uint64_t process_context_addr; + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +union MESAPI_AMD_LOG { + struct { + union MES_API_HEADER header; + uint64_t p_buffer_memory; + uint64_t p_buffer_size_used; + struct MES_API_STATUS api_status; + }; + + uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; +}; + +#pragma pack(pop) +#endif -- cgit From 948ceec7c41574666dd1b78fd6bad4d89cdae452 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 6 May 2022 11:41:20 -0400 Subject: drm/amdgpu/mes: fix format specifier for size_t To avoid a warning on 32 bit. Reported-by: kernel test robot Reviewed-by: Guchun Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 72bafba1c470..69a70a0aaed9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -135,7 +135,7 @@ static int amdgpu_mes_doorbell_init(struct amdgpu_device *adev) adev->mes.doorbell_id_offset = doorbell_start_offset / sizeof(u32); adev->mes.max_doorbell_slices = doorbell_process_limit; - DRM_INFO("max_doorbell_slices=%ld\n", doorbell_process_limit); + DRM_INFO("max_doorbell_slices=%zu\n", doorbell_process_limit); return 0; } -- cgit