import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / mt8127 / mali / mali / linux / mali_sync.c
1 /*
2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2012-2013 ARM Limited
5 * ALL RIGHTS RESERVED
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
9 */
10
11 #include "mali_sync.h"
12
13 #include "mali_osk.h"
14 #include "mali_kernel_common.h"
15 #include "mali_timeline.h"
16
17 #include <linux/file.h>
18 #include <linux/seq_file.h>
19 #include <linux/module.h>
20
21 struct mali_sync_pt {
22 struct sync_pt sync_pt;
23 struct mali_sync_flag *flag;
24 };
25
26 /**
27 * The sync flag is used to connect sync fences to the Mali Timeline system. Sync fences can be
28 * created from a sync flag, and when the flag is signaled, the sync fences will also be signaled.
29 */
30 struct mali_sync_flag {
31 struct sync_timeline *sync_tl; /**< Sync timeline this flag is connected to. */
32 u32 point; /**< Point on timeline. */
33 int status; /**< 0 if unsignaled, 1 if signaled without error or negative if signaled with error. */
34 struct kref refcount; /**< Reference count. */
35 };
36
37 MALI_STATIC_INLINE struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
38 {
39 return container_of(pt, struct mali_sync_pt, sync_pt);
40 }
41
42 static struct sync_pt *timeline_dup(struct sync_pt *pt)
43 {
44 struct mali_sync_pt *mpt, *new_mpt;
45 struct sync_pt *new_pt;
46
47 MALI_DEBUG_ASSERT_POINTER(pt);
48 mpt = to_mali_sync_pt(pt);
49
50 new_pt = sync_pt_create(pt->parent, sizeof(struct mali_sync_pt));
51 if (NULL == new_pt) return NULL;
52
53 new_mpt = to_mali_sync_pt(new_pt);
54
55 mali_sync_flag_get(mpt->flag);
56 new_mpt->flag = mpt->flag;
57
58 return new_pt;
59 }
60
61 static int timeline_has_signaled(struct sync_pt *pt)
62 {
63 struct mali_sync_pt *mpt;
64
65 MALI_DEBUG_ASSERT_POINTER(pt);
66 mpt = to_mali_sync_pt(pt);
67
68 MALI_DEBUG_ASSERT_POINTER(mpt->flag);
69
70 return mpt->flag->status;
71 }
72
73 static int timeline_compare(struct sync_pt *pta, struct sync_pt *ptb)
74 {
75 struct mali_sync_pt *mpta;
76 struct mali_sync_pt *mptb;
77 u32 a, b;
78
79 MALI_DEBUG_ASSERT_POINTER(pta);
80 MALI_DEBUG_ASSERT_POINTER(ptb);
81 mpta = to_mali_sync_pt(pta);
82 mptb = to_mali_sync_pt(ptb);
83
84 MALI_DEBUG_ASSERT_POINTER(mpta->flag);
85 MALI_DEBUG_ASSERT_POINTER(mptb->flag);
86
87 a = mpta->flag->point;
88 b = mpta->flag->point;
89
90 if (a == b) return 0;
91
92 return ((b - a) < (a - b) ? -1 : 1);
93 }
94
95 static void timeline_free_pt(struct sync_pt *pt)
96 {
97 struct mali_sync_pt *mpt;
98
99 MALI_DEBUG_ASSERT_POINTER(pt);
100 mpt = to_mali_sync_pt(pt);
101
102 mali_sync_flag_put(mpt->flag);
103 }
104
105 static void timeline_release(struct sync_timeline *sync_timeline)
106 {
107 module_put(THIS_MODULE);
108 }
109
110 static void timeline_print_pt(struct seq_file *s, struct sync_pt *sync_pt)
111 {
112 struct mali_sync_pt *mpt;
113
114 MALI_DEBUG_ASSERT_POINTER(s);
115 MALI_DEBUG_ASSERT_POINTER(sync_pt);
116
117 mpt = to_mali_sync_pt(sync_pt);
118 MALI_DEBUG_ASSERT_POINTER(mpt->flag);
119
120 seq_printf(s, "%u", mpt->flag->point);
121 }
122
123 static struct sync_timeline_ops mali_timeline_ops = {
124 .driver_name = "Mali",
125 .dup = timeline_dup,
126 .has_signaled = timeline_has_signaled,
127 .compare = timeline_compare,
128 .free_pt = timeline_free_pt,
129 .release_obj = timeline_release,
130 .print_pt = timeline_print_pt,
131 };
132
133 struct sync_timeline *mali_sync_timeline_create(const char *name)
134 {
135 struct sync_timeline *sync_tl;
136
137 sync_tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct sync_timeline), name);
138 if (NULL == sync_tl) return NULL;
139
140 /* Grab a reference on the module to ensure the callbacks are present
141 * as long some timeline exists. The reference is released when the
142 * timeline is freed.
143 * Since this function is called from a ioctl on an open file we know
144 * we already have a reference, so using __module_get is safe. */
145 __module_get(THIS_MODULE);
146
147 return sync_tl;
148 }
149
150 mali_bool mali_sync_timeline_is_ours(struct sync_timeline *sync_tl)
151 {
152 MALI_DEBUG_ASSERT_POINTER(sync_tl);
153 return (sync_tl->ops == &mali_timeline_ops) ? MALI_TRUE : MALI_FALSE;
154 }
155
156 s32 mali_sync_fence_fd_alloc(struct sync_fence *sync_fence)
157 {
158 s32 fd = -1;
159
160 fd = get_unused_fd();
161 if (fd < 0) {
162 sync_fence_put(sync_fence);
163 MALI_DEBUG_PRINT(1, ("get_unused_fd() got fd < 0, fd=%x\n", fd));
164 return -1;
165 }
166 sync_fence_install(sync_fence, fd);
167
168 return fd;
169 }
170
171 struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2)
172 {
173 struct sync_fence *sync_fence;
174
175 MALI_DEBUG_ASSERT_POINTER(sync_fence1);
176 MALI_DEBUG_ASSERT_POINTER(sync_fence1);
177
178 sync_fence = sync_fence_merge("mali_merge_fence", sync_fence1, sync_fence2);
179 sync_fence_put(sync_fence1);
180 sync_fence_put(sync_fence2);
181
182 return sync_fence;
183 }
184
185 struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl)
186 {
187 struct mali_sync_flag *flag;
188 struct sync_fence *sync_fence;
189
190 MALI_DEBUG_ASSERT_POINTER(sync_tl);
191
192 flag = mali_sync_flag_create(sync_tl, 0);
193 if (NULL == flag) return NULL;
194
195 sync_fence = mali_sync_flag_create_fence(flag);
196
197 mali_sync_flag_signal(flag, 0);
198 mali_sync_flag_put(flag);
199
200 return sync_fence;
201 }
202
203 struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, mali_timeline_point point)
204 {
205 struct mali_sync_flag *flag;
206
207 if (NULL == sync_tl) return NULL;
208
209 flag = _mali_osk_calloc(1, sizeof(*flag));
210 if (NULL == flag) return NULL;
211
212 flag->sync_tl = sync_tl;
213 flag->point = point;
214
215 flag->status = 0;
216 kref_init(&flag->refcount);
217
218 return flag;
219 }
220
221 void mali_sync_flag_get(struct mali_sync_flag *flag)
222 {
223 MALI_DEBUG_ASSERT_POINTER(flag);
224 kref_get(&flag->refcount);
225 }
226
227 /**
228 * Free sync flag.
229 *
230 * @param ref kref object embedded in sync flag that should be freed.
231 */
232 static void mali_sync_flag_free(struct kref *ref)
233 {
234 struct mali_sync_flag *flag;
235
236 MALI_DEBUG_ASSERT_POINTER(ref);
237 flag = container_of(ref, struct mali_sync_flag, refcount);
238
239 _mali_osk_free(flag);
240 }
241
242 void mali_sync_flag_put(struct mali_sync_flag *flag)
243 {
244 MALI_DEBUG_ASSERT_POINTER(flag);
245 kref_put(&flag->refcount, mali_sync_flag_free);
246 }
247
248 void mali_sync_flag_signal(struct mali_sync_flag *flag, int error)
249 {
250 MALI_DEBUG_ASSERT_POINTER(flag);
251
252 MALI_DEBUG_ASSERT(0 == flag->status);
253 flag->status = (0 > error) ? error : 1;
254
255 _mali_osk_write_mem_barrier();
256
257 sync_timeline_signal(flag->sync_tl);
258 }
259
260 /**
261 * Create a sync point attached to given sync flag.
262 *
263 * @note Sync points must be triggered in *exactly* the same order as they are created.
264 *
265 * @param flag Sync flag.
266 * @return New sync point if successful, NULL if not.
267 */
268 static struct sync_pt *mali_sync_flag_create_pt(struct mali_sync_flag *flag)
269 {
270 struct sync_pt *pt;
271 struct mali_sync_pt *mpt;
272
273 MALI_DEBUG_ASSERT_POINTER(flag);
274 MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
275
276 pt = sync_pt_create(flag->sync_tl, sizeof(struct mali_sync_pt));
277 if (NULL == pt) return NULL;
278
279 mali_sync_flag_get(flag);
280
281 mpt = to_mali_sync_pt(pt);
282 mpt->flag = flag;
283
284 return pt;
285 }
286
287 struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag)
288 {
289 struct sync_pt *sync_pt;
290 struct sync_fence *sync_fence;
291
292 MALI_DEBUG_ASSERT_POINTER(flag);
293 MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
294
295 sync_pt = mali_sync_flag_create_pt(flag);
296 if (NULL == sync_pt) return NULL;
297
298 sync_fence = sync_fence_create("mali_flag_fence", sync_pt);
299 if (NULL == sync_fence) {
300 sync_pt_free(sync_pt);
301 return NULL;
302 }
303
304 return sync_fence;
305 }