diff options
author | Shashank Sharma <shashank.sharma@amd.com> | 2023-10-10 13:17:43 +0300 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2025-04-08 23:48:15 +0300 |
commit | 5501117d24a38dadff3dbd8d3102559b27929668 (patch) | |
tree | 857a5a8f6b030daf121037a30e9aec2b40fd227a /drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c | |
parent | bf33cb6551a8c5b9d68d2983678e1a05c89428c5 (diff) | |
download | linux-5501117d24a38dadff3dbd8d3102559b27929668.tar.xz |
drm/amdgpu: add new IOCTL for usermode queue
This patch adds:
- A new IOCTL function to create and destroy
- A new structure to keep all the user queue data in one place.
- A function to generate unique index for the queue.
V1: Worked on review comments from RFC patch series:
- Alex: Keep a list of queues, instead of single queue per process.
- Christian: Use the queue manager instead of global ptrs,
Don't keep the queue structure in amdgpu_ctx
V2: Worked on review comments:
- Christian:
- Formatting of text
- There is no need for queuing of userqueues, with idr in place
- Alex:
- Remove use_doorbell, its unnecessary
- Reuse amdgpu_mqd_props for saving mqd fields
- Code formatting and re-arrangement
V3:
- Integration with doorbell manager
V4:
- Accommodate MQD union related changes in UAPI (Alex)
- Do not set the queue size twice (Bas)
V5:
- Remove wrapper functions for queue indexing (Christian)
- Do not save the queue id/idr in queue itself (Christian)
- Move the idr allocation in the IP independent generic space
(Christian)
V6:
- Check the validity of input IP type (Christian)
V7:
- Move uq_func from uq_mgr to adev (Alex)
- Add missing free(queue) for error cases (Yifan)
V9:
- Rebase
V10: Addressed review comments from Christian, and added R-B:
- Do not initialize the local variable
- Convert DRM_ERROR to DEBUG.
V11:
- check the input flags to be zero (Alex)
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Christian Koenig <christian.koenig@amd.com>
Reviewed-by: Christian Koenig <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Shashank Sharma <shashank.sharma@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c index effc0c7c02cf..cf7fe68d9277 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c @@ -23,6 +23,126 @@ */ #include "amdgpu.h" +#include "amdgpu_vm.h" +#include "amdgpu_userqueue.h" + +static struct amdgpu_usermode_queue * +amdgpu_userqueue_find(struct amdgpu_userq_mgr *uq_mgr, int qid) +{ + return idr_find(&uq_mgr->userq_idr, qid); +} + +static int +amdgpu_userqueue_destroy(struct drm_file *filp, int queue_id) +{ + struct amdgpu_fpriv *fpriv = filp->driver_priv; + struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr; + struct amdgpu_device *adev = uq_mgr->adev; + const struct amdgpu_userq_funcs *uq_funcs; + struct amdgpu_usermode_queue *queue; + + mutex_lock(&uq_mgr->userq_mutex); + + queue = amdgpu_userqueue_find(uq_mgr, queue_id); + if (!queue) { + DRM_DEBUG_DRIVER("Invalid queue id to destroy\n"); + mutex_unlock(&uq_mgr->userq_mutex); + return -EINVAL; + } + + uq_funcs = adev->userq_funcs[queue->queue_type]; + uq_funcs->mqd_destroy(uq_mgr, queue); + idr_remove(&uq_mgr->userq_idr, queue_id); + kfree(queue); + + mutex_unlock(&uq_mgr->userq_mutex); + return 0; +} + +static int +amdgpu_userqueue_create(struct drm_file *filp, union drm_amdgpu_userq *args) +{ + struct amdgpu_fpriv *fpriv = filp->driver_priv; + struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr; + struct amdgpu_device *adev = uq_mgr->adev; + const struct amdgpu_userq_funcs *uq_funcs; + struct amdgpu_usermode_queue *queue; + int qid, r = 0; + + if (args->in.flags) { + DRM_ERROR("Usermode queue flags not supported yet\n"); + return -EINVAL; + } + + mutex_lock(&uq_mgr->userq_mutex); + + uq_funcs = adev->userq_funcs[args->in.ip_type]; + if (!uq_funcs) { + DRM_ERROR("Usermode queue is not supported for this IP (%u)\n", args->in.ip_type); + r = -EINVAL; + goto unlock; + } + + queue = kzalloc(sizeof(struct amdgpu_usermode_queue), GFP_KERNEL); + if (!queue) { + DRM_ERROR("Failed to allocate memory for queue\n"); + r = -ENOMEM; + goto unlock; + } + queue->doorbell_handle = args->in.doorbell_handle; + queue->doorbell_index = args->in.doorbell_offset; + queue->queue_type = args->in.ip_type; + queue->flags = args->in.flags; + queue->vm = &fpriv->vm; + + r = uq_funcs->mqd_create(uq_mgr, &args->in, queue); + if (r) { + DRM_ERROR("Failed to create Queue\n"); + kfree(queue); + goto unlock; + } + + qid = idr_alloc(&uq_mgr->userq_idr, queue, 1, AMDGPU_MAX_USERQ_COUNT, GFP_KERNEL); + if (qid < 0) { + DRM_ERROR("Failed to allocate a queue id\n"); + uq_funcs->mqd_destroy(uq_mgr, queue); + kfree(queue); + r = -ENOMEM; + goto unlock; + } + args->out.queue_id = qid; + +unlock: + mutex_unlock(&uq_mgr->userq_mutex); + return r; +} + +int amdgpu_userq_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + union drm_amdgpu_userq *args = data; + int r; + + switch (args->in.op) { + case AMDGPU_USERQ_OP_CREATE: + r = amdgpu_userqueue_create(filp, args); + if (r) + DRM_ERROR("Failed to create usermode queue\n"); + break; + + case AMDGPU_USERQ_OP_FREE: + r = amdgpu_userqueue_destroy(filp, args->in.queue_id); + if (r) + DRM_ERROR("Failed to destroy usermode queue\n"); + break; + + default: + DRM_DEBUG_DRIVER("Invalid user queue op specified: %d\n", args->in.op); + return -EINVAL; + } + + return r; +} int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct amdgpu_device *adev) { |