summaryrefslogtreecommitdiff
path: root/drivers/gpu/arm/midgard/mali_kbase_fence.h
blob: 8d392996f56e92336eabab6318c4e996e59d1a96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*
 *
 * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */



#ifndef _KBASE_FENCE_H_
#define _KBASE_FENCE_H_

/*
 * mali_kbase_fence.[hc] has common fence code used by both
 * - CONFIG_MALI_DMA_FENCE - implicit DMA fences
 * - CONFIG_SYNC_FILE      - explicit fences beginning with 4.9 kernel
 */

#if defined(CONFIG_MALI_DMA_FENCE) || defined(CONFIG_SYNC_FILE)

#include <linux/list.h>
#include "mali_kbase_fence_defs.h"
#include "mali_kbase.h"

#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
extern const struct fence_ops kbase_fence_ops;
#else
extern const struct dma_fence_ops kbase_fence_ops;
#endif

/**
* struct kbase_fence_cb - Mali dma-fence callback data struct
* @fence_cb: Callback function
* @katom:    Pointer to katom that is waiting on this callback
* @fence:    Pointer to the fence object on which this callback is waiting
* @node:     List head for linking this callback to the katom
*/
struct kbase_fence_cb {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
	struct fence_cb fence_cb;
	struct fence *fence;
#else
	struct dma_fence_cb fence_cb;
	struct dma_fence *fence;
#endif
	struct kbase_jd_atom *katom;
	struct list_head node;
};

/**
 * kbase_fence_out_new() - Creates a new output fence and puts it on the atom
 * @katom: Atom to create an output fence for
 *
 * return: A new fence object on success, NULL on failure.
 */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
struct fence *kbase_fence_out_new(struct kbase_jd_atom *katom);
#else
struct dma_fence *kbase_fence_out_new(struct kbase_jd_atom *katom);
#endif

#if defined(CONFIG_SYNC_FILE)
/**
 * kbase_fence_fence_in_set() - Assign input fence to atom
 * @katom: Atom to assign input fence to
 * @fence: Input fence to assign to atom
 *
 * This function will take ownership of one fence reference!
 */
#define kbase_fence_fence_in_set(katom, fence) \
	do { \
		WARN_ON((katom)->dma_fence.fence_in); \
		(katom)->dma_fence.fence_in = fence; \
	} while (0)
#endif

/**
 * kbase_fence_out_remove() - Removes the output fence from atom
 * @katom: Atom to remove output fence for
 *
 * This will also release the reference to this fence which the atom keeps
 */
static inline void kbase_fence_out_remove(struct kbase_jd_atom *katom)
{
	if (katom->dma_fence.fence) {
		dma_fence_put(katom->dma_fence.fence);
		katom->dma_fence.fence = NULL;
	}
}

#if defined(CONFIG_SYNC_FILE)
/**
 * kbase_fence_out_remove() - Removes the input fence from atom
 * @katom: Atom to remove input fence for
 *
 * This will also release the reference to this fence which the atom keeps
 */
static inline void kbase_fence_in_remove(struct kbase_jd_atom *katom)
{
	if (katom->dma_fence.fence_in) {
		dma_fence_put(katom->dma_fence.fence_in);
		katom->dma_fence.fence_in = NULL;
	}
}
#endif

/**
 * kbase_fence_out_is_ours() - Check if atom has a valid fence created by us
 * @katom: Atom to check output fence for
 *
 * Return: true if fence exists and is valid, otherwise false
 */
static inline bool kbase_fence_out_is_ours(struct kbase_jd_atom *katom)
{
	return katom->dma_fence.fence &&
				katom->dma_fence.fence->ops == &kbase_fence_ops;
}

/**
 * kbase_fence_out_signal() - Signal output fence of atom
 * @katom: Atom to signal output fence for
 * @status: Status to signal with (0 for success, < 0 for error)
 *
 * Return: 0 on success, < 0 on error
 */
static inline int kbase_fence_out_signal(struct kbase_jd_atom *katom,
					 int status)
{
	katom->dma_fence.fence->status = status;
	return dma_fence_signal(katom->dma_fence.fence);
}

/**
 * kbase_fence_add_callback() - Add callback on @fence to block @katom
 * @katom: Pointer to katom that will be blocked by @fence
 * @fence: Pointer to fence on which to set up the callback
 * @callback: Pointer to function to be called when fence is signaled
 *
 * Caller needs to hold a reference to @fence when calling this function, and
 * the caller is responsible for releasing that reference.  An additional
 * reference to @fence will be taken when the callback was successfully set up
 * and @fence needs to be kept valid until the callback has been called and
 * cleanup have been done.
 *
 * Return: 0 on success: fence was either already signaled, or callback was
 * set up. Negative error code is returned on error.
 */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
int kbase_fence_add_callback(struct kbase_jd_atom *katom,
			     struct fence *fence,
			     fence_func_t callback);
#else
int kbase_fence_add_callback(struct kbase_jd_atom *katom,
			     struct dma_fence *fence,
			     dma_fence_func_t callback);
#endif

/**
 * kbase_fence_dep_count_set() - Set dep_count value on atom to specified value
 * @katom: Atom to set dep_count for
 * @val: value to set dep_count to
 *
 * The dep_count is available to the users of this module so that they can
 * synchronize completion of the wait with cancellation and adding of more
 * callbacks. For instance, a user could do the following:
 *
 * dep_count set to 1
 * callback #1 added, dep_count is increased to 2
 *                             callback #1 happens, dep_count decremented to 1
 *                             since dep_count > 0, no completion is done
 * callback #2 is added, dep_count is increased to 2
 * dep_count decremented to 1
 *                             callback #2 happens, dep_count decremented to 0
 *                             since dep_count now is zero, completion executes
 *
 * The dep_count can also be used to make sure that the completion only
 * executes once. This is typically done by setting dep_count to -1 for the
 * thread that takes on this responsibility.
 */
static inline void
kbase_fence_dep_count_set(struct kbase_jd_atom *katom, int val)
{
	atomic_set(&katom->dma_fence.dep_count, val);
}

/**
 * kbase_fence_dep_count_dec_and_test() - Decrements dep_count
 * @katom: Atom to decrement dep_count for
 *
 * See @kbase_fence_dep_count_set for general description about dep_count
 *
 * Return: true if value was decremented to zero, otherwise false
 */
static inline bool
kbase_fence_dep_count_dec_and_test(struct kbase_jd_atom *katom)
{
	return atomic_dec_and_test(&katom->dma_fence.dep_count);
}

/**
 * kbase_fence_dep_count_read() - Returns the current dep_count value
 * @katom: Pointer to katom
 *
 * See @kbase_fence_dep_count_set for general description about dep_count
 *
 * Return: The current dep_count value
 */
static inline int kbase_fence_dep_count_read(struct kbase_jd_atom *katom)
{
	return atomic_read(&katom->dma_fence.dep_count);
}

/**
 * kbase_fence_free_callbacks() - Free dma-fence callbacks on a katom
 * @katom: Pointer to katom
 *
 * This function will free all fence callbacks on the katom's list of
 * callbacks. Callbacks that have not yet been called, because their fence
 * hasn't yet signaled, will first be removed from the fence.
 *
 * Locking: katom->dma_fence.callbacks list assumes jctx.lock is held.
 *
 * Return: true if dep_count reached 0, otherwise false.
 */
bool kbase_fence_free_callbacks(struct kbase_jd_atom *katom);

#if defined(CONFIG_SYNC_FILE)
/**
 * kbase_fence_in_get() - Retrieve input fence for atom.
 * @katom: Atom to get input fence from
 *
 * A ref will be taken for the fence, so use @kbase_fence_put() to release it
 *
 * Return: The fence, or NULL if there is no input fence for atom
 */
#define kbase_fence_in_get(katom) dma_fence_get((katom)->dma_fence.fence_in)
#endif

/**
 * kbase_fence_out_get() - Retrieve output fence for atom.
 * @katom: Atom to get output fence from
 *
 * A ref will be taken for the fence, so use @kbase_fence_put() to release it
 *
 * Return: The fence, or NULL if there is no output fence for atom
 */
#define kbase_fence_out_get(katom) dma_fence_get((katom)->dma_fence.fence)

/**
 * kbase_fence_put() - Releases a reference to a fence
 * @fence: Fence to release reference for.
 */
#define kbase_fence_put(fence) dma_fence_put(fence)


#endif /* CONFIG_MALI_DMA_FENCE || defined(CONFIG_SYNC_FILE */

#endif /* _KBASE_FENCE_H_ */