forked from mirrors/linux
		
	dma-buf: add reservation_object_fences helper
Add a new helper to get a consistent set of pointers from the reservation object. While at it group all access helpers together in the header file. v2: correctly return shared_count as well Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/322378/?series=64837&rev=1
This commit is contained in:
		
							parent
							
								
									0e2f733add
								
							
						
					
					
						commit
						67c97fb79a
					
				
					 3 changed files with 101 additions and 127 deletions
				
			
		| 
						 | 
				
			
			@ -199,7 +199,7 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
 | 
			
		|||
	struct reservation_object_list *fobj;
 | 
			
		||||
	struct dma_fence *fence_excl;
 | 
			
		||||
	__poll_t events;
 | 
			
		||||
	unsigned shared_count, seq;
 | 
			
		||||
	unsigned shared_count;
 | 
			
		||||
 | 
			
		||||
	dmabuf = file->private_data;
 | 
			
		||||
	if (!dmabuf || !dmabuf->resv)
 | 
			
		||||
| 
						 | 
				
			
			@ -213,21 +213,8 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
 | 
			
		|||
	if (!events)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
retry:
 | 
			
		||||
	seq = read_seqcount_begin(&resv->seq);
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
 | 
			
		||||
	fobj = rcu_dereference(resv->fence);
 | 
			
		||||
	if (fobj)
 | 
			
		||||
		shared_count = fobj->shared_count;
 | 
			
		||||
	else
 | 
			
		||||
		shared_count = 0;
 | 
			
		||||
	fence_excl = rcu_dereference(resv->fence_excl);
 | 
			
		||||
	if (read_seqcount_retry(&resv->seq, seq)) {
 | 
			
		||||
		rcu_read_unlock();
 | 
			
		||||
		goto retry;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reservation_object_fences(resv, &fence_excl, &fobj, &shared_count);
 | 
			
		||||
	if (fence_excl && (!(events & EPOLLOUT) || shared_count == 0)) {
 | 
			
		||||
		struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl;
 | 
			
		||||
		__poll_t pevents = EPOLLIN;
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,7 +1144,6 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
 | 
			
		|||
	struct reservation_object *robj;
 | 
			
		||||
	struct reservation_object_list *fobj;
 | 
			
		||||
	struct dma_fence *fence;
 | 
			
		||||
	unsigned seq;
 | 
			
		||||
	int count = 0, attach_count, shared_count, i;
 | 
			
		||||
	size_t size = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1188,16 +1174,9 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
 | 
			
		|||
				buf_obj->name ?: "");
 | 
			
		||||
 | 
			
		||||
		robj = buf_obj->resv;
 | 
			
		||||
		while (true) {
 | 
			
		||||
			seq = read_seqcount_begin(&robj->seq);
 | 
			
		||||
		rcu_read_lock();
 | 
			
		||||
			fobj = rcu_dereference(robj->fence);
 | 
			
		||||
			shared_count = fobj ? fobj->shared_count : 0;
 | 
			
		||||
			fence = rcu_dereference(robj->fence_excl);
 | 
			
		||||
			if (!read_seqcount_retry(&robj->seq, seq))
 | 
			
		||||
				break;
 | 
			
		||||
		reservation_object_fences(robj, &fence, &fobj, &shared_count);
 | 
			
		||||
		rcu_read_unlock();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (fence)
 | 
			
		||||
			seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -317,17 +317,15 @@ int reservation_object_copy_fences(struct reservation_object *dst,
 | 
			
		|||
{
 | 
			
		||||
	struct reservation_object_list *src_list, *dst_list;
 | 
			
		||||
	struct dma_fence *old, *new;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	unsigned int i, shared_count;
 | 
			
		||||
 | 
			
		||||
	reservation_object_assert_held(dst);
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	src_list = rcu_dereference(src->fence);
 | 
			
		||||
 | 
			
		||||
retry:
 | 
			
		||||
	if (src_list) {
 | 
			
		||||
		unsigned shared_count = src_list->shared_count;
 | 
			
		||||
 | 
			
		||||
	reservation_object_fences(src, &new, &src_list, &shared_count);
 | 
			
		||||
	if (shared_count) {
 | 
			
		||||
		rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
		dst_list = reservation_object_list_alloc(shared_count);
 | 
			
		||||
| 
						 | 
				
			
			@ -335,14 +333,14 @@ int reservation_object_copy_fences(struct reservation_object *dst,
 | 
			
		|||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		rcu_read_lock();
 | 
			
		||||
		src_list = rcu_dereference(src->fence);
 | 
			
		||||
		if (!src_list || src_list->shared_count > shared_count) {
 | 
			
		||||
		reservation_object_fences(src, &new, &src_list, &shared_count);
 | 
			
		||||
		if (!src_list || shared_count > dst_list->shared_max) {
 | 
			
		||||
			kfree(dst_list);
 | 
			
		||||
			goto retry;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dst_list->shared_count = 0;
 | 
			
		||||
		for (i = 0; i < src_list->shared_count; ++i) {
 | 
			
		||||
		for (i = 0; i < shared_count; ++i) {
 | 
			
		||||
			struct dma_fence *fence;
 | 
			
		||||
 | 
			
		||||
			fence = rcu_dereference(src_list->shared[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +350,6 @@ int reservation_object_copy_fences(struct reservation_object *dst,
 | 
			
		|||
 | 
			
		||||
			if (!dma_fence_get_rcu(fence)) {
 | 
			
		||||
				reservation_object_list_free(dst_list);
 | 
			
		||||
				src_list = rcu_dereference(src->fence);
 | 
			
		||||
				goto retry;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -367,7 +364,10 @@ int reservation_object_copy_fences(struct reservation_object *dst,
 | 
			
		|||
		dst_list = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	new = dma_fence_get_rcu_safe(&src->fence_excl);
 | 
			
		||||
	if (new && !dma_fence_get_rcu(new)) {
 | 
			
		||||
		reservation_object_list_free(dst_list);
 | 
			
		||||
		goto retry;
 | 
			
		||||
	}
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
	src_list = reservation_object_get_list(dst);
 | 
			
		||||
| 
						 | 
				
			
			@ -413,19 +413,18 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 | 
			
		|||
 | 
			
		||||
	do {
 | 
			
		||||
		struct reservation_object_list *fobj;
 | 
			
		||||
		unsigned int i, seq;
 | 
			
		||||
		unsigned int i;
 | 
			
		||||
		size_t sz = 0;
 | 
			
		||||
 | 
			
		||||
		shared_count = i = 0;
 | 
			
		||||
		i = 0;
 | 
			
		||||
 | 
			
		||||
		rcu_read_lock();
 | 
			
		||||
		seq = read_seqcount_begin(&obj->seq);
 | 
			
		||||
		reservation_object_fences(obj, &fence_excl, &fobj,
 | 
			
		||||
					  &shared_count);
 | 
			
		||||
 | 
			
		||||
		fence_excl = rcu_dereference(obj->fence_excl);
 | 
			
		||||
		if (fence_excl && !dma_fence_get_rcu(fence_excl))
 | 
			
		||||
			goto unlock;
 | 
			
		||||
 | 
			
		||||
		fobj = rcu_dereference(obj->fence);
 | 
			
		||||
		if (fobj)
 | 
			
		||||
			sz += sizeof(*shared) * fobj->shared_max;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -453,7 +452,6 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 | 
			
		|||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			shared = nshared;
 | 
			
		||||
			shared_count = fobj ? fobj->shared_count : 0;
 | 
			
		||||
			for (i = 0; i < shared_count; ++i) {
 | 
			
		||||
				shared[i] = rcu_dereference(fobj->shared[i]);
 | 
			
		||||
				if (!dma_fence_get_rcu(shared[i]))
 | 
			
		||||
| 
						 | 
				
			
			@ -461,7 +459,7 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
 | 
			
		||||
		if (i != shared_count) {
 | 
			
		||||
			while (i--)
 | 
			
		||||
				dma_fence_put(shared[i]);
 | 
			
		||||
			dma_fence_put(fence_excl);
 | 
			
		||||
| 
						 | 
				
			
			@ -505,18 +503,17 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
 | 
			
		|||
					 bool wait_all, bool intr,
 | 
			
		||||
					 unsigned long timeout)
 | 
			
		||||
{
 | 
			
		||||
	struct reservation_object_list *fobj;
 | 
			
		||||
	struct dma_fence *fence;
 | 
			
		||||
	unsigned seq, shared_count;
 | 
			
		||||
	unsigned shared_count;
 | 
			
		||||
	long ret = timeout ? timeout : 1;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
retry:
 | 
			
		||||
	shared_count = 0;
 | 
			
		||||
	seq = read_seqcount_begin(&obj->seq);
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	i = -1;
 | 
			
		||||
 | 
			
		||||
	fence = rcu_dereference(obj->fence_excl);
 | 
			
		||||
	reservation_object_fences(obj, &fence, &fobj, &shared_count);
 | 
			
		||||
	if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
 | 
			
		||||
		if (!dma_fence_get_rcu(fence))
 | 
			
		||||
			goto unlock_retry;
 | 
			
		||||
| 
						 | 
				
			
			@ -531,12 +528,6 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (wait_all) {
 | 
			
		||||
		struct reservation_object_list *fobj =
 | 
			
		||||
						rcu_dereference(obj->fence);
 | 
			
		||||
 | 
			
		||||
		if (fobj)
 | 
			
		||||
			shared_count = fobj->shared_count;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; !fence && i < shared_count; ++i) {
 | 
			
		||||
			struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -559,11 +550,6 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
 | 
			
		|||
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	if (fence) {
 | 
			
		||||
		if (read_seqcount_retry(&obj->seq, seq)) {
 | 
			
		||||
			dma_fence_put(fence);
 | 
			
		||||
			goto retry;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = dma_fence_wait_timeout(fence, intr, ret);
 | 
			
		||||
		dma_fence_put(fence);
 | 
			
		||||
		if (ret > 0 && wait_all && (i + 1 < shared_count))
 | 
			
		||||
| 
						 | 
				
			
			@ -608,24 +594,19 @@ reservation_object_test_signaled_single(struct dma_fence *passed_fence)
 | 
			
		|||
bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
 | 
			
		||||
					  bool test_all)
 | 
			
		||||
{
 | 
			
		||||
	unsigned seq, shared_count;
 | 
			
		||||
	struct reservation_object_list *fobj;
 | 
			
		||||
	struct dma_fence *fence_excl;
 | 
			
		||||
	unsigned shared_count;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
retry:
 | 
			
		||||
	ret = true;
 | 
			
		||||
	shared_count = 0;
 | 
			
		||||
	seq = read_seqcount_begin(&obj->seq);
 | 
			
		||||
 | 
			
		||||
	reservation_object_fences(obj, &fence_excl, &fobj, &shared_count);
 | 
			
		||||
	if (test_all) {
 | 
			
		||||
		unsigned i;
 | 
			
		||||
 | 
			
		||||
		struct reservation_object_list *fobj =
 | 
			
		||||
						rcu_dereference(obj->fence);
 | 
			
		||||
 | 
			
		||||
		if (fobj)
 | 
			
		||||
			shared_count = fobj->shared_count;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < shared_count; ++i) {
 | 
			
		||||
			struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -635,23 +616,12 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
 | 
			
		|||
			else if (!ret)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (read_seqcount_retry(&obj->seq, seq))
 | 
			
		||||
			goto retry;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!shared_count) {
 | 
			
		||||
		struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
 | 
			
		||||
 | 
			
		||||
		if (fence_excl) {
 | 
			
		||||
			ret = reservation_object_test_signaled_single(
 | 
			
		||||
								fence_excl);
 | 
			
		||||
	if (!shared_count && fence_excl) {
 | 
			
		||||
		ret = reservation_object_test_signaled_single(fence_excl);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			goto retry;
 | 
			
		||||
 | 
			
		||||
			if (read_seqcount_retry(&obj->seq, seq))
 | 
			
		||||
				goto retry;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,6 +81,25 @@ struct reservation_object {
 | 
			
		|||
#define reservation_object_assert_held(obj) \
 | 
			
		||||
	lockdep_assert_held(&(obj)->lock.base)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * reservation_object_get_excl - get the reservation object's
 | 
			
		||||
 * exclusive fence, with update-side lock held
 | 
			
		||||
 * @obj: the reservation object
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the exclusive fence (if any).  Does NOT take a
 | 
			
		||||
 * reference. Writers must hold obj->lock, readers may only
 | 
			
		||||
 * hold a RCU read side lock.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS
 | 
			
		||||
 * The exclusive fence or NULL
 | 
			
		||||
 */
 | 
			
		||||
static inline struct dma_fence *
 | 
			
		||||
reservation_object_get_excl(struct reservation_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	return rcu_dereference_protected(obj->fence_excl,
 | 
			
		||||
					 reservation_object_held(obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * reservation_object_get_list - get the reservation object's
 | 
			
		||||
 * shared fence list, with update-side lock held
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +115,57 @@ reservation_object_get_list(struct reservation_object *obj)
 | 
			
		|||
					 reservation_object_held(obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * reservation_object_fences - read consistent fence pointers
 | 
			
		||||
 * @obj: reservation object where we get the fences from
 | 
			
		||||
 * @excl: pointer for the exclusive fence
 | 
			
		||||
 * @list: pointer for the shared fence list
 | 
			
		||||
 *
 | 
			
		||||
 * Make sure we have a consisten exclusive fence and shared fence list.
 | 
			
		||||
 * Must be called with rcu read side lock held.
 | 
			
		||||
 */
 | 
			
		||||
static inline void
 | 
			
		||||
reservation_object_fences(struct reservation_object *obj,
 | 
			
		||||
			  struct dma_fence **excl,
 | 
			
		||||
			  struct reservation_object_list **list,
 | 
			
		||||
			  u32 *shared_count)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int seq;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		seq = read_seqcount_begin(&obj->seq);
 | 
			
		||||
		*excl = rcu_dereference(obj->fence_excl);
 | 
			
		||||
		*list = rcu_dereference(obj->fence);
 | 
			
		||||
		*shared_count = *list ? (*list)->shared_count : 0;
 | 
			
		||||
	} while (read_seqcount_retry(&obj->seq, seq));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * reservation_object_get_excl_rcu - get the reservation object's
 | 
			
		||||
 * exclusive fence, without lock held.
 | 
			
		||||
 * @obj: the reservation object
 | 
			
		||||
 *
 | 
			
		||||
 * If there is an exclusive fence, this atomically increments it's
 | 
			
		||||
 * reference count and returns it.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS
 | 
			
		||||
 * The exclusive fence or NULL if none
 | 
			
		||||
 */
 | 
			
		||||
static inline struct dma_fence *
 | 
			
		||||
reservation_object_get_excl_rcu(struct reservation_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	struct dma_fence *fence;
 | 
			
		||||
 | 
			
		||||
	if (!rcu_access_pointer(obj->fence_excl))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	fence = dma_fence_get_rcu_safe(&obj->fence_excl);
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
	return fence;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * reservation_object_lock - lock the reservation object
 | 
			
		||||
 * @obj: the reservation object
 | 
			
		||||
| 
						 | 
				
			
			@ -239,51 +309,6 @@ reservation_object_unlock(struct reservation_object *obj)
 | 
			
		|||
	ww_mutex_unlock(&obj->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * reservation_object_get_excl - get the reservation object's
 | 
			
		||||
 * exclusive fence, with update-side lock held
 | 
			
		||||
 * @obj: the reservation object
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the exclusive fence (if any).  Does NOT take a
 | 
			
		||||
 * reference. Writers must hold obj->lock, readers may only
 | 
			
		||||
 * hold a RCU read side lock.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS
 | 
			
		||||
 * The exclusive fence or NULL
 | 
			
		||||
 */
 | 
			
		||||
static inline struct dma_fence *
 | 
			
		||||
reservation_object_get_excl(struct reservation_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	return rcu_dereference_protected(obj->fence_excl,
 | 
			
		||||
					 reservation_object_held(obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * reservation_object_get_excl_rcu - get the reservation object's
 | 
			
		||||
 * exclusive fence, without lock held.
 | 
			
		||||
 * @obj: the reservation object
 | 
			
		||||
 *
 | 
			
		||||
 * If there is an exclusive fence, this atomically increments it's
 | 
			
		||||
 * reference count and returns it.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS
 | 
			
		||||
 * The exclusive fence or NULL if none
 | 
			
		||||
 */
 | 
			
		||||
static inline struct dma_fence *
 | 
			
		||||
reservation_object_get_excl_rcu(struct reservation_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	struct dma_fence *fence;
 | 
			
		||||
 | 
			
		||||
	if (!rcu_access_pointer(obj->fence_excl))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	fence = dma_fence_get_rcu_safe(&obj->fence_excl);
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
	return fence;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void reservation_object_init(struct reservation_object *obj);
 | 
			
		||||
void reservation_object_fini(struct reservation_object *obj);
 | 
			
		||||
int reservation_object_reserve_shared(struct reservation_object *obj,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue