When a hung user queue triggers a reset, its context becomes corrupted
and must not be replayed. Mark both the queue and its owning process as
guilty so that user space is notified that the offending queue is no
longer usable and must recreate the context before resubmitting work.

Signed-off-by: Prike Liang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c   |  4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 48 +++++++++++++++++++++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h |  5 ++-
 3 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index b15ed4a534f1..1094057d2e1d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -589,7 +589,9 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev,
        if (ctx->generation != amdgpu_vm_generation(adev, &fpriv->vm))
                out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST;
 
-       if (amdgpu_ctx_guilty(ctx))
+       if (amdgpu_ctx_guilty(ctx) ||
+           ((out->state.flags & AMDGPU_CTX_QUERY2_FLAGS_RESET) &&
+            READ_ONCE(fpriv->userq_mgr.guilty)))
                out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY;
 
        if (amdgpu_in_reset(adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 6c92575213c1..6bd8867a6eae 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -126,6 +126,7 @@ static void amdgpu_userq_hang_detect_work(struct 
work_struct *work)
                adev->userq_funcs[queue->queue_type];
        struct drm_wedge_task_info *info = NULL;
        struct amdgpu_task_info *ti = NULL;
+       unsigned long flags;
        bool gpu_reset = false;
 
        if (unlikely(adev->debug_disable_gpu_ring_reset)) {
@@ -148,6 +149,11 @@ static void amdgpu_userq_hang_detect_work(struct 
work_struct *work)
                }
        }
 
+       xa_lock_irqsave(&adev->userq_doorbell_xa, flags);
+       WRITE_ONCE(queue->guilty, true);
+       WRITE_ONCE(uq_mgr->guilty, true);
+       xa_unlock_irqrestore(&adev->userq_doorbell_xa, flags);
+
        if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type,
                                                 AMDGPU_RESET_TYPE_PER_QUEUE)) {
                int r;
@@ -174,7 +180,7 @@ static void amdgpu_userq_hang_detect_work(struct 
work_struct *work)
         * handler to another is illegal if you don't take extra precautions!
         */
        if (gpu_reset)
-               amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
+               amdgpu_userq_mgr_reset_work(&uq_mgr->reset_work);
 }
 
 /*
@@ -338,6 +344,10 @@ static int amdgpu_userq_restore_helper(struct 
amdgpu_usermode_queue *queue)
                adev->userq_funcs[queue->queue_type];
        int r = 0;
 
+       if (READ_ONCE(queue->guilty) ||
+           queue->generation != amdgpu_vm_generation(adev, queue->vm))
+               return 0;
+
        if (queue->state == AMDGPU_USERQ_STATE_PREEMPTED) {
                trace_amdgpu_userq_state_start(queue);
 
@@ -388,9 +398,12 @@ static int amdgpu_userq_map_helper(struct 
amdgpu_usermode_queue *queue)
                adev->userq_funcs[queue->queue_type];
        int r;
 
+       if (READ_ONCE(queue->guilty) ||
+           queue->generation != amdgpu_vm_generation(adev, queue->vm))
+               return 0;
+
        if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
                trace_amdgpu_userq_state_start(queue);
-
                r = userq_funcs->map(queue);
                if (r) {
                        trace_amdgpu_userq_state_changed(queue, 
AMDGPU_USERQ_STATE_HUNG);
@@ -630,6 +643,27 @@ static int amdgpu_userq_priority_permit(struct drm_file 
*filp,
        return -EACCES;
 }
 
+static void amdgpu_userq_mgr_clear_guilty(struct amdgpu_userq_mgr *uq_mgr)
+{
+       struct xarray *xa = &uq_mgr->adev->userq_doorbell_xa;
+       struct amdgpu_usermode_queue *queue;
+       unsigned long flags, queue_id;
+
+       xa_lock_irqsave(xa, flags);
+       if (!READ_ONCE(uq_mgr->guilty))
+               goto unlock;
+
+       xa_for_each(xa, queue_id, queue) {
+               if (queue->userq_mgr == uq_mgr && READ_ONCE(queue->guilty))
+                       goto unlock;
+       }
+
+       WRITE_ONCE(uq_mgr->guilty, false);
+
+unlock:
+       xa_unlock_irqrestore(xa, flags);
+}
+
 static int
 amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
 {
@@ -789,6 +823,7 @@ amdgpu_userq_create(struct drm_file *filp, union 
drm_amdgpu_userq *args)
                return r;
        }
 
+       amdgpu_userq_mgr_clear_guilty(uq_mgr);
        amdgpu_debugfs_userq_init(filp, queue, qid);
        trace_amdgpu_userq_create_end(queue, 0);
        args->out.queue_id = qid;
@@ -831,7 +866,8 @@ amdgpu_userq_query_status(struct drm_file *filp, union 
drm_amdgpu_userq *args)
        }
 
        args->out_qs.flags = 0;
-       if (queue->state == AMDGPU_USERQ_STATE_HUNG)
+       if (queue->state == AMDGPU_USERQ_STATE_HUNG ||
+           READ_ONCE(queue->guilty))
                args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_HUNG;
        if (queue->generation != amdgpu_vm_generation(adev, &fpriv->vm))
                args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_VRAMLOST;
@@ -1594,7 +1630,11 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, 
bool vram_lost)
        int ret = 0, r;
 
        xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
-               if (queue->state == AMDGPU_USERQ_STATE_HUNG && !vram_lost) {
+               if (vram_lost || READ_ONCE(queue->guilty) ||
+                   queue->generation != amdgpu_vm_generation(adev, queue->vm))
+                       continue;
+
+               if (queue->state == AMDGPU_USERQ_STATE_HUNG) {
                        trace_amdgpu_userq_state_start(queue);
 
                        userq_funcs = adev->userq_funcs[queue->queue_type];
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
index 40228c60a1ea..f2eca744a3c5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
@@ -51,6 +51,8 @@ struct amdgpu_userq_obj {
 struct amdgpu_usermode_queue {
        int                     queue_type;
        enum amdgpu_userq_state state;
+       /* Reset due to a hang; must not be re-mapped, userspace recreates. */
+       bool                    guilty;
        uint64_t                doorbell_handle;
        uint64_t                doorbell_index;
        u32                     doorbell_offset;
@@ -132,7 +134,8 @@ struct amdgpu_userq_mgr {
        struct drm_file                 *file;
        struct mutex                    proc_ctx_lock;
        struct amdgpu_userq_obj         proc_ctx_obj;
-
+       /* Set when any queue owned by this process is reset guilty */
+       bool                            guilty;
        bool                            proc_ctx_allocated;
        uint32_t                        proc_ctx_array_index;
        /**
-- 
2.34.1

Reply via email to