A hung user queue must not be replayed after reset because its context
may be corrupted. so Skip guilty queues and queues whose VM generation
has changed when mapping or restoring them.

Signed-off-by: Prike Liang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 19 +++++++++++++++++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h |  2 ++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 6c4743ddf04a..cc212226fb48 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -148,6 +148,8 @@ static void amdgpu_userq_hang_detect_work(struct 
work_struct *work)
                }
        }
 
+       WRITE_ONCE(queue->guilty, true);
+
        if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type,
                                                 AMDGPU_RESET_TYPE_PER_QUEUE)) {
                int r;
@@ -174,7 +176,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 +340,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,6 +394,10 @@ 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);
 
@@ -833,6 +843,7 @@ 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 ||
            queue->state == AMDGPU_USERQ_STATE_INVALID_VA ||
+           READ_ONCE(queue->guilty) ||
            queue->generation != amdgpu_vm_generation(adev, &fpriv->vm))
                args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_BROKEN;
        if (amdgpu_in_reset(adev))
@@ -1598,7 +1609,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 d1a2e2a45861..69d6ad4e6b11 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;
-- 
2.34.1

Reply via email to