amdgpu_ring_set_fence_errors_and_reemit() and
amdgpu_ring_backup_unprocessed_commands() masked last_seq and sync_seq to
fence-array indices before the loop, then walked a do/while until the two
indices met. When hardware completed every command before the driver
signalled the fences, last_seq == sync_seq, but the masked-index do/while
could not tell that empty interval from a full table and walked the whole
fence array, backing up and replaying already-completed commands.

Read the raw sequence numbers, return early through amdgpu_fence_process()
when they are equal, and mask only at the array index. Guard the
force-completion against a NULL guilty_fence so a non-guilty backup does
not dereference it.

Signed-off-by: Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 24 +++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index 6537e8845fb6..3017ddcefbe2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -724,8 +724,14 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct 
amdgpu_ring *ring,
        bool is_guilty_fence;
        bool is_guilty_context;
 
-       last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask;
-       seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask;
+       last_seq = amdgpu_fence_read(ring);
+       seq = ring->fence_drv.sync_seq;
+
+       /* Hardware completion can precede the interrupt which signals fences. 
*/
+       if (last_seq == seq) {
+               amdgpu_fence_process(ring);
+               return;
+       }
 
        /* If there is nothing to reemit, return early and set an error on the 
fence
         * if applicable. If all of the fences are siganlled, this will be a 
nop.
@@ -743,9 +749,8 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct 
amdgpu_ring *ring,
        spin_lock_irqsave(&ring->fence_drv.lock, flags);
        do {
                last_seq++;
-               last_seq &= ring->fence_drv.num_fences_mask;
 
-               ptr = &ring->fence_drv.fences[last_seq];
+               ptr = &ring->fence_drv.fences[last_seq & 
ring->fence_drv.num_fences_mask];
                rcu_read_lock();
                unprocessed = rcu_dereference(*ptr);
 
@@ -802,8 +807,8 @@ void amdgpu_ring_backup_unprocessed_commands(struct 
amdgpu_ring *ring,
        struct amdgpu_fence *fence;
        u32 seq, last_seq;
 
-       last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask;
-       seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask;
+       last_seq = amdgpu_fence_read(ring);
+       seq = ring->fence_drv.sync_seq;
        ring->ring_backup_entries_to_copy = 0;
 
        /*
@@ -816,11 +821,10 @@ void amdgpu_ring_backup_unprocessed_commands(struct 
amdgpu_ring *ring,
        }
        ring->guilty_fence = guilty_fence;
 
-       do {
+       while (last_seq != seq) {
                last_seq++;
-               last_seq &= ring->fence_drv.num_fences_mask;
 
-               ptr = &ring->fence_drv.fences[last_seq];
+               ptr = &ring->fence_drv.fences[last_seq & 
ring->fence_drv.num_fences_mask];
                rcu_read_lock();
                unprocessed = rcu_dereference(*ptr);
 
@@ -830,7 +834,7 @@ void amdgpu_ring_backup_unprocessed_commands(struct 
amdgpu_ring *ring,
                        amdgpu_ring_backup_unprocessed_command(ring, fence);
                }
                rcu_read_unlock();
-       } while (last_seq != seq);
+       }
 }
 
 struct amdgpu_fence *
-- 
2.49.0

Reply via email to