summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index ea69b1bac7c6..3043ad041bb4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -727,6 +727,15 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct amdgpu_ring *ring,
last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask;
seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask;
+ /* 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.
+ * if there are still fences and ring_backup_entries_to_copy is 0, then
+ * we are skipping it on purpose.
+ */
+ if (!ring->ring_backup_entries_to_copy) {
+ amdgpu_fence_driver_force_completion(ring, &guilty_fence->base);
+ return;
+ }
ring->reemit = true;
amdgpu_ring_alloc(ring, ring->ring_backup_entries_to_copy);
spin_lock_irqsave(&ring->fence_drv.lock, flags);
@@ -741,7 +750,8 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct amdgpu_ring *ring,
if (unprocessed && !dma_fence_is_signaled_locked(unprocessed)) {
fence = container_of(unprocessed, struct amdgpu_fence, base);
is_guilty_fence = fence == guilty_fence;
- is_guilty_context = fence->context == guilty_fence->context;
+ is_guilty_context = guilty_fence ?
+ (fence->context == guilty_fence->context) : false;
/* mark all fences from the guilty context with an error */
if (is_guilty_fence)
@@ -794,6 +804,17 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring,
seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask;
ring->ring_backup_entries_to_copy = 0;
+ /* if we've already seen this fence, return early.
+ * ring->ring_backup_entries_to_copy is set to 0 so
+ * the reemit helper will return early as well to
+ * avoid getting stuck in a reemit loop.
+ */
+ if (ring->guilty_fence == guilty_fence) {
+ ring->guilty_fence = NULL;
+ return;
+ }
+ ring->guilty_fence = guilty_fence;
+
do {
last_seq++;
last_seq &= ring->fence_drv.num_fences_mask;
@@ -811,6 +832,36 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring,
} while (last_seq != seq);
}
+struct amdgpu_fence *
+amdgpu_ring_find_guilty_fence(struct amdgpu_ring *ring)
+{
+ struct dma_fence *unprocessed;
+ struct dma_fence __rcu **ptr;
+ 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;
+
+ do {
+ last_seq++;
+ last_seq &= ring->fence_drv.num_fences_mask;
+
+ ptr = &ring->fence_drv.fences[last_seq];
+ rcu_read_lock();
+ unprocessed = rcu_dereference(*ptr);
+
+ if (unprocessed && !dma_fence_is_signaled(unprocessed)) {
+ fence = container_of(unprocessed, struct amdgpu_fence, base);
+ rcu_read_unlock();
+ return fence;
+ }
+ rcu_read_unlock();
+ } while (last_seq != seq);
+
+ return NULL;
+}
+
/*
* Common fence implementation
*/