18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright © 2017 Intel Corporation 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 138c2ecf20Sopenharmony_ci * Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 218c2ecf20Sopenharmony_ci * IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "i915_syncmap.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "i915_gem.h" /* GEM_BUG_ON() */ 308c2ecf20Sopenharmony_ci#include "i915_selftest.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define SHIFT ilog2(KSYNCMAP) 338c2ecf20Sopenharmony_ci#define MASK (KSYNCMAP - 1) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * struct i915_syncmap is a layer of a radixtree that maps a u64 fence 378c2ecf20Sopenharmony_ci * context id to the last u32 fence seqno waited upon from that context. 388c2ecf20Sopenharmony_ci * Unlike lib/radixtree it uses a parent pointer that allows traversal back to 398c2ecf20Sopenharmony_ci * the root. This allows us to access the whole tree via a single pointer 408c2ecf20Sopenharmony_ci * to the most recently used layer. We expect fence contexts to be dense 418c2ecf20Sopenharmony_ci * and most reuse to be on the same i915_gem_context but on neighbouring 428c2ecf20Sopenharmony_ci * engines (i.e. on adjacent contexts) and reuse the same leaf, a very 438c2ecf20Sopenharmony_ci * effective lookup cache. If the new lookup is not on the same leaf, we 448c2ecf20Sopenharmony_ci * expect it to be on the neighbouring branch. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * A leaf holds an array of u32 seqno, and has height 0. The bitmap field 478c2ecf20Sopenharmony_ci * allows us to store whether a particular seqno is valid (i.e. allows us 488c2ecf20Sopenharmony_ci * to distinguish unset from 0). 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * A branch holds an array of layer pointers, and has height > 0, and always 518c2ecf20Sopenharmony_ci * has at least 2 layers (either branches or leaves) below it. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * For example, 548c2ecf20Sopenharmony_ci * for x in 558c2ecf20Sopenharmony_ci * 0 1 2 0x10 0x11 0x200 0x201 568c2ecf20Sopenharmony_ci * 0x500000 0x500001 0x503000 0x503001 578c2ecf20Sopenharmony_ci * 0xE<<60: 588c2ecf20Sopenharmony_ci * i915_syncmap_set(&sync, x, lower_32_bits(x)); 598c2ecf20Sopenharmony_ci * will build a tree like: 608c2ecf20Sopenharmony_ci * 0xXXXXXXXXXXXXXXXX 618c2ecf20Sopenharmony_ci * 0-> 0x0000000000XXXXXX 628c2ecf20Sopenharmony_ci * | 0-> 0x0000000000000XXX 638c2ecf20Sopenharmony_ci * | | 0-> 0x00000000000000XX 648c2ecf20Sopenharmony_ci * | | | 0-> 0x000000000000000X 0:0, 1:1, 2:2 658c2ecf20Sopenharmony_ci * | | | 1-> 0x000000000000001X 0:10, 1:11 668c2ecf20Sopenharmony_ci * | | 2-> 0x000000000000020X 0:200, 1:201 678c2ecf20Sopenharmony_ci * | 5-> 0x000000000050XXXX 688c2ecf20Sopenharmony_ci * | 0-> 0x000000000050000X 0:500000, 1:500001 698c2ecf20Sopenharmony_ci * | 3-> 0x000000000050300X 0:503000, 1:503001 708c2ecf20Sopenharmony_ci * e-> 0xe00000000000000X e:e 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistruct i915_syncmap { 748c2ecf20Sopenharmony_ci u64 prefix; 758c2ecf20Sopenharmony_ci unsigned int height; 768c2ecf20Sopenharmony_ci unsigned int bitmap; 778c2ecf20Sopenharmony_ci struct i915_syncmap *parent; 788c2ecf20Sopenharmony_ci /* 798c2ecf20Sopenharmony_ci * Following this header is an array of either seqno or child pointers: 808c2ecf20Sopenharmony_ci * union { 818c2ecf20Sopenharmony_ci * u32 seqno[KSYNCMAP]; 828c2ecf20Sopenharmony_ci * struct i915_syncmap *child[KSYNCMAP]; 838c2ecf20Sopenharmony_ci * }; 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * i915_syncmap_init -- initialise the #i915_syncmap 898c2ecf20Sopenharmony_ci * @root: pointer to the #i915_syncmap 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_civoid i915_syncmap_init(struct i915_syncmap **root) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci BUILD_BUG_ON_NOT_POWER_OF_2(KSYNCMAP); 948c2ecf20Sopenharmony_ci BUILD_BUG_ON_NOT_POWER_OF_2(SHIFT); 958c2ecf20Sopenharmony_ci BUILD_BUG_ON(KSYNCMAP > BITS_PER_TYPE((*root)->bitmap)); 968c2ecf20Sopenharmony_ci *root = NULL; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic inline u32 *__sync_seqno(struct i915_syncmap *p) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci GEM_BUG_ON(p->height); 1028c2ecf20Sopenharmony_ci return (u32 *)(p + 1); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic inline struct i915_syncmap **__sync_child(struct i915_syncmap *p) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci GEM_BUG_ON(!p->height); 1088c2ecf20Sopenharmony_ci return (struct i915_syncmap **)(p + 1); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline unsigned int 1128c2ecf20Sopenharmony_ci__sync_branch_idx(const struct i915_syncmap *p, u64 id) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci return (id >> p->height) & MASK; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic inline unsigned int 1188c2ecf20Sopenharmony_ci__sync_leaf_idx(const struct i915_syncmap *p, u64 id) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci GEM_BUG_ON(p->height); 1218c2ecf20Sopenharmony_ci return id & MASK; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic inline u64 __sync_branch_prefix(const struct i915_syncmap *p, u64 id) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci return id >> p->height >> SHIFT; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic inline u64 __sync_leaf_prefix(const struct i915_syncmap *p, u64 id) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci GEM_BUG_ON(p->height); 1328c2ecf20Sopenharmony_ci return id >> SHIFT; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic inline bool seqno_later(u32 a, u32 b) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci return (s32)(a - b) >= 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/** 1418c2ecf20Sopenharmony_ci * i915_syncmap_is_later -- compare against the last know sync point 1428c2ecf20Sopenharmony_ci * @root: pointer to the #i915_syncmap 1438c2ecf20Sopenharmony_ci * @id: the context id (other timeline) we are synchronising to 1448c2ecf20Sopenharmony_ci * @seqno: the sequence number along the other timeline 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * If we have already synchronised this @root timeline with another (@id) then 1478c2ecf20Sopenharmony_ci * we can omit any repeated or earlier synchronisation requests. If the two 1488c2ecf20Sopenharmony_ci * timelines are already coupled, we can also omit the dependency between the 1498c2ecf20Sopenharmony_ci * two as that is already known via the timeline. 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * Returns true if the two timelines are already synchronised wrt to @seqno, 1528c2ecf20Sopenharmony_ci * false if not and the synchronisation must be emitted. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_cibool i915_syncmap_is_later(struct i915_syncmap **root, u64 id, u32 seqno) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct i915_syncmap *p; 1578c2ecf20Sopenharmony_ci unsigned int idx; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci p = *root; 1608c2ecf20Sopenharmony_ci if (!p) 1618c2ecf20Sopenharmony_ci return false; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (likely(__sync_leaf_prefix(p, id) == p->prefix)) 1648c2ecf20Sopenharmony_ci goto found; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* First climb the tree back to a parent branch */ 1678c2ecf20Sopenharmony_ci do { 1688c2ecf20Sopenharmony_ci p = p->parent; 1698c2ecf20Sopenharmony_ci if (!p) 1708c2ecf20Sopenharmony_ci return false; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (__sync_branch_prefix(p, id) == p->prefix) 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci } while (1); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* And then descend again until we find our leaf */ 1778c2ecf20Sopenharmony_ci do { 1788c2ecf20Sopenharmony_ci if (!p->height) 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci p = __sync_child(p)[__sync_branch_idx(p, id)]; 1828c2ecf20Sopenharmony_ci if (!p) 1838c2ecf20Sopenharmony_ci return false; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (__sync_branch_prefix(p, id) != p->prefix) 1868c2ecf20Sopenharmony_ci return false; 1878c2ecf20Sopenharmony_ci } while (1); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci *root = p; 1908c2ecf20Sopenharmony_cifound: 1918c2ecf20Sopenharmony_ci idx = __sync_leaf_idx(p, id); 1928c2ecf20Sopenharmony_ci if (!(p->bitmap & BIT(idx))) 1938c2ecf20Sopenharmony_ci return false; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return seqno_later(__sync_seqno(p)[idx], seqno); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic struct i915_syncmap * 1998c2ecf20Sopenharmony_ci__sync_alloc_leaf(struct i915_syncmap *parent, u64 id) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct i915_syncmap *p; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci p = kmalloc(sizeof(*p) + KSYNCMAP * sizeof(u32), GFP_KERNEL); 2048c2ecf20Sopenharmony_ci if (unlikely(!p)) 2058c2ecf20Sopenharmony_ci return NULL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci p->parent = parent; 2088c2ecf20Sopenharmony_ci p->height = 0; 2098c2ecf20Sopenharmony_ci p->bitmap = 0; 2108c2ecf20Sopenharmony_ci p->prefix = __sync_leaf_prefix(p, id); 2118c2ecf20Sopenharmony_ci return p; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic inline void __sync_set_seqno(struct i915_syncmap *p, u64 id, u32 seqno) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci unsigned int idx = __sync_leaf_idx(p, id); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci p->bitmap |= BIT(idx); 2198c2ecf20Sopenharmony_ci __sync_seqno(p)[idx] = seqno; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic inline void __sync_set_child(struct i915_syncmap *p, 2238c2ecf20Sopenharmony_ci unsigned int idx, 2248c2ecf20Sopenharmony_ci struct i915_syncmap *child) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci p->bitmap |= BIT(idx); 2278c2ecf20Sopenharmony_ci __sync_child(p)[idx] = child; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic noinline int __sync_set(struct i915_syncmap **root, u64 id, u32 seqno) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct i915_syncmap *p = *root; 2338c2ecf20Sopenharmony_ci unsigned int idx; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!p) { 2368c2ecf20Sopenharmony_ci p = __sync_alloc_leaf(NULL, id); 2378c2ecf20Sopenharmony_ci if (unlikely(!p)) 2388c2ecf20Sopenharmony_ci return -ENOMEM; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci goto found; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Caller handled the likely cached case */ 2448c2ecf20Sopenharmony_ci GEM_BUG_ON(__sync_leaf_prefix(p, id) == p->prefix); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Climb back up the tree until we find a common prefix */ 2478c2ecf20Sopenharmony_ci do { 2488c2ecf20Sopenharmony_ci if (!p->parent) 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci p = p->parent; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (__sync_branch_prefix(p, id) == p->prefix) 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci } while (1); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * No shortcut, we have to descend the tree to find the right layer 2598c2ecf20Sopenharmony_ci * containing this fence. 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * Each layer in the tree holds 16 (KSYNCMAP) pointers, either fences 2628c2ecf20Sopenharmony_ci * or lower layers. Leaf nodes (height = 0) contain the fences, all 2638c2ecf20Sopenharmony_ci * other nodes (height > 0) are internal layers that point to a lower 2648c2ecf20Sopenharmony_ci * node. Each internal layer has at least 2 descendents. 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * Starting at the top, we check whether the current prefix matches. If 2678c2ecf20Sopenharmony_ci * it doesn't, we have gone past our target and need to insert a join 2688c2ecf20Sopenharmony_ci * into the tree, and a new leaf node for the target as a descendent 2698c2ecf20Sopenharmony_ci * of the join, as well as the original layer. 2708c2ecf20Sopenharmony_ci * 2718c2ecf20Sopenharmony_ci * The matching prefix means we are still following the right branch 2728c2ecf20Sopenharmony_ci * of the tree. If it has height 0, we have found our leaf and just 2738c2ecf20Sopenharmony_ci * need to replace the fence slot with ourselves. If the height is 2748c2ecf20Sopenharmony_ci * not zero, our slot contains the next layer in the tree (unless 2758c2ecf20Sopenharmony_ci * it is empty, in which case we can add ourselves as a new leaf). 2768c2ecf20Sopenharmony_ci * As descend the tree the prefix grows (and height decreases). 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci do { 2798c2ecf20Sopenharmony_ci struct i915_syncmap *next; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (__sync_branch_prefix(p, id) != p->prefix) { 2828c2ecf20Sopenharmony_ci unsigned int above; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Insert a join above the current layer */ 2858c2ecf20Sopenharmony_ci next = kzalloc(sizeof(*next) + KSYNCMAP * sizeof(next), 2868c2ecf20Sopenharmony_ci GFP_KERNEL); 2878c2ecf20Sopenharmony_ci if (unlikely(!next)) 2888c2ecf20Sopenharmony_ci return -ENOMEM; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Compute the height at which these two diverge */ 2918c2ecf20Sopenharmony_ci above = fls64(__sync_branch_prefix(p, id) ^ p->prefix); 2928c2ecf20Sopenharmony_ci above = round_up(above, SHIFT); 2938c2ecf20Sopenharmony_ci next->height = above + p->height; 2948c2ecf20Sopenharmony_ci next->prefix = __sync_branch_prefix(next, id); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Insert the join into the parent */ 2978c2ecf20Sopenharmony_ci if (p->parent) { 2988c2ecf20Sopenharmony_ci idx = __sync_branch_idx(p->parent, id); 2998c2ecf20Sopenharmony_ci __sync_child(p->parent)[idx] = next; 3008c2ecf20Sopenharmony_ci GEM_BUG_ON(!(p->parent->bitmap & BIT(idx))); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci next->parent = p->parent; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Compute the idx of the other branch, not our id! */ 3058c2ecf20Sopenharmony_ci idx = p->prefix >> (above - SHIFT) & MASK; 3068c2ecf20Sopenharmony_ci __sync_set_child(next, idx, p); 3078c2ecf20Sopenharmony_ci p->parent = next; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* Ascend to the join */ 3108c2ecf20Sopenharmony_ci p = next; 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci if (!p->height) 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Descend into the next layer */ 3178c2ecf20Sopenharmony_ci GEM_BUG_ON(!p->height); 3188c2ecf20Sopenharmony_ci idx = __sync_branch_idx(p, id); 3198c2ecf20Sopenharmony_ci next = __sync_child(p)[idx]; 3208c2ecf20Sopenharmony_ci if (!next) { 3218c2ecf20Sopenharmony_ci next = __sync_alloc_leaf(p, id); 3228c2ecf20Sopenharmony_ci if (unlikely(!next)) 3238c2ecf20Sopenharmony_ci return -ENOMEM; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci __sync_set_child(p, idx, next); 3268c2ecf20Sopenharmony_ci p = next; 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci p = next; 3318c2ecf20Sopenharmony_ci } while (1); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cifound: 3348c2ecf20Sopenharmony_ci GEM_BUG_ON(p->prefix != __sync_leaf_prefix(p, id)); 3358c2ecf20Sopenharmony_ci __sync_set_seqno(p, id, seqno); 3368c2ecf20Sopenharmony_ci *root = p; 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/** 3418c2ecf20Sopenharmony_ci * i915_syncmap_set -- mark the most recent syncpoint between contexts 3428c2ecf20Sopenharmony_ci * @root: pointer to the #i915_syncmap 3438c2ecf20Sopenharmony_ci * @id: the context id (other timeline) we have synchronised to 3448c2ecf20Sopenharmony_ci * @seqno: the sequence number along the other timeline 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * When we synchronise this @root timeline with another (@id), we also know 3478c2ecf20Sopenharmony_ci * that we have synchronized with all previous seqno along that timeline. If 3488c2ecf20Sopenharmony_ci * we then have a request to synchronise with the same seqno or older, we can 3498c2ecf20Sopenharmony_ci * omit it, see i915_syncmap_is_later() 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * Returns 0 on success, or a negative error code. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ciint i915_syncmap_set(struct i915_syncmap **root, u64 id, u32 seqno) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct i915_syncmap *p = *root; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * We expect to be called in sequence following is_later(id), which 3598c2ecf20Sopenharmony_ci * should have preloaded the root for us. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci if (likely(p && __sync_leaf_prefix(p, id) == p->prefix)) { 3628c2ecf20Sopenharmony_ci __sync_set_seqno(p, id, seqno); 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return __sync_set(root, id, seqno); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic void __sync_free(struct i915_syncmap *p) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci if (p->height) { 3728c2ecf20Sopenharmony_ci unsigned int i; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci while ((i = ffs(p->bitmap))) { 3758c2ecf20Sopenharmony_ci p->bitmap &= ~0u << i; 3768c2ecf20Sopenharmony_ci __sync_free(__sync_child(p)[i - 1]); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci kfree(p); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/** 3848c2ecf20Sopenharmony_ci * i915_syncmap_free -- free all memory associated with the syncmap 3858c2ecf20Sopenharmony_ci * @root: pointer to the #i915_syncmap 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * Either when the timeline is to be freed and we no longer need the sync 3888c2ecf20Sopenharmony_ci * point tracking, or when the fences are all known to be signaled and the 3898c2ecf20Sopenharmony_ci * sync point tracking is redundant, we can free the #i915_syncmap to recover 3908c2ecf20Sopenharmony_ci * its allocations. 3918c2ecf20Sopenharmony_ci * 3928c2ecf20Sopenharmony_ci * Will reinitialise the @root pointer so that the #i915_syncmap is ready for 3938c2ecf20Sopenharmony_ci * reuse. 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_civoid i915_syncmap_free(struct i915_syncmap **root) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct i915_syncmap *p; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci p = *root; 4008c2ecf20Sopenharmony_ci if (!p) 4018c2ecf20Sopenharmony_ci return; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci while (p->parent) 4048c2ecf20Sopenharmony_ci p = p->parent; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci __sync_free(p); 4078c2ecf20Sopenharmony_ci *root = NULL; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 4118c2ecf20Sopenharmony_ci#include "selftests/i915_syncmap.c" 4128c2ecf20Sopenharmony_ci#endif 413