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
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.
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
= mpta
->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
);
163 MALI_DEBUG_PRINT(1, ("get_unused_fd() got fd < 0, fd=%x\n", fd
));
166 sync_fence_install(sync_fence
, fd
);
171 struct sync_fence
*mali_sync_fence_merge(struct sync_fence
*sync_fence1
, struct sync_fence
*sync_fence2
)
173 struct sync_fence
*sync_fence
;
175 MALI_DEBUG_ASSERT_POINTER(sync_fence1
);
176 MALI_DEBUG_ASSERT_POINTER(sync_fence1
);
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
);
185 struct sync_fence
*mali_sync_timeline_create_signaled_fence(struct sync_timeline
*sync_tl
)
187 struct mali_sync_flag
*flag
;
188 struct sync_fence
*sync_fence
;
190 MALI_DEBUG_ASSERT_POINTER(sync_tl
);
192 flag
= mali_sync_flag_create(sync_tl
, 0);
193 if (NULL
== flag
) return NULL
;
195 sync_fence
= mali_sync_flag_create_fence(flag
);
197 mali_sync_flag_signal(flag
, 0);
198 mali_sync_flag_put(flag
);
203 struct mali_sync_flag
*mali_sync_flag_create(struct sync_timeline
*sync_tl
, mali_timeline_point point
)
205 struct mali_sync_flag
*flag
;
207 if (NULL
== sync_tl
) return NULL
;
209 flag
= _mali_osk_calloc(1, sizeof(*flag
));
210 if (NULL
== flag
) return NULL
;
212 flag
->sync_tl
= sync_tl
;
216 kref_init(&flag
->refcount
);
221 void mali_sync_flag_get(struct mali_sync_flag
*flag
)
223 MALI_DEBUG_ASSERT_POINTER(flag
);
224 kref_get(&flag
->refcount
);
230 * @param ref kref object embedded in sync flag that should be freed.
232 static void mali_sync_flag_free(struct kref
*ref
)
234 struct mali_sync_flag
*flag
;
236 MALI_DEBUG_ASSERT_POINTER(ref
);
237 flag
= container_of(ref
, struct mali_sync_flag
, refcount
);
239 _mali_osk_free(flag
);
242 void mali_sync_flag_put(struct mali_sync_flag
*flag
)
244 MALI_DEBUG_ASSERT_POINTER(flag
);
245 kref_put(&flag
->refcount
, mali_sync_flag_free
);
248 void mali_sync_flag_signal(struct mali_sync_flag
*flag
, int error
)
250 MALI_DEBUG_ASSERT_POINTER(flag
);
252 MALI_DEBUG_ASSERT(0 == flag
->status
);
253 flag
->status
= (0 > error
) ? error
: 1;
255 _mali_osk_write_mem_barrier();
257 sync_timeline_signal(flag
->sync_tl
);
261 * Create a sync point attached to given sync flag.
263 * @note Sync points must be triggered in *exactly* the same order as they are created.
265 * @param flag Sync flag.
266 * @return New sync point if successful, NULL if not.
268 static struct sync_pt
*mali_sync_flag_create_pt(struct mali_sync_flag
*flag
)
271 struct mali_sync_pt
*mpt
;
273 MALI_DEBUG_ASSERT_POINTER(flag
);
274 MALI_DEBUG_ASSERT_POINTER(flag
->sync_tl
);
276 pt
= sync_pt_create(flag
->sync_tl
, sizeof(struct mali_sync_pt
));
277 if (NULL
== pt
) return NULL
;
279 mali_sync_flag_get(flag
);
281 mpt
= to_mali_sync_pt(pt
);
287 struct sync_fence
*mali_sync_flag_create_fence(struct mali_sync_flag
*flag
)
289 struct sync_pt
*sync_pt
;
290 struct sync_fence
*sync_fence
;
292 MALI_DEBUG_ASSERT_POINTER(flag
);
293 MALI_DEBUG_ASSERT_POINTER(flag
->sync_tl
);
295 sync_pt
= mali_sync_flag_create_pt(flag
);
296 if (NULL
== sync_pt
) return NULL
;
298 sync_fence
= sync_fence_create("mali_flag_fence", sync_pt
);
299 if (NULL
== sync_fence
) {
300 sync_pt_free(sync_pt
);