2 * Copyright (C) 2012-2014 ARM Limited. All rights reserved.
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
11 #include "mali_sync.h"
14 #include "mali_kernel_common.h"
15 #include "mali_timeline.h"
17 #include <linux/file.h>
18 #include <linux/seq_file.h>
19 #include <linux/module.h>
22 struct sync_pt sync_pt;
23 struct mali_sync_flag *flag;
24 struct sync_timeline *sync_tl; /**< Sync timeline this pt is connected to. */
28 * The sync flag is used to connect sync fences to the Mali Timeline system. Sync fences can be
29 * created from a sync flag, and when the flag is signaled, the sync fences will also be signaled.
31 struct mali_sync_flag {
32 struct sync_timeline *sync_tl; /**< Sync timeline this flag is connected to. */
33 u32 point; /**< Point on timeline. */
34 int status; /**< 0 if unsignaled, 1 if signaled without error or negative if signaled with error. */
35 struct kref refcount; /**< Reference count. */
39 * Mali sync timeline is used to connect mali timeline to sync_timeline.
40 * When fence timeout can print more detailed mali timeline system info.
42 struct mali_sync_timeline_container {
43 struct sync_timeline sync_timeline;
44 struct mali_timeline *timeline;
47 MALI_STATIC_INLINE struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
49 return container_of(pt, struct mali_sync_pt, sync_pt);
52 MALI_STATIC_INLINE struct mali_sync_timeline_container *to_mali_sync_tl_container(struct sync_timeline *sync_tl)
54 return container_of(sync_tl, struct mali_sync_timeline_container, sync_timeline);
57 static struct sync_pt *timeline_dup(struct sync_pt *pt)
59 struct mali_sync_pt *mpt, *new_mpt;
60 struct sync_pt *new_pt;
62 MALI_DEBUG_ASSERT_POINTER(pt);
63 mpt = to_mali_sync_pt(pt);
65 new_pt = sync_pt_create(mpt->sync_tl, sizeof(struct mali_sync_pt));
66 if (NULL == new_pt) return NULL;
68 new_mpt = to_mali_sync_pt(new_pt);
70 mali_sync_flag_get(mpt->flag);
71 new_mpt->flag = mpt->flag;
72 new_mpt->sync_tl = mpt->sync_tl;
77 static int timeline_has_signaled(struct sync_pt *pt)
79 struct mali_sync_pt *mpt;
81 MALI_DEBUG_ASSERT_POINTER(pt);
82 mpt = to_mali_sync_pt(pt);
84 MALI_DEBUG_ASSERT_POINTER(mpt->flag);
86 return mpt->flag->status;
89 static int timeline_compare(struct sync_pt *pta, struct sync_pt *ptb)
91 struct mali_sync_pt *mpta;
92 struct mali_sync_pt *mptb;
95 MALI_DEBUG_ASSERT_POINTER(pta);
96 MALI_DEBUG_ASSERT_POINTER(ptb);
97 mpta = to_mali_sync_pt(pta);
98 mptb = to_mali_sync_pt(ptb);
100 MALI_DEBUG_ASSERT_POINTER(mpta->flag);
101 MALI_DEBUG_ASSERT_POINTER(mptb->flag);
103 a = mpta->flag->point;
104 b = mptb->flag->point;
106 if (a == b) return 0;
108 return ((b - a) < (a - b) ? -1 : 1);
111 static void timeline_free_pt(struct sync_pt *pt)
113 struct mali_sync_pt *mpt;
115 MALI_DEBUG_ASSERT_POINTER(pt);
116 mpt = to_mali_sync_pt(pt);
118 mali_sync_flag_put(mpt->flag);
121 static void timeline_release(struct sync_timeline *sync_timeline)
123 module_put(THIS_MODULE);
126 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
127 static void timeline_print_pt(struct seq_file *s, struct sync_pt *sync_pt)
129 struct mali_sync_pt *mpt;
131 MALI_DEBUG_ASSERT_POINTER(s);
132 MALI_DEBUG_ASSERT_POINTER(sync_pt);
134 mpt = to_mali_sync_pt(sync_pt);
136 /* It is possible this sync point is just under construct,
137 * make sure the flag is valid before accessing it
140 seq_printf(s, "%u", mpt->flag->point);
142 seq_printf(s, "uninitialized");
147 static void timeline_pt_value_str(struct sync_pt *pt, char *str, int size)
149 struct mali_sync_pt *mpt;
151 MALI_DEBUG_ASSERT_POINTER(str);
152 MALI_DEBUG_ASSERT_POINTER(pt);
154 mpt = to_mali_sync_pt(pt);
156 /* It is possible this sync point is just under construct,
157 * make sure the flag is valid before accessing it
160 _mali_osk_snprintf(str, size, "%u", mpt->flag->point);
162 _mali_osk_snprintf(str, size, "uninitialized");
166 static void timeline_value_str(struct sync_timeline *timeline, char *str, int size)
168 struct mali_sync_timeline_container *mali_sync_tl;
170 MALI_DEBUG_ASSERT_POINTER(timeline);
171 MALI_DEBUG_ASSERT_POINTER(str);
173 mali_sync_tl = to_mali_sync_tl_container(timeline);
175 MALI_DEBUG_ASSERT_POINTER(mali_sync_tl);
177 if (NULL != mali_sync_tl->timeline) {
178 _mali_osk_snprintf(str, size, "oldest (%u) next (%u)\n", mali_sync_tl->timeline->point_oldest,
179 mali_sync_tl->timeline->point_next);
184 static struct sync_timeline_ops mali_timeline_ops = {
185 .driver_name = "Mali",
187 .has_signaled = timeline_has_signaled,
188 .compare = timeline_compare,
189 .free_pt = timeline_free_pt,
190 .release_obj = timeline_release,
191 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
192 .print_pt = timeline_print_pt,
194 .pt_value_str = timeline_pt_value_str,
195 .timeline_value_str = timeline_value_str,
199 struct sync_timeline *mali_sync_timeline_create(struct mali_timeline *timeline, const char *name)
201 struct sync_timeline *sync_tl;
202 struct mali_sync_timeline_container *mali_sync_tl;
204 sync_tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct mali_sync_timeline_container), name);
205 if (NULL == sync_tl) return NULL;
207 mali_sync_tl = to_mali_sync_tl_container(sync_tl);
208 mali_sync_tl->timeline = timeline;
210 /* Grab a reference on the module to ensure the callbacks are present
211 * as long some timeline exists. The reference is released when the
213 * Since this function is called from a ioctl on an open file we know
214 * we already have a reference, so using __module_get is safe. */
215 __module_get(THIS_MODULE);
220 mali_bool mali_sync_timeline_is_ours(struct sync_timeline *sync_tl)
222 MALI_DEBUG_ASSERT_POINTER(sync_tl);
223 return (sync_tl->ops == &mali_timeline_ops) ? MALI_TRUE : MALI_FALSE;
226 s32 mali_sync_fence_fd_alloc(struct sync_fence *sync_fence)
230 fd = get_unused_fd();
232 sync_fence_put(sync_fence);
235 sync_fence_install(sync_fence, fd);
240 struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2)
242 struct sync_fence *sync_fence;
244 MALI_DEBUG_ASSERT_POINTER(sync_fence1);
245 MALI_DEBUG_ASSERT_POINTER(sync_fence1);
247 sync_fence = sync_fence_merge("mali_merge_fence", sync_fence1, sync_fence2);
248 sync_fence_put(sync_fence1);
249 sync_fence_put(sync_fence2);
254 struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl)
256 struct mali_sync_flag *flag;
257 struct sync_fence *sync_fence;
259 MALI_DEBUG_ASSERT_POINTER(sync_tl);
261 flag = mali_sync_flag_create(sync_tl, 0);
262 if (NULL == flag) return NULL;
264 sync_fence = mali_sync_flag_create_fence(flag);
266 mali_sync_flag_signal(flag, 0);
267 mali_sync_flag_put(flag);
272 struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, mali_timeline_point point)
274 struct mali_sync_flag *flag;
276 if (NULL == sync_tl) return NULL;
278 flag = _mali_osk_calloc(1, sizeof(*flag));
279 if (NULL == flag) return NULL;
281 flag->sync_tl = sync_tl;
285 kref_init(&flag->refcount);
290 void mali_sync_flag_get(struct mali_sync_flag *flag)
292 MALI_DEBUG_ASSERT_POINTER(flag);
293 kref_get(&flag->refcount);
299 * @param ref kref object embedded in sync flag that should be freed.
301 static void mali_sync_flag_free(struct kref *ref)
303 struct mali_sync_flag *flag;
305 MALI_DEBUG_ASSERT_POINTER(ref);
306 flag = container_of(ref, struct mali_sync_flag, refcount);
308 _mali_osk_free(flag);
311 void mali_sync_flag_put(struct mali_sync_flag *flag)
313 MALI_DEBUG_ASSERT_POINTER(flag);
314 kref_put(&flag->refcount, mali_sync_flag_free);
317 void mali_sync_flag_signal(struct mali_sync_flag *flag, int error)
319 MALI_DEBUG_ASSERT_POINTER(flag);
321 MALI_DEBUG_ASSERT(0 == flag->status);
322 flag->status = (0 > error) ? error : 1;
324 _mali_osk_write_mem_barrier();
326 sync_timeline_signal(flag->sync_tl);
330 * Create a sync point attached to given sync flag.
332 * @note Sync points must be triggered in *exactly* the same order as they are created.
334 * @param flag Sync flag.
335 * @return New sync point if successful, NULL if not.
337 static struct sync_pt *mali_sync_flag_create_pt(struct mali_sync_flag *flag)
340 struct mali_sync_pt *mpt;
342 MALI_DEBUG_ASSERT_POINTER(flag);
343 MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
345 pt = sync_pt_create(flag->sync_tl, sizeof(struct mali_sync_pt));
346 if (NULL == pt) return NULL;
348 mali_sync_flag_get(flag);
350 mpt = to_mali_sync_pt(pt);
352 mpt->sync_tl = flag->sync_tl;
357 struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag)
359 struct sync_pt *sync_pt;
360 struct sync_fence *sync_fence;
362 MALI_DEBUG_ASSERT_POINTER(flag);
363 MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
365 sync_pt = mali_sync_flag_create_pt(flag);
366 if (NULL == sync_pt) return NULL;
368 sync_fence = sync_fence_create("mali_flag_fence", sync_pt);
369 if (NULL == sync_fence) {
370 sync_pt_free(sync_pt);