]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
drm/amdgpu: fix old fence check in amdgpu_fence_emit
authorChristian König <christian.koenig@amd.com>
Fri, 29 Mar 2019 18:30:23 +0000 (19:30 +0100)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 14 Aug 2019 09:18:49 +0000 (11:18 +0200)
BugLink: https://bugs.launchpad.net/bugs/1838700
[ Upstream commit 3d2aca8c8620346abdba96c6300d2c0b90a1d0cc ]

We don't hold a reference to the old fence, so it can go away
any time we are waiting for it to signal.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Chunming Zhou <david1.zhou@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c

index 2fa95aef74d5200449c94a0215f04be60e8cb184..b4bea3e7b1a4e7403e1514b4e5eb0a831f69b2c9 100644 (file)
@@ -135,8 +135,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;
 
        fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL);
        if (fence == NULL)
@@ -152,15 +153,24 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f)
                               seq, 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;