1 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2 /*
3  *
4  * (C) COPYRIGHT 2010-2018, 2020-2021 ARM Limited. All rights reserved.
5  *
6  * This program is free software and is provided to you under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation, and any use by you of this program is subject to the terms
9  * of such GNU license.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you can access it online at
18  * http://www.gnu.org/licenses/gpl-2.0.html.
19  *
20  */
21 
22 #ifndef _KBASE_FENCE_H_
23 #define _KBASE_FENCE_H_
24 
25 /*
26  * mali_kbase_fence.[hc] has common fence code used by both
27  * - CONFIG_MALI_BIFROST_DMA_FENCE - implicit DMA fences
28  * - CONFIG_SYNC_FILE      - explicit fences beginning with 4.9 kernel
29  */
30 
31 #if defined(CONFIG_MALI_BIFROST_DMA_FENCE) || defined(CONFIG_SYNC_FILE)
32 
33 #include <linux/list.h>
34 #include "mali_kbase_fence_defs.h"
35 #include "mali_kbase.h"
36 
37 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
38 extern const struct fence_ops kbase_fence_ops;
39 #else
40 extern const struct dma_fence_ops kbase_fence_ops;
41 #endif
42 
43 /**
44 * struct kbase_fence_cb - Mali dma-fence callback data struct
45 * @fence_cb: Callback function
46 * @katom:    Pointer to katom that is waiting on this callback
47 * @fence:    Pointer to the fence object on which this callback is waiting
48 * @node:     List head for linking this callback to the katom
49 */
50 struct kbase_fence_cb {
51 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
52 	struct fence_cb fence_cb;
53 	struct fence *fence;
54 #else
55 	struct dma_fence_cb fence_cb;
56 	struct dma_fence *fence;
57 #endif
58 	struct kbase_jd_atom *katom;
59 	struct list_head node;
60 };
61 
62 /**
63  * kbase_fence_out_new() - Creates a new output fence and puts it on the atom
64  * @katom: Atom to create an output fence for
65  *
66  * return: A new fence object on success, NULL on failure.
67  */
68 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
69 struct fence *kbase_fence_out_new(struct kbase_jd_atom *katom);
70 #else
71 struct dma_fence *kbase_fence_out_new(struct kbase_jd_atom *katom);
72 #endif
73 
74 #if defined(CONFIG_SYNC_FILE)
75 /**
76  * kbase_fence_fence_in_set() - Assign input fence to atom
77  * @katom: Atom to assign input fence to
78  * @fence: Input fence to assign to atom
79  *
80  * This function will take ownership of one fence reference!
81  */
82 #define kbase_fence_fence_in_set(katom, fence) \
83 	do { \
84 		WARN_ON((katom)->dma_fence.fence_in); \
85 		(katom)->dma_fence.fence_in = fence; \
86 	} while (0)
87 #endif
88 
89 
90 #if !MALI_USE_CSF
91 /**
92  * kbase_fence_out_remove() - Removes the output fence from atom
93  * @katom: Atom to remove output fence for
94  *
95  * This will also release the reference to this fence which the atom keeps
96  */
kbase_fence_out_remove(struct kbase_jd_atom *katom)97 static inline void kbase_fence_out_remove(struct kbase_jd_atom *katom)
98 {
99 	if (katom->dma_fence.fence) {
100 		dma_fence_put(katom->dma_fence.fence);
101 		katom->dma_fence.fence = NULL;
102 	}
103 }
104 
105 #if defined(CONFIG_SYNC_FILE)
106 /**
107  * kbase_fence_out_remove() - Removes the input fence from atom
108  * @katom: Atom to remove input fence for
109  *
110  * This will also release the reference to this fence which the atom keeps
111  */
kbase_fence_in_remove(struct kbase_jd_atom *katom)112 static inline void kbase_fence_in_remove(struct kbase_jd_atom *katom)
113 {
114 	if (katom->dma_fence.fence_in) {
115 		dma_fence_put(katom->dma_fence.fence_in);
116 		katom->dma_fence.fence_in = NULL;
117 	}
118 }
119 #endif
120 
121 /**
122  * kbase_fence_out_is_ours() - Check if atom has a valid fence created by us
123  * @katom: Atom to check output fence for
124  *
125  * Return: true if fence exists and is valid, otherwise false
126  */
kbase_fence_out_is_ours(struct kbase_jd_atom *katom)127 static inline bool kbase_fence_out_is_ours(struct kbase_jd_atom *katom)
128 {
129 	return katom->dma_fence.fence &&
130 				katom->dma_fence.fence->ops == &kbase_fence_ops;
131 }
132 
133 /**
134  * kbase_fence_out_signal() - Signal output fence of atom
135  * @katom: Atom to signal output fence for
136  * @status: Status to signal with (0 for success, < 0 for error)
137  *
138  * Return: 0 on success, < 0 on error
139  */
kbase_fence_out_signal(struct kbase_jd_atom *katom, int status)140 static inline int kbase_fence_out_signal(struct kbase_jd_atom *katom,
141 					 int status)
142 {
143 	if (status) {
144 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE && \
145 	  KERNEL_VERSION(4, 9, 68) <= LINUX_VERSION_CODE)
146 		fence_set_error(katom->dma_fence.fence, status);
147 #elif (KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE)
148 		dma_fence_set_error(katom->dma_fence.fence, status);
149 #else
150 		katom->dma_fence.fence->status = status;
151 #endif
152 	}
153 	return dma_fence_signal(katom->dma_fence.fence);
154 }
155 
156 /**
157  * kbase_fence_add_callback() - Add callback on @fence to block @katom
158  * @katom: Pointer to katom that will be blocked by @fence
159  * @fence: Pointer to fence on which to set up the callback
160  * @callback: Pointer to function to be called when fence is signaled
161  *
162  * Caller needs to hold a reference to @fence when calling this function, and
163  * the caller is responsible for releasing that reference.  An additional
164  * reference to @fence will be taken when the callback was successfully set up
165  * and @fence needs to be kept valid until the callback has been called and
166  * cleanup have been done.
167  *
168  * Return: 0 on success: fence was either already signaled, or callback was
169  * set up. Negative error code is returned on error.
170  */
171 #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
172 int kbase_fence_add_callback(struct kbase_jd_atom *katom,
173 			     struct fence *fence,
174 			     fence_func_t callback);
175 #else
176 int kbase_fence_add_callback(struct kbase_jd_atom *katom,
177 			     struct dma_fence *fence,
178 			     dma_fence_func_t callback);
179 #endif
180 
181 /**
182  * kbase_fence_dep_count_set() - Set dep_count value on atom to specified value
183  * @katom: Atom to set dep_count for
184  * @val: value to set dep_count to
185  *
186  * The dep_count is available to the users of this module so that they can
187  * synchronize completion of the wait with cancellation and adding of more
188  * callbacks. For instance, a user could do the following:
189  *
190  * dep_count set to 1
191  * callback #1 added, dep_count is increased to 2
192  *                             callback #1 happens, dep_count decremented to 1
193  *                             since dep_count > 0, no completion is done
194  * callback #2 is added, dep_count is increased to 2
195  * dep_count decremented to 1
196  *                             callback #2 happens, dep_count decremented to 0
197  *                             since dep_count now is zero, completion executes
198  *
199  * The dep_count can also be used to make sure that the completion only
200  * executes once. This is typically done by setting dep_count to -1 for the
201  * thread that takes on this responsibility.
202  */
203 static inline void
kbase_fence_dep_count_set(struct kbase_jd_atom *katom, int val)204 kbase_fence_dep_count_set(struct kbase_jd_atom *katom, int val)
205 {
206 	atomic_set(&katom->dma_fence.dep_count, val);
207 }
208 
209 /**
210  * kbase_fence_dep_count_dec_and_test() - Decrements dep_count
211  * @katom: Atom to decrement dep_count for
212  *
213  * See @kbase_fence_dep_count_set for general description about dep_count
214  *
215  * Return: true if value was decremented to zero, otherwise false
216  */
217 static inline bool
kbase_fence_dep_count_dec_and_test(struct kbase_jd_atom *katom)218 kbase_fence_dep_count_dec_and_test(struct kbase_jd_atom *katom)
219 {
220 	return atomic_dec_and_test(&katom->dma_fence.dep_count);
221 }
222 
223 /**
224  * kbase_fence_dep_count_read() - Returns the current dep_count value
225  * @katom: Pointer to katom
226  *
227  * See @kbase_fence_dep_count_set for general description about dep_count
228  *
229  * Return: The current dep_count value
230  */
kbase_fence_dep_count_read(struct kbase_jd_atom *katom)231 static inline int kbase_fence_dep_count_read(struct kbase_jd_atom *katom)
232 {
233 	return atomic_read(&katom->dma_fence.dep_count);
234 }
235 
236 /**
237  * kbase_fence_free_callbacks() - Free dma-fence callbacks on a katom
238  * @katom: Pointer to katom
239  *
240  * This function will free all fence callbacks on the katom's list of
241  * callbacks. Callbacks that have not yet been called, because their fence
242  * hasn't yet signaled, will first be removed from the fence.
243  *
244  * Locking: katom->dma_fence.callbacks list assumes jctx.lock is held.
245  *
246  * Return: true if dep_count reached 0, otherwise false.
247  */
248 bool kbase_fence_free_callbacks(struct kbase_jd_atom *katom);
249 
250 #if defined(CONFIG_SYNC_FILE)
251 /**
252  * kbase_fence_in_get() - Retrieve input fence for atom.
253  * @katom: Atom to get input fence from
254  *
255  * A ref will be taken for the fence, so use @kbase_fence_put() to release it
256  *
257  * Return: The fence, or NULL if there is no input fence for atom
258  */
259 #define kbase_fence_in_get(katom) dma_fence_get((katom)->dma_fence.fence_in)
260 #endif
261 
262 /**
263  * kbase_fence_out_get() - Retrieve output fence for atom.
264  * @katom: Atom to get output fence from
265  *
266  * A ref will be taken for the fence, so use @kbase_fence_put() to release it
267  *
268  * Return: The fence, or NULL if there is no output fence for atom
269  */
270 #define kbase_fence_out_get(katom) dma_fence_get((katom)->dma_fence.fence)
271 
272 #endif /* !MALI_USE_CSF */
273 
274 /**
275  * kbase_fence_put() - Releases a reference to a fence
276  * @fence: Fence to release reference for.
277  */
278 #define kbase_fence_put(fence) dma_fence_put(fence)
279 
280 
281 #endif /* CONFIG_MALI_BIFROST_DMA_FENCE || defined(CONFIG_SYNC_FILE */
282 
283 #endif /* _KBASE_FENCE_H_ */
284