18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst)
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Based on bo.c which bears the following copyright notice,
58c2ecf20Sopenharmony_ci * but is dual licensed:
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
88c2ecf20Sopenharmony_ci * All Rights Reserved.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
118c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
128c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
138c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
148c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
158c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
168c2ecf20Sopenharmony_ci * the following conditions:
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
198c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
208c2ecf20Sopenharmony_ci * of the Software.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
238c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
248c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
258c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
268c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
278c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
288c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci **************************************************************************/
318c2ecf20Sopenharmony_ci/*
328c2ecf20Sopenharmony_ci * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/dma-resv.h>
368c2ecf20Sopenharmony_ci#include <linux/export.h>
378c2ecf20Sopenharmony_ci#include <linux/mm.h>
388c2ecf20Sopenharmony_ci#include <linux/sched/mm.h>
398c2ecf20Sopenharmony_ci#include <linux/mmu_notifier.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/**
428c2ecf20Sopenharmony_ci * DOC: Reservation Object Overview
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * The reservation object provides a mechanism to manage shared and
458c2ecf20Sopenharmony_ci * exclusive fences associated with a buffer.  A reservation object
468c2ecf20Sopenharmony_ci * can have attached one exclusive fence (normally associated with
478c2ecf20Sopenharmony_ci * write operations) or N shared fences (read operations).  The RCU
488c2ecf20Sopenharmony_ci * mechanism is used to protect read access to fences from locked
498c2ecf20Sopenharmony_ci * write-side updates.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciDEFINE_WD_CLASS(reservation_ww_class);
538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(reservation_ww_class);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/**
568c2ecf20Sopenharmony_ci * dma_resv_list_alloc - allocate fence list
578c2ecf20Sopenharmony_ci * @shared_max: number of fences we need space for
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci * Allocate a new dma_resv_list and make sure to correctly initialize
608c2ecf20Sopenharmony_ci * shared_max.
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_cistatic struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct dma_resv_list *list;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	list = kmalloc(offsetof(typeof(*list), shared[shared_max]), GFP_KERNEL);
678c2ecf20Sopenharmony_ci	if (!list)
688c2ecf20Sopenharmony_ci		return NULL;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)) /
718c2ecf20Sopenharmony_ci		sizeof(*list->shared);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return list;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/**
778c2ecf20Sopenharmony_ci * dma_resv_list_free - free fence list
788c2ecf20Sopenharmony_ci * @list: list to free
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * Free a dma_resv_list and make sure to drop all references.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_cistatic void dma_resv_list_free(struct dma_resv_list *list)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	unsigned int i;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (!list)
878c2ecf20Sopenharmony_ci		return;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	for (i = 0; i < list->shared_count; ++i)
908c2ecf20Sopenharmony_ci		dma_fence_put(rcu_dereference_protected(list->shared[i], true));
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	kfree_rcu(list, rcu);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_LOCKDEP)
968c2ecf20Sopenharmony_cistatic int __init dma_resv_lockdep(void)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct mm_struct *mm = mm_alloc();
998c2ecf20Sopenharmony_ci	struct ww_acquire_ctx ctx;
1008c2ecf20Sopenharmony_ci	struct dma_resv obj;
1018c2ecf20Sopenharmony_ci	struct address_space mapping;
1028c2ecf20Sopenharmony_ci	int ret;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (!mm)
1058c2ecf20Sopenharmony_ci		return -ENOMEM;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	dma_resv_init(&obj);
1088c2ecf20Sopenharmony_ci	address_space_init_once(&mapping);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	mmap_read_lock(mm);
1118c2ecf20Sopenharmony_ci	ww_acquire_init(&ctx, &reservation_ww_class);
1128c2ecf20Sopenharmony_ci	ret = dma_resv_lock(&obj, &ctx);
1138c2ecf20Sopenharmony_ci	if (ret == -EDEADLK)
1148c2ecf20Sopenharmony_ci		dma_resv_lock_slow(&obj, &ctx);
1158c2ecf20Sopenharmony_ci	fs_reclaim_acquire(GFP_KERNEL);
1168c2ecf20Sopenharmony_ci	/* for unmap_mapping_range on trylocked buffer objects in shrinkers */
1178c2ecf20Sopenharmony_ci	i_mmap_lock_write(&mapping);
1188c2ecf20Sopenharmony_ci	i_mmap_unlock_write(&mapping);
1198c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU_NOTIFIER
1208c2ecf20Sopenharmony_ci	lock_map_acquire(&__mmu_notifier_invalidate_range_start_map);
1218c2ecf20Sopenharmony_ci	__dma_fence_might_wait();
1228c2ecf20Sopenharmony_ci	lock_map_release(&__mmu_notifier_invalidate_range_start_map);
1238c2ecf20Sopenharmony_ci#else
1248c2ecf20Sopenharmony_ci	__dma_fence_might_wait();
1258c2ecf20Sopenharmony_ci#endif
1268c2ecf20Sopenharmony_ci	fs_reclaim_release(GFP_KERNEL);
1278c2ecf20Sopenharmony_ci	ww_mutex_unlock(&obj.lock);
1288c2ecf20Sopenharmony_ci	ww_acquire_fini(&ctx);
1298c2ecf20Sopenharmony_ci	mmap_read_unlock(mm);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	mmput(mm);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_cisubsys_initcall(dma_resv_lockdep);
1368c2ecf20Sopenharmony_ci#endif
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/**
1398c2ecf20Sopenharmony_ci * dma_resv_init - initialize a reservation object
1408c2ecf20Sopenharmony_ci * @obj: the reservation object
1418c2ecf20Sopenharmony_ci */
1428c2ecf20Sopenharmony_civoid dma_resv_init(struct dma_resv *obj)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	ww_mutex_init(&obj->lock, &reservation_ww_class);
1458c2ecf20Sopenharmony_ci	seqcount_ww_mutex_init(&obj->seq, &obj->lock);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(obj->fence, NULL);
1488c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(obj->fence_excl, NULL);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dma_resv_init);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/**
1538c2ecf20Sopenharmony_ci * dma_resv_fini - destroys a reservation object
1548c2ecf20Sopenharmony_ci * @obj: the reservation object
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_civoid dma_resv_fini(struct dma_resv *obj)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct dma_resv_list *fobj;
1598c2ecf20Sopenharmony_ci	struct dma_fence *excl;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/*
1628c2ecf20Sopenharmony_ci	 * This object should be dead and all references must have
1638c2ecf20Sopenharmony_ci	 * been released to it, so no need to be protected with rcu.
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	excl = rcu_dereference_protected(obj->fence_excl, 1);
1668c2ecf20Sopenharmony_ci	if (excl)
1678c2ecf20Sopenharmony_ci		dma_fence_put(excl);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	fobj = rcu_dereference_protected(obj->fence, 1);
1708c2ecf20Sopenharmony_ci	dma_resv_list_free(fobj);
1718c2ecf20Sopenharmony_ci	ww_mutex_destroy(&obj->lock);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dma_resv_fini);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/**
1768c2ecf20Sopenharmony_ci * dma_resv_reserve_shared - Reserve space to add shared fences to
1778c2ecf20Sopenharmony_ci * a dma_resv.
1788c2ecf20Sopenharmony_ci * @obj: reservation object
1798c2ecf20Sopenharmony_ci * @num_fences: number of fences we want to add
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci * Should be called before dma_resv_add_shared_fence().  Must
1828c2ecf20Sopenharmony_ci * be called with obj->lock held.
1838c2ecf20Sopenharmony_ci *
1848c2ecf20Sopenharmony_ci * RETURNS
1858c2ecf20Sopenharmony_ci * Zero for success, or -errno
1868c2ecf20Sopenharmony_ci */
1878c2ecf20Sopenharmony_ciint dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct dma_resv_list *old, *new;
1908c2ecf20Sopenharmony_ci	unsigned int i, j, k, max;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	dma_resv_assert_held(obj);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	old = dma_resv_get_list(obj);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (old && old->shared_max) {
1978c2ecf20Sopenharmony_ci		if ((old->shared_count + num_fences) <= old->shared_max)
1988c2ecf20Sopenharmony_ci			return 0;
1998c2ecf20Sopenharmony_ci		else
2008c2ecf20Sopenharmony_ci			max = max(old->shared_count + num_fences,
2018c2ecf20Sopenharmony_ci				  old->shared_max * 2);
2028c2ecf20Sopenharmony_ci	} else {
2038c2ecf20Sopenharmony_ci		max = max(4ul, roundup_pow_of_two(num_fences));
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	new = dma_resv_list_alloc(max);
2078c2ecf20Sopenharmony_ci	if (!new)
2088c2ecf20Sopenharmony_ci		return -ENOMEM;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/*
2118c2ecf20Sopenharmony_ci	 * no need to bump fence refcounts, rcu_read access
2128c2ecf20Sopenharmony_ci	 * requires the use of kref_get_unless_zero, and the
2138c2ecf20Sopenharmony_ci	 * references from the old struct are carried over to
2148c2ecf20Sopenharmony_ci	 * the new.
2158c2ecf20Sopenharmony_ci	 */
2168c2ecf20Sopenharmony_ci	for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
2178c2ecf20Sopenharmony_ci		struct dma_fence *fence;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		fence = rcu_dereference_protected(old->shared[i],
2208c2ecf20Sopenharmony_ci						  dma_resv_held(obj));
2218c2ecf20Sopenharmony_ci		if (dma_fence_is_signaled(fence))
2228c2ecf20Sopenharmony_ci			RCU_INIT_POINTER(new->shared[--k], fence);
2238c2ecf20Sopenharmony_ci		else
2248c2ecf20Sopenharmony_ci			RCU_INIT_POINTER(new->shared[j++], fence);
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	new->shared_count = j;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/*
2298c2ecf20Sopenharmony_ci	 * We are not changing the effective set of fences here so can
2308c2ecf20Sopenharmony_ci	 * merely update the pointer to the new array; both existing
2318c2ecf20Sopenharmony_ci	 * readers and new readers will see exactly the same set of
2328c2ecf20Sopenharmony_ci	 * active (unsignaled) shared fences. Individual fences and the
2338c2ecf20Sopenharmony_ci	 * old array are protected by RCU and so will not vanish under
2348c2ecf20Sopenharmony_ci	 * the gaze of the rcu_read_lock() readers.
2358c2ecf20Sopenharmony_ci	 */
2368c2ecf20Sopenharmony_ci	rcu_assign_pointer(obj->fence, new);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (!old)
2398c2ecf20Sopenharmony_ci		return 0;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* Drop the references to the signaled fences */
2428c2ecf20Sopenharmony_ci	for (i = k; i < max; ++i) {
2438c2ecf20Sopenharmony_ci		struct dma_fence *fence;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		fence = rcu_dereference_protected(new->shared[i],
2468c2ecf20Sopenharmony_ci						  dma_resv_held(obj));
2478c2ecf20Sopenharmony_ci		dma_fence_put(fence);
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci	kfree_rcu(old, rcu);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dma_resv_reserve_shared);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/**
2568c2ecf20Sopenharmony_ci * dma_resv_add_shared_fence - Add a fence to a shared slot
2578c2ecf20Sopenharmony_ci * @obj: the reservation object
2588c2ecf20Sopenharmony_ci * @fence: the shared fence to add
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci * Add a fence to a shared slot, obj->lock must be held, and
2618c2ecf20Sopenharmony_ci * dma_resv_reserve_shared() has been called.
2628c2ecf20Sopenharmony_ci */
2638c2ecf20Sopenharmony_civoid dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct dma_resv_list *fobj;
2668c2ecf20Sopenharmony_ci	struct dma_fence *old;
2678c2ecf20Sopenharmony_ci	unsigned int i, count;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	dma_fence_get(fence);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	dma_resv_assert_held(obj);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	fobj = dma_resv_get_list(obj);
2748c2ecf20Sopenharmony_ci	count = fobj->shared_count;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	write_seqcount_begin(&obj->seq);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	for (i = 0; i < count; ++i) {
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		old = rcu_dereference_protected(fobj->shared[i],
2818c2ecf20Sopenharmony_ci						dma_resv_held(obj));
2828c2ecf20Sopenharmony_ci		if (old->context == fence->context ||
2838c2ecf20Sopenharmony_ci		    dma_fence_is_signaled(old))
2848c2ecf20Sopenharmony_ci			goto replace;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	BUG_ON(fobj->shared_count >= fobj->shared_max);
2888c2ecf20Sopenharmony_ci	old = NULL;
2898c2ecf20Sopenharmony_ci	count++;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cireplace:
2928c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(fobj->shared[i], fence);
2938c2ecf20Sopenharmony_ci	/* pointer update must be visible before we extend the shared_count */
2948c2ecf20Sopenharmony_ci	smp_store_mb(fobj->shared_count, count);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	write_seqcount_end(&obj->seq);
2978c2ecf20Sopenharmony_ci	dma_fence_put(old);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dma_resv_add_shared_fence);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/**
3028c2ecf20Sopenharmony_ci * dma_resv_add_excl_fence - Add an exclusive fence.
3038c2ecf20Sopenharmony_ci * @obj: the reservation object
3048c2ecf20Sopenharmony_ci * @fence: the shared fence to add
3058c2ecf20Sopenharmony_ci *
3068c2ecf20Sopenharmony_ci * Add a fence to the exclusive slot.  The obj->lock must be held.
3078c2ecf20Sopenharmony_ci */
3088c2ecf20Sopenharmony_civoid dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct dma_fence *old_fence = dma_resv_get_excl(obj);
3118c2ecf20Sopenharmony_ci	struct dma_resv_list *old;
3128c2ecf20Sopenharmony_ci	u32 i = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	dma_resv_assert_held(obj);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	old = dma_resv_get_list(obj);
3178c2ecf20Sopenharmony_ci	if (old)
3188c2ecf20Sopenharmony_ci		i = old->shared_count;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (fence)
3218c2ecf20Sopenharmony_ci		dma_fence_get(fence);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	write_seqcount_begin(&obj->seq);
3248c2ecf20Sopenharmony_ci	/* write_seqcount_begin provides the necessary memory barrier */
3258c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(obj->fence_excl, fence);
3268c2ecf20Sopenharmony_ci	if (old)
3278c2ecf20Sopenharmony_ci		old->shared_count = 0;
3288c2ecf20Sopenharmony_ci	write_seqcount_end(&obj->seq);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* inplace update, no shared fences */
3318c2ecf20Sopenharmony_ci	while (i--)
3328c2ecf20Sopenharmony_ci		dma_fence_put(rcu_dereference_protected(old->shared[i],
3338c2ecf20Sopenharmony_ci						dma_resv_held(obj)));
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	dma_fence_put(old_fence);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dma_resv_add_excl_fence);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci/**
3408c2ecf20Sopenharmony_ci* dma_resv_copy_fences - Copy all fences from src to dst.
3418c2ecf20Sopenharmony_ci* @dst: the destination reservation object
3428c2ecf20Sopenharmony_ci* @src: the source reservation object
3438c2ecf20Sopenharmony_ci*
3448c2ecf20Sopenharmony_ci* Copy all fences from src to dst. dst-lock must be held.
3458c2ecf20Sopenharmony_ci*/
3468c2ecf20Sopenharmony_ciint dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct dma_resv_list *src_list, *dst_list;
3498c2ecf20Sopenharmony_ci	struct dma_fence *old, *new;
3508c2ecf20Sopenharmony_ci	unsigned i;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	dma_resv_assert_held(dst);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	rcu_read_lock();
3558c2ecf20Sopenharmony_ci	src_list = rcu_dereference(src->fence);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ciretry:
3588c2ecf20Sopenharmony_ci	if (src_list) {
3598c2ecf20Sopenharmony_ci		unsigned shared_count = src_list->shared_count;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		rcu_read_unlock();
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		dst_list = dma_resv_list_alloc(shared_count);
3648c2ecf20Sopenharmony_ci		if (!dst_list)
3658c2ecf20Sopenharmony_ci			return -ENOMEM;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		rcu_read_lock();
3688c2ecf20Sopenharmony_ci		src_list = rcu_dereference(src->fence);
3698c2ecf20Sopenharmony_ci		if (!src_list || src_list->shared_count > shared_count) {
3708c2ecf20Sopenharmony_ci			kfree(dst_list);
3718c2ecf20Sopenharmony_ci			goto retry;
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		dst_list->shared_count = 0;
3758c2ecf20Sopenharmony_ci		for (i = 0; i < src_list->shared_count; ++i) {
3768c2ecf20Sopenharmony_ci			struct dma_fence *fence;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci			fence = rcu_dereference(src_list->shared[i]);
3798c2ecf20Sopenharmony_ci			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
3808c2ecf20Sopenharmony_ci				     &fence->flags))
3818c2ecf20Sopenharmony_ci				continue;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci			if (!dma_fence_get_rcu(fence)) {
3848c2ecf20Sopenharmony_ci				dma_resv_list_free(dst_list);
3858c2ecf20Sopenharmony_ci				src_list = rcu_dereference(src->fence);
3868c2ecf20Sopenharmony_ci				goto retry;
3878c2ecf20Sopenharmony_ci			}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci			if (dma_fence_is_signaled(fence)) {
3908c2ecf20Sopenharmony_ci				dma_fence_put(fence);
3918c2ecf20Sopenharmony_ci				continue;
3928c2ecf20Sopenharmony_ci			}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci			rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence);
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci	} else {
3978c2ecf20Sopenharmony_ci		dst_list = NULL;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	new = dma_fence_get_rcu_safe(&src->fence_excl);
4018c2ecf20Sopenharmony_ci	rcu_read_unlock();
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	src_list = dma_resv_get_list(dst);
4048c2ecf20Sopenharmony_ci	old = dma_resv_get_excl(dst);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	write_seqcount_begin(&dst->seq);
4078c2ecf20Sopenharmony_ci	/* write_seqcount_begin provides the necessary memory barrier */
4088c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(dst->fence_excl, new);
4098c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(dst->fence, dst_list);
4108c2ecf20Sopenharmony_ci	write_seqcount_end(&dst->seq);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	dma_resv_list_free(src_list);
4138c2ecf20Sopenharmony_ci	dma_fence_put(old);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return 0;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dma_resv_copy_fences);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/**
4208c2ecf20Sopenharmony_ci * dma_resv_get_fences_rcu - Get an object's shared and exclusive
4218c2ecf20Sopenharmony_ci * fences without update side lock held
4228c2ecf20Sopenharmony_ci * @obj: the reservation object
4238c2ecf20Sopenharmony_ci * @pfence_excl: the returned exclusive fence (or NULL)
4248c2ecf20Sopenharmony_ci * @pshared_count: the number of shared fences returned
4258c2ecf20Sopenharmony_ci * @pshared: the array of shared fence ptrs returned (array is krealloc'd to
4268c2ecf20Sopenharmony_ci * the required size, and must be freed by caller)
4278c2ecf20Sopenharmony_ci *
4288c2ecf20Sopenharmony_ci * Retrieve all fences from the reservation object. If the pointer for the
4298c2ecf20Sopenharmony_ci * exclusive fence is not specified the fence is put into the array of the
4308c2ecf20Sopenharmony_ci * shared fences as well. Returns either zero or -ENOMEM.
4318c2ecf20Sopenharmony_ci */
4328c2ecf20Sopenharmony_ciint dma_resv_get_fences_rcu(struct dma_resv *obj,
4338c2ecf20Sopenharmony_ci			    struct dma_fence **pfence_excl,
4348c2ecf20Sopenharmony_ci			    unsigned *pshared_count,
4358c2ecf20Sopenharmony_ci			    struct dma_fence ***pshared)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct dma_fence **shared = NULL;
4388c2ecf20Sopenharmony_ci	struct dma_fence *fence_excl;
4398c2ecf20Sopenharmony_ci	unsigned int shared_count;
4408c2ecf20Sopenharmony_ci	int ret = 1;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	do {
4438c2ecf20Sopenharmony_ci		struct dma_resv_list *fobj;
4448c2ecf20Sopenharmony_ci		unsigned int i, seq;
4458c2ecf20Sopenharmony_ci		size_t sz = 0;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		shared_count = i = 0;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		rcu_read_lock();
4508c2ecf20Sopenharmony_ci		seq = read_seqcount_begin(&obj->seq);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		fence_excl = rcu_dereference(obj->fence_excl);
4538c2ecf20Sopenharmony_ci		if (fence_excl && !dma_fence_get_rcu(fence_excl))
4548c2ecf20Sopenharmony_ci			goto unlock;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		fobj = rcu_dereference(obj->fence);
4578c2ecf20Sopenharmony_ci		if (fobj)
4588c2ecf20Sopenharmony_ci			sz += sizeof(*shared) * fobj->shared_max;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		if (!pfence_excl && fence_excl)
4618c2ecf20Sopenharmony_ci			sz += sizeof(*shared);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		if (sz) {
4648c2ecf20Sopenharmony_ci			struct dma_fence **nshared;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci			nshared = krealloc(shared, sz,
4678c2ecf20Sopenharmony_ci					   GFP_NOWAIT | __GFP_NOWARN);
4688c2ecf20Sopenharmony_ci			if (!nshared) {
4698c2ecf20Sopenharmony_ci				rcu_read_unlock();
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci				dma_fence_put(fence_excl);
4728c2ecf20Sopenharmony_ci				fence_excl = NULL;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci				nshared = krealloc(shared, sz, GFP_KERNEL);
4758c2ecf20Sopenharmony_ci				if (nshared) {
4768c2ecf20Sopenharmony_ci					shared = nshared;
4778c2ecf20Sopenharmony_ci					continue;
4788c2ecf20Sopenharmony_ci				}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci				ret = -ENOMEM;
4818c2ecf20Sopenharmony_ci				break;
4828c2ecf20Sopenharmony_ci			}
4838c2ecf20Sopenharmony_ci			shared = nshared;
4848c2ecf20Sopenharmony_ci			shared_count = fobj ? fobj->shared_count : 0;
4858c2ecf20Sopenharmony_ci			for (i = 0; i < shared_count; ++i) {
4868c2ecf20Sopenharmony_ci				shared[i] = rcu_dereference(fobj->shared[i]);
4878c2ecf20Sopenharmony_ci				if (!dma_fence_get_rcu(shared[i]))
4888c2ecf20Sopenharmony_ci					break;
4898c2ecf20Sopenharmony_ci			}
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
4938c2ecf20Sopenharmony_ci			while (i--)
4948c2ecf20Sopenharmony_ci				dma_fence_put(shared[i]);
4958c2ecf20Sopenharmony_ci			dma_fence_put(fence_excl);
4968c2ecf20Sopenharmony_ci			goto unlock;
4978c2ecf20Sopenharmony_ci		}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		ret = 0;
5008c2ecf20Sopenharmony_ciunlock:
5018c2ecf20Sopenharmony_ci		rcu_read_unlock();
5028c2ecf20Sopenharmony_ci	} while (ret);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (pfence_excl)
5058c2ecf20Sopenharmony_ci		*pfence_excl = fence_excl;
5068c2ecf20Sopenharmony_ci	else if (fence_excl)
5078c2ecf20Sopenharmony_ci		shared[shared_count++] = fence_excl;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (!shared_count) {
5108c2ecf20Sopenharmony_ci		kfree(shared);
5118c2ecf20Sopenharmony_ci		shared = NULL;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	*pshared_count = shared_count;
5158c2ecf20Sopenharmony_ci	*pshared = shared;
5168c2ecf20Sopenharmony_ci	return ret;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci/**
5218c2ecf20Sopenharmony_ci * dma_resv_wait_timeout_rcu - Wait on reservation's objects
5228c2ecf20Sopenharmony_ci * shared and/or exclusive fences.
5238c2ecf20Sopenharmony_ci * @obj: the reservation object
5248c2ecf20Sopenharmony_ci * @wait_all: if true, wait on all fences, else wait on just exclusive fence
5258c2ecf20Sopenharmony_ci * @intr: if true, do interruptible wait
5268c2ecf20Sopenharmony_ci * @timeout: timeout value in jiffies or zero to return immediately
5278c2ecf20Sopenharmony_ci *
5288c2ecf20Sopenharmony_ci * RETURNS
5298c2ecf20Sopenharmony_ci * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
5308c2ecf20Sopenharmony_ci * greater than zer on success.
5318c2ecf20Sopenharmony_ci */
5328c2ecf20Sopenharmony_cilong dma_resv_wait_timeout_rcu(struct dma_resv *obj,
5338c2ecf20Sopenharmony_ci			       bool wait_all, bool intr,
5348c2ecf20Sopenharmony_ci			       unsigned long timeout)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct dma_fence *fence;
5378c2ecf20Sopenharmony_ci	unsigned seq, shared_count;
5388c2ecf20Sopenharmony_ci	long ret = timeout ? timeout : 1;
5398c2ecf20Sopenharmony_ci	int i;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ciretry:
5428c2ecf20Sopenharmony_ci	shared_count = 0;
5438c2ecf20Sopenharmony_ci	seq = read_seqcount_begin(&obj->seq);
5448c2ecf20Sopenharmony_ci	rcu_read_lock();
5458c2ecf20Sopenharmony_ci	i = -1;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	fence = rcu_dereference(obj->fence_excl);
5488c2ecf20Sopenharmony_ci	if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
5498c2ecf20Sopenharmony_ci		if (!dma_fence_get_rcu(fence))
5508c2ecf20Sopenharmony_ci			goto unlock_retry;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		if (dma_fence_is_signaled(fence)) {
5538c2ecf20Sopenharmony_ci			dma_fence_put(fence);
5548c2ecf20Sopenharmony_ci			fence = NULL;
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	} else {
5588c2ecf20Sopenharmony_ci		fence = NULL;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (wait_all) {
5628c2ecf20Sopenharmony_ci		struct dma_resv_list *fobj = rcu_dereference(obj->fence);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		if (fobj)
5658c2ecf20Sopenharmony_ci			shared_count = fobj->shared_count;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		for (i = 0; !fence && i < shared_count; ++i) {
5688c2ecf20Sopenharmony_ci			struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
5718c2ecf20Sopenharmony_ci				     &lfence->flags))
5728c2ecf20Sopenharmony_ci				continue;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci			if (!dma_fence_get_rcu(lfence))
5758c2ecf20Sopenharmony_ci				goto unlock_retry;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci			if (dma_fence_is_signaled(lfence)) {
5788c2ecf20Sopenharmony_ci				dma_fence_put(lfence);
5798c2ecf20Sopenharmony_ci				continue;
5808c2ecf20Sopenharmony_ci			}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci			fence = lfence;
5838c2ecf20Sopenharmony_ci			break;
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	rcu_read_unlock();
5888c2ecf20Sopenharmony_ci	if (fence) {
5898c2ecf20Sopenharmony_ci		if (read_seqcount_retry(&obj->seq, seq)) {
5908c2ecf20Sopenharmony_ci			dma_fence_put(fence);
5918c2ecf20Sopenharmony_ci			goto retry;
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci		ret = dma_fence_wait_timeout(fence, intr, ret);
5958c2ecf20Sopenharmony_ci		dma_fence_put(fence);
5968c2ecf20Sopenharmony_ci		if (ret > 0 && wait_all && (i + 1 < shared_count))
5978c2ecf20Sopenharmony_ci			goto retry;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci	return ret;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ciunlock_retry:
6028c2ecf20Sopenharmony_ci	rcu_read_unlock();
6038c2ecf20Sopenharmony_ci	goto retry;
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	struct dma_fence *fence, *lfence = passed_fence;
6118c2ecf20Sopenharmony_ci	int ret = 1;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
6148c2ecf20Sopenharmony_ci		fence = dma_fence_get_rcu(lfence);
6158c2ecf20Sopenharmony_ci		if (!fence)
6168c2ecf20Sopenharmony_ci			return -1;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		ret = !!dma_fence_is_signaled(fence);
6198c2ecf20Sopenharmony_ci		dma_fence_put(fence);
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci	return ret;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci/**
6258c2ecf20Sopenharmony_ci * dma_resv_test_signaled_rcu - Test if a reservation object's
6268c2ecf20Sopenharmony_ci * fences have been signaled.
6278c2ecf20Sopenharmony_ci * @obj: the reservation object
6288c2ecf20Sopenharmony_ci * @test_all: if true, test all fences, otherwise only test the exclusive
6298c2ecf20Sopenharmony_ci * fence
6308c2ecf20Sopenharmony_ci *
6318c2ecf20Sopenharmony_ci * RETURNS
6328c2ecf20Sopenharmony_ci * true if all fences signaled, else false
6338c2ecf20Sopenharmony_ci */
6348c2ecf20Sopenharmony_cibool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	unsigned seq, shared_count;
6378c2ecf20Sopenharmony_ci	int ret;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	rcu_read_lock();
6408c2ecf20Sopenharmony_ciretry:
6418c2ecf20Sopenharmony_ci	ret = true;
6428c2ecf20Sopenharmony_ci	shared_count = 0;
6438c2ecf20Sopenharmony_ci	seq = read_seqcount_begin(&obj->seq);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (test_all) {
6468c2ecf20Sopenharmony_ci		unsigned i;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		struct dma_resv_list *fobj = rcu_dereference(obj->fence);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		if (fobj)
6518c2ecf20Sopenharmony_ci			shared_count = fobj->shared_count;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		for (i = 0; i < shared_count; ++i) {
6548c2ecf20Sopenharmony_ci			struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci			ret = dma_resv_test_signaled_single(fence);
6578c2ecf20Sopenharmony_ci			if (ret < 0)
6588c2ecf20Sopenharmony_ci				goto retry;
6598c2ecf20Sopenharmony_ci			else if (!ret)
6608c2ecf20Sopenharmony_ci				break;
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		if (read_seqcount_retry(&obj->seq, seq))
6648c2ecf20Sopenharmony_ci			goto retry;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (!shared_count) {
6688c2ecf20Sopenharmony_ci		struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci		if (fence_excl) {
6718c2ecf20Sopenharmony_ci			ret = dma_resv_test_signaled_single(fence_excl);
6728c2ecf20Sopenharmony_ci			if (ret < 0)
6738c2ecf20Sopenharmony_ci				goto retry;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci			if (read_seqcount_retry(&obj->seq, seq))
6768c2ecf20Sopenharmony_ci				goto retry;
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci	}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	rcu_read_unlock();
6818c2ecf20Sopenharmony_ci	return ret;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu);
684