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.

Signed-off-by: Alex Deucher <alexander.deuc...@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 52 +++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index e56fae10400db..95e1495d9a24c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -561,6 +561,51 @@ 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;
+       }
+
+       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 +656,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;
-- 
2.49.0

Reply via email to