xref: /linux/drivers/gpu/drm/xe/xe_range_fence.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1845f64bdSThomas Hellström // SPDX-License-Identifier: MIT
2845f64bdSThomas Hellström /*
3845f64bdSThomas Hellström  * Copyright © 2023 Intel Corporation
4845f64bdSThomas Hellström  */
5845f64bdSThomas Hellström 
6845f64bdSThomas Hellström #include <linux/dma-fence.h>
7845f64bdSThomas Hellström #include <linux/interval_tree_generic.h>
8845f64bdSThomas Hellström #include <linux/slab.h>
9845f64bdSThomas Hellström 
10845f64bdSThomas Hellström #include "xe_macros.h"
11845f64bdSThomas Hellström #include "xe_range_fence.h"
12845f64bdSThomas Hellström 
13845f64bdSThomas Hellström #define XE_RANGE_TREE_START(_node)	((_node)->start)
14845f64bdSThomas Hellström #define XE_RANGE_TREE_LAST(_node)	((_node)->last)
15845f64bdSThomas Hellström 
16845f64bdSThomas Hellström INTERVAL_TREE_DEFINE(struct xe_range_fence, rb, u64, __subtree_last,
17845f64bdSThomas Hellström 		     XE_RANGE_TREE_START, XE_RANGE_TREE_LAST, static,
18845f64bdSThomas Hellström 		     xe_range_fence_tree);
19845f64bdSThomas Hellström 
20845f64bdSThomas Hellström static void
xe_range_fence_signal_notify(struct dma_fence * fence,struct dma_fence_cb * cb)21845f64bdSThomas Hellström xe_range_fence_signal_notify(struct dma_fence *fence, struct dma_fence_cb *cb)
22845f64bdSThomas Hellström {
23845f64bdSThomas Hellström 	struct xe_range_fence *rfence = container_of(cb, typeof(*rfence), cb);
24845f64bdSThomas Hellström 	struct xe_range_fence_tree *tree = rfence->tree;
25845f64bdSThomas Hellström 
26845f64bdSThomas Hellström 	llist_add(&rfence->link, &tree->list);
27845f64bdSThomas Hellström }
28845f64bdSThomas Hellström 
__xe_range_fence_tree_cleanup(struct xe_range_fence_tree * tree)29845f64bdSThomas Hellström static bool __xe_range_fence_tree_cleanup(struct xe_range_fence_tree *tree)
30845f64bdSThomas Hellström {
31845f64bdSThomas Hellström 	struct llist_node *node = llist_del_all(&tree->list);
32845f64bdSThomas Hellström 	struct xe_range_fence *rfence, *next;
33845f64bdSThomas Hellström 
34845f64bdSThomas Hellström 	llist_for_each_entry_safe(rfence, next, node, link) {
35845f64bdSThomas Hellström 		xe_range_fence_tree_remove(rfence, &tree->root);
36845f64bdSThomas Hellström 		dma_fence_put(rfence->fence);
37845f64bdSThomas Hellström 		kfree(rfence);
38845f64bdSThomas Hellström 	}
39845f64bdSThomas Hellström 
40845f64bdSThomas Hellström 	return !!node;
41845f64bdSThomas Hellström }
42845f64bdSThomas Hellström 
43845f64bdSThomas Hellström /**
44845f64bdSThomas Hellström  * xe_range_fence_insert() - range fence insert
45845f64bdSThomas Hellström  * @tree: range fence tree to insert intoi
46845f64bdSThomas Hellström  * @rfence: range fence
47845f64bdSThomas Hellström  * @ops: range fence ops
48845f64bdSThomas Hellström  * @start: start address of range fence
49845f64bdSThomas Hellström  * @last: last address of range fence
50845f64bdSThomas Hellström  * @fence: dma fence which signals range fence can be removed + freed
51845f64bdSThomas Hellström  *
52845f64bdSThomas Hellström  * Return: 0 on success, non-zero on failure
53845f64bdSThomas Hellström  */
xe_range_fence_insert(struct xe_range_fence_tree * tree,struct xe_range_fence * rfence,const struct xe_range_fence_ops * ops,u64 start,u64 last,struct dma_fence * fence)54845f64bdSThomas Hellström int xe_range_fence_insert(struct xe_range_fence_tree *tree,
55845f64bdSThomas Hellström 			  struct xe_range_fence *rfence,
56845f64bdSThomas Hellström 			  const struct xe_range_fence_ops *ops,
57845f64bdSThomas Hellström 			  u64 start, u64 last, struct dma_fence *fence)
58845f64bdSThomas Hellström {
59845f64bdSThomas Hellström 	int err = 0;
60845f64bdSThomas Hellström 
61845f64bdSThomas Hellström 	__xe_range_fence_tree_cleanup(tree);
62845f64bdSThomas Hellström 
63845f64bdSThomas Hellström 	if (dma_fence_is_signaled(fence))
64845f64bdSThomas Hellström 		goto free;
65845f64bdSThomas Hellström 
66845f64bdSThomas Hellström 	rfence->ops = ops;
67845f64bdSThomas Hellström 	rfence->start = start;
68845f64bdSThomas Hellström 	rfence->last = last;
69845f64bdSThomas Hellström 	rfence->tree = tree;
70845f64bdSThomas Hellström 	rfence->fence = dma_fence_get(fence);
71845f64bdSThomas Hellström 	err = dma_fence_add_callback(fence, &rfence->cb,
72845f64bdSThomas Hellström 				     xe_range_fence_signal_notify);
73845f64bdSThomas Hellström 	if (err == -ENOENT) {
74845f64bdSThomas Hellström 		dma_fence_put(fence);
75845f64bdSThomas Hellström 		err = 0;
76845f64bdSThomas Hellström 		goto free;
77845f64bdSThomas Hellström 	} else if (err == 0) {
78845f64bdSThomas Hellström 		xe_range_fence_tree_insert(rfence, &tree->root);
79845f64bdSThomas Hellström 		return 0;
80845f64bdSThomas Hellström 	}
81845f64bdSThomas Hellström 
82845f64bdSThomas Hellström free:
83845f64bdSThomas Hellström 	if (ops->free)
84845f64bdSThomas Hellström 		ops->free(rfence);
85845f64bdSThomas Hellström 
86845f64bdSThomas Hellström 	return err;
87845f64bdSThomas Hellström }
88845f64bdSThomas Hellström 
xe_range_fence_tree_remove_all(struct xe_range_fence_tree * tree)89845f64bdSThomas Hellström static void xe_range_fence_tree_remove_all(struct xe_range_fence_tree *tree)
90845f64bdSThomas Hellström {
91845f64bdSThomas Hellström 	struct xe_range_fence *rfence;
92845f64bdSThomas Hellström 	bool retry = true;
93845f64bdSThomas Hellström 
94845f64bdSThomas Hellström 	rfence = xe_range_fence_tree_iter_first(&tree->root, 0, U64_MAX);
95845f64bdSThomas Hellström 	while (rfence) {
96845f64bdSThomas Hellström 		/* Should be ok with the minimalistic callback */
97845f64bdSThomas Hellström 		if (dma_fence_remove_callback(rfence->fence, &rfence->cb))
98845f64bdSThomas Hellström 			llist_add(&rfence->link, &tree->list);
99845f64bdSThomas Hellström 		rfence = xe_range_fence_tree_iter_next(rfence, 0, U64_MAX);
100845f64bdSThomas Hellström 	}
101845f64bdSThomas Hellström 
102845f64bdSThomas Hellström 	while (retry)
103845f64bdSThomas Hellström 		retry = __xe_range_fence_tree_cleanup(tree);
104845f64bdSThomas Hellström }
105845f64bdSThomas Hellström 
106845f64bdSThomas Hellström /**
107845f64bdSThomas Hellström  * xe_range_fence_tree_init() - Init range fence tree
108845f64bdSThomas Hellström  * @tree: range fence tree
109845f64bdSThomas Hellström  */
xe_range_fence_tree_init(struct xe_range_fence_tree * tree)110845f64bdSThomas Hellström void xe_range_fence_tree_init(struct xe_range_fence_tree *tree)
111845f64bdSThomas Hellström {
112845f64bdSThomas Hellström 	memset(tree, 0, sizeof(*tree));
113845f64bdSThomas Hellström }
114845f64bdSThomas Hellström 
115845f64bdSThomas Hellström /**
116845f64bdSThomas Hellström  * xe_range_fence_tree_fini() - Fini range fence tree
117845f64bdSThomas Hellström  * @tree: range fence tree
118845f64bdSThomas Hellström  */
xe_range_fence_tree_fini(struct xe_range_fence_tree * tree)119845f64bdSThomas Hellström void xe_range_fence_tree_fini(struct xe_range_fence_tree *tree)
120845f64bdSThomas Hellström {
121845f64bdSThomas Hellström 	xe_range_fence_tree_remove_all(tree);
122845f64bdSThomas Hellström 	XE_WARN_ON(!RB_EMPTY_ROOT(&tree->root.rb_root));
123845f64bdSThomas Hellström }
124845f64bdSThomas Hellström 
125845f64bdSThomas Hellström /**
126845f64bdSThomas Hellström  * xe_range_fence_tree_first() - range fence tree iterator first
127845f64bdSThomas Hellström  * @tree: range fence tree
128845f64bdSThomas Hellström  * @start: start address of range fence
129845f64bdSThomas Hellström  * @last: last address of range fence
130845f64bdSThomas Hellström  *
131845f64bdSThomas Hellström  * Return: first range fence found in range or NULL
132845f64bdSThomas Hellström  */
133845f64bdSThomas Hellström struct xe_range_fence *
xe_range_fence_tree_first(struct xe_range_fence_tree * tree,u64 start,u64 last)134845f64bdSThomas Hellström xe_range_fence_tree_first(struct xe_range_fence_tree *tree, u64 start,
135845f64bdSThomas Hellström 			  u64 last)
136845f64bdSThomas Hellström {
137845f64bdSThomas Hellström 	return xe_range_fence_tree_iter_first(&tree->root, start, last);
138845f64bdSThomas Hellström }
139845f64bdSThomas Hellström 
140845f64bdSThomas Hellström /**
141845f64bdSThomas Hellström  * xe_range_fence_tree_next() - range fence tree iterator next
142845f64bdSThomas Hellström  * @rfence: current range fence
143845f64bdSThomas Hellström  * @start: start address of range fence
144845f64bdSThomas Hellström  * @last: last address of range fence
145845f64bdSThomas Hellström  *
146845f64bdSThomas Hellström  * Return: next range fence found in range or NULL
147845f64bdSThomas Hellström  */
148845f64bdSThomas Hellström struct xe_range_fence *
xe_range_fence_tree_next(struct xe_range_fence * rfence,u64 start,u64 last)149845f64bdSThomas Hellström xe_range_fence_tree_next(struct xe_range_fence *rfence, u64 start, u64 last)
150845f64bdSThomas Hellström {
151845f64bdSThomas Hellström 	return xe_range_fence_tree_iter_next(rfence, start, last);
152845f64bdSThomas Hellström }
153845f64bdSThomas Hellström 
xe_range_fence_free(struct xe_range_fence * rfence)154*f2c9364dSArnd Bergmann static void xe_range_fence_free(struct xe_range_fence *rfence)
155*f2c9364dSArnd Bergmann {
156*f2c9364dSArnd Bergmann 	kfree(rfence);
157*f2c9364dSArnd Bergmann }
158*f2c9364dSArnd Bergmann 
159845f64bdSThomas Hellström const struct xe_range_fence_ops xe_range_fence_kfree_ops = {
160*f2c9364dSArnd Bergmann 	.free = xe_range_fence_free,
161845f64bdSThomas Hellström };
162