162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright © 2017 Intel Corporation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next 1262306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 1362306a36Sopenharmony_ci * Software. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1862306a36Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1962306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2062306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2162306a36Sopenharmony_ci * IN THE SOFTWARE. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "i915_syncmap.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "i915_gem.h" /* GEM_BUG_ON() */ 3062306a36Sopenharmony_ci#include "i915_selftest.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define SHIFT ilog2(KSYNCMAP) 3362306a36Sopenharmony_ci#define MASK (KSYNCMAP - 1) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * struct i915_syncmap is a layer of a radixtree that maps a u64 fence 3762306a36Sopenharmony_ci * context id to the last u32 fence seqno waited upon from that context. 3862306a36Sopenharmony_ci * Unlike lib/radixtree it uses a parent pointer that allows traversal back to 3962306a36Sopenharmony_ci * the root. This allows us to access the whole tree via a single pointer 4062306a36Sopenharmony_ci * to the most recently used layer. We expect fence contexts to be dense 4162306a36Sopenharmony_ci * and most reuse to be on the same i915_gem_context but on neighbouring 4262306a36Sopenharmony_ci * engines (i.e. on adjacent contexts) and reuse the same leaf, a very 4362306a36Sopenharmony_ci * effective lookup cache. If the new lookup is not on the same leaf, we 4462306a36Sopenharmony_ci * expect it to be on the neighbouring branch. 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * A leaf holds an array of u32 seqno, and has height 0. The bitmap field 4762306a36Sopenharmony_ci * allows us to store whether a particular seqno is valid (i.e. allows us 4862306a36Sopenharmony_ci * to distinguish unset from 0). 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * A branch holds an array of layer pointers, and has height > 0, and always 5162306a36Sopenharmony_ci * has at least 2 layers (either branches or leaves) below it. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * For example, 5462306a36Sopenharmony_ci * for x in 5562306a36Sopenharmony_ci * 0 1 2 0x10 0x11 0x200 0x201 5662306a36Sopenharmony_ci * 0x500000 0x500001 0x503000 0x503001 5762306a36Sopenharmony_ci * 0xE<<60: 5862306a36Sopenharmony_ci * i915_syncmap_set(&sync, x, lower_32_bits(x)); 5962306a36Sopenharmony_ci * will build a tree like: 6062306a36Sopenharmony_ci * 0xXXXXXXXXXXXXXXXX 6162306a36Sopenharmony_ci * 0-> 0x0000000000XXXXXX 6262306a36Sopenharmony_ci * | 0-> 0x0000000000000XXX 6362306a36Sopenharmony_ci * | | 0-> 0x00000000000000XX 6462306a36Sopenharmony_ci * | | | 0-> 0x000000000000000X 0:0, 1:1, 2:2 6562306a36Sopenharmony_ci * | | | 1-> 0x000000000000001X 0:10, 1:11 6662306a36Sopenharmony_ci * | | 2-> 0x000000000000020X 0:200, 1:201 6762306a36Sopenharmony_ci * | 5-> 0x000000000050XXXX 6862306a36Sopenharmony_ci * | 0-> 0x000000000050000X 0:500000, 1:500001 6962306a36Sopenharmony_ci * | 3-> 0x000000000050300X 0:503000, 1:503001 7062306a36Sopenharmony_ci * e-> 0xe00000000000000X e:e 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct i915_syncmap { 7462306a36Sopenharmony_ci u64 prefix; 7562306a36Sopenharmony_ci unsigned int height; 7662306a36Sopenharmony_ci unsigned int bitmap; 7762306a36Sopenharmony_ci struct i915_syncmap *parent; 7862306a36Sopenharmony_ci /* 7962306a36Sopenharmony_ci * Following this header is an array of either seqno or child pointers: 8062306a36Sopenharmony_ci * union { 8162306a36Sopenharmony_ci * u32 seqno[KSYNCMAP]; 8262306a36Sopenharmony_ci * struct i915_syncmap *child[KSYNCMAP]; 8362306a36Sopenharmony_ci * }; 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/** 8862306a36Sopenharmony_ci * i915_syncmap_init -- initialise the #i915_syncmap 8962306a36Sopenharmony_ci * @root: pointer to the #i915_syncmap 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_civoid i915_syncmap_init(struct i915_syncmap **root) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci BUILD_BUG_ON_NOT_POWER_OF_2(KSYNCMAP); 9462306a36Sopenharmony_ci BUILD_BUG_ON_NOT_POWER_OF_2(SHIFT); 9562306a36Sopenharmony_ci BUILD_BUG_ON(KSYNCMAP > BITS_PER_TYPE((*root)->bitmap)); 9662306a36Sopenharmony_ci *root = NULL; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic inline u32 *__sync_seqno(struct i915_syncmap *p) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci GEM_BUG_ON(p->height); 10262306a36Sopenharmony_ci return (u32 *)(p + 1); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic inline struct i915_syncmap **__sync_child(struct i915_syncmap *p) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci GEM_BUG_ON(!p->height); 10862306a36Sopenharmony_ci return (struct i915_syncmap **)(p + 1); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic inline unsigned int 11262306a36Sopenharmony_ci__sync_branch_idx(const struct i915_syncmap *p, u64 id) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci return (id >> p->height) & MASK; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline unsigned int 11862306a36Sopenharmony_ci__sync_leaf_idx(const struct i915_syncmap *p, u64 id) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci GEM_BUG_ON(p->height); 12162306a36Sopenharmony_ci return id & MASK; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic inline u64 __sync_branch_prefix(const struct i915_syncmap *p, u64 id) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci return id >> p->height >> SHIFT; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic inline u64 __sync_leaf_prefix(const struct i915_syncmap *p, u64 id) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci GEM_BUG_ON(p->height); 13262306a36Sopenharmony_ci return id >> SHIFT; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic inline bool seqno_later(u32 a, u32 b) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return (s32)(a - b) >= 0; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/** 14162306a36Sopenharmony_ci * i915_syncmap_is_later -- compare against the last know sync point 14262306a36Sopenharmony_ci * @root: pointer to the #i915_syncmap 14362306a36Sopenharmony_ci * @id: the context id (other timeline) we are synchronising to 14462306a36Sopenharmony_ci * @seqno: the sequence number along the other timeline 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * If we have already synchronised this @root timeline with another (@id) then 14762306a36Sopenharmony_ci * we can omit any repeated or earlier synchronisation requests. If the two 14862306a36Sopenharmony_ci * timelines are already coupled, we can also omit the dependency between the 14962306a36Sopenharmony_ci * two as that is already known via the timeline. 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * Returns true if the two timelines are already synchronised wrt to @seqno, 15262306a36Sopenharmony_ci * false if not and the synchronisation must be emitted. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_cibool i915_syncmap_is_later(struct i915_syncmap **root, u64 id, u32 seqno) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct i915_syncmap *p; 15762306a36Sopenharmony_ci unsigned int idx; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci p = *root; 16062306a36Sopenharmony_ci if (!p) 16162306a36Sopenharmony_ci return false; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (likely(__sync_leaf_prefix(p, id) == p->prefix)) 16462306a36Sopenharmony_ci goto found; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* First climb the tree back to a parent branch */ 16762306a36Sopenharmony_ci do { 16862306a36Sopenharmony_ci p = p->parent; 16962306a36Sopenharmony_ci if (!p) 17062306a36Sopenharmony_ci return false; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (__sync_branch_prefix(p, id) == p->prefix) 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci } while (1); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* And then descend again until we find our leaf */ 17762306a36Sopenharmony_ci do { 17862306a36Sopenharmony_ci if (!p->height) 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci p = __sync_child(p)[__sync_branch_idx(p, id)]; 18262306a36Sopenharmony_ci if (!p) 18362306a36Sopenharmony_ci return false; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (__sync_branch_prefix(p, id) != p->prefix) 18662306a36Sopenharmony_ci return false; 18762306a36Sopenharmony_ci } while (1); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci *root = p; 19062306a36Sopenharmony_cifound: 19162306a36Sopenharmony_ci idx = __sync_leaf_idx(p, id); 19262306a36Sopenharmony_ci if (!(p->bitmap & BIT(idx))) 19362306a36Sopenharmony_ci return false; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return seqno_later(__sync_seqno(p)[idx], seqno); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic struct i915_syncmap * 19962306a36Sopenharmony_ci__sync_alloc_leaf(struct i915_syncmap *parent, u64 id) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct i915_syncmap *p; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci p = kmalloc(sizeof(*p) + KSYNCMAP * sizeof(u32), GFP_KERNEL); 20462306a36Sopenharmony_ci if (unlikely(!p)) 20562306a36Sopenharmony_ci return NULL; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci p->parent = parent; 20862306a36Sopenharmony_ci p->height = 0; 20962306a36Sopenharmony_ci p->bitmap = 0; 21062306a36Sopenharmony_ci p->prefix = __sync_leaf_prefix(p, id); 21162306a36Sopenharmony_ci return p; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic inline void __sync_set_seqno(struct i915_syncmap *p, u64 id, u32 seqno) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci unsigned int idx = __sync_leaf_idx(p, id); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci p->bitmap |= BIT(idx); 21962306a36Sopenharmony_ci __sync_seqno(p)[idx] = seqno; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic inline void __sync_set_child(struct i915_syncmap *p, 22362306a36Sopenharmony_ci unsigned int idx, 22462306a36Sopenharmony_ci struct i915_syncmap *child) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci p->bitmap |= BIT(idx); 22762306a36Sopenharmony_ci __sync_child(p)[idx] = child; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic noinline int __sync_set(struct i915_syncmap **root, u64 id, u32 seqno) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct i915_syncmap *p = *root; 23362306a36Sopenharmony_ci unsigned int idx; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (!p) { 23662306a36Sopenharmony_ci p = __sync_alloc_leaf(NULL, id); 23762306a36Sopenharmony_ci if (unlikely(!p)) 23862306a36Sopenharmony_ci return -ENOMEM; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci goto found; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Caller handled the likely cached case */ 24462306a36Sopenharmony_ci GEM_BUG_ON(__sync_leaf_prefix(p, id) == p->prefix); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Climb back up the tree until we find a common prefix */ 24762306a36Sopenharmony_ci do { 24862306a36Sopenharmony_ci if (!p->parent) 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci p = p->parent; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (__sync_branch_prefix(p, id) == p->prefix) 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci } while (1); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * No shortcut, we have to descend the tree to find the right layer 25962306a36Sopenharmony_ci * containing this fence. 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Each layer in the tree holds 16 (KSYNCMAP) pointers, either fences 26262306a36Sopenharmony_ci * or lower layers. Leaf nodes (height = 0) contain the fences, all 26362306a36Sopenharmony_ci * other nodes (height > 0) are internal layers that point to a lower 26462306a36Sopenharmony_ci * node. Each internal layer has at least 2 descendents. 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * Starting at the top, we check whether the current prefix matches. If 26762306a36Sopenharmony_ci * it doesn't, we have gone past our target and need to insert a join 26862306a36Sopenharmony_ci * into the tree, and a new leaf node for the target as a descendent 26962306a36Sopenharmony_ci * of the join, as well as the original layer. 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * The matching prefix means we are still following the right branch 27262306a36Sopenharmony_ci * of the tree. If it has height 0, we have found our leaf and just 27362306a36Sopenharmony_ci * need to replace the fence slot with ourselves. If the height is 27462306a36Sopenharmony_ci * not zero, our slot contains the next layer in the tree (unless 27562306a36Sopenharmony_ci * it is empty, in which case we can add ourselves as a new leaf). 27662306a36Sopenharmony_ci * As descend the tree the prefix grows (and height decreases). 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci do { 27962306a36Sopenharmony_ci struct i915_syncmap *next; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (__sync_branch_prefix(p, id) != p->prefix) { 28262306a36Sopenharmony_ci unsigned int above; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Insert a join above the current layer */ 28562306a36Sopenharmony_ci next = kzalloc(sizeof(*next) + KSYNCMAP * sizeof(next), 28662306a36Sopenharmony_ci GFP_KERNEL); 28762306a36Sopenharmony_ci if (unlikely(!next)) 28862306a36Sopenharmony_ci return -ENOMEM; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Compute the height at which these two diverge */ 29162306a36Sopenharmony_ci above = fls64(__sync_branch_prefix(p, id) ^ p->prefix); 29262306a36Sopenharmony_ci above = round_up(above, SHIFT); 29362306a36Sopenharmony_ci next->height = above + p->height; 29462306a36Sopenharmony_ci next->prefix = __sync_branch_prefix(next, id); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* Insert the join into the parent */ 29762306a36Sopenharmony_ci if (p->parent) { 29862306a36Sopenharmony_ci idx = __sync_branch_idx(p->parent, id); 29962306a36Sopenharmony_ci __sync_child(p->parent)[idx] = next; 30062306a36Sopenharmony_ci GEM_BUG_ON(!(p->parent->bitmap & BIT(idx))); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci next->parent = p->parent; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Compute the idx of the other branch, not our id! */ 30562306a36Sopenharmony_ci idx = p->prefix >> (above - SHIFT) & MASK; 30662306a36Sopenharmony_ci __sync_set_child(next, idx, p); 30762306a36Sopenharmony_ci p->parent = next; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Ascend to the join */ 31062306a36Sopenharmony_ci p = next; 31162306a36Sopenharmony_ci } else { 31262306a36Sopenharmony_ci if (!p->height) 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Descend into the next layer */ 31762306a36Sopenharmony_ci GEM_BUG_ON(!p->height); 31862306a36Sopenharmony_ci idx = __sync_branch_idx(p, id); 31962306a36Sopenharmony_ci next = __sync_child(p)[idx]; 32062306a36Sopenharmony_ci if (!next) { 32162306a36Sopenharmony_ci next = __sync_alloc_leaf(p, id); 32262306a36Sopenharmony_ci if (unlikely(!next)) 32362306a36Sopenharmony_ci return -ENOMEM; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci __sync_set_child(p, idx, next); 32662306a36Sopenharmony_ci p = next; 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci p = next; 33162306a36Sopenharmony_ci } while (1); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cifound: 33462306a36Sopenharmony_ci GEM_BUG_ON(p->prefix != __sync_leaf_prefix(p, id)); 33562306a36Sopenharmony_ci __sync_set_seqno(p, id, seqno); 33662306a36Sopenharmony_ci *root = p; 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/** 34162306a36Sopenharmony_ci * i915_syncmap_set -- mark the most recent syncpoint between contexts 34262306a36Sopenharmony_ci * @root: pointer to the #i915_syncmap 34362306a36Sopenharmony_ci * @id: the context id (other timeline) we have synchronised to 34462306a36Sopenharmony_ci * @seqno: the sequence number along the other timeline 34562306a36Sopenharmony_ci * 34662306a36Sopenharmony_ci * When we synchronise this @root timeline with another (@id), we also know 34762306a36Sopenharmony_ci * that we have synchronized with all previous seqno along that timeline. If 34862306a36Sopenharmony_ci * we then have a request to synchronise with the same seqno or older, we can 34962306a36Sopenharmony_ci * omit it, see i915_syncmap_is_later() 35062306a36Sopenharmony_ci * 35162306a36Sopenharmony_ci * Returns 0 on success, or a negative error code. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ciint i915_syncmap_set(struct i915_syncmap **root, u64 id, u32 seqno) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct i915_syncmap *p = *root; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * We expect to be called in sequence following is_later(id), which 35962306a36Sopenharmony_ci * should have preloaded the root for us. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci if (likely(p && __sync_leaf_prefix(p, id) == p->prefix)) { 36262306a36Sopenharmony_ci __sync_set_seqno(p, id, seqno); 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return __sync_set(root, id, seqno); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void __sync_free(struct i915_syncmap *p) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci if (p->height) { 37262306a36Sopenharmony_ci unsigned int i; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci while ((i = ffs(p->bitmap))) { 37562306a36Sopenharmony_ci p->bitmap &= ~0u << i; 37662306a36Sopenharmony_ci __sync_free(__sync_child(p)[i - 1]); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci kfree(p); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/** 38462306a36Sopenharmony_ci * i915_syncmap_free -- free all memory associated with the syncmap 38562306a36Sopenharmony_ci * @root: pointer to the #i915_syncmap 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * Either when the timeline is to be freed and we no longer need the sync 38862306a36Sopenharmony_ci * point tracking, or when the fences are all known to be signaled and the 38962306a36Sopenharmony_ci * sync point tracking is redundant, we can free the #i915_syncmap to recover 39062306a36Sopenharmony_ci * its allocations. 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * Will reinitialise the @root pointer so that the #i915_syncmap is ready for 39362306a36Sopenharmony_ci * reuse. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_civoid i915_syncmap_free(struct i915_syncmap **root) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct i915_syncmap *p; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci p = *root; 40062306a36Sopenharmony_ci if (!p) 40162306a36Sopenharmony_ci return; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci while (p->parent) 40462306a36Sopenharmony_ci p = p->parent; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci __sync_free(p); 40762306a36Sopenharmony_ci *root = NULL; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 41162306a36Sopenharmony_ci#include "selftests/i915_syncmap.c" 41262306a36Sopenharmony_ci#endif 413