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