@@ -244,7 +244,10 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
goto out;
for (i = 0; i < shared_count; ++i) {
- struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
+ struct dma_fence *fence;
+
+ fence = reservation_object_shared_fence(
+ rcu_dereference(fobj->shared[i]));
if (!dma_fence_get_rcu(fence)) {
/*
@@ -1062,7 +1065,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
fence->ops->get_timeline_name(fence),
dma_fence_is_signaled(fence) ? "" : "un");
for (i = 0; i < shared_count; i++) {
- fence = rcu_dereference(fobj->shared[i]);
+ fence = reservation_object_shared_fence(
+ rcu_dereference(fobj->shared[i]));
if (!dma_fence_get_rcu(fence))
continue;
seq_printf(s, "\tShared fence: %s %s %ssignalled\n",
@@ -93,14 +93,14 @@ int reservation_object_reserve_shared(struct reservation_object *obj)
* the new.
*/
for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
- struct dma_fence *fence;
+ void *e;
- fence = rcu_dereference_protected(old->shared[i],
- reservation_object_held(obj));
- if (dma_fence_is_signaled(fence))
- RCU_INIT_POINTER(new->shared[--k], fence);
+ e = rcu_dereference_protected(old->shared[i],
+ reservation_object_held(obj));
+ if (dma_fence_is_signaled(reservation_object_shared_fence(e)))
+ RCU_INIT_POINTER(new->shared[--k], e);
else
- RCU_INIT_POINTER(new->shared[j++], fence);
+ RCU_INIT_POINTER(new->shared[j++], e);
}
new->shared_count = j;
new->shared_max = max;
@@ -120,11 +120,11 @@ int reservation_object_reserve_shared(struct reservation_object *obj)
/* Drop the references to the signaled fences */
for (i = k; i < new->shared_max; ++i) {
- struct dma_fence *fence;
+ void *e;
- fence = rcu_dereference_protected(new->shared[i],
- reservation_object_held(obj));
- dma_fence_put(fence);
+ e = rcu_dereference_protected(new->shared[i],
+ reservation_object_held(obj));
+ dma_fence_put(reservation_object_shared_fence(e));
}
kfree_rcu(old, rcu);
@@ -141,7 +141,8 @@ EXPORT_SYMBOL(reservation_object_reserve_shared);
* reservation_object_reserve_shared() has been called.
*/
void reservation_object_add_shared_fence(struct reservation_object *obj,
- struct dma_fence *fence)
+ struct dma_fence *fence,
+ bool is_write)
{
struct reservation_object_list *fobj;
unsigned int i;
@@ -155,13 +156,17 @@ void reservation_object_add_shared_fence(struct reservation_object *obj,
for (i = 0; i < fobj->shared_count; ++i) {
struct dma_fence *old_fence;
+ void *e;
- old_fence = rcu_dereference_protected(fobj->shared[i],
- reservation_object_held(obj));
- if (old_fence->context == fence->context ||
+ e = rcu_dereference_protected(fobj->shared[i],
+ reservation_object_held(obj));
+ old_fence = reservation_object_shared_fence(e);
+ if ((old_fence->context == fence->context &&
+ reservation_object_shared_is_write(e) == is_write) ||
dma_fence_is_signaled(old_fence)) {
/* memory barrier is added by write_seqcount_begin */
- RCU_INIT_POINTER(fobj->shared[i], fence);
+ RCU_INIT_POINTER(fobj->shared[i],
+ (void *)(is_write | (long)fence));
write_seqcount_end(&obj->seq);
preempt_enable();
dma_fence_put(old_fence);
@@ -173,7 +178,8 @@ void reservation_object_add_shared_fence(struct reservation_object *obj,
* memory barrier is added by write_seqcount_begin,
* fobj->shared_count is protected by this lock too
*/
- RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
+ RCU_INIT_POINTER(fobj->shared[fobj->shared_count],
+ (void *)(is_write | (long)fence));
fobj->shared_count++;
write_seqcount_end(&obj->seq);
@@ -213,8 +219,7 @@ void reservation_object_add_excl_fence(struct reservation_object *obj,
/* inplace update, no shared fences */
while (i--)
- dma_fence_put(rcu_dereference_protected(old->shared[i],
- reservation_object_held(obj)));
+ dma_fence_put(reservation_object_get_shared_fence(obj, old, i));
dma_fence_put(old_fence);
}
@@ -260,8 +265,10 @@ int reservation_object_copy_fences(struct reservation_object *dst,
dst_list->shared_max = shared_count;
for (i = 0; i < src_list->shared_count; ++i) {
struct dma_fence *fence;
+ void *e;
- fence = rcu_dereference(src_list->shared[i]);
+ e = rcu_dereference(src_list->shared[i]);
+ fence = reservation_object_shared_fence(e);
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&fence->flags))
continue;
@@ -277,7 +284,7 @@ int reservation_object_copy_fences(struct reservation_object *dst,
continue;
}
- rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence);
+ rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], e);
}
} else {
dst_list = NULL;
@@ -368,7 +375,9 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
shared = nshared;
shared_count = fobj ? fobj->shared_count : 0;
for (i = 0; i < shared_count; ++i) {
- shared[i] = rcu_dereference(fobj->shared[i]);
+ void *e = rcu_dereference(fobj->shared[i]);
+
+ shared[i] = reservation_object_shared_fence(e);
if (!dma_fence_get_rcu(shared[i]))
break;
}
@@ -456,8 +465,10 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
shared_count = fobj->shared_count;
for (i = 0; !fence && i < shared_count; ++i) {
- struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
+ void *e = rcu_dereference(fobj->shared[i]);
+ struct dma_fence *lfence;
+ lfence = reservation_object_shared_fence(e);
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&lfence->flags))
continue;
@@ -545,8 +556,10 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
shared_count = fobj->shared_count;
for (i = 0; i < shared_count; ++i) {
- struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
+ void *e = rcu_dereference(fobj->shared[i]);
+ struct dma_fence *fence;
+ fence = reservation_object_shared_fence(e);
ret = reservation_object_test_signaled_single(fence);
if (ret < 0)
goto retry;
@@ -1342,7 +1342,7 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
struct reservation_object *resv = bo->tbo.resv;
if (shared)
- reservation_object_add_shared_fence(resv, fence);
+ reservation_object_add_shared_fence(resv, fence, true);
else
reservation_object_add_excl_fence(resv, fence);
}
@@ -214,7 +214,8 @@ static void submit_attach_object_fences(struct etnaviv_gem_submit *submit)
submit->out_fence);
else
reservation_object_add_shared_fence(etnaviv_obj->resv,
- submit->out_fence);
+ submit->out_fence,
+ false);
submit_unlock_object(submit, i);
}
@@ -4552,8 +4552,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
unsigned int shared_count = list->shared_count, i;
for (i = 0; i < shared_count; ++i) {
- struct dma_fence *fence =
- rcu_dereference(list->shared[i]);
+ struct dma_fence *fence;
+
+ fence = reservation_object_shared_fence(
+ rcu_dereference(list->shared[i]));
args->busy |= busy_check_reader(fence);
}
@@ -1771,7 +1771,7 @@ static void eb_export_fence(struct i915_vma *vma,
if (flags & EXEC_OBJECT_WRITE)
reservation_object_add_excl_fence(resv, &rq->fence);
else if (reservation_object_reserve_shared(resv) == 0)
- reservation_object_add_shared_fence(resv, &rq->fence);
+ reservation_object_add_shared_fence(resv, &rq->fence, false);
reservation_object_unlock(resv);
}
@@ -672,7 +672,8 @@ void msm_gem_move_to_active(struct drm_gem_object *obj,
if (exclusive)
reservation_object_add_excl_fence(msm_obj->resv, fence);
else
- reservation_object_add_shared_fence(msm_obj->resv, fence);
+ reservation_object_add_shared_fence(msm_obj->resv, fence,
+ false);
list_del_init(&msm_obj->mm_list);
list_add_tail(&msm_obj->mm_list, &gpu->active_list);
}
@@ -1657,7 +1657,7 @@ nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool excl
if (exclusive)
reservation_object_add_excl_fence(resv, &fence->base);
else if (fence)
- reservation_object_add_shared_fence(resv, &fence->base);
+ reservation_object_add_shared_fence(resv, &fence->base, false);
}
struct ttm_bo_driver nouveau_bo_driver = {
@@ -466,7 +466,8 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release)
bo = entry->bo;
qbo = to_qxl_bo(bo);
- reservation_object_add_shared_fence(bo->resv, &release->base);
+ reservation_object_add_shared_fence(bo->resv, &release->base,
+ false);
ttm_bo_add_to_lru(bo);
reservation_object_unlock(bo->resv);
}
@@ -870,7 +870,7 @@ void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
struct reservation_object *resv = bo->tbo.resv;
if (shared)
- reservation_object_add_shared_fence(resv, &fence->base);
+ reservation_object_add_shared_fence(resv, &fence->base, false);
else
reservation_object_add_excl_fence(resv, &fence->base);
}
@@ -794,7 +794,7 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
spin_unlock(&man->move_lock);
if (fence) {
- reservation_object_add_shared_fence(bo->resv, fence);
+ reservation_object_add_shared_fence(bo->resv, fence, true);
ret = reservation_object_reserve_shared(bo->resv);
if (unlikely(ret))
@@ -202,7 +202,8 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
list_for_each_entry(entry, list, head) {
bo = entry->bo;
if (entry->shared)
- reservation_object_add_shared_fence(bo->resv, fence);
+ reservation_object_add_shared_fence(bo->resv, fence,
+ true);
else
reservation_object_add_excl_fence(bo->resv, fence);
ttm_bo_add_to_lru(bo);
@@ -536,7 +536,8 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
bo = to_vc4_bo(&exec->bo[i]->base);
bo->seqno = seqno;
- reservation_object_add_shared_fence(bo->resv, exec->fence);
+ reservation_object_add_shared_fence(bo->resv, exec->fence,
+ false);
}
list_for_each_entry(bo, &exec->unref_list, unref_head) {
@@ -194,7 +194,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
if (arg->flags & VGEM_FENCE_WRITE)
reservation_object_add_excl_fence(resv, fence);
else if ((ret = reservation_object_reserve_shared(resv)) == 0)
- reservation_object_add_shared_fence(resv, fence);
+ reservation_object_add_shared_fence(resv, fence, false);
reservation_object_unlock(resv);
/* Record the fence in our idr for later signaling */
@@ -59,7 +59,7 @@ extern const char reservation_seqcount_string[];
struct reservation_object_list {
struct rcu_head rcu;
u32 shared_count, shared_max;
- struct dma_fence __rcu *shared[];
+ void * __rcu *shared[];
};
/**
@@ -80,6 +80,8 @@ struct reservation_object {
#define reservation_object_held(obj) lockdep_is_held(&(obj)->lock.base)
#define reservation_object_assert_held(obj) \
lockdep_assert_held(&(obj)->lock.base)
+#define reservation_object_shared_fence(e) ((struct dma_fence *)((long)e & ~1ul))
+#define reservation_object_shared_is_write(e) ((long)e & 1)
/**
* reservation_object_init - initialize a reservation object
@@ -116,8 +118,11 @@ reservation_object_fini(struct reservation_object *obj)
fobj = rcu_dereference_protected(obj->fence, 1);
if (fobj) {
- for (i = 0; i < fobj->shared_count; ++i)
- dma_fence_put(rcu_dereference_protected(fobj->shared[i], 1));
+ for (i = 0; i < fobj->shared_count; ++i) {
+ void *e = rcu_dereference_protected(fobj->shared[i], 1);
+
+ dma_fence_put(reservation_object_shared_fence(e));
+ }
kfree(fobj);
}
@@ -155,8 +160,10 @@ reservation_object_get_shared_fence(struct reservation_object *obj,
struct reservation_object_list *list,
unsigned int idx)
{
- return rcu_dereference_protected(list->shared[idx],
- reservation_object_held(obj));
+ void *e = rcu_dereference_protected(list->shared[idx],
+ reservation_object_held(obj));
+
+ return reservation_object_shared_fence(e);
}
/**
@@ -282,7 +289,8 @@ reservation_object_get_excl_rcu(struct reservation_object *obj)
int reservation_object_reserve_shared(struct reservation_object *obj);
void reservation_object_add_shared_fence(struct reservation_object *obj,
- struct dma_fence *fence);
+ struct dma_fence *fence,
+ bool as_write);
void reservation_object_add_excl_fence(struct reservation_object *obj,
struct dma_fence *fence);
Note if the added fence is a write by using the lsb in the fenc pointer. Signed-off-by: Christian König <christian.koenig@amd.com> --- drivers/dma-buf/dma-buf.c | 8 +++- drivers/dma-buf/reservation.c | 59 +++++++++++++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 3 +- drivers/gpu/drm/i915/i915_gem.c | 6 ++- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/msm/msm_gem.c | 3 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- drivers/gpu/drm/qxl/qxl_release.c | 3 +- drivers/gpu/drm/radeon/radeon_object.c | 2 +- drivers/gpu/drm/ttm/ttm_bo.c | 2 +- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 3 +- drivers/gpu/drm/vc4/vc4_gem.c | 3 +- drivers/gpu/drm/vgem/vgem_fence.c | 2 +- include/linux/reservation.h | 20 +++++++--- 15 files changed, 76 insertions(+), 44 deletions(-)