On Fri, Apr 26, 2024 at 9:48 AM Shashank Sharma <shashank.sharma@xxxxxxx> wrote: > > A Memory queue descriptor (MQD) of a userqueue defines it in > the hw's context. As MQD format can vary between different > graphics IPs, we need gfx GEN specific handlers to create MQDs. > > This patch: > - Adds a new file which will be used for MES based userqueue > functions targeting GFX and SDMA IP. > - Introduces MQD handler functions for the usermode queues. > - Adds new functions to create and destroy userqueue MQD for > MES-V11 for GFX IP. > > V1: Worked on review comments from Alex: > - Make MQD functions GEN and IP specific > > V2: Worked on review comments from Alex: > - Reuse the existing adev->mqd[ip] for MQD creation > - Formatting and arrangement of code > > V3: > - Integration with doorbell manager > > V4: Review comments addressed: > - Do not create a new file for userq, reuse gfx_v11_0.c (Alex) > - Align name of structure members (Luben) > - Don't break up the Cc tag list and the Sob tag list in commit > message (Luben) > V5: > - No need to reserve the bo for MQD (Christian). > - Some more changes to support IP specific MQD creation. > > V6: > - Add a comment reminding us to replace the amdgpu_bo_create_kernel() > calls while creating MQD object to amdgpu_bo_create() once eviction > fences are ready (Christian). > > V7: > - Re-arrange userqueue functions in adev instead of uq_mgr (Alex) > - Use memdup_user instead of copy_from_user (Christian) > > V9: > - Moved userqueue code from gfx_v11_0.c to new file mes_v11_0.c so > that it can be reused for SDMA userqueues as well (Shashank, Alex) > > Cc: Alex Deucher <alexander.deucher@xxxxxxx> > Cc: Christian Koenig <christian.koenig@xxxxxxx> > Signed-off-by: Shashank Sharma <shashank.sharma@xxxxxxx> > Signed-off-by: Arvind Yadav <arvind.yadav@xxxxxxx> > --- > drivers/gpu/drm/amd/amdgpu/Makefile | 3 +- > drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 4 + > .../gpu/drm/amd/amdgpu/mes_v11_0_userqueue.c | 110 ++++++++++++++++++ > 3 files changed, 116 insertions(+), 1 deletion(-) > create mode 100644 drivers/gpu/drm/amd/amdgpu/mes_v11_0_userqueue.c > > diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile > index 05a2d1714070..a640bfa468ad 100644 > --- a/drivers/gpu/drm/amd/amdgpu/Makefile > +++ b/drivers/gpu/drm/amd/amdgpu/Makefile > @@ -184,7 +184,8 @@ amdgpu-y += \ > amdgpu-y += \ > amdgpu_mes.o \ > mes_v10_1.o \ > - mes_v11_0.o > + mes_v11_0.o \ > + mes_v11_0_userqueue.o > > # add UVD block > amdgpu-y += \ > diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c > index f7325b02a191..525bd0f4d3f7 100644 > --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c > +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c > @@ -1331,6 +1331,8 @@ static int gfx_v11_0_rlc_backdoor_autoload_enable(struct amdgpu_device *adev) > return 0; > } > > +extern const struct amdgpu_userq_funcs userq_mes_v11_0_funcs; > + > static int gfx_v11_0_sw_init(void *handle) > { > int i, j, k, r, ring_id = 0; > @@ -1347,6 +1349,7 @@ static int gfx_v11_0_sw_init(void *handle) > adev->gfx.mec.num_mec = 2; > adev->gfx.mec.num_pipe_per_mec = 4; > adev->gfx.mec.num_queue_per_pipe = 4; > + adev->userq_funcs[AMDGPU_HW_IP_GFX] = &userq_mes_v11_0_funcs; > break; > case IP_VERSION(11, 0, 1): > case IP_VERSION(11, 0, 4): > @@ -1358,6 +1361,7 @@ static int gfx_v11_0_sw_init(void *handle) > adev->gfx.mec.num_mec = 1; > adev->gfx.mec.num_pipe_per_mec = 4; > adev->gfx.mec.num_queue_per_pipe = 4; > + adev->userq_funcs[AMDGPU_HW_IP_GFX] = &userq_mes_v11_0_funcs; Does this work on APUs yet? If not, we should limit it to just dGPUs for now. Also, we should add minimum firmware version checks for user queue support. > break; > default: > adev->gfx.me.num_me = 1; > diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0_userqueue.c > new file mode 100644 > index 000000000000..9e7dee77d344 > --- /dev/null > +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0_userqueue.c > @@ -0,0 +1,110 @@ > +// SPDX-License-Identifier: MIT > +/* > + * Copyright 2024 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.h" > +#include "amdgpu_gfx.h" > +#include "v11_structs.h" > +#include "mes_v11_0.h" > +#include "amdgpu_userqueue.h" > + > +static int mes_v11_0_userq_mqd_create(struct amdgpu_userq_mgr *uq_mgr, > + struct drm_amdgpu_userq_in *args_in, > + struct amdgpu_usermode_queue *queue) > +{ > + struct amdgpu_device *adev = uq_mgr->adev; > + struct amdgpu_mqd *mqd_hw_default = &adev->mqds[queue->queue_type]; > + struct drm_amdgpu_userq_mqd *mqd_user; > + struct amdgpu_mqd_prop *userq_props; > + int r; > + > + /* Incoming MQD parameters from userspace to be saved here */ > + memset(&mqd_user, 0, sizeof(mqd_user)); > + > + /* Structure to initialize MQD for userqueue using generic MQD init function */ > + userq_props = kzalloc(sizeof(struct amdgpu_mqd_prop), GFP_KERNEL); > + if (!userq_props) { > + DRM_ERROR("Failed to allocate memory for userq_props\n"); > + return -ENOMEM; > + } > + > + if (args_in->mqd_size != sizeof(struct drm_amdgpu_userq_mqd)) { > + DRM_ERROR("MQD size mismatch\n"); > + r = -EINVAL; > + goto free_props; > + } > + > + mqd_user = memdup_user(u64_to_user_ptr(args_in->mqd), args_in->mqd_size); > + if (IS_ERR(mqd_user)) { > + DRM_ERROR("Failed to read user MQD\n"); > + r = -EFAULT; > + goto free_props; > + } > + > + r = amdgpu_userqueue_create_object(uq_mgr, &queue->mqd, mqd_hw_default->mqd_size); > + if (r) { > + DRM_ERROR("Failed to create MQD object for userqueue\n"); > + goto free_mqd_user; > + } > + > + /* Initialize the MQD BO with user given values */ > + userq_props->wptr_gpu_addr = mqd_user->wptr_va; > + userq_props->rptr_gpu_addr = mqd_user->rptr_va; > + userq_props->queue_size = mqd_user->queue_size; > + userq_props->hqd_base_gpu_addr = mqd_user->queue_va; > + userq_props->mqd_gpu_addr = queue->mqd.gpu_addr; We should validate the user virtual addresses and make sure they are non-0 and not part of the reserved areas of the address space. Alex > + userq_props->use_doorbell = true; > + > + queue->userq_prop = userq_props; > + > + r = mqd_hw_default->init_mqd(adev, (void *)queue->mqd.cpu_ptr, userq_props); > + if (r) { > + DRM_ERROR("Failed to initialize MQD for userqueue\n"); > + goto free_mqd; > + } > + > + return 0; > + > +free_mqd: > + amdgpu_userqueue_destroy_object(uq_mgr, &queue->mqd); > + > +free_mqd_user: > + kfree(mqd_user); > + > +free_props: > + kfree(userq_props); > + > + return r; > +} > + > +static void > +mes_v11_0_userq_mqd_destroy(struct amdgpu_userq_mgr *uq_mgr, > + struct amdgpu_usermode_queue *queue) > +{ > + kfree(queue->userq_prop); > + amdgpu_userqueue_destroy_object(uq_mgr, &queue->mqd); > +} > + > +const struct amdgpu_userq_funcs userq_mes_v11_0_funcs = { > + .mqd_create = mes_v11_0_userq_mqd_create, > + .mqd_destroy = mes_v11_0_userq_mqd_destroy, > +}; > -- > 2.43.2 >