tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / linux / mali_sync.c
1 /*
2  * Copyright (C) 2012 ARM Limited. All rights reserved.
3  * 
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.
6  * 
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.
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 = mptb->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                 return -1;
164         }
165         sync_fence_install(sync_fence, fd);
166
167         return fd;
168 }
169
170 struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2)
171 {
172         struct sync_fence *sync_fence;
173
174         MALI_DEBUG_ASSERT_POINTER(sync_fence1);
175         MALI_DEBUG_ASSERT_POINTER(sync_fence1);
176
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);
180
181         return sync_fence;
182 }
183
184 struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl)
185 {
186         struct mali_sync_flag *flag;
187         struct sync_fence *sync_fence;
188
189         MALI_DEBUG_ASSERT_POINTER(sync_tl);
190
191         flag = mali_sync_flag_create(sync_tl, 0);
192         if (NULL == flag) return NULL;
193
194         sync_fence = mali_sync_flag_create_fence(flag);
195
196         mali_sync_flag_signal(flag, 0);
197         mali_sync_flag_put(flag);
198
199         return sync_fence;
200 }
201
202 struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, mali_timeline_point point)
203 {
204         struct mali_sync_flag *flag;
205
206         if (NULL == sync_tl) return NULL;
207
208         flag = _mali_osk_calloc(1, sizeof(*flag));
209         if (NULL == flag) return NULL;
210
211         flag->sync_tl = sync_tl;
212         flag->point = point;
213
214         flag->status = 0;
215         kref_init(&flag->refcount);
216
217         return flag;
218 }
219
220 void mali_sync_flag_get(struct mali_sync_flag *flag)
221 {
222         MALI_DEBUG_ASSERT_POINTER(flag);
223         kref_get(&flag->refcount);
224 }
225
226 /**
227  * Free sync flag.
228  *
229  * @param ref kref object embedded in sync flag that should be freed.
230  */
231 static void mali_sync_flag_free(struct kref *ref)
232 {
233         struct mali_sync_flag *flag;
234
235         MALI_DEBUG_ASSERT_POINTER(ref);
236         flag = container_of(ref, struct mali_sync_flag, refcount);
237
238         _mali_osk_free(flag);
239 }
240
241 void mali_sync_flag_put(struct mali_sync_flag *flag)
242 {
243         MALI_DEBUG_ASSERT_POINTER(flag);
244         kref_put(&flag->refcount, mali_sync_flag_free);
245 }
246
247 void mali_sync_flag_signal(struct mali_sync_flag *flag, int error)
248 {
249         MALI_DEBUG_ASSERT_POINTER(flag);
250
251         MALI_DEBUG_ASSERT(0 == flag->status);
252         flag->status = (0 > error) ? error : 1;
253
254         _mali_osk_write_mem_barrier();
255
256         sync_timeline_signal(flag->sync_tl);
257 }
258
259 /**
260  * Create a sync point attached to given sync flag.
261  *
262  * @note Sync points must be triggered in *exactly* the same order as they are created.
263  *
264  * @param flag Sync flag.
265  * @return New sync point if successful, NULL if not.
266  */
267 static struct sync_pt *mali_sync_flag_create_pt(struct mali_sync_flag *flag)
268 {
269         struct sync_pt *pt;
270         struct mali_sync_pt *mpt;
271
272         MALI_DEBUG_ASSERT_POINTER(flag);
273         MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
274
275         pt = sync_pt_create(flag->sync_tl, sizeof(struct mali_sync_pt));
276         if (NULL == pt) return NULL;
277
278         mali_sync_flag_get(flag);
279
280         mpt = to_mali_sync_pt(pt);
281         mpt->flag = flag;
282
283         return pt;
284 }
285
286 struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag)
287 {
288         struct sync_pt    *sync_pt;
289         struct sync_fence *sync_fence;
290
291         MALI_DEBUG_ASSERT_POINTER(flag);
292         MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
293
294         sync_pt = mali_sync_flag_create_pt(flag);
295         if (NULL == sync_pt) return NULL;
296
297         sync_fence = sync_fence_create("mali_flag_fence", sync_pt);
298         if (NULL == sync_fence) {
299                 sync_pt_free(sync_pt);
300                 return NULL;
301         }
302
303         return sync_fence;
304 }