summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2019-05-31 23:50:50 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2019-05-31 23:50:50 +0000
commit826cc98932bd8908186fc8574c3c3f31129d2b80 (patch)
treeacedcbc44c5d013131caeadbadf30b8182de6ece /sys/dev
parent596e35ebc93e210f086d49bf2c533a1746b2b35a (diff)
drm/amdgpu: fix old fence check in amdgpu_fence_emit
From Christian Koenig d8a36f8418034bacef0b5b73c0822f41646d77ba in linux 4.19.y/4.19.47 3d2aca8c8620346abdba96c6300d2c0b90a1d0cc in mainline linux
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/drm/amd/amdgpu/amdgpu_fence.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/sys/dev/pci/drm/amd/amdgpu/amdgpu_fence.c b/sys/dev/pci/drm/amd/amdgpu/amdgpu_fence.c
index fcb4dfacd26..9234e9d8b1e 100644
--- a/sys/dev/pci/drm/amd/amdgpu/amdgpu_fence.c
+++ b/sys/dev/pci/drm/amd/amdgpu/amdgpu_fence.c
@@ -145,8 +145,9 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f,
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_fence *fence;
- struct dma_fence *old, **ptr;
+ struct dma_fence __rcu **ptr;
uint32_t seq;
+ int r;
#ifdef __linux__
fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL);
@@ -166,15 +167,24 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f,
seq, flags | AMDGPU_FENCE_FLAG_INT);
ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
+ if (unlikely(rcu_dereference_protected(*ptr, 1))) {
+ struct dma_fence *old;
+
+ rcu_read_lock();
+ old = dma_fence_get_rcu_safe(ptr);
+ rcu_read_unlock();
+
+ if (old) {
+ r = dma_fence_wait(old, false);
+ dma_fence_put(old);
+ if (r)
+ return r;
+ }
+ }
+
/* This function can't be called concurrently anyway, otherwise
* emitting the fence would mess up the hardware ring buffer.
*/
- old = rcu_dereference_protected(*ptr, 1);
- if (old && !dma_fence_is_signaled(old)) {
- DRM_INFO("rcu slot is busy\n");
- dma_fence_wait(old, false);
- }
-
rcu_assign_pointer(*ptr, dma_fence_get(&fence->base));
*f = &fence->base;