[PATCH 8/8] drm/amdgpu/userq: enable support for creating gangs
Alex Deucher
alexander.deucher at amd.com
Mon Apr 28 21:20:50 UTC 2025
Gangs are sets of userqs that schedule together. You
specify the primary and secondary queues and the scheduler
will make sure they always run at the same time.
v2: handle setting up the gang again after unmaps
Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 95 +++++++++++++++++++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 2 +
2 files changed, 97 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index e56fae10400db..e42b8cd78884c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -92,19 +92,39 @@ amdgpu_userq_unmap_helper(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_device *adev = uq_mgr->adev;
const struct amdgpu_userq_funcs *userq_funcs =
adev->userq_funcs[queue->queue_type];
+ struct amdgpu_usermode_queue *secondary_queue = NULL;
bool gpu_reset = false;
int r = 0;
+ if (queue->gang_primary)
+ secondary_queue = queue->gang_secondary;
+
if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
r = userq_funcs->unmap(uq_mgr, queue);
if (r) {
queue->state = AMDGPU_USERQ_STATE_HUNG;
gpu_reset = amdgpu_userq_queue_reset_helper(uq_mgr, queue);
+ if (gpu_reset)
+ goto reset;
} else {
queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
}
}
+ if (secondary_queue) {
+ if (secondary_queue->state == AMDGPU_USERQ_STATE_MAPPED) {
+ r = userq_funcs->unmap(uq_mgr, secondary_queue);
+ if (r) {
+ secondary_queue->state = AMDGPU_USERQ_STATE_HUNG;
+ gpu_reset = amdgpu_userq_queue_reset_helper(uq_mgr, secondary_queue);
+ if (gpu_reset)
+ goto reset;
+ } else {
+ secondary_queue->state = AMDGPU_USERQ_STATE_MAPPED;
+ }
+ }
+ }
+reset:
if (gpu_reset)
amdgpu_userq_gpu_reset(adev);
@@ -118,19 +138,40 @@ amdgpu_userq_map_helper(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_device *adev = uq_mgr->adev;
const struct amdgpu_userq_funcs *userq_funcs =
adev->userq_funcs[queue->queue_type];
+ struct amdgpu_usermode_queue *secondary_queue = NULL;
bool gpu_reset = false;
int r = 0;
+ if (queue->gang_primary)
+ secondary_queue = queue->gang_secondary;
+
if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
r = userq_funcs->map(uq_mgr, queue);
if (r) {
queue->state = AMDGPU_USERQ_STATE_HUNG;
gpu_reset = amdgpu_userq_queue_reset_helper(uq_mgr, queue);
+ if (gpu_reset)
+ goto reset;
} else {
queue->state = AMDGPU_USERQ_STATE_MAPPED;
}
}
+ if (secondary_queue) {
+ if (secondary_queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
+ r = userq_funcs->map(uq_mgr, secondary_queue);
+ if (r) {
+ secondary_queue->state = AMDGPU_USERQ_STATE_HUNG;
+ gpu_reset = amdgpu_userq_queue_reset_helper(uq_mgr, secondary_queue);
+ if (gpu_reset)
+ goto reset;
+ } else {
+ secondary_queue->state = AMDGPU_USERQ_STATE_MAPPED;
+ }
+ }
+ r = userq_funcs->set_gang(uq_mgr, queue, secondary_queue);
+ }
+reset:
if (gpu_reset)
amdgpu_userq_gpu_reset(adev);
@@ -561,6 +602,53 @@ amdgpu_userq_query_status(struct drm_file *filp, union drm_amdgpu_userq *args)
return 0;
}
+static int
+amdgpu_userq_create_gang(struct drm_file *filp, union drm_amdgpu_userq *args)
+{
+ struct amdgpu_usermode_queue *primary_queue, *secondary_queue;
+ struct amdgpu_fpriv *fpriv = filp->driver_priv;
+ struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
+ const struct amdgpu_userq_funcs *userq_funcs;
+ struct amdgpu_device *adev = uq_mgr->adev;
+ int primary_queue_id = args->in_cg.primary_queue_id;
+ int secondary_queue_id = args->in_cg.secondary_queue_id;
+ int r;
+
+ mutex_lock(&uq_mgr->userq_mutex);
+ primary_queue = amdgpu_userq_find(uq_mgr, primary_queue_id);
+ if (!primary_queue) {
+ dev_err(adev->dev, "Invalid gang primary queue id\n");
+ mutex_unlock(&uq_mgr->userq_mutex);
+ return -EINVAL;
+ }
+ if ((primary_queue->queue_type != AMDGPU_HW_IP_GFX) &&
+ (primary_queue->queue_type != AMDGPU_HW_IP_COMPUTE)) {
+ dev_err(adev->dev, "Invalid gang primary queue type\n");
+ mutex_unlock(&uq_mgr->userq_mutex);
+ return -EINVAL;
+ }
+ secondary_queue = amdgpu_userq_find(uq_mgr, secondary_queue_id);
+ if (!secondary_queue) {
+ dev_err(adev->dev, "Invalid gang secondary queue id\n");
+ mutex_unlock(&uq_mgr->userq_mutex);
+ return -EINVAL;
+ }
+ if ((secondary_queue->queue_type != AMDGPU_HW_IP_GFX) &&
+ (secondary_queue->queue_type != AMDGPU_HW_IP_COMPUTE)) {
+ dev_err(adev->dev, "Invalid gang secondary queue type\n");
+ mutex_unlock(&uq_mgr->userq_mutex);
+ return -EINVAL;
+ }
+
+ primary_queue->gang_primary = true;
+ primary_queue->gang_secondary = secondary_queue;
+ userq_funcs = adev->userq_funcs[primary_queue->queue_type];
+ r = userq_funcs->set_gang(uq_mgr, primary_queue, secondary_queue);
+ mutex_unlock(&uq_mgr->userq_mutex);
+
+ return r;
+}
+
int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
@@ -611,6 +699,13 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
if (r)
DRM_ERROR("Failed to query usermode queue status\n");
break;
+ case AMDGPU_USERQ_OP_CREATE_GANG:
+ if (args->in_cg.pad)
+ return -EINVAL;
+ r = amdgpu_userq_create_gang(filp, args);
+ if (r)
+ DRM_ERROR("Failed to create usermode queue gang\n");
+ break;
default:
DRM_DEBUG_DRIVER("Invalid user queue op specified: %d\n", args->in.op);
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
index ca11f7748d031..40510b4d824b8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
@@ -66,6 +66,8 @@ struct amdgpu_usermode_queue {
u32 xcp_id;
int priority;
uint64_t generation;
+ bool gang_primary;
+ struct amdgpu_usermode_queue *gang_secondary;
};
struct amdgpu_userq_funcs {
--
2.49.0
More information about the amd-gfx
mailing list