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