* drm/amdgpu: v5 of LIST and CHANGE options for amdgpu userq @ 2026-10-20 19:47 David Francis 2026-10-20 19:48 ` [PATCH v5 1/2] drm/amdgpu: Add LIST option to USERQ ioctl David Francis 2026-10-20 19:48 ` [PATCH v5 2/2] drm/amdgpu: Add CHANGE_ID option for " David Francis 0 siblings, 2 replies; 5+ messages in thread From: David Francis @ 2026-10-20 19:47 UTC (permalink / raw) To: amd-gfx; +Cc: Tvrtko.Ursulin All comments on v4 have been addressed. In addition, there are now igt tests (tests/amdgpu: tests for amdgpu userq list and change) on igt-dev, and CRIU changes (https://github.com/fdavid-amd/criu/tree/amdgpu-userq) accompanying these changes ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v5 1/2] drm/amdgpu: Add LIST option to USERQ ioctl 2026-10-20 19:47 drm/amdgpu: v5 of LIST and CHANGE options for amdgpu userq David Francis @ 2026-10-20 19:48 ` David Francis 2026-10-22 10:09 ` Tvrtko Ursulin 2026-10-20 19:48 ` [PATCH v5 2/2] drm/amdgpu: Add CHANGE_ID option for " David Francis 1 sibling, 1 reply; 5+ messages in thread From: David Francis @ 2026-10-20 19:48 UTC (permalink / raw) To: amd-gfx; +Cc: Tvrtko.Ursulin, David Francis Add a new option to ioctl USERQ which provides information to a process about their own user queues. The returned data is in the same format as that used to create the queue in the first place. The interface uses retries; the user can guess at the number of queues required; if insufficiently large, the correct value will be returned. The same is done for the mqd sizes of each entry. v3: Don't acquire xa_lock and other misc fixes v4: Don't acquire mutex either and other misc fixes v5: Small fixes; now with accompanying igt and criu changes Signed-off-by: David Francis <David.Francis@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 145 +++++++++++++++++++++- include/uapi/drm/amdgpu_drm.h | 40 ++++++ 2 files changed, 182 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 3fe10d6af757..5aa53b2f4355 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -850,6 +850,8 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, args->in.mqd_size) return -EINVAL; break; + case AMDGPU_USERQ_OP_LIST: + break; default: return -EINVAL; } @@ -857,6 +859,142 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, return 0; } +static int +amdgpu_userq_list(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 drm_amdgpu_userq_list_entry *entries; + struct amdgpu_usermode_queue *queue; + size_t mqd_size, entry_buffer_size; + uint32_t num_queues = 0; + unsigned long queue_id; + int i = 0; + int ret; + + xa_for_each(&uq_mgr->userq_xa, queue_id, queue) + num_queues += 1; + + /** + * If the num_entries buffer is too small, return the correct size. + * User should try again with the right space allocated. + */ + if (num_queues > args->list_in_out.num_entries) { + args->list_in_out.num_entries = num_queues; + return 0; + } + args->list_in_out.num_entries = num_queues; + + if (num_queues == 0) + return 0; + + ret = check_mul_overflow(num_queues, sizeof(*entries), &entry_buffer_size); + if (ret) + return -E2BIG; + + entries = kvmalloc_objs(typeof(*entries), num_queues, GFP_KERNEL); + if (!entries) + return -ENOMEM; + + ret = copy_from_user(entries, u64_to_user_ptr(args->list_in_out.entries), + entry_buffer_size); + if (ret) { + ret = -EFAULT; + goto exit; + } + + xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { + /** + * The xa may have added or removed queues since we counted + * them, so break if there are now more queues than entries. + */ + if (i >= num_queues) + break; + /** + * Check mqd size. As with num_entries, return the right sizes + * if they are too small. These sizes also serve as + * versioning for the mqd. Despite the names, these are the + * mqd sizes for both gfx11 and gfx12. + */ + if (queue->queue_type == AMDGPU_HW_IP_COMPUTE) { + mqd_size = sizeof(struct drm_amdgpu_userq_mqd_compute_gfx11); + } else if (queue->queue_type == AMDGPU_HW_IP_GFX) { + mqd_size = sizeof(struct drm_amdgpu_userq_mqd_gfx11); + } else if (queue->queue_type == AMDGPU_HW_IP_DMA) { + mqd_size = sizeof(struct drm_amdgpu_userq_mqd_sdma_gfx11); + } else { + drm_err_once(adev_to_drm(uq_mgr->adev), "Unrecognized queue type in USERQ_OP_LIST"); + ret = -EINVAL; + goto exit; + } + + + if (mqd_size > entries[i].mqd_size) { + entries[i].mqd_size = mqd_size; + entries[i].ip_type = queue->queue_type; + i += 1; + continue; + } + entries[i].mqd_size = mqd_size; + entries[i].ip_type = queue->queue_type; + + entries[i].queue_id = queue_id; + /* userq prop handling */ + entries[i].queue_va = queue->userq_prop->hqd_base_gpu_addr; + entries[i].queue_size = queue->userq_prop->queue_size; + entries[i].rptr_va = queue->userq_prop->rptr_gpu_addr; + entries[i].wptr_va = queue->userq_prop->wptr_gpu_addr; + /* flag handling (AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK are the only flags in use) */ + entries[i].flags = (queue->priority << AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT) + & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK; + /* doorbell handling */ + entries[i].doorbell_handle = queue->doorbell_handle; + /* This is the inverse of the calculation used in amdgpu_doorbell_index_on_bar + * doorbell_index = db_bo_offset / sizeof(u32) + * + doorbell_offset * DIV_ROUND_UP(db_size, 4) + * db_size is always sizeof(u64) = 8 + */ + entries[i].doorbell_offset = + (queue->doorbell_index - amdgpu_bo_gpu_offset_no_check(queue->db_obj.obj) / 4) / 2; + + if (queue->queue_type == AMDGPU_HW_IP_COMPUTE) { + struct drm_amdgpu_userq_mqd_compute_gfx11 compute_mqd = {0}; + + compute_mqd.eop_va = queue->userq_prop->eop_gpu_addr; + + ret = copy_to_user(u64_to_user_ptr(entries[i].mqd_data), + &compute_mqd, mqd_size); + } else if (queue->queue_type == AMDGPU_HW_IP_GFX) { + struct drm_amdgpu_userq_mqd_gfx11 mqd_gfx_v11 = {0}; + + mqd_gfx_v11.shadow_va = queue->userq_prop->shadow_addr; + mqd_gfx_v11.csa_va = queue->userq_prop->csa_addr; + + ret = copy_to_user(u64_to_user_ptr(entries[i].mqd_data), + &mqd_gfx_v11, mqd_size); + } else if (queue->queue_type == AMDGPU_HW_IP_DMA) { + struct drm_amdgpu_userq_mqd_sdma_gfx11 mqd_sdma_v11 = {0}; + + mqd_sdma_v11.csa_va = queue->userq_prop->csa_addr; + + ret = copy_to_user(u64_to_user_ptr(entries[i].mqd_data), + &mqd_sdma_v11, mqd_size); + } + if (ret) { + ret = -EFAULT; + goto exit; + } + i += 1; + } + ret = copy_to_user(u64_to_user_ptr(args->list_in_out.entries), entries, + entry_buffer_size); + if (ret) + ret = -EFAULT; +exit: + kvfree(entries); + return ret; +} + bool amdgpu_userq_enabled(struct drm_device *dev) { struct amdgpu_device *adev = drm_to_adev(dev); @@ -891,7 +1029,7 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, drm_file_err(filp, "Failed to create usermode queue\n"); break; - case AMDGPU_USERQ_OP_FREE: { + case AMDGPU_USERQ_OP_FREE: xa_lock(&fpriv->userq_mgr.userq_xa); queue = __xa_erase(&fpriv->userq_mgr.userq_xa, args->in.queue_id); xa_unlock(&fpriv->userq_mgr.userq_xa); @@ -900,8 +1038,9 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, amdgpu_userq_put(queue); break; - } - + case AMDGPU_USERQ_OP_LIST: + r = amdgpu_userq_list(filp, args); + break; default: drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op); return -EINVAL; diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index b32c72a662b6..92738d630eea 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -332,6 +332,7 @@ union drm_amdgpu_ctx { /* user queue IOCTL operations */ #define AMDGPU_USERQ_OP_CREATE 1 #define AMDGPU_USERQ_OP_FREE 2 +#define AMDGPU_USERQ_OP_LIST 3 /* queue priority levels */ /* low < normal low < normal high < high */ @@ -425,9 +426,48 @@ struct drm_amdgpu_userq_out { __u32 _pad; }; +struct drm_amdgpu_userq_list_entry { + /** Userspace pointer to buffer holding mqd */ + __u64 mqd_data; + /** + * In: Size of mqd_data user-allocated buffer. + * Out: If mqd_data was insufficiently large, the + * size it needs to be. + */ + __u32 mqd_size; + + /** Definitions same as drm_amdgpu_userq_in */ + __u32 queue_id; + __u32 ip_type; + __u32 doorbell_handle; + __u32 doorbell_offset; + __u32 flags; + __u64 queue_va; + __u64 queue_size; + __u64 rptr_va; + __u64 wptr_va; +}; + +struct drm_amdgpu_userq_list_in_out { + /** + * For operation AMDGPU_USERQ_OP_LIST: User will provide a buffer, which the + * driver will fill with information about all of that process's queues on this device. + */ + /** AMDGPU_USERQ_OP_LIST */ + __u32 op; + /** + * Size of entries buffer / Number of handles in process + * (if larger than size of buffer, must retry) + */ + __u32 num_entries; + /* User pointer to array of drm_amdgpu_userq_list_entry */ + __u64 entries; +}; + union drm_amdgpu_userq { struct drm_amdgpu_userq_in in; struct drm_amdgpu_userq_out out; + struct drm_amdgpu_userq_list_in_out list_in_out; }; /* GFX V11 IP specific MQD parameters */ -- 2.34.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/2] drm/amdgpu: Add LIST option to USERQ ioctl 2026-10-20 19:48 ` [PATCH v5 1/2] drm/amdgpu: Add LIST option to USERQ ioctl David Francis @ 2026-10-22 10:09 ` Tvrtko Ursulin 0 siblings, 0 replies; 5+ messages in thread From: Tvrtko Ursulin @ 2026-10-22 10:09 UTC (permalink / raw) To: David Francis, amd-gfx On 20/10/2026 20:48, David Francis wrote: > Add a new option to ioctl USERQ which provides information > to a process about their own user queues. > > The returned data is in the same format as that used to > create the queue in the first place. > > The interface uses retries; the user can guess at the number > of queues required; if insufficiently large, the correct > value will be returned. > The same is done for the mqd sizes of each entry. > > v3: Don't acquire xa_lock and other misc fixes > v4: Don't acquire mutex either and other misc fixes > v5: Small fixes; now with accompanying igt and criu changes LGTM! Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> Regards, Tvrtko > > Signed-off-by: David Francis <David.Francis@amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 145 +++++++++++++++++++++- > include/uapi/drm/amdgpu_drm.h | 40 ++++++ > 2 files changed, 182 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > index 3fe10d6af757..5aa53b2f4355 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > @@ -850,6 +850,8 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, > args->in.mqd_size) > return -EINVAL; > break; > + case AMDGPU_USERQ_OP_LIST: > + break; > default: > return -EINVAL; > } > @@ -857,6 +859,142 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, > return 0; > } > > +static int > +amdgpu_userq_list(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 drm_amdgpu_userq_list_entry *entries; > + struct amdgpu_usermode_queue *queue; > + size_t mqd_size, entry_buffer_size; > + uint32_t num_queues = 0; > + unsigned long queue_id; > + int i = 0; > + int ret; > + > + xa_for_each(&uq_mgr->userq_xa, queue_id, queue) > + num_queues += 1; > + > + /** > + * If the num_entries buffer is too small, return the correct size. > + * User should try again with the right space allocated. > + */ > + if (num_queues > args->list_in_out.num_entries) { > + args->list_in_out.num_entries = num_queues; > + return 0; > + } > + args->list_in_out.num_entries = num_queues; > + > + if (num_queues == 0) > + return 0; > + > + ret = check_mul_overflow(num_queues, sizeof(*entries), &entry_buffer_size); > + if (ret) > + return -E2BIG; > + > + entries = kvmalloc_objs(typeof(*entries), num_queues, GFP_KERNEL); > + if (!entries) > + return -ENOMEM; > + > + ret = copy_from_user(entries, u64_to_user_ptr(args->list_in_out.entries), > + entry_buffer_size); > + if (ret) { > + ret = -EFAULT; > + goto exit; > + } > + > + xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { > + /** > + * The xa may have added or removed queues since we counted > + * them, so break if there are now more queues than entries. > + */ > + if (i >= num_queues) > + break; > + /** > + * Check mqd size. As with num_entries, return the right sizes > + * if they are too small. These sizes also serve as > + * versioning for the mqd. Despite the names, these are the > + * mqd sizes for both gfx11 and gfx12. > + */ > + if (queue->queue_type == AMDGPU_HW_IP_COMPUTE) { > + mqd_size = sizeof(struct drm_amdgpu_userq_mqd_compute_gfx11); > + } else if (queue->queue_type == AMDGPU_HW_IP_GFX) { > + mqd_size = sizeof(struct drm_amdgpu_userq_mqd_gfx11); > + } else if (queue->queue_type == AMDGPU_HW_IP_DMA) { > + mqd_size = sizeof(struct drm_amdgpu_userq_mqd_sdma_gfx11); > + } else { > + drm_err_once(adev_to_drm(uq_mgr->adev), "Unrecognized queue type in USERQ_OP_LIST"); > + ret = -EINVAL; > + goto exit; > + } > + > + > + if (mqd_size > entries[i].mqd_size) { > + entries[i].mqd_size = mqd_size; > + entries[i].ip_type = queue->queue_type; > + i += 1; > + continue; > + } > + entries[i].mqd_size = mqd_size; > + entries[i].ip_type = queue->queue_type; > + > + entries[i].queue_id = queue_id; > + /* userq prop handling */ > + entries[i].queue_va = queue->userq_prop->hqd_base_gpu_addr; > + entries[i].queue_size = queue->userq_prop->queue_size; > + entries[i].rptr_va = queue->userq_prop->rptr_gpu_addr; > + entries[i].wptr_va = queue->userq_prop->wptr_gpu_addr; > + /* flag handling (AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK are the only flags in use) */ > + entries[i].flags = (queue->priority << AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT) > + & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK; > + /* doorbell handling */ > + entries[i].doorbell_handle = queue->doorbell_handle; > + /* This is the inverse of the calculation used in amdgpu_doorbell_index_on_bar > + * doorbell_index = db_bo_offset / sizeof(u32) > + * + doorbell_offset * DIV_ROUND_UP(db_size, 4) > + * db_size is always sizeof(u64) = 8 > + */ > + entries[i].doorbell_offset = > + (queue->doorbell_index - amdgpu_bo_gpu_offset_no_check(queue->db_obj.obj) / 4) / 2; > + > + if (queue->queue_type == AMDGPU_HW_IP_COMPUTE) { > + struct drm_amdgpu_userq_mqd_compute_gfx11 compute_mqd = {0}; > + > + compute_mqd.eop_va = queue->userq_prop->eop_gpu_addr; > + > + ret = copy_to_user(u64_to_user_ptr(entries[i].mqd_data), > + &compute_mqd, mqd_size); > + } else if (queue->queue_type == AMDGPU_HW_IP_GFX) { > + struct drm_amdgpu_userq_mqd_gfx11 mqd_gfx_v11 = {0}; > + > + mqd_gfx_v11.shadow_va = queue->userq_prop->shadow_addr; > + mqd_gfx_v11.csa_va = queue->userq_prop->csa_addr; > + > + ret = copy_to_user(u64_to_user_ptr(entries[i].mqd_data), > + &mqd_gfx_v11, mqd_size); > + } else if (queue->queue_type == AMDGPU_HW_IP_DMA) { > + struct drm_amdgpu_userq_mqd_sdma_gfx11 mqd_sdma_v11 = {0}; > + > + mqd_sdma_v11.csa_va = queue->userq_prop->csa_addr; > + > + ret = copy_to_user(u64_to_user_ptr(entries[i].mqd_data), > + &mqd_sdma_v11, mqd_size); > + } > + if (ret) { > + ret = -EFAULT; > + goto exit; > + } > + i += 1; > + } > + ret = copy_to_user(u64_to_user_ptr(args->list_in_out.entries), entries, > + entry_buffer_size); > + if (ret) > + ret = -EFAULT; > +exit: > + kvfree(entries); > + return ret; > +} > + > bool amdgpu_userq_enabled(struct drm_device *dev) > { > struct amdgpu_device *adev = drm_to_adev(dev); > @@ -891,7 +1029,7 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, > drm_file_err(filp, "Failed to create usermode queue\n"); > break; > > - case AMDGPU_USERQ_OP_FREE: { > + case AMDGPU_USERQ_OP_FREE: > xa_lock(&fpriv->userq_mgr.userq_xa); > queue = __xa_erase(&fpriv->userq_mgr.userq_xa, args->in.queue_id); > xa_unlock(&fpriv->userq_mgr.userq_xa); > @@ -900,8 +1038,9 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, > > amdgpu_userq_put(queue); > break; > - } > - > + case AMDGPU_USERQ_OP_LIST: > + r = amdgpu_userq_list(filp, args); > + break; > default: > drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op); > return -EINVAL; > diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h > index b32c72a662b6..92738d630eea 100644 > --- a/include/uapi/drm/amdgpu_drm.h > +++ b/include/uapi/drm/amdgpu_drm.h > @@ -332,6 +332,7 @@ union drm_amdgpu_ctx { > /* user queue IOCTL operations */ > #define AMDGPU_USERQ_OP_CREATE 1 > #define AMDGPU_USERQ_OP_FREE 2 > +#define AMDGPU_USERQ_OP_LIST 3 > > /* queue priority levels */ > /* low < normal low < normal high < high */ > @@ -425,9 +426,48 @@ struct drm_amdgpu_userq_out { > __u32 _pad; > }; > > +struct drm_amdgpu_userq_list_entry { > + /** Userspace pointer to buffer holding mqd */ > + __u64 mqd_data; > + /** > + * In: Size of mqd_data user-allocated buffer. > + * Out: If mqd_data was insufficiently large, the > + * size it needs to be. > + */ > + __u32 mqd_size; > + > + /** Definitions same as drm_amdgpu_userq_in */ > + __u32 queue_id; > + __u32 ip_type; > + __u32 doorbell_handle; > + __u32 doorbell_offset; > + __u32 flags; > + __u64 queue_va; > + __u64 queue_size; > + __u64 rptr_va; > + __u64 wptr_va; > +}; > + > +struct drm_amdgpu_userq_list_in_out { > + /** > + * For operation AMDGPU_USERQ_OP_LIST: User will provide a buffer, which the > + * driver will fill with information about all of that process's queues on this device. > + */ > + /** AMDGPU_USERQ_OP_LIST */ > + __u32 op; > + /** > + * Size of entries buffer / Number of handles in process > + * (if larger than size of buffer, must retry) > + */ > + __u32 num_entries; > + /* User pointer to array of drm_amdgpu_userq_list_entry */ > + __u64 entries; > +}; > + > union drm_amdgpu_userq { > struct drm_amdgpu_userq_in in; > struct drm_amdgpu_userq_out out; > + struct drm_amdgpu_userq_list_in_out list_in_out; > }; > > /* GFX V11 IP specific MQD parameters */ ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v5 2/2] drm/amdgpu: Add CHANGE_ID option for USERQ ioctl 2026-10-20 19:47 drm/amdgpu: v5 of LIST and CHANGE options for amdgpu userq David Francis 2026-10-20 19:48 ` [PATCH v5 1/2] drm/amdgpu: Add LIST option to USERQ ioctl David Francis @ 2026-10-20 19:48 ` David Francis 2026-10-22 10:11 ` Tvrtko Ursulin 1 sibling, 1 reply; 5+ messages in thread From: David Francis @ 2026-10-20 19:48 UTC (permalink / raw) To: amd-gfx; +Cc: Tvrtko.Ursulin, David Francis Add a new option to the USERQ ioctl, which is called with the queue_id of an existing user queue and an unused queue_id, and changes that queue's id to the new value. Calling with an invalid new handle will fail. Calling with new_handle = handle will succeed if that queue exists but not do anything. Performing this operation on a queue with signals or waits outstanding is fine, as those hold not the queue_id but a direct reference to the queue object. v3: Poison queue and misc fixes v4: Using xas interface v5: Now with accompanying igt and criu changes Signed-off-by: David Francis <David.Francis@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 46 +++++++++++++++++++++++ include/uapi/drm/amdgpu_drm.h | 17 +++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 5aa53b2f4355..1310004ec63f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -852,6 +852,11 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, break; case AMDGPU_USERQ_OP_LIST: break; + case AMDGPU_USERQ_OP_CHANGE_ID: + if (!args->change_in.new_queue_id || + args->change_in.new_queue_id > AMDGPU_MAX_USERQ_COUNT) + return -EINVAL; + break; default: return -EINVAL; } @@ -995,6 +1000,44 @@ amdgpu_userq_list(struct drm_file *filp, union drm_amdgpu_userq *args) return ret; } +static int amdgpu_userq_change_id(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; + XA_STATE(xas, &uq_mgr->userq_xa, args->change_in.new_queue_id); + struct amdgpu_usermode_queue *queue; + int ret; + + if (args->change_in.new_queue_id == args->change_in.queue_id) + return -EINVAL; + + do { + xas_lock(&xas); + + queue = xa_load(&uq_mgr->userq_xa, args->change_in.queue_id); + if (!queue) { + ret = -EINVAL; + goto unlock; + } + + if (xas_load(&xas)) { + ret = -EBUSY; + goto unlock; + } + + xas_store(&xas, queue); + ret = xas_error(&xas); + if (ret) + goto unlock; + + __xa_erase(&uq_mgr->userq_xa, args->change_in.queue_id); +unlock: + xas_unlock(&xas); + } while (xas_nomem(&xas, GFP_KERNEL)); + + return ret; +} + bool amdgpu_userq_enabled(struct drm_device *dev) { struct amdgpu_device *adev = drm_to_adev(dev); @@ -1041,6 +1084,9 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, case AMDGPU_USERQ_OP_LIST: r = amdgpu_userq_list(filp, args); break; + case AMDGPU_USERQ_OP_CHANGE_ID: + r = amdgpu_userq_change_id(filp, args); + break; default: drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op); return -EINVAL; diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 92738d630eea..37d0efd1eda4 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -330,9 +330,10 @@ union drm_amdgpu_ctx { }; /* user queue IOCTL operations */ -#define AMDGPU_USERQ_OP_CREATE 1 -#define AMDGPU_USERQ_OP_FREE 2 -#define AMDGPU_USERQ_OP_LIST 3 +#define AMDGPU_USERQ_OP_CREATE 1 +#define AMDGPU_USERQ_OP_FREE 2 +#define AMDGPU_USERQ_OP_LIST 3 +#define AMDGPU_USERQ_OP_CHANGE_ID 4 /* queue priority levels */ /* low < normal low < normal high < high */ @@ -464,10 +465,20 @@ struct drm_amdgpu_userq_list_in_out { __u64 entries; }; +struct drm_amdgpu_userq_change_id_in { + /** AMDGPU_USERQ_OP_CHANGE_ID */ + __u32 op; + /** Queue id of some queue */ + __u32 queue_id; + /** Queue id to change that queue to */ + __u32 new_queue_id; +}; + union drm_amdgpu_userq { struct drm_amdgpu_userq_in in; struct drm_amdgpu_userq_out out; struct drm_amdgpu_userq_list_in_out list_in_out; + struct drm_amdgpu_userq_change_id_in change_in; }; /* GFX V11 IP specific MQD parameters */ -- 2.34.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v5 2/2] drm/amdgpu: Add CHANGE_ID option for USERQ ioctl 2026-10-20 19:48 ` [PATCH v5 2/2] drm/amdgpu: Add CHANGE_ID option for " David Francis @ 2026-10-22 10:11 ` Tvrtko Ursulin 0 siblings, 0 replies; 5+ messages in thread From: Tvrtko Ursulin @ 2026-10-22 10:11 UTC (permalink / raw) To: David Francis, amd-gfx On 20/10/2026 20:48, David Francis wrote: > Add a new option to the USERQ ioctl, which is called with > the queue_id of an existing user queue and an unused queue_id, > and changes that queue's id to the new value. > > Calling with an invalid new handle will fail. Calling with new_handle > = handle will succeed if that queue exists but not do anything. > > Performing this operation on a queue with signals or waits > outstanding is fine, as those hold not the queue_id but a > direct reference to the queue object. > > v3: Poison queue and misc fixes > v4: Using xas interface > v5: Now with accompanying igt and criu changes LGTM as well. Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> Regards, Tvrtko > > Signed-off-by: David Francis <David.Francis@amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 46 +++++++++++++++++++++++ > include/uapi/drm/amdgpu_drm.h | 17 +++++++-- > 2 files changed, 60 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > index 5aa53b2f4355..1310004ec63f 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > @@ -852,6 +852,11 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, > break; > case AMDGPU_USERQ_OP_LIST: > break; > + case AMDGPU_USERQ_OP_CHANGE_ID: > + if (!args->change_in.new_queue_id || > + args->change_in.new_queue_id > AMDGPU_MAX_USERQ_COUNT) > + return -EINVAL; > + break; > default: > return -EINVAL; > } > @@ -995,6 +1000,44 @@ amdgpu_userq_list(struct drm_file *filp, union drm_amdgpu_userq *args) > return ret; > } > > +static int amdgpu_userq_change_id(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; > + XA_STATE(xas, &uq_mgr->userq_xa, args->change_in.new_queue_id); > + struct amdgpu_usermode_queue *queue; > + int ret; > + > + if (args->change_in.new_queue_id == args->change_in.queue_id) > + return -EINVAL; > + > + do { > + xas_lock(&xas); > + > + queue = xa_load(&uq_mgr->userq_xa, args->change_in.queue_id); > + if (!queue) { > + ret = -EINVAL; > + goto unlock; > + } > + > + if (xas_load(&xas)) { > + ret = -EBUSY; > + goto unlock; > + } > + > + xas_store(&xas, queue); > + ret = xas_error(&xas); > + if (ret) > + goto unlock; > + > + __xa_erase(&uq_mgr->userq_xa, args->change_in.queue_id); > +unlock: > + xas_unlock(&xas); > + } while (xas_nomem(&xas, GFP_KERNEL)); > + > + return ret; > +} > + > bool amdgpu_userq_enabled(struct drm_device *dev) > { > struct amdgpu_device *adev = drm_to_adev(dev); > @@ -1041,6 +1084,9 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, > case AMDGPU_USERQ_OP_LIST: > r = amdgpu_userq_list(filp, args); > break; > + case AMDGPU_USERQ_OP_CHANGE_ID: > + r = amdgpu_userq_change_id(filp, args); > + break; > default: > drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op); > return -EINVAL; > diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h > index 92738d630eea..37d0efd1eda4 100644 > --- a/include/uapi/drm/amdgpu_drm.h > +++ b/include/uapi/drm/amdgpu_drm.h > @@ -330,9 +330,10 @@ union drm_amdgpu_ctx { > }; > > /* user queue IOCTL operations */ > -#define AMDGPU_USERQ_OP_CREATE 1 > -#define AMDGPU_USERQ_OP_FREE 2 > -#define AMDGPU_USERQ_OP_LIST 3 > +#define AMDGPU_USERQ_OP_CREATE 1 > +#define AMDGPU_USERQ_OP_FREE 2 > +#define AMDGPU_USERQ_OP_LIST 3 > +#define AMDGPU_USERQ_OP_CHANGE_ID 4 > > /* queue priority levels */ > /* low < normal low < normal high < high */ > @@ -464,10 +465,20 @@ struct drm_amdgpu_userq_list_in_out { > __u64 entries; > }; > > +struct drm_amdgpu_userq_change_id_in { > + /** AMDGPU_USERQ_OP_CHANGE_ID */ > + __u32 op; > + /** Queue id of some queue */ > + __u32 queue_id; > + /** Queue id to change that queue to */ > + __u32 new_queue_id; > +}; > + > union drm_amdgpu_userq { > struct drm_amdgpu_userq_in in; > struct drm_amdgpu_userq_out out; > struct drm_amdgpu_userq_list_in_out list_in_out; > + struct drm_amdgpu_userq_change_id_in change_in; > }; > > /* GFX V11 IP specific MQD parameters */ ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-22 10:11 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-20 19:47 drm/amdgpu: v5 of LIST and CHANGE options for amdgpu userq David Francis 2026-10-20 19:48 ` [PATCH v5 1/2] drm/amdgpu: Add LIST option to USERQ ioctl David Francis 2026-10-22 10:09 ` Tvrtko Ursulin 2026-10-20 19:48 ` [PATCH v5 2/2] drm/amdgpu: Add CHANGE_ID option for " David Francis 2026-10-22 10:11 ` Tvrtko Ursulin
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.