xref: /dflybsd-src/sys/dev/drm/linux_reservation.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
13306aed3SFrançois Tigeot /*
23306aed3SFrançois Tigeot  * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst)
33306aed3SFrançois Tigeot  *
43306aed3SFrançois Tigeot  * Based on bo.c which bears the following copyright notice,
53306aed3SFrançois Tigeot  * but is dual licensed:
63306aed3SFrançois Tigeot  *
73306aed3SFrançois Tigeot  * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
83306aed3SFrançois Tigeot  * All Rights Reserved.
93306aed3SFrançois Tigeot  *
103306aed3SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
113306aed3SFrançois Tigeot  * copy of this software and associated documentation files (the
123306aed3SFrançois Tigeot  * "Software"), to deal in the Software without restriction, including
133306aed3SFrançois Tigeot  * without limitation the rights to use, copy, modify, merge, publish,
143306aed3SFrançois Tigeot  * distribute, sub license, and/or sell copies of the Software, and to
153306aed3SFrançois Tigeot  * permit persons to whom the Software is furnished to do so, subject to
163306aed3SFrançois Tigeot  * the following conditions:
173306aed3SFrançois Tigeot  *
183306aed3SFrançois Tigeot  * The above copyright notice and this permission notice (including the
193306aed3SFrançois Tigeot  * next paragraph) shall be included in all copies or substantial portions
203306aed3SFrançois Tigeot  * of the Software.
213306aed3SFrançois Tigeot  *
223306aed3SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
233306aed3SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
243306aed3SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
253306aed3SFrançois Tigeot  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
263306aed3SFrançois Tigeot  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
273306aed3SFrançois Tigeot  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
283306aed3SFrançois Tigeot  * USE OR OTHER DEALINGS IN THE SOFTWARE.
293306aed3SFrançois Tigeot  *
303306aed3SFrançois Tigeot  **************************************************************************/
313306aed3SFrançois Tigeot /*
323306aed3SFrançois Tigeot  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
333306aed3SFrançois Tigeot  */
343306aed3SFrançois Tigeot 
353306aed3SFrançois Tigeot #include <linux/reservation.h>
363306aed3SFrançois Tigeot #include <linux/export.h>
373306aed3SFrançois Tigeot 
383306aed3SFrançois Tigeot /**
393306aed3SFrançois Tigeot  * DOC: Reservation Object Overview
403306aed3SFrançois Tigeot  *
413306aed3SFrançois Tigeot  * The reservation object provides a mechanism to manage shared and
423306aed3SFrançois Tigeot  * exclusive fences associated with a buffer.  A reservation object
433306aed3SFrançois Tigeot  * can have attached one exclusive fence (normally associated with
443306aed3SFrançois Tigeot  * write operations) or N shared fences (read operations).  The RCU
453306aed3SFrançois Tigeot  * mechanism is used to protect read access to fences from locked
463306aed3SFrançois Tigeot  * write-side updates.
473306aed3SFrançois Tigeot  */
483306aed3SFrançois Tigeot 
493306aed3SFrançois Tigeot DEFINE_WW_CLASS(reservation_ww_class);
503306aed3SFrançois Tigeot EXPORT_SYMBOL(reservation_ww_class);
513306aed3SFrançois Tigeot 
523306aed3SFrançois Tigeot struct lock_class_key reservation_seqcount_class;
533306aed3SFrançois Tigeot EXPORT_SYMBOL(reservation_seqcount_class);
543306aed3SFrançois Tigeot 
553306aed3SFrançois Tigeot const char reservation_seqcount_string[] = "reservation_seqcount";
563306aed3SFrançois Tigeot EXPORT_SYMBOL(reservation_seqcount_string);
579a12856eSFrançois Tigeot 
589a12856eSFrançois Tigeot /**
599a12856eSFrançois Tigeot  * reservation_object_reserve_shared - Reserve space to add a shared
609a12856eSFrançois Tigeot  * fence to a reservation_object.
619a12856eSFrançois Tigeot  * @obj: reservation object
629a12856eSFrançois Tigeot  *
639a12856eSFrançois Tigeot  * Should be called before reservation_object_add_shared_fence().  Must
649a12856eSFrançois Tigeot  * be called with obj->lock held.
659a12856eSFrançois Tigeot  *
669a12856eSFrançois Tigeot  * RETURNS
679a12856eSFrançois Tigeot  * Zero for success, or -errno
689a12856eSFrançois Tigeot  */
reservation_object_reserve_shared(struct reservation_object * obj)699a12856eSFrançois Tigeot int reservation_object_reserve_shared(struct reservation_object *obj)
709a12856eSFrançois Tigeot {
719a12856eSFrançois Tigeot 	struct reservation_object_list *fobj, *old;
729a12856eSFrançois Tigeot 	u32 max;
739a12856eSFrançois Tigeot 
749a12856eSFrançois Tigeot 	old = reservation_object_get_list(obj);
759a12856eSFrançois Tigeot 
769a12856eSFrançois Tigeot 	if (old && old->shared_max) {
779a12856eSFrançois Tigeot 		if (old->shared_count < old->shared_max) {
789a12856eSFrançois Tigeot 			/* perform an in-place update */
799a12856eSFrançois Tigeot 			kfree(obj->staged);
809a12856eSFrançois Tigeot 			obj->staged = NULL;
819a12856eSFrançois Tigeot 			return 0;
829a12856eSFrançois Tigeot 		} else
839a12856eSFrançois Tigeot 			max = old->shared_max * 2;
849a12856eSFrançois Tigeot 	} else
859a12856eSFrançois Tigeot 		max = 4;
869a12856eSFrançois Tigeot 
879a12856eSFrançois Tigeot 	/*
889a12856eSFrançois Tigeot 	 * resize obj->staged or allocate if it doesn't exist,
899a12856eSFrançois Tigeot 	 * noop if already correct size
909a12856eSFrançois Tigeot 	 */
919a12856eSFrançois Tigeot 	fobj = krealloc(obj->staged, offsetof(typeof(*fobj), shared[max]),
926559babbSFrançois Tigeot 			M_DRM, GFP_KERNEL);
939a12856eSFrançois Tigeot 	if (!fobj)
949a12856eSFrançois Tigeot 		return -ENOMEM;
959a12856eSFrançois Tigeot 
969a12856eSFrançois Tigeot 	obj->staged = fobj;
979a12856eSFrançois Tigeot 	fobj->shared_max = max;
989a12856eSFrançois Tigeot 	return 0;
999a12856eSFrançois Tigeot }
1009a12856eSFrançois Tigeot EXPORT_SYMBOL(reservation_object_reserve_shared);
1019a12856eSFrançois Tigeot 
1029a12856eSFrançois Tigeot static void
reservation_object_add_shared_inplace(struct reservation_object * obj,struct reservation_object_list * fobj,struct dma_fence * fence)1039a12856eSFrançois Tigeot reservation_object_add_shared_inplace(struct reservation_object *obj,
1049a12856eSFrançois Tigeot 				      struct reservation_object_list *fobj,
1056559babbSFrançois Tigeot 				      struct dma_fence *fence)
1069a12856eSFrançois Tigeot {
1079a12856eSFrançois Tigeot 	u32 i;
1089a12856eSFrançois Tigeot 
1096559babbSFrançois Tigeot 	dma_fence_get(fence);
1109a12856eSFrançois Tigeot 
1119a12856eSFrançois Tigeot 	preempt_disable();
1129a12856eSFrançois Tigeot 	write_seqcount_begin(&obj->seq);
1139a12856eSFrançois Tigeot 
1149a12856eSFrançois Tigeot 	for (i = 0; i < fobj->shared_count; ++i) {
1156559babbSFrançois Tigeot 		struct dma_fence *old_fence;
1169a12856eSFrançois Tigeot 
1179a12856eSFrançois Tigeot 		old_fence = rcu_dereference_protected(fobj->shared[i],
1189a12856eSFrançois Tigeot 						reservation_object_held(obj));
1199a12856eSFrançois Tigeot 
1209a12856eSFrançois Tigeot 		if (old_fence->context == fence->context) {
1219a12856eSFrançois Tigeot 			/* memory barrier is added by write_seqcount_begin */
1229a12856eSFrançois Tigeot 			RCU_INIT_POINTER(fobj->shared[i], fence);
1239a12856eSFrançois Tigeot 			write_seqcount_end(&obj->seq);
1249a12856eSFrançois Tigeot 			preempt_enable();
1259a12856eSFrançois Tigeot 
1266559babbSFrançois Tigeot 			dma_fence_put(old_fence);
1279a12856eSFrançois Tigeot 			return;
1289a12856eSFrançois Tigeot 		}
1299a12856eSFrançois Tigeot 	}
1309a12856eSFrançois Tigeot 
1319a12856eSFrançois Tigeot 	/*
1329a12856eSFrançois Tigeot 	 * memory barrier is added by write_seqcount_begin,
1339a12856eSFrançois Tigeot 	 * fobj->shared_count is protected by this lock too
1349a12856eSFrançois Tigeot 	 */
1359a12856eSFrançois Tigeot 	RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
1369a12856eSFrançois Tigeot 	fobj->shared_count++;
1379a12856eSFrançois Tigeot 
1389a12856eSFrançois Tigeot 	write_seqcount_end(&obj->seq);
1399a12856eSFrançois Tigeot 	preempt_enable();
1409a12856eSFrançois Tigeot }
1419a12856eSFrançois Tigeot 
1429a12856eSFrançois Tigeot static void
reservation_object_add_shared_replace(struct reservation_object * obj,struct reservation_object_list * old,struct reservation_object_list * fobj,struct dma_fence * fence)1439a12856eSFrançois Tigeot reservation_object_add_shared_replace(struct reservation_object *obj,
1449a12856eSFrançois Tigeot 				      struct reservation_object_list *old,
1459a12856eSFrançois Tigeot 				      struct reservation_object_list *fobj,
1466559babbSFrançois Tigeot 				      struct dma_fence *fence)
1479a12856eSFrançois Tigeot {
1489a12856eSFrançois Tigeot 	unsigned i;
1496559babbSFrançois Tigeot 	struct dma_fence *old_fence = NULL;
1509a12856eSFrançois Tigeot 
1516559babbSFrançois Tigeot 	dma_fence_get(fence);
1529a12856eSFrançois Tigeot 
1539a12856eSFrançois Tigeot 	if (!old) {
1549a12856eSFrançois Tigeot 		RCU_INIT_POINTER(fobj->shared[0], fence);
1559a12856eSFrançois Tigeot 		fobj->shared_count = 1;
1569a12856eSFrançois Tigeot 		goto done;
1579a12856eSFrançois Tigeot 	}
1589a12856eSFrançois Tigeot 
1599a12856eSFrançois Tigeot 	/*
1609a12856eSFrançois Tigeot 	 * no need to bump fence refcounts, rcu_read access
1619a12856eSFrançois Tigeot 	 * requires the use of kref_get_unless_zero, and the
1629a12856eSFrançois Tigeot 	 * references from the old struct are carried over to
1639a12856eSFrançois Tigeot 	 * the new.
1649a12856eSFrançois Tigeot 	 */
1659a12856eSFrançois Tigeot 	fobj->shared_count = old->shared_count;
1669a12856eSFrançois Tigeot 
1679a12856eSFrançois Tigeot 	for (i = 0; i < old->shared_count; ++i) {
1686559babbSFrançois Tigeot 		struct dma_fence *check;
1699a12856eSFrançois Tigeot 
1709a12856eSFrançois Tigeot 		check = rcu_dereference_protected(old->shared[i],
1719a12856eSFrançois Tigeot 						reservation_object_held(obj));
1729a12856eSFrançois Tigeot 
1739a12856eSFrançois Tigeot 		if (!old_fence && check->context == fence->context) {
1749a12856eSFrançois Tigeot 			old_fence = check;
1759a12856eSFrançois Tigeot 			RCU_INIT_POINTER(fobj->shared[i], fence);
1769a12856eSFrançois Tigeot 		} else
1779a12856eSFrançois Tigeot 			RCU_INIT_POINTER(fobj->shared[i], check);
1789a12856eSFrançois Tigeot 	}
1799a12856eSFrançois Tigeot 	if (!old_fence) {
1809a12856eSFrançois Tigeot 		RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
1819a12856eSFrançois Tigeot 		fobj->shared_count++;
1829a12856eSFrançois Tigeot 	}
1839a12856eSFrançois Tigeot 
1849a12856eSFrançois Tigeot done:
1859a12856eSFrançois Tigeot 	preempt_disable();
1869a12856eSFrançois Tigeot 	write_seqcount_begin(&obj->seq);
1879a12856eSFrançois Tigeot 	/*
1889a12856eSFrançois Tigeot 	 * RCU_INIT_POINTER can be used here,
1899a12856eSFrançois Tigeot 	 * seqcount provides the necessary barriers
1909a12856eSFrançois Tigeot 	 */
1919a12856eSFrançois Tigeot 	RCU_INIT_POINTER(obj->fence, fobj);
1929a12856eSFrançois Tigeot 	write_seqcount_end(&obj->seq);
1939a12856eSFrançois Tigeot 	preempt_enable();
1949a12856eSFrançois Tigeot 
1959a12856eSFrançois Tigeot 	if (old)
1968141ce26SMatthew Dillon 		kfree_rcu(old, NULL);
1979a12856eSFrançois Tigeot 
1986559babbSFrançois Tigeot 	dma_fence_put(old_fence);
1999a12856eSFrançois Tigeot }
2009a12856eSFrançois Tigeot 
2019a12856eSFrançois Tigeot /**
2029a12856eSFrançois Tigeot  * reservation_object_add_shared_fence - Add a fence to a shared slot
2039a12856eSFrançois Tigeot  * @obj: the reservation object
2049a12856eSFrançois Tigeot  * @fence: the shared fence to add
2059a12856eSFrançois Tigeot  *
2069a12856eSFrançois Tigeot  * Add a fence to a shared slot, obj->lock must be held, and
2076559babbSFrançois Tigeot  * reservation_object_reserve_shared() has been called.
2089a12856eSFrançois Tigeot  */
reservation_object_add_shared_fence(struct reservation_object * obj,struct dma_fence * fence)2099a12856eSFrançois Tigeot void reservation_object_add_shared_fence(struct reservation_object *obj,
2106559babbSFrançois Tigeot 					 struct dma_fence *fence)
2119a12856eSFrançois Tigeot {
2129a12856eSFrançois Tigeot 	struct reservation_object_list *old, *fobj = obj->staged;
2139a12856eSFrançois Tigeot 
2149a12856eSFrançois Tigeot 	old = reservation_object_get_list(obj);
2159a12856eSFrançois Tigeot 	obj->staged = NULL;
2169a12856eSFrançois Tigeot 
2179a12856eSFrançois Tigeot 	if (!fobj) {
2189a12856eSFrançois Tigeot 		BUG_ON(old->shared_count >= old->shared_max);
2199a12856eSFrançois Tigeot 		reservation_object_add_shared_inplace(obj, old, fence);
2209a12856eSFrançois Tigeot 	} else
2219a12856eSFrançois Tigeot 		reservation_object_add_shared_replace(obj, old, fobj, fence);
2229a12856eSFrançois Tigeot }
2239a12856eSFrançois Tigeot EXPORT_SYMBOL(reservation_object_add_shared_fence);
2249a12856eSFrançois Tigeot 
2259a12856eSFrançois Tigeot /**
2269a12856eSFrançois Tigeot  * reservation_object_add_excl_fence - Add an exclusive fence.
2279a12856eSFrançois Tigeot  * @obj: the reservation object
2289a12856eSFrançois Tigeot  * @fence: the shared fence to add
2299a12856eSFrançois Tigeot  *
2309a12856eSFrançois Tigeot  * Add a fence to the exclusive slot.  The obj->lock must be held.
2319a12856eSFrançois Tigeot  */
reservation_object_add_excl_fence(struct reservation_object * obj,struct dma_fence * fence)2329a12856eSFrançois Tigeot void reservation_object_add_excl_fence(struct reservation_object *obj,
2336559babbSFrançois Tigeot 				       struct dma_fence *fence)
2349a12856eSFrançois Tigeot {
2356559babbSFrançois Tigeot 	struct dma_fence *old_fence = reservation_object_get_excl(obj);
2369a12856eSFrançois Tigeot 	struct reservation_object_list *old;
2379a12856eSFrançois Tigeot 	u32 i = 0;
2389a12856eSFrançois Tigeot 
2399a12856eSFrançois Tigeot 	old = reservation_object_get_list(obj);
2409a12856eSFrançois Tigeot 	if (old)
2419a12856eSFrançois Tigeot 		i = old->shared_count;
2429a12856eSFrançois Tigeot 
2439a12856eSFrançois Tigeot 	if (fence)
2446559babbSFrançois Tigeot 		dma_fence_get(fence);
2459a12856eSFrançois Tigeot 
2469a12856eSFrançois Tigeot 	preempt_disable();
2479a12856eSFrançois Tigeot 	write_seqcount_begin(&obj->seq);
2489a12856eSFrançois Tigeot 	/* write_seqcount_begin provides the necessary memory barrier */
2499a12856eSFrançois Tigeot 	RCU_INIT_POINTER(obj->fence_excl, fence);
2509a12856eSFrançois Tigeot 	if (old)
2519a12856eSFrançois Tigeot 		old->shared_count = 0;
2529a12856eSFrançois Tigeot 	write_seqcount_end(&obj->seq);
2539a12856eSFrançois Tigeot 	preempt_enable();
2549a12856eSFrançois Tigeot 
2559a12856eSFrançois Tigeot 	/* inplace update, no shared fences */
2569a12856eSFrançois Tigeot 	while (i--)
2576559babbSFrançois Tigeot 		dma_fence_put(rcu_dereference_protected(old->shared[i],
2589a12856eSFrançois Tigeot 						reservation_object_held(obj)));
2599a12856eSFrançois Tigeot 
2606559babbSFrançois Tigeot 	dma_fence_put(old_fence);
2619a12856eSFrançois Tigeot }
2629a12856eSFrançois Tigeot EXPORT_SYMBOL(reservation_object_add_excl_fence);
2639a12856eSFrançois Tigeot 
2649a12856eSFrançois Tigeot /**
2653f2dd94aSFrançois Tigeot * reservation_object_copy_fences - Copy all fences from src to dst.
2663f2dd94aSFrançois Tigeot * @dst: the destination reservation object
2673f2dd94aSFrançois Tigeot * @src: the source reservation object
2683f2dd94aSFrançois Tigeot *
2693f2dd94aSFrançois Tigeot * Copy all fences from src to dst. Both src->lock as well as dst-lock must be
2703f2dd94aSFrançois Tigeot * held.
2713f2dd94aSFrançois Tigeot */
reservation_object_copy_fences(struct reservation_object * dst,struct reservation_object * src)2723f2dd94aSFrançois Tigeot int reservation_object_copy_fences(struct reservation_object *dst,
2733f2dd94aSFrançois Tigeot 				   struct reservation_object *src)
2743f2dd94aSFrançois Tigeot {
2753f2dd94aSFrançois Tigeot 	struct reservation_object_list *src_list, *dst_list;
2763f2dd94aSFrançois Tigeot 	struct dma_fence *old, *new;
2773f2dd94aSFrançois Tigeot 	size_t size;
2783f2dd94aSFrançois Tigeot 	unsigned i;
2793f2dd94aSFrançois Tigeot 
2803f2dd94aSFrançois Tigeot 	src_list = reservation_object_get_list(src);
2813f2dd94aSFrançois Tigeot 
2823f2dd94aSFrançois Tigeot 	if (src_list) {
2833f2dd94aSFrançois Tigeot 		size = offsetof(typeof(*src_list),
2843f2dd94aSFrançois Tigeot 				shared[src_list->shared_count]);
2853f2dd94aSFrançois Tigeot 		dst_list = kmalloc(size, M_DRM, GFP_KERNEL);
2863f2dd94aSFrançois Tigeot 		if (!dst_list)
2873f2dd94aSFrançois Tigeot 			return -ENOMEM;
2883f2dd94aSFrançois Tigeot 
2893f2dd94aSFrançois Tigeot 		dst_list->shared_count = src_list->shared_count;
2903f2dd94aSFrançois Tigeot 		dst_list->shared_max = src_list->shared_count;
2913f2dd94aSFrançois Tigeot 		for (i = 0; i < src_list->shared_count; ++i)
2923f2dd94aSFrançois Tigeot 			dst_list->shared[i] =
2933f2dd94aSFrançois Tigeot 				dma_fence_get(src_list->shared[i]);
2943f2dd94aSFrançois Tigeot 	} else {
2953f2dd94aSFrançois Tigeot 		dst_list = NULL;
2963f2dd94aSFrançois Tigeot 	}
2973f2dd94aSFrançois Tigeot 
2983f2dd94aSFrançois Tigeot 	kfree(dst->staged);
2993f2dd94aSFrançois Tigeot 	dst->staged = NULL;
3003f2dd94aSFrançois Tigeot 
3013f2dd94aSFrançois Tigeot 	src_list = reservation_object_get_list(dst);
3023f2dd94aSFrançois Tigeot 
3033f2dd94aSFrançois Tigeot 	old = reservation_object_get_excl(dst);
3043f2dd94aSFrançois Tigeot 	new = reservation_object_get_excl(src);
3053f2dd94aSFrançois Tigeot 
3063f2dd94aSFrançois Tigeot 	dma_fence_get(new);
3073f2dd94aSFrançois Tigeot 
3083f2dd94aSFrançois Tigeot 	preempt_disable();
3093f2dd94aSFrançois Tigeot 	write_seqcount_begin(&dst->seq);
3103f2dd94aSFrançois Tigeot 	/* write_seqcount_begin provides the necessary memory barrier */
3113f2dd94aSFrançois Tigeot 	RCU_INIT_POINTER(dst->fence_excl, new);
3123f2dd94aSFrançois Tigeot 	RCU_INIT_POINTER(dst->fence, dst_list);
3133f2dd94aSFrançois Tigeot 	write_seqcount_end(&dst->seq);
3143f2dd94aSFrançois Tigeot 	preempt_enable();
3153f2dd94aSFrançois Tigeot 
3163f2dd94aSFrançois Tigeot 	if (src_list)
3173f2dd94aSFrançois Tigeot 		kfree_rcu(src_list, rcu);
3183f2dd94aSFrançois Tigeot 	dma_fence_put(old);
3193f2dd94aSFrançois Tigeot 
3203f2dd94aSFrançois Tigeot 	return 0;
3213f2dd94aSFrançois Tigeot }
3223f2dd94aSFrançois Tigeot EXPORT_SYMBOL(reservation_object_copy_fences);
3233f2dd94aSFrançois Tigeot 
3243f2dd94aSFrançois Tigeot /**
3259a12856eSFrançois Tigeot  * reservation_object_get_fences_rcu - Get an object's shared and exclusive
3269a12856eSFrançois Tigeot  * fences without update side lock held
3279a12856eSFrançois Tigeot  * @obj: the reservation object
3289a12856eSFrançois Tigeot  * @pfence_excl: the returned exclusive fence (or NULL)
3299a12856eSFrançois Tigeot  * @pshared_count: the number of shared fences returned
3309a12856eSFrançois Tigeot  * @pshared: the array of shared fence ptrs returned (array is krealloc'd to
3319a12856eSFrançois Tigeot  * the required size, and must be freed by caller)
3329a12856eSFrançois Tigeot  *
3339a12856eSFrançois Tigeot  * RETURNS
3349a12856eSFrançois Tigeot  * Zero or -errno
3359a12856eSFrançois Tigeot  */
reservation_object_get_fences_rcu(struct reservation_object * obj,struct dma_fence ** pfence_excl,unsigned * pshared_count,struct dma_fence *** pshared)3369a12856eSFrançois Tigeot int reservation_object_get_fences_rcu(struct reservation_object *obj,
3376559babbSFrançois Tigeot 				      struct dma_fence **pfence_excl,
3389a12856eSFrançois Tigeot 				      unsigned *pshared_count,
3396559babbSFrançois Tigeot 				      struct dma_fence ***pshared)
3409a12856eSFrançois Tigeot {
3416559babbSFrançois Tigeot 	struct dma_fence **shared = NULL;
3426559babbSFrançois Tigeot 	struct dma_fence *fence_excl;
3436559babbSFrançois Tigeot 	unsigned int shared_count;
3446559babbSFrançois Tigeot 	int ret = 1;
3459a12856eSFrançois Tigeot 
3466559babbSFrançois Tigeot 	do {
3479a12856eSFrançois Tigeot 		struct reservation_object_list *fobj;
3489a12856eSFrançois Tigeot 		unsigned seq;
3496559babbSFrançois Tigeot 		unsigned int i;
3509a12856eSFrançois Tigeot 
3516559babbSFrançois Tigeot 		shared_count = i = 0;
3529a12856eSFrançois Tigeot 
3539a12856eSFrançois Tigeot 		rcu_read_lock();
3546559babbSFrançois Tigeot 		seq = read_seqcount_begin(&obj->seq);
3556559babbSFrançois Tigeot 
3566559babbSFrançois Tigeot 		fence_excl = rcu_dereference(obj->fence_excl);
3576559babbSFrançois Tigeot 		if (fence_excl && !dma_fence_get_rcu(fence_excl))
3586559babbSFrançois Tigeot 			goto unlock;
3599a12856eSFrançois Tigeot 
3609a12856eSFrançois Tigeot 		fobj = rcu_dereference(obj->fence);
3619a12856eSFrançois Tigeot 		if (fobj) {
3626559babbSFrançois Tigeot 			struct dma_fence **nshared;
3639a12856eSFrançois Tigeot 			size_t sz = sizeof(*shared) * fobj->shared_max;
3649a12856eSFrançois Tigeot 
3653f2dd94aSFrançois Tigeot 			nshared = krealloc(shared, sz, M_DRM,
3663f2dd94aSFrançois Tigeot 					   GFP_NOWAIT | __GFP_NOWARN);
3679a12856eSFrançois Tigeot 			if (!nshared) {
3689a12856eSFrançois Tigeot 				rcu_read_unlock();
3693f2dd94aSFrançois Tigeot 				nshared = krealloc(shared, sz, M_DRM,
3703f2dd94aSFrançois Tigeot 						   GFP_KERNEL);
3719a12856eSFrançois Tigeot 				if (nshared) {
3729a12856eSFrançois Tigeot 					shared = nshared;
3739a12856eSFrançois Tigeot 					continue;
3749a12856eSFrançois Tigeot 				}
3759a12856eSFrançois Tigeot 
3769a12856eSFrançois Tigeot 				ret = -ENOMEM;
3779a12856eSFrançois Tigeot 				break;
3789a12856eSFrançois Tigeot 			}
3799a12856eSFrançois Tigeot 			shared = nshared;
3809a12856eSFrançois Tigeot 			shared_count = fobj->shared_count;
3819a12856eSFrançois Tigeot 
3829a12856eSFrançois Tigeot 			for (i = 0; i < shared_count; ++i) {
3836559babbSFrançois Tigeot 				shared[i] = rcu_dereference(fobj->shared[i]);
3846559babbSFrançois Tigeot 				if (!dma_fence_get_rcu(shared[i]))
3859a12856eSFrançois Tigeot 					break;
3869a12856eSFrançois Tigeot 			}
3876559babbSFrançois Tigeot 		}
3889a12856eSFrançois Tigeot 
3896559babbSFrançois Tigeot 		if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
3906559babbSFrançois Tigeot 			while (i--)
3916559babbSFrançois Tigeot 				dma_fence_put(shared[i]);
3926559babbSFrançois Tigeot 			dma_fence_put(fence_excl);
3936559babbSFrançois Tigeot 			goto unlock;
3946559babbSFrançois Tigeot 		}
3956559babbSFrançois Tigeot 
3966559babbSFrançois Tigeot 		ret = 0;
3979a12856eSFrançois Tigeot unlock:
3989a12856eSFrançois Tigeot 		rcu_read_unlock();
3996559babbSFrançois Tigeot 	} while (ret);
4006559babbSFrançois Tigeot 
4016559babbSFrançois Tigeot 	if (!shared_count) {
4029a12856eSFrançois Tigeot 		kfree(shared);
4036559babbSFrançois Tigeot 		shared = NULL;
4049a12856eSFrançois Tigeot 	}
4056559babbSFrançois Tigeot 
406*78973132SSergey Zigachev 	if (pshared_count)
4076559babbSFrançois Tigeot 		*pshared_count = shared_count;
408*78973132SSergey Zigachev 	if (pshared)
4096559babbSFrançois Tigeot 		*pshared = shared;
410*78973132SSergey Zigachev 	if (pfence_excl)
4119a12856eSFrançois Tigeot 		*pfence_excl = fence_excl;
4129a12856eSFrançois Tigeot 
4139a12856eSFrançois Tigeot 	return ret;
4149a12856eSFrançois Tigeot }
4159a12856eSFrançois Tigeot EXPORT_SYMBOL_GPL(reservation_object_get_fences_rcu);
4169a12856eSFrançois Tigeot 
4179a12856eSFrançois Tigeot /**
4189a12856eSFrançois Tigeot  * reservation_object_wait_timeout_rcu - Wait on reservation's objects
4199a12856eSFrançois Tigeot  * shared and/or exclusive fences.
4209a12856eSFrançois Tigeot  * @obj: the reservation object
4219a12856eSFrançois Tigeot  * @wait_all: if true, wait on all fences, else wait on just exclusive fence
4229a12856eSFrançois Tigeot  * @intr: if true, do interruptible wait
4239a12856eSFrançois Tigeot  * @timeout: timeout value in jiffies or zero to return immediately
4249a12856eSFrançois Tigeot  *
4259a12856eSFrançois Tigeot  * RETURNS
4269a12856eSFrançois Tigeot  * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
4279a12856eSFrançois Tigeot  * greater than zer on success.
4289a12856eSFrançois Tigeot  */
reservation_object_wait_timeout_rcu(struct reservation_object * obj,bool wait_all,bool intr,unsigned long timeout)4299a12856eSFrançois Tigeot long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
4309a12856eSFrançois Tigeot 					 bool wait_all, bool intr,
4319a12856eSFrançois Tigeot 					 unsigned long timeout)
4329a12856eSFrançois Tigeot {
4336559babbSFrançois Tigeot 	struct dma_fence *fence;
4349a12856eSFrançois Tigeot 	unsigned seq, shared_count, i = 0;
4353f2dd94aSFrançois Tigeot 	long ret = timeout ? timeout : 1;
4369a12856eSFrançois Tigeot 
4379a12856eSFrançois Tigeot retry:
4389a12856eSFrançois Tigeot 	shared_count = 0;
4399a12856eSFrançois Tigeot 	seq = read_seqcount_begin(&obj->seq);
4409a12856eSFrançois Tigeot 	rcu_read_lock();
4419a12856eSFrançois Tigeot 
4423f2dd94aSFrançois Tigeot 	fence = rcu_dereference(obj->fence_excl);
4433f2dd94aSFrançois Tigeot 	if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
4443f2dd94aSFrançois Tigeot 		if (!dma_fence_get_rcu(fence))
4453f2dd94aSFrançois Tigeot 			goto unlock_retry;
4463f2dd94aSFrançois Tigeot 
4473f2dd94aSFrançois Tigeot 		if (dma_fence_is_signaled(fence)) {
4483f2dd94aSFrançois Tigeot 			dma_fence_put(fence);
4493f2dd94aSFrançois Tigeot 			fence = NULL;
4503f2dd94aSFrançois Tigeot 		}
4513f2dd94aSFrançois Tigeot 
4523f2dd94aSFrançois Tigeot 	} else {
4533f2dd94aSFrançois Tigeot 		fence = NULL;
4543f2dd94aSFrançois Tigeot 	}
4553f2dd94aSFrançois Tigeot 
4563f2dd94aSFrançois Tigeot 	if (!fence && wait_all) {
4579a12856eSFrançois Tigeot 		struct reservation_object_list *fobj =
4589a12856eSFrançois Tigeot 						rcu_dereference(obj->fence);
4599a12856eSFrançois Tigeot 
4609a12856eSFrançois Tigeot 		if (fobj)
4619a12856eSFrançois Tigeot 			shared_count = fobj->shared_count;
4629a12856eSFrançois Tigeot 
4639a12856eSFrançois Tigeot 		for (i = 0; i < shared_count; ++i) {
4646559babbSFrançois Tigeot 			struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
4659a12856eSFrançois Tigeot 
4666559babbSFrançois Tigeot 			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
4676559babbSFrançois Tigeot 				     &lfence->flags))
4689a12856eSFrançois Tigeot 				continue;
4699a12856eSFrançois Tigeot 
4706559babbSFrançois Tigeot 			if (!dma_fence_get_rcu(lfence))
4719a12856eSFrançois Tigeot 				goto unlock_retry;
4729a12856eSFrançois Tigeot 
4736559babbSFrançois Tigeot 			if (dma_fence_is_signaled(lfence)) {
4746559babbSFrançois Tigeot 				dma_fence_put(lfence);
4759a12856eSFrançois Tigeot 				continue;
4769a12856eSFrançois Tigeot 			}
4779a12856eSFrançois Tigeot 
4789a12856eSFrançois Tigeot 			fence = lfence;
4799a12856eSFrançois Tigeot 			break;
4809a12856eSFrançois Tigeot 		}
4819a12856eSFrançois Tigeot 	}
4829a12856eSFrançois Tigeot 
4839a12856eSFrançois Tigeot 	rcu_read_unlock();
4849a12856eSFrançois Tigeot 	if (fence) {
4856559babbSFrançois Tigeot 		if (read_seqcount_retry(&obj->seq, seq)) {
4866559babbSFrançois Tigeot 			dma_fence_put(fence);
4876559babbSFrançois Tigeot 			goto retry;
4886559babbSFrançois Tigeot 		}
4896559babbSFrançois Tigeot 
4906559babbSFrançois Tigeot 		ret = dma_fence_wait_timeout(fence, intr, ret);
4916559babbSFrançois Tigeot 		dma_fence_put(fence);
4929a12856eSFrançois Tigeot 		if (ret > 0 && wait_all && (i + 1 < shared_count))
4939a12856eSFrançois Tigeot 			goto retry;
4949a12856eSFrançois Tigeot 	}
4959a12856eSFrançois Tigeot 	return ret;
4969a12856eSFrançois Tigeot 
4979a12856eSFrançois Tigeot unlock_retry:
4989a12856eSFrançois Tigeot 	rcu_read_unlock();
4999a12856eSFrançois Tigeot 	goto retry;
5009a12856eSFrançois Tigeot }
5019a12856eSFrançois Tigeot EXPORT_SYMBOL_GPL(reservation_object_wait_timeout_rcu);
5029a12856eSFrançois Tigeot 
5039a12856eSFrançois Tigeot 
5049a12856eSFrançois Tigeot static inline int
reservation_object_test_signaled_single(struct dma_fence * passed_fence)5056559babbSFrançois Tigeot reservation_object_test_signaled_single(struct dma_fence *passed_fence)
5069a12856eSFrançois Tigeot {
5076559babbSFrançois Tigeot 	struct dma_fence *fence, *lfence = passed_fence;
5089a12856eSFrançois Tigeot 	int ret = 1;
5099a12856eSFrançois Tigeot 
5106559babbSFrançois Tigeot 	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
5116559babbSFrançois Tigeot 		fence = dma_fence_get_rcu(lfence);
5129a12856eSFrançois Tigeot 		if (!fence)
5139a12856eSFrançois Tigeot 			return -1;
5149a12856eSFrançois Tigeot 
5156559babbSFrançois Tigeot 		ret = !!dma_fence_is_signaled(fence);
5166559babbSFrançois Tigeot 		dma_fence_put(fence);
5179a12856eSFrançois Tigeot 	}
5189a12856eSFrançois Tigeot 	return ret;
5199a12856eSFrançois Tigeot }
5209a12856eSFrançois Tigeot 
5219a12856eSFrançois Tigeot /**
5229a12856eSFrançois Tigeot  * reservation_object_test_signaled_rcu - Test if a reservation object's
5239a12856eSFrançois Tigeot  * fences have been signaled.
5249a12856eSFrançois Tigeot  * @obj: the reservation object
5259a12856eSFrançois Tigeot  * @test_all: if true, test all fences, otherwise only test the exclusive
5269a12856eSFrançois Tigeot  * fence
5279a12856eSFrançois Tigeot  *
5289a12856eSFrançois Tigeot  * RETURNS
5299a12856eSFrançois Tigeot  * true if all fences signaled, else false
5309a12856eSFrançois Tigeot  */
reservation_object_test_signaled_rcu(struct reservation_object * obj,bool test_all)5319a12856eSFrançois Tigeot bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
5329a12856eSFrançois Tigeot 					  bool test_all)
5339a12856eSFrançois Tigeot {
5349a12856eSFrançois Tigeot 	unsigned seq, shared_count;
5356559babbSFrançois Tigeot 	int ret;
5369a12856eSFrançois Tigeot 
5376559babbSFrançois Tigeot 	rcu_read_lock();
5389a12856eSFrançois Tigeot retry:
5396559babbSFrançois Tigeot 	ret = true;
5409a12856eSFrançois Tigeot 	shared_count = 0;
5419a12856eSFrançois Tigeot 	seq = read_seqcount_begin(&obj->seq);
5429a12856eSFrançois Tigeot 
5439a12856eSFrançois Tigeot 	if (test_all) {
5449a12856eSFrançois Tigeot 		unsigned i;
5459a12856eSFrançois Tigeot 
5469a12856eSFrançois Tigeot 		struct reservation_object_list *fobj =
5479a12856eSFrançois Tigeot 						rcu_dereference(obj->fence);
5489a12856eSFrançois Tigeot 
5499a12856eSFrançois Tigeot 		if (fobj)
5509a12856eSFrançois Tigeot 			shared_count = fobj->shared_count;
5519a12856eSFrançois Tigeot 
5529a12856eSFrançois Tigeot 		for (i = 0; i < shared_count; ++i) {
5536559babbSFrançois Tigeot 			struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
5549a12856eSFrançois Tigeot 
5559a12856eSFrançois Tigeot 			ret = reservation_object_test_signaled_single(fence);
5569a12856eSFrançois Tigeot 			if (ret < 0)
5576559babbSFrançois Tigeot 				goto retry;
5589a12856eSFrançois Tigeot 			else if (!ret)
5599a12856eSFrançois Tigeot 				break;
5609a12856eSFrançois Tigeot 		}
5619a12856eSFrançois Tigeot 
5626559babbSFrançois Tigeot 		if (read_seqcount_retry(&obj->seq, seq))
5636559babbSFrançois Tigeot 			goto retry;
5649a12856eSFrançois Tigeot 	}
5659a12856eSFrançois Tigeot 
5669a12856eSFrançois Tigeot 	if (!shared_count) {
5676559babbSFrançois Tigeot 		struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
5689a12856eSFrançois Tigeot 
5699a12856eSFrançois Tigeot 		if (fence_excl) {
5709a12856eSFrançois Tigeot 			ret = reservation_object_test_signaled_single(
5719a12856eSFrançois Tigeot 								fence_excl);
5729a12856eSFrançois Tigeot 			if (ret < 0)
5736559babbSFrançois Tigeot 				goto retry;
5746559babbSFrançois Tigeot 
5756559babbSFrançois Tigeot 			if (read_seqcount_retry(&obj->seq, seq))
5766559babbSFrançois Tigeot 				goto retry;
5779a12856eSFrançois Tigeot 		}
5789a12856eSFrançois Tigeot 	}
5799a12856eSFrançois Tigeot 
5809a12856eSFrançois Tigeot 	rcu_read_unlock();
5819a12856eSFrançois Tigeot 	return ret;
5829a12856eSFrançois Tigeot }
5839a12856eSFrançois Tigeot EXPORT_SYMBOL_GPL(reservation_object_test_signaled_rcu);
584