]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amdgpu: adjust MES API used for suspend and resume
authorJesse.Zhang <Jesse.Zhang@amd.com>
Thu, 4 Sep 2025 08:30:08 +0000 (16:30 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 15 Sep 2025 21:02:28 +0000 (17:02 -0400)
Use the suspend and resume API rather than remove queue
and add queue API.  The former just preempts the queue
while the latter remove it from the scheduler completely.
There is no need to do that, we only need preemption
in this case.

V2: replace queue_active with queue state
v3: set the suspend_fence_addr
v4: allocate another per queue buffer for the suspend fence, and  set the sequence number.
    also wait for the suspend fence. (Alex)
v5: use a wb slot (Alex)
v6: Change the timeout period. For MES, the default timeout  is  2100000; /* 2100 ms */ (Alex)

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Jesse Zhang <Jesse.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/mes_userqueue.c

index 3a4fd6de08ce7d63fb22744a1070aae811ad4ce4..2db9b2c63693db7c9584f365bca2e2d15b8a6acc 100644 (file)
@@ -404,10 +404,82 @@ mes_userq_mqd_destroy(struct amdgpu_userq_mgr *uq_mgr,
        amdgpu_userq_destroy_object(uq_mgr, &queue->mqd);
 }
 
+static int mes_userq_preempt(struct amdgpu_userq_mgr *uq_mgr,
+                               struct amdgpu_usermode_queue *queue)
+{
+       struct amdgpu_device *adev = uq_mgr->adev;
+       struct mes_suspend_gang_input queue_input;
+       struct amdgpu_userq_obj *ctx = &queue->fw_obj;
+       signed long timeout = 2100000; /* 2100 ms */
+       u64 fence_gpu_addr;
+       u32 fence_offset;
+       u64 *fence_ptr;
+       int i, r;
+
+       if (queue->state != AMDGPU_USERQ_STATE_MAPPED)
+               return 0;
+       r = amdgpu_device_wb_get(adev, &fence_offset);
+       if (r)
+               return r;
+
+       fence_gpu_addr = adev->wb.gpu_addr + (fence_offset * 4);
+       fence_ptr = (u64 *)&adev->wb.wb[fence_offset];
+       *fence_ptr = 0;
+
+       memset(&queue_input, 0x0, sizeof(struct mes_suspend_gang_input));
+       queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ;
+       queue_input.suspend_fence_addr = fence_gpu_addr;
+       queue_input.suspend_fence_value = 1;
+       amdgpu_mes_lock(&adev->mes);
+       r = adev->mes.funcs->suspend_gang(&adev->mes, &queue_input);
+       amdgpu_mes_unlock(&adev->mes);
+       if (r) {
+               DRM_ERROR("Failed to suspend gang: %d\n", r);
+               goto out;
+       }
+
+       for (i = 0; i < timeout; i++) {
+               if (*fence_ptr == 1)
+                       goto out;
+               udelay(1);
+       }
+       r = -ETIMEDOUT;
+
+out:
+       amdgpu_device_wb_free(adev, fence_offset);
+       return r;
+}
+
+static int mes_userq_restore(struct amdgpu_userq_mgr *uq_mgr,
+                               struct amdgpu_usermode_queue *queue)
+{
+       struct amdgpu_device *adev = uq_mgr->adev;
+       struct mes_resume_gang_input queue_input;
+       struct amdgpu_userq_obj *ctx = &queue->fw_obj;
+       int r;
+
+       if (queue->state == AMDGPU_USERQ_STATE_HUNG)
+               return -EINVAL;
+       if (queue->state != AMDGPU_USERQ_STATE_PREEMPTED)
+               return 0;
+
+       memset(&queue_input, 0x0, sizeof(struct mes_resume_gang_input));
+       queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ;
+
+       amdgpu_mes_lock(&adev->mes);
+       r = adev->mes.funcs->resume_gang(&adev->mes, &queue_input);
+       amdgpu_mes_unlock(&adev->mes);
+       if (r)
+               dev_err(adev->dev, "Failed to resume queue, err (%d)\n", r);
+       return r;
+}
+
 const struct amdgpu_userq_funcs userq_mes_funcs = {
        .mqd_create = mes_userq_mqd_create,
        .mqd_destroy = mes_userq_mqd_destroy,
        .unmap = mes_userq_unmap,
        .map = mes_userq_map,
        .detect_and_reset = mes_userq_detect_and_reset,
+       .preempt = mes_userq_preempt,
+       .restore = mes_userq_restore,
 };