2 * Copyright (C) 2012 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;
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.
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. */
37 MALI_STATIC_INLINE struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
39 return container_of(pt, struct mali_sync_pt, sync_pt);
42 static struct sync_pt *timeline_dup(struct sync_pt *pt)
44 struct mali_sync_pt *mpt, *new_mpt;
45 struct sync_pt *new_pt;
47 MALI_DEBUG_ASSERT_POINTER(pt);
48 mpt = to_mali_sync_pt(pt);
50 new_pt = sync_pt_create(pt->parent, sizeof(struct mali_sync_pt));
51 if (NULL == new_pt) return NULL;
53 new_mpt = to_mali_sync_pt(new_pt);
55 mali_sync_flag_get(mpt->flag);
56 new_mpt->flag = mpt->flag;
61 static int timeline_has_signaled(struct sync_pt *pt)
63 struct mali_sync_pt *mpt;
65 MALI_DEBUG_ASSERT_POINTER(pt);
66 mpt = to_mali_sync_pt(pt);
68 MALI_DEBUG_ASSERT_POINTER(mpt->flag);
70 return mpt->flag->status;
73 static int timeline_compare(struct sync_pt *pta, struct sync_pt *ptb)
75 struct mali_sync_pt *mpta;
76 struct mali_sync_pt *mptb;
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);
84 MALI_DEBUG_ASSERT_POINTER(mpta->flag);
85 MALI_DEBUG_ASSERT_POINTER(mptb->flag);
87 a = mpta->flag->point;
88 b = mptb->flag->point;
92 return ((b - a) < (a - b) ? -1 : 1);
95 static void timeline_free_pt(struct sync_pt *pt)
97 struct mali_sync_pt *mpt;
99 MALI_DEBUG_ASSERT_POINTER(pt);
100 mpt = to_mali_sync_pt(pt);
102 mali_sync_flag_put(mpt->flag);
105 static void timeline_release(struct sync_timeline *sync_timeline)
107 module_put(THIS_MODULE);
110 static void timeline_print_pt(struct seq_file *s, struct sync_pt *sync_pt)
112 struct mali_sync_pt *mpt;
114 MALI_DEBUG_ASSERT_POINTER(s);
115 MALI_DEBUG_ASSERT_POINTER(sync_pt);
117 mpt = to_mali_sync_pt(sync_pt);
118 MALI_DEBUG_ASSERT_POINTER(mpt->flag);
120 seq_printf(s, "%u", mpt->flag->point);
123 static struct sync_timeline_ops mali_timeline_ops = {
124 .driver_name = "Mali",
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,
133 struct sync_timeline *mali_sync_timeline_create(const char *name)
135 struct sync_timeline *sync_tl;
137 sync_tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct sync_timeline), name);
138 if (NULL == sync_tl) return NULL;
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
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);
150 mali_bool mali_sync_timeline_is_ours(struct sync_timeline *sync_tl)
152 MALI_DEBUG_ASSERT_POINTER(sync_tl);
153 return (sync_tl->ops == &mali_timeline_ops) ? MALI_TRUE : MALI_FALSE;
156 s32 mali_sync_fence_fd_alloc(struct sync_fence *sync_fence)
160 fd = get_unused_fd();
162 sync_fence_put(sync_fence);
165 sync_fence_install(sync_fence, fd);
170 struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2)
172 struct sync_fence *sync_fence;
174 MALI_DEBUG_ASSERT_POINTER(sync_fence1);
175 MALI_DEBUG_ASSERT_POINTER(sync_fence1);
177 sync_fence = sync_fence_merge("mali_merge_fence", sync_fence1, sync_fence2);
178 sync_fence_put(sync_fence1);
179 sync_fence_put(sync_fence2);
184 struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl)
186 struct mali_sync_flag *flag;
187 struct sync_fence *sync_fence;
189 MALI_DEBUG_ASSERT_POINTER(sync_tl);
191 flag = mali_sync_flag_create(sync_tl, 0);
192 if (NULL == flag) return NULL;
194 sync_fence = mali_sync_flag_create_fence(flag);
196 mali_sync_flag_signal(flag, 0);
197 mali_sync_flag_put(flag);
202 struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, mali_timeline_point point)
204 struct mali_sync_flag *flag;
206 if (NULL == sync_tl) return NULL;
208 flag = _mali_osk_calloc(1, sizeof(*flag));
209 if (NULL == flag) return NULL;
211 flag->sync_tl = sync_tl;
215 kref_init(&flag->refcount);
220 void mali_sync_flag_get(struct mali_sync_flag *flag)
222 MALI_DEBUG_ASSERT_POINTER(flag);
223 kref_get(&flag->refcount);
229 * @param ref kref object embedded in sync flag that should be freed.
231 static void mali_sync_flag_free(struct kref *ref)
233 struct mali_sync_flag *flag;
235 MALI_DEBUG_ASSERT_POINTER(ref);
236 flag = container_of(ref, struct mali_sync_flag, refcount);
238 _mali_osk_free(flag);
241 void mali_sync_flag_put(struct mali_sync_flag *flag)
243 MALI_DEBUG_ASSERT_POINTER(flag);
244 kref_put(&flag->refcount, mali_sync_flag_free);
247 void mali_sync_flag_signal(struct mali_sync_flag *flag, int error)
249 MALI_DEBUG_ASSERT_POINTER(flag);
251 MALI_DEBUG_ASSERT(0 == flag->status);
252 flag->status = (0 > error) ? error : 1;
254 _mali_osk_write_mem_barrier();
256 sync_timeline_signal(flag->sync_tl);
260 * Create a sync point attached to given sync flag.
262 * @note Sync points must be triggered in *exactly* the same order as they are created.
264 * @param flag Sync flag.
265 * @return New sync point if successful, NULL if not.
267 static struct sync_pt *mali_sync_flag_create_pt(struct mali_sync_flag *flag)
270 struct mali_sync_pt *mpt;
272 MALI_DEBUG_ASSERT_POINTER(flag);
273 MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
275 pt = sync_pt_create(flag->sync_tl, sizeof(struct mali_sync_pt));
276 if (NULL == pt) return NULL;
278 mali_sync_flag_get(flag);
280 mpt = to_mali_sync_pt(pt);
286 struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag)
288 struct sync_pt *sync_pt;
289 struct sync_fence *sync_fence;
291 MALI_DEBUG_ASSERT_POINTER(flag);
292 MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
294 sync_pt = mali_sync_flag_create_pt(flag);
295 if (NULL == sync_pt) return NULL;
297 sync_fence = sync_fence_create("mali_flag_fence", sync_pt);
298 if (NULL == sync_fence) {
299 sync_pt_free(sync_pt);