UPSTREAM: DT/arm,gic-v3: Documment PPI partition support
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / linux / mali_sync.c
1 /*
2  * Copyright (C) 2012-2014 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         struct sync_timeline *sync_tl;  /**< Sync timeline this pt is connected to. */
25 };
26
27 /**
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.
30  */
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. */
36 };
37
38 /**
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.
41  */
42 struct mali_sync_timeline_container {
43         struct sync_timeline sync_timeline;
44         struct mali_timeline *timeline;
45 };
46
47 MALI_STATIC_INLINE struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
48 {
49         return container_of(pt, struct mali_sync_pt, sync_pt);
50 }
51
52 MALI_STATIC_INLINE struct mali_sync_timeline_container *to_mali_sync_tl_container(struct sync_timeline *sync_tl)
53 {
54         return container_of(sync_tl, struct mali_sync_timeline_container, sync_timeline);
55 }
56
57 static struct sync_pt *timeline_dup(struct sync_pt *pt)
58 {
59         struct mali_sync_pt *mpt, *new_mpt;
60         struct sync_pt *new_pt;
61
62         MALI_DEBUG_ASSERT_POINTER(pt);
63         mpt = to_mali_sync_pt(pt);
64
65         new_pt = sync_pt_create(mpt->sync_tl, sizeof(struct mali_sync_pt));
66         if (NULL == new_pt) return NULL;
67
68         new_mpt = to_mali_sync_pt(new_pt);
69
70         mali_sync_flag_get(mpt->flag);
71         new_mpt->flag = mpt->flag;
72         new_mpt->sync_tl = mpt->sync_tl;
73
74         return new_pt;
75 }
76
77 static int timeline_has_signaled(struct sync_pt *pt)
78 {
79         struct mali_sync_pt *mpt;
80
81         MALI_DEBUG_ASSERT_POINTER(pt);
82         mpt = to_mali_sync_pt(pt);
83
84         MALI_DEBUG_ASSERT_POINTER(mpt->flag);
85
86         return mpt->flag->status;
87 }
88
89 static int timeline_compare(struct sync_pt *pta, struct sync_pt *ptb)
90 {
91         struct mali_sync_pt *mpta;
92         struct mali_sync_pt *mptb;
93         u32 a, b;
94
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);
99
100         MALI_DEBUG_ASSERT_POINTER(mpta->flag);
101         MALI_DEBUG_ASSERT_POINTER(mptb->flag);
102
103         a = mpta->flag->point;
104         b = mptb->flag->point;
105
106         if (a == b) return 0;
107
108         return ((b - a) < (a - b) ? -1 : 1);
109 }
110
111 static void timeline_free_pt(struct sync_pt *pt)
112 {
113         struct mali_sync_pt *mpt;
114
115         MALI_DEBUG_ASSERT_POINTER(pt);
116         mpt = to_mali_sync_pt(pt);
117
118         mali_sync_flag_put(mpt->flag);
119 }
120
121 static void timeline_release(struct sync_timeline *sync_timeline)
122 {
123         module_put(THIS_MODULE);
124 }
125
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)
128 {
129         struct mali_sync_pt *mpt;
130
131         MALI_DEBUG_ASSERT_POINTER(s);
132         MALI_DEBUG_ASSERT_POINTER(sync_pt);
133
134         mpt = to_mali_sync_pt(sync_pt);
135
136         /* It is possible this sync point is just under construct,
137          * make sure the flag is valid before accessing it
138         */
139         if (mpt->flag) {
140                 seq_printf(s, "%u", mpt->flag->point);
141         } else {
142                 seq_printf(s, "uninitialized");
143         }
144 }
145
146 #else
147 static void timeline_pt_value_str(struct sync_pt *pt, char *str, int size)
148 {
149         struct mali_sync_pt *mpt;
150
151         MALI_DEBUG_ASSERT_POINTER(str);
152         MALI_DEBUG_ASSERT_POINTER(pt);
153
154         mpt = to_mali_sync_pt(pt);
155
156         /* It is possible this sync point is just under construct,
157          * make sure the flag is valid before accessing it
158         */
159         if (mpt->flag) {
160                 _mali_osk_snprintf(str, size, "%u", mpt->flag->point);
161         } else {
162                 _mali_osk_snprintf(str, size, "uninitialized");
163         }
164 }
165
166 static void timeline_value_str(struct sync_timeline *timeline, char *str, int size)
167 {
168         struct mali_sync_timeline_container *mali_sync_tl;
169
170         MALI_DEBUG_ASSERT_POINTER(timeline);
171         MALI_DEBUG_ASSERT_POINTER(str);
172
173         mali_sync_tl = to_mali_sync_tl_container(timeline);
174
175         MALI_DEBUG_ASSERT_POINTER(mali_sync_tl);
176
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);
180         }
181 }
182 #endif
183
184 static struct sync_timeline_ops mali_timeline_ops = {
185         .driver_name    = "Mali",
186         .dup            = timeline_dup,
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,
193 #else
194         .pt_value_str = timeline_pt_value_str,
195         .timeline_value_str = timeline_value_str,
196 #endif
197 };
198
199 struct sync_timeline *mali_sync_timeline_create(struct mali_timeline *timeline, const char *name)
200 {
201         struct sync_timeline *sync_tl;
202         struct mali_sync_timeline_container *mali_sync_tl;
203
204         sync_tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct mali_sync_timeline_container), name);
205         if (NULL == sync_tl) return NULL;
206
207         mali_sync_tl = to_mali_sync_tl_container(sync_tl);
208         mali_sync_tl->timeline = timeline;
209
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
212          * timeline is freed.
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);
216
217         return sync_tl;
218 }
219
220 mali_bool mali_sync_timeline_is_ours(struct sync_timeline *sync_tl)
221 {
222         MALI_DEBUG_ASSERT_POINTER(sync_tl);
223         return (sync_tl->ops == &mali_timeline_ops) ? MALI_TRUE : MALI_FALSE;
224 }
225
226 s32 mali_sync_fence_fd_alloc(struct sync_fence *sync_fence)
227 {
228         s32 fd = -1;
229
230         fd = get_unused_fd();
231         if (fd < 0) {
232                 sync_fence_put(sync_fence);
233                 return -1;
234         }
235         sync_fence_install(sync_fence, fd);
236
237         return fd;
238 }
239
240 struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2)
241 {
242         struct sync_fence *sync_fence;
243
244         MALI_DEBUG_ASSERT_POINTER(sync_fence1);
245         MALI_DEBUG_ASSERT_POINTER(sync_fence1);
246
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);
250
251         return sync_fence;
252 }
253
254 struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl)
255 {
256         struct mali_sync_flag *flag;
257         struct sync_fence *sync_fence;
258
259         MALI_DEBUG_ASSERT_POINTER(sync_tl);
260
261         flag = mali_sync_flag_create(sync_tl, 0);
262         if (NULL == flag) return NULL;
263
264         sync_fence = mali_sync_flag_create_fence(flag);
265
266         mali_sync_flag_signal(flag, 0);
267         mali_sync_flag_put(flag);
268
269         return sync_fence;
270 }
271
272 struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, mali_timeline_point point)
273 {
274         struct mali_sync_flag *flag;
275
276         if (NULL == sync_tl) return NULL;
277
278         flag = _mali_osk_calloc(1, sizeof(*flag));
279         if (NULL == flag) return NULL;
280
281         flag->sync_tl = sync_tl;
282         flag->point = point;
283
284         flag->status = 0;
285         kref_init(&flag->refcount);
286
287         return flag;
288 }
289
290 void mali_sync_flag_get(struct mali_sync_flag *flag)
291 {
292         MALI_DEBUG_ASSERT_POINTER(flag);
293         kref_get(&flag->refcount);
294 }
295
296 /**
297  * Free sync flag.
298  *
299  * @param ref kref object embedded in sync flag that should be freed.
300  */
301 static void mali_sync_flag_free(struct kref *ref)
302 {
303         struct mali_sync_flag *flag;
304
305         MALI_DEBUG_ASSERT_POINTER(ref);
306         flag = container_of(ref, struct mali_sync_flag, refcount);
307
308         _mali_osk_free(flag);
309 }
310
311 void mali_sync_flag_put(struct mali_sync_flag *flag)
312 {
313         MALI_DEBUG_ASSERT_POINTER(flag);
314         kref_put(&flag->refcount, mali_sync_flag_free);
315 }
316
317 void mali_sync_flag_signal(struct mali_sync_flag *flag, int error)
318 {
319         MALI_DEBUG_ASSERT_POINTER(flag);
320
321         MALI_DEBUG_ASSERT(0 == flag->status);
322         flag->status = (0 > error) ? error : 1;
323
324         _mali_osk_write_mem_barrier();
325
326         sync_timeline_signal(flag->sync_tl);
327 }
328
329 /**
330  * Create a sync point attached to given sync flag.
331  *
332  * @note Sync points must be triggered in *exactly* the same order as they are created.
333  *
334  * @param flag Sync flag.
335  * @return New sync point if successful, NULL if not.
336  */
337 static struct sync_pt *mali_sync_flag_create_pt(struct mali_sync_flag *flag)
338 {
339         struct sync_pt *pt;
340         struct mali_sync_pt *mpt;
341
342         MALI_DEBUG_ASSERT_POINTER(flag);
343         MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
344
345         pt = sync_pt_create(flag->sync_tl, sizeof(struct mali_sync_pt));
346         if (NULL == pt) return NULL;
347
348         mali_sync_flag_get(flag);
349
350         mpt = to_mali_sync_pt(pt);
351         mpt->flag = flag;
352         mpt->sync_tl = flag->sync_tl;
353
354         return pt;
355 }
356
357 struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag)
358 {
359         struct sync_pt    *sync_pt;
360         struct sync_fence *sync_fence;
361
362         MALI_DEBUG_ASSERT_POINTER(flag);
363         MALI_DEBUG_ASSERT_POINTER(flag->sync_tl);
364
365         sync_pt = mali_sync_flag_create_pt(flag);
366         if (NULL == sync_pt) return NULL;
367
368         sync_fence = sync_fence_create("mali_flag_fence", sync_pt);
369         if (NULL == sync_fence) {
370                 sync_pt_free(sync_pt);
371                 return NULL;
372         }
373
374         return sync_fence;
375 }