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