Initialize Tizen 2.3
[adaptation/ap_samsung/libtbm-exynos4412.git] / src / tbm_bufmgr_exynos4412.c
1 /**************************************************************************
2
3 libtbm_exynos4412
4
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <sys/ioctl.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <sys/mman.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <xf86drm.h>
47 #include <tbm_bufmgr.h>
48 #include <tbm_bufmgr_backend.h>
49 #include "exynos_drm.h"
50 #include <pthread.h>
51
52 #define DEBUG
53 #define USE_DMAIMPORT
54 #define TBM_EXYNOS4412_LOG(...) fprintf (stderr, __VA_ARGS__)
55
56 #ifdef DEBUG
57 static int bDebug = 0;
58 #define DBG(...) if(bDebug&0x1) TBM_EXYNOS4412_LOG (__VA_ARGS__)
59 #else
60 #define DBG(...)
61 #endif
62
63 /* check condition */
64 #define EXYNOS4412_RETURN_IF_FAIL(cond) {\
65     if (!(cond)) {\
66         TBM_EXYNOS4412_LOG ("[%s] : '%s' failed.\n", __FUNCTION__, #cond);\
67         return;\
68     }\
69 }
70 #define EXYNOS4412_RETURN_VAL_IF_FAIL(cond, val) {\
71     if (!(cond)) {\
72         TBM_EXYNOS4412_LOG ("[%s] : '%s' failed.\n", __FUNCTION__, #cond);\
73         return val;\
74     }\
75 }
76
77 struct dma_buf_info {
78         unsigned long   size;
79         unsigned int    fence_supported;
80         unsigned int    padding;
81 };
82
83 #define DMA_BUF_ACCESS_READ             0x1
84 #define DMA_BUF_ACCESS_WRITE            0x2
85 #define DMA_BUF_ACCESS_DMA              0x4
86 #define DMA_BUF_ACCESS_MAX              0x8
87
88 #define DMA_FENCE_LIST_MAX              5
89
90 struct dma_buf_fence {
91         unsigned long           ctx;
92         unsigned int            type;
93 };
94
95 #define DMABUF_IOCTL_BASE       'F'
96 #define DMABUF_IOWR(nr, type)   _IOWR(DMABUF_IOCTL_BASE, nr, type)
97
98 #define DMABUF_IOCTL_GET_INFO   DMABUF_IOWR(0x00, struct dma_buf_info)
99 #define DMABUF_IOCTL_GET_FENCE  DMABUF_IOWR(0x01, struct dma_buf_fence)
100 #define DMABUF_IOCTL_PUT_FENCE  DMABUF_IOWR(0x02, struct dma_buf_fence)
101
102 typedef struct _tbm_bufmgr_exynos4412 *tbm_bufmgr_exynos4412;
103 typedef struct _tbm_bo_exynos4412 *tbm_bo_exynos4412;
104
105 typedef struct _exynos4412_private
106 {
107     int ref_count;
108 } PrivGem;
109
110 /* tbm buffor object for exynos4412 */
111 struct _tbm_bo_exynos4412
112 {
113     int fd;
114
115     unsigned int name;    /* FLINK ID */
116
117     unsigned int gem;     /* GEM Handle */
118
119     unsigned int dmabuf;  /* fd for dmabuf */
120
121     void *pBase;          /* virtual address */
122
123     unsigned int size;
124
125     unsigned int flags_exynos;
126     unsigned int flags_tbm;
127
128     PrivGem* private;
129
130     pthread_mutex_t mutex;
131     struct dma_buf_fence dma_fence[DMA_FENCE_LIST_MAX];
132     int device;
133     int opt;
134 };
135
136 /* tbm bufmgr private for exynos4412 */
137 struct _tbm_bufmgr_exynos4412
138 {
139     int fd;
140     int isLocal;
141     void* hashBos;
142
143     int use_dma_fence;
144 };
145
146 char *STR_DEVICE[]=
147 {
148     "DEF",
149     "CPU",
150     "2D",
151     "3D",
152     "MM"
153 };
154
155 char *STR_OPT[]=
156 {
157     "NONE",
158     "RD",
159     "WR",
160     "RDWR"
161 };
162
163 static unsigned int
164 _get_exynos_flag_from_tbm (unsigned int ftbm)
165 {
166     unsigned int flags = 0;
167
168     if (ftbm & TBM_BO_SCANOUT)
169         flags |= EXYNOS_BO_CONTIG;
170     else
171         flags |= EXYNOS_BO_NONCONTIG;
172
173     if (ftbm & TBM_BO_WC)
174         flags |= EXYNOS_BO_WC;
175     else if (ftbm & TBM_BO_NONCACHABLE)
176         flags |= EXYNOS_BO_NONCACHABLE;
177     else
178         flags |= EXYNOS_BO_CACHABLE;
179
180     return flags;
181 }
182
183 static unsigned int
184 _get_tbm_flag_from_exynos (unsigned int fexynos)
185 {
186     unsigned int flags = 0;
187
188     if (fexynos & EXYNOS_BO_NONCONTIG)
189         flags |= TBM_BO_DEFAULT;
190     else
191         flags |= TBM_BO_SCANOUT;
192
193     if (fexynos & EXYNOS_BO_WC)
194         flags |= TBM_BO_WC;
195     else if (fexynos & EXYNOS_BO_CACHABLE)
196         flags |= TBM_BO_DEFAULT;
197     else
198         flags |= TBM_BO_NONCACHABLE;
199
200     return flags;
201 }
202
203 static unsigned int
204 _get_name (int fd, unsigned int gem)
205 {
206     struct drm_gem_flink arg = {0,};
207
208     arg.handle = gem;
209     if (drmIoctl (fd, DRM_IOCTL_GEM_FLINK, &arg))
210     {
211         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
212                  "error %s:%d fail to get flink gem=%d\n",
213                  getpid(), __FUNCTION__, __LINE__, gem);
214         return 0;
215     }
216
217     return (unsigned int)arg.name;
218 }
219
220 static tbm_bo_handle
221 _exynos4412_bo_handle (tbm_bo_exynos4412 bo_exynos4412, int device)
222 {
223     tbm_bo_handle bo_handle;
224     memset (&bo_handle, 0x0, sizeof (uint64_t));
225
226     switch(device)
227     {
228     case TBM_DEVICE_DEFAULT:
229     case TBM_DEVICE_2D:
230         bo_handle.u32 = (uint32_t)bo_exynos4412->gem;
231         break;
232     case TBM_DEVICE_CPU:
233         if (!bo_exynos4412->pBase)
234         {
235             struct drm_exynos_gem_mmap arg = {0,};
236
237             arg.handle = bo_exynos4412->gem;
238             arg.size = bo_exynos4412->size;
239             if (drmCommandWriteRead (bo_exynos4412->fd, DRM_EXYNOS_GEM_MMAP, &arg, sizeof(arg)))
240             {
241                 TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
242                          "error %s:%d Cannot usrptr gem=%d\n",
243                          getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem);
244                 return (tbm_bo_handle) NULL;
245             }
246             bo_exynos4412->pBase = (void*)((uint32_t)arg.mapped);
247         }
248
249         bo_handle.ptr = (void *)bo_exynos4412->pBase;
250         break;
251     case TBM_DEVICE_3D:
252         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
253                  "warning %s:%d(UMP not supported. Return DMABUF).\n",
254                  getpid(), __FUNCTION__, __LINE__);
255     case TBM_DEVICE_MM:
256         if (!bo_exynos4412->dmabuf)
257         {
258             struct drm_prime_handle arg = {0, };
259
260             arg.handle = bo_exynos4412->gem;
261             if (drmIoctl (bo_exynos4412->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg))
262             {
263                 TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
264                          "error %s:%d Cannot dmabuf=%d\n",
265                          getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem);
266                 return (tbm_bo_handle) NULL;
267             }
268             bo_exynos4412->dmabuf = arg.fd;
269         }
270
271         bo_handle.u32 = (uint32_t)bo_exynos4412->dmabuf;
272         break;
273     default:
274         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
275                  "error %s:%d Not supported device:%d\n",
276                  getpid(), __FUNCTION__, __LINE__, device);
277         bo_handle.ptr = (void *) NULL;
278         break;
279     }
280
281     return bo_handle;
282 }
283
284 static int
285 _exynos4412_cache_flush (int fd, tbm_bo_exynos4412 bo_exynos4412, int flags)
286 {
287     struct drm_exynos_gem_cache_op cache_op = {0, };
288     int ret;
289
290     /* if bo_exynos4412 is null, do cache_flush_all */
291     if(bo_exynos4412)
292     {
293         cache_op.flags = 0;
294         cache_op.usr_addr = (uint64_t)((uint32_t)bo_exynos4412->pBase);
295         cache_op.size = bo_exynos4412->size;
296     }
297     else
298     {
299         flags = TBM_CACHE_FLUSH_ALL;
300         cache_op.flags = 0;
301         cache_op.usr_addr = 0;
302         cache_op.size = 0;
303     }
304
305     if (flags & TBM_CACHE_INV)
306     {
307         if(flags & TBM_CACHE_ALL)
308             cache_op.flags |= EXYNOS_DRM_CACHE_INV_ALL;
309         else
310             cache_op.flags |= EXYNOS_DRM_CACHE_INV_RANGE;
311     }
312
313     if (flags & TBM_CACHE_CLN)
314     {
315         if(flags & TBM_CACHE_ALL)
316             cache_op.flags |= EXYNOS_DRM_CACHE_CLN_ALL;
317         else
318             cache_op.flags |= EXYNOS_DRM_CACHE_CLN_RANGE;
319     }
320
321     if(flags & TBM_CACHE_ALL)
322         cache_op.flags |= EXYNOS_DRM_ALL_CACHES_CORES;
323
324     ret = drmCommandWriteRead (fd, DRM_EXYNOS_GEM_CACHE_OP, &cache_op, sizeof(cache_op));
325     if (ret)
326     {
327         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
328                  "error %s:%d fail to flush the cache.\n",
329                  getpid(), __FUNCTION__, __LINE__);
330         return 0;
331     }
332
333     return 1;
334 }
335
336 static int
337 tbm_exynos4412_bo_size (tbm_bo bo)
338 {
339     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
340
341     tbm_bo_exynos4412 bo_exynos4412;
342
343     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
344
345     return bo_exynos4412->size;
346 }
347
348 static void *
349 tbm_exynos4412_bo_alloc (tbm_bo bo, int size, int flags)
350 {
351     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
352
353     tbm_bo_exynos4412 bo_exynos4412;
354     tbm_bufmgr_exynos4412 bufmgr_exynos4412;
355     unsigned int exynos_flags;
356
357     bufmgr_exynos4412 = (tbm_bufmgr_exynos4412)tbm_backend_get_bufmgr_priv(bo);
358     EXYNOS4412_RETURN_VAL_IF_FAIL (bufmgr_exynos4412!=NULL, 0);
359
360     bo_exynos4412 = calloc (1, sizeof(struct _tbm_bo_exynos4412));
361     if (!bo_exynos4412)
362     {
363         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
364                  "error %s:%d fail to allocate the bo private\n",
365                  getpid(), __FUNCTION__, __LINE__);
366         return 0;
367     }
368
369     exynos_flags = _get_exynos_flag_from_tbm (flags);
370     if((flags & TBM_BO_SCANOUT) &&
371         size <= 4*1024)
372     {
373         exynos_flags |= EXYNOS_BO_NONCONTIG;
374     }
375
376     struct drm_exynos_gem_create arg = {0, };
377     arg.size = size;
378     arg.flags = exynos_flags;
379     if (drmCommandWriteRead(bufmgr_exynos4412->fd, DRM_EXYNOS_GEM_CREATE, &arg, sizeof(arg)))
380     {
381         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
382                  "error %s:%d Cannot create bo(flag:%x, size:%d)\n",
383                  getpid(), __FUNCTION__, __LINE__, arg.flags, (unsigned int)arg.size);
384         free (bo_exynos4412);
385         return 0;
386     }
387
388     bo_exynos4412->fd = bufmgr_exynos4412->fd;
389     bo_exynos4412->gem = arg.handle;
390     bo_exynos4412->size = size;
391     bo_exynos4412->flags_tbm = flags;
392     bo_exynos4412->flags_exynos = exynos_flags;
393     bo_exynos4412->name = _get_name (bo_exynos4412->fd, bo_exynos4412->gem);
394
395     pthread_mutex_init(&bo_exynos4412->mutex, NULL);
396
397     if (bufmgr_exynos4412->use_dma_fence
398         && !bo_exynos4412->dmabuf)
399     {
400         struct drm_prime_handle arg = {0, };
401
402         arg.handle = bo_exynos4412->gem;
403         if (drmIoctl (bo_exynos4412->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg))
404         {
405             TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
406                     "error %s:%d Cannot dmabuf=%d\n",
407                     getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem);
408             free (bo_exynos4412);
409             return 0;
410         }
411         bo_exynos4412->dmabuf = arg.fd;
412     }
413
414     /* add bo to hash */
415     PrivGem* privGem = calloc (1, sizeof(PrivGem));
416     privGem->ref_count = 1;
417     if (drmHashInsert(bufmgr_exynos4412->hashBos, bo_exynos4412->name, (void *)privGem) < 0)
418     {
419         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
420                  "error %s:%d Cannot insert bo to Hash(%d)\n",
421                  getpid(), __FUNCTION__, __LINE__, bo_exynos4412->name);
422     }
423
424     DBG ("[libtbm-exynos4412:%d] %s size:%d, gem:%d(%d), flags:%d(%d)\n", getpid(),
425          __FUNCTION__, bo_exynos4412->size,
426          bo_exynos4412->gem, bo_exynos4412->name,
427          flags, exynos_flags);
428
429     return (void *)bo_exynos4412;
430 }
431
432 static void
433 tbm_exynos4412_bo_free(tbm_bo bo)
434 {
435     tbm_bo_exynos4412 bo_exynos4412;
436     tbm_bufmgr_exynos4412 bufmgr_exynos4412;
437
438     if (!bo)
439         return;
440
441     bufmgr_exynos4412 = (tbm_bufmgr_exynos4412)tbm_backend_get_bufmgr_priv(bo);
442     EXYNOS4412_RETURN_IF_FAIL (bufmgr_exynos4412!=NULL);
443
444     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
445     EXYNOS4412_RETURN_IF_FAIL (bo_exynos4412!=NULL);
446
447     DBG ("[libtbm-exynos4412:%d] %s size:%d, gem:%d(%d)\n",
448          getpid(), __FUNCTION__, bo_exynos4412->size, bo_exynos4412->gem, bo_exynos4412->name);
449
450     if (bo_exynos4412->pBase)
451     {
452         if (munmap(bo_exynos4412->pBase, bo_exynos4412->size) == -1)
453         {
454             TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
455                      "error %s:%d\n",
456                      getpid(), __FUNCTION__, __LINE__);
457         }
458     }
459
460     /* close dmabuf */
461     if (bo_exynos4412->dmabuf)
462     {
463         close (bo_exynos4412->dmabuf);
464         bo_exynos4412->dmabuf = 0;
465     }
466
467     /* delete bo from hash */
468     PrivGem *privGem = NULL;
469     int ret;
470
471     ret = drmHashLookup (bufmgr_exynos4412->hashBos, bo_exynos4412->name, (void**)&privGem);
472     if (ret == 0)
473     {
474         privGem->ref_count--;
475         if (privGem->ref_count == 0)
476         {
477             drmHashDelete (bufmgr_exynos4412->hashBos, bo_exynos4412->name);
478             free (privGem);
479             privGem = NULL;
480         }
481     }
482     else
483     {
484         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
485                  "warning %s:%d Cannot find bo to Hash(%d), ret=%d\n",
486                  getpid(), __FUNCTION__, __LINE__, bo_exynos4412->name, ret);
487     }
488
489     /* Free gem handle */
490     struct drm_gem_close arg = {0, };
491     memset (&arg, 0, sizeof(arg));
492     arg.handle = bo_exynos4412->gem;
493     if (drmIoctl (bo_exynos4412->fd, DRM_IOCTL_GEM_CLOSE, &arg))
494     {
495         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
496                  "error %s:%d\n",
497                  getpid(), __FUNCTION__, __LINE__);
498     }
499
500     free (bo_exynos4412);
501 }
502
503
504 static void *
505 tbm_exynos4412_bo_import (tbm_bo bo, unsigned int key)
506 {
507     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
508
509     tbm_bufmgr_exynos4412 bufmgr_exynos4412;
510     tbm_bo_exynos4412 bo_exynos4412;
511
512     bufmgr_exynos4412 = (tbm_bufmgr_exynos4412)tbm_backend_get_bufmgr_priv(bo);
513     EXYNOS4412_RETURN_VAL_IF_FAIL (bufmgr_exynos4412!=NULL, 0);
514
515     struct drm_gem_open arg = {0, };
516     struct drm_exynos_gem_info info = {0, };
517
518     arg.name = key;
519     if (drmIoctl(bufmgr_exynos4412->fd, DRM_IOCTL_GEM_OPEN, &arg))
520     {
521         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
522                 "error %s:%d Cannot open gem name=%d\n",
523                 getpid(), __FUNCTION__, __LINE__, key);
524         return 0;
525     }
526
527     info.handle = arg.handle;
528     if (drmCommandWriteRead(bufmgr_exynos4412->fd,
529                            DRM_EXYNOS_GEM_GET,
530                            &info,
531                            sizeof(struct drm_exynos_gem_info)))
532     {
533         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
534                 "error %s:%d Cannot get gem info=%d\n",
535                 getpid(), __FUNCTION__, __LINE__, key);
536         return 0;
537     }
538
539     bo_exynos4412 = calloc (1, sizeof(struct _tbm_bo_exynos4412));
540     if (!bo_exynos4412)
541     {
542         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
543                 "error %s:%d fail to allocate the bo private\n",
544                 getpid(), __FUNCTION__, __LINE__);
545         return 0;
546     }
547
548     bo_exynos4412->fd = bufmgr_exynos4412->fd;
549     bo_exynos4412->gem = arg.handle;
550     bo_exynos4412->size = arg.size;
551     bo_exynos4412->flags_exynos = info.flags;
552     bo_exynos4412->name = key;
553     bo_exynos4412->flags_tbm = _get_tbm_flag_from_exynos (bo_exynos4412->flags_exynos);
554
555     if (!bo_exynos4412->dmabuf)
556     {
557         struct drm_prime_handle arg = {0, };
558
559         arg.handle = bo_exynos4412->gem;
560         if (drmIoctl (bo_exynos4412->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg))
561         {
562             TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
563                     "error %s:%d Cannot dmabuf=%d\n",
564                     getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem);
565             free (bo_exynos4412);
566             return 0;
567         }
568         bo_exynos4412->dmabuf = arg.fd;
569     }
570
571     /* add bo to hash */
572     PrivGem *privGem = NULL;
573     int ret;
574
575     ret = drmHashLookup (bufmgr_exynos4412->hashBos, bo_exynos4412->name, (void**)&privGem);
576     if (ret == 0)
577     {
578         privGem->ref_count++;
579     }
580     else if (ret == 1)
581     {
582         privGem = calloc (1, sizeof(PrivGem));
583         privGem->ref_count = 1;
584         if (drmHashInsert (bufmgr_exynos4412->hashBos, bo_exynos4412->name, (void *)privGem) < 0)
585         {
586             TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
587                     "error %s:%d Cannot insert bo to Hash(%d)\n",
588                     getpid(), __FUNCTION__, __LINE__, bo_exynos4412->name);
589         }
590     }
591     else
592     {
593         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
594                 "error %s:%d Cannot insert bo to Hash(%d)\n",
595                 getpid(), __FUNCTION__, __LINE__, bo_exynos4412->name);
596     }
597
598     DBG ("[libtbm-exynos4412:%d] %s size:%d, gem:%d(%d), flags:%d(%d)\n", getpid(),
599          __FUNCTION__, bo_exynos4412->size,
600          bo_exynos4412->gem, bo_exynos4412->name,
601          bo_exynos4412->flags_tbm, bo_exynos4412->flags_exynos);
602
603     return (void *)bo_exynos4412;
604 }
605
606 static unsigned int
607 tbm_exynos4412_bo_export (tbm_bo bo)
608 {
609     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
610
611     tbm_bo_exynos4412 bo_exynos4412;
612
613     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
614     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, 0);
615
616     if (!bo_exynos4412->name)
617     {
618         bo_exynos4412->name = _get_name(bo_exynos4412->fd, bo_exynos4412->gem);
619         if (!bo_exynos4412->name)
620         {
621             TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
622                     "error %s:%d Cannot get name\n",
623                     getpid(), __FUNCTION__, __LINE__);
624             return 0;
625         }
626     }
627
628     DBG ("[libtbm-exynos4412:%d] %s size:%d, gem:%d(%d), flags:%d(%d)\n", getpid(),
629          __FUNCTION__, bo_exynos4412->size,
630          bo_exynos4412->gem, bo_exynos4412->name,
631          bo_exynos4412->flags_tbm, bo_exynos4412->flags_exynos);
632
633     return (unsigned int)bo_exynos4412->name;
634 }
635
636 static tbm_bo_handle
637 tbm_exynos4412_bo_get_handle (tbm_bo bo, int device)
638 {
639     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, (tbm_bo_handle) NULL);
640
641     tbm_bo_handle bo_handle;
642     tbm_bo_exynos4412 bo_exynos4412;
643
644     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
645     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, (tbm_bo_handle) NULL);
646
647     if (!bo_exynos4412->gem)
648     {
649         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
650                 "error %s:%d Cannot map gem=%d\n",
651                 getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem);
652         return (tbm_bo_handle) NULL;
653     }
654
655     DBG ("[libtbm-exynos4412:%d] %s gem:%d(%d), %s\n", getpid(),
656          __FUNCTION__, bo_exynos4412->gem, bo_exynos4412->name, STR_DEVICE[device]);
657
658     /*Get mapped bo_handle*/
659     bo_handle = _exynos4412_bo_handle (bo_exynos4412, device);
660     if (bo_handle.ptr == NULL)
661     {
662         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
663                 "error %s:%d Cannot get handle: gem:%d, device:%d\n",
664                 getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem, device);
665         return (tbm_bo_handle) NULL;
666     }
667
668     return bo_handle;
669 }
670
671 static tbm_bo_handle
672 tbm_exynos4412_bo_map (tbm_bo bo, int device, int opt)
673 {
674     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, (tbm_bo_handle) NULL);
675
676     tbm_bo_handle bo_handle;
677     tbm_bo_exynos4412 bo_exynos4412;
678
679     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
680     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, (tbm_bo_handle) NULL);
681
682     if (!bo_exynos4412->gem)
683     {
684         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
685                 "error %s:%d Cannot map gem=%d\n",
686                 getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem);
687         return (tbm_bo_handle) NULL;
688     }
689
690     DBG ("[libtbm-exynos4412:%d] %s gem:%d(%d), %s, %s\n", getpid(),
691          __FUNCTION__, bo_exynos4412->gem, bo_exynos4412->name, STR_DEVICE[device], STR_OPT[opt]);
692
693     /*Get mapped bo_handle*/
694     bo_handle = _exynos4412_bo_handle (bo_exynos4412, device);
695     if (bo_handle.ptr == NULL)
696     {
697         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
698                 "error %s:%d Cannot get handle: gem:%d, device:%d, opt:%d\n",
699                 getpid(), __FUNCTION__, __LINE__, bo_exynos4412->gem, device, opt);
700         return (tbm_bo_handle) NULL;
701     }
702
703     return bo_handle;
704 }
705
706 static int
707 tbm_exynos4412_bo_unmap (tbm_bo bo)
708 {
709     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
710
711     tbm_bo_exynos4412 bo_exynos4412;
712
713     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
714     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, 0);
715
716     if (!bo_exynos4412->gem)
717         return 0;
718
719     DBG ("[libtbm-exynos4412:%d] %s gem:%d(%d) \n", getpid(),
720          __FUNCTION__, bo_exynos4412->gem, bo_exynos4412->name);
721
722     return 1;
723 }
724
725 static int
726 tbm_exynos4412_bo_cache_flush (tbm_bo bo, int flags)
727 {
728     tbm_bufmgr_exynos4412 bufmgr_exynos4412 = (tbm_bufmgr_exynos4412)tbm_backend_get_bufmgr_priv(bo);
729     EXYNOS4412_RETURN_VAL_IF_FAIL (bufmgr_exynos4412!=NULL, 0);
730
731     /* cache flush is managed by kernel side when using dma-fence. */
732     if (bufmgr_exynos4412->use_dma_fence)
733        return 1;
734
735     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
736
737     tbm_bo_exynos4412 bo_exynos4412;
738
739     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
740     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, 0);
741
742     if (!_exynos4412_cache_flush(bo_exynos4412->fd, bo_exynos4412, flags))
743         return 0;
744
745     return 1;
746 }
747
748 static int
749 tbm_exynos4412_bo_get_global_key (tbm_bo bo)
750 {
751     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
752
753     tbm_bo_exynos4412 bo_exynos4412;
754
755     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
756     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, 0);
757
758     if (!bo_exynos4412->name)
759     {
760         if (!bo_exynos4412->gem)
761             return 0;
762
763         bo_exynos4412->name = _get_name(bo_exynos4412->fd, bo_exynos4412->gem);
764     }
765
766     return bo_exynos4412->name;
767 }
768
769 static int
770 tbm_exynos4412_bo_lock(tbm_bo bo, int device, int opt)
771 {
772     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
773
774     tbm_bufmgr_exynos4412 bufmgr_exynos4412;
775     tbm_bo_exynos4412 bo_exynos4412;
776     struct dma_buf_fence fence;
777     int ret=0;
778
779     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
780     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, 0);
781
782     bufmgr_exynos4412 = (tbm_bufmgr_exynos4412)tbm_backend_get_bufmgr_priv(bo);
783     EXYNOS4412_RETURN_VAL_IF_FAIL (bufmgr_exynos4412!=NULL, 0);
784
785     memset(&fence, 0, sizeof(struct dma_buf_fence));
786
787     /* Check if the given type is valid or not. */
788     if (opt & TBM_OPTION_WRITE)
789     {
790         if (device == TBM_DEVICE_CPU)
791             fence.type = DMA_BUF_ACCESS_WRITE;
792         else if (device == TBM_DEVICE_3D)
793             fence.type = DMA_BUF_ACCESS_WRITE | DMA_BUF_ACCESS_DMA;
794         else
795         {
796             DBG ("[libtbm-exynos4412:%d] %s GET_FENCE is ignored(device type is not 3D/CPU),\n", getpid(), __FUNCTION__);
797             return 0;
798         }
799     }
800     else if (opt & TBM_OPTION_READ)
801     {
802         if (device == TBM_DEVICE_CPU)
803             fence.type = DMA_BUF_ACCESS_READ;
804         else if (device == TBM_DEVICE_3D)
805             fence.type = DMA_BUF_ACCESS_READ | DMA_BUF_ACCESS_DMA;
806         else
807         {
808             DBG ("[libtbm-exynos4412:%d] %s GET_FENCE is ignored(device type is not 3D/CPU),\n", getpid(), __FUNCTION__);
809             return 0;
810         }
811     }
812     else
813     {
814         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] error %s:%d Invalid argument\n", getpid(), __FUNCTION__, __LINE__);
815         return 0;
816     }
817
818     /* Check if the tbm manager supports dma fence or not. */
819     if (!bufmgr_exynos4412->use_dma_fence)
820     {
821         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
822                 "error %s:%d  Not support DMA FENCE(%s)\n",
823                 getpid(), __FUNCTION__, __LINE__, strerror(errno) );
824         return 0;
825
826     }
827
828     ret = ioctl(bo_exynos4412->dmabuf, DMABUF_IOCTL_GET_FENCE, &fence);
829     if (ret < 0)
830     {
831         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
832                 "error %s:%d  Can not set GET FENCE(%s)\n",
833                 getpid(), __FUNCTION__, __LINE__, strerror(errno) );
834         return 0;
835     }
836
837     pthread_mutex_lock(&bo_exynos4412->mutex);
838     int i;
839     for (i = 0; i < DMA_FENCE_LIST_MAX; i++)
840     {
841         if (bo_exynos4412->dma_fence[i].ctx == 0)
842         {
843             bo_exynos4412->dma_fence[i].type = fence.type;
844             bo_exynos4412->dma_fence[i].ctx = fence.ctx;
845             break;
846         }
847     }
848     if (i == DMA_FENCE_LIST_MAX)
849     {
850         //TODO: if dma_fence list is full, it needs realloc. I will fix this. by minseok3.kim
851         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
852                 "error %s:%d  fence list is full\n",
853                 getpid(), __FUNCTION__, __LINE__);
854     }
855     pthread_mutex_unlock(&bo_exynos4412->mutex);
856
857     DBG ("[libtbm-exynos4412:%d] %s DMABUF_IOCTL_GET_FENCE! flink_id=%d dmabuf=%d\n", getpid(),
858             __FUNCTION__, bo_exynos4412->name, bo_exynos4412->dmabuf);
859
860     return 1;
861 }
862
863 static int
864 tbm_exynos4412_bo_unlock(tbm_bo bo)
865 {
866     EXYNOS4412_RETURN_VAL_IF_FAIL (bo!=NULL, 0);
867
868     tbm_bo_exynos4412 bo_exynos4412;
869     struct dma_buf_fence fence;
870     int ret=0;
871
872     bo_exynos4412 = (tbm_bo_exynos4412)tbm_backend_get_bo_priv(bo);
873     EXYNOS4412_RETURN_VAL_IF_FAIL (bo_exynos4412!=NULL, 0);
874
875     if (!bo_exynos4412->dma_fence[0].ctx)
876     {
877         DBG ("[libtbm-exynos4412:%d] %s FENCE not support or ignored,\n", getpid(), __FUNCTION__);
878         return 0;
879     }
880
881     if (!bo_exynos4412->dma_fence[0].type)
882     {
883         DBG ("[libtbm-exynos4412:%d] %s device type is not 3D/CPU,\n", getpid(), __FUNCTION__);
884         return 0;
885     }
886
887     pthread_mutex_lock(&bo_exynos4412->mutex);
888     fence.type = bo_exynos4412->dma_fence[0].type;
889     fence.ctx = bo_exynos4412->dma_fence[0].ctx;
890     int i;
891     for (i = 1; i < DMA_FENCE_LIST_MAX; i++)
892     {
893         bo_exynos4412->dma_fence[i-1].type = bo_exynos4412->dma_fence[i].type;
894         bo_exynos4412->dma_fence[i-1].ctx = bo_exynos4412->dma_fence[i].ctx;
895     }
896     bo_exynos4412->dma_fence[DMA_FENCE_LIST_MAX-1].type = 0;
897     bo_exynos4412->dma_fence[DMA_FENCE_LIST_MAX-1].ctx = 0;
898     pthread_mutex_unlock(&bo_exynos4412->mutex);
899
900     ret = ioctl(bo_exynos4412->dmabuf, DMABUF_IOCTL_PUT_FENCE, &fence);
901     if (ret < 0)
902     {
903         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] "
904                 "error %s:%d  Can not set PUT FENCE(%s)\n",
905                 getpid(), __FUNCTION__, __LINE__, strerror(errno) );
906         return 0;
907     }
908
909     DBG ("[libtbm-exynos4412:%d] %s DMABUF_IOCTL_PUT_FENCE! flink_id=%d dmabuf=%d\n", getpid(),
910             __FUNCTION__, bo_exynos4412->name, bo_exynos4412->dmabuf);
911
912     return 1;
913 }
914
915 static void
916 tbm_exynos4412_bufmgr_deinit (void *priv)
917 {
918     EXYNOS4412_RETURN_IF_FAIL (priv!=NULL);
919
920     tbm_bufmgr_exynos4412 bufmgr_exynos4412;
921
922     bufmgr_exynos4412 = (tbm_bufmgr_exynos4412)priv;
923
924     if (bufmgr_exynos4412->hashBos)
925     {
926         unsigned long key;
927         void *value;
928
929         while (drmHashFirst(bufmgr_exynos4412->hashBos, &key, &value) > 0)
930         {
931             free (value);
932             drmHashDelete (bufmgr_exynos4412->hashBos, key);
933         }
934
935         drmHashDestroy (bufmgr_exynos4412->hashBos);
936         bufmgr_exynos4412->hashBos = NULL;
937     }
938
939     free (bufmgr_exynos4412);
940 }
941
942 MODULEINITPPROTO (init_tbm_bufmgr_priv);
943
944 static TBMModuleVersionInfo Exynos4412VersRec =
945 {
946     "exynos4412",
947     "Samsung",
948     TBM_ABI_VERSION,
949 };
950
951 TBMModuleData tbmModuleData = { &Exynos4412VersRec, init_tbm_bufmgr_priv};
952
953 int
954 init_tbm_bufmgr_priv (tbm_bufmgr bufmgr, int fd)
955 {
956     tbm_bufmgr_exynos4412 bufmgr_exynos4412;
957     tbm_bufmgr_backend bufmgr_backend;
958
959     if (!bufmgr)
960         return 0;
961
962     bufmgr_exynos4412 = calloc (1, sizeof(struct _tbm_bufmgr_exynos4412));
963     if (!bufmgr_exynos4412)
964     {
965         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] error: Fail to alloc bufmgr_exynos4412!\n", getpid());
966         return 0;
967     }
968
969     bufmgr_exynos4412->fd = fd;
970     if (bufmgr_exynos4412->fd < 0)
971     {
972         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] error: Fail to create drm!\n", getpid());
973         free (bufmgr_exynos4412);
974         return 0;
975     }
976
977     //Create Hash Table
978     bufmgr_exynos4412->hashBos = drmHashCreate ();
979
980     //Check if the tbm manager supports dma fence or not.
981     int fp = open("/sys/module/dmabuf_sync/parameters/enabled", O_RDONLY);
982     int length;
983     char buf[1];
984     if (fp != -1)
985     {
986         length = read(fp, buf, 1);
987
988         if (length == 1 && buf[0] == '1')
989             bufmgr_exynos4412->use_dma_fence = 1;
990
991         close(fp);
992     }
993
994     bufmgr_backend = tbm_backend_alloc();
995     if (!bufmgr_backend)
996     {
997         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] error: Fail to create drm!\n", getpid());
998         free (bufmgr_exynos4412);
999         return 0;
1000     }
1001
1002     bufmgr_backend->priv = (void *)bufmgr_exynos4412;
1003     bufmgr_backend->bufmgr_deinit = tbm_exynos4412_bufmgr_deinit,
1004     bufmgr_backend->bo_size = tbm_exynos4412_bo_size,
1005     bufmgr_backend->bo_alloc = tbm_exynos4412_bo_alloc,
1006     bufmgr_backend->bo_free = tbm_exynos4412_bo_free,
1007     bufmgr_backend->bo_import = tbm_exynos4412_bo_import,
1008     bufmgr_backend->bo_export = tbm_exynos4412_bo_export,
1009     bufmgr_backend->bo_get_handle = tbm_exynos4412_bo_get_handle,
1010     bufmgr_backend->bo_map = tbm_exynos4412_bo_map,
1011     bufmgr_backend->bo_unmap = tbm_exynos4412_bo_unmap,
1012     bufmgr_backend->bo_cache_flush = tbm_exynos4412_bo_cache_flush,
1013     bufmgr_backend->bo_get_global_key = tbm_exynos4412_bo_get_global_key;
1014
1015     if (bufmgr_exynos4412->use_dma_fence)
1016     {
1017         bufmgr_backend->flags = (TBM_LOCK_CTRL_BACKEND | TBM_CACHE_CTRL_BACKEND);
1018         bufmgr_backend->bo_lock = NULL;
1019         bufmgr_backend->bo_lock2 = tbm_exynos4412_bo_lock;
1020         bufmgr_backend->bo_unlock = tbm_exynos4412_bo_unlock;
1021     }
1022     else
1023     {
1024         bufmgr_backend->flags = 0;
1025         bufmgr_backend->bo_lock = NULL;
1026         bufmgr_backend->bo_unlock = NULL;
1027     }
1028
1029     if (!tbm_backend_init (bufmgr, bufmgr_backend))
1030     {
1031         TBM_EXYNOS4412_LOG ("[libtbm-exynos4412:%d] error: Fail to init backend!\n", getpid());
1032         tbm_backend_free (bufmgr_backend);
1033         free (bufmgr_exynos4412);
1034         return 0;
1035     }
1036
1037 #ifdef DEBUG
1038     {
1039         char* env;
1040         env = getenv ("TBM_EXYNOS4412_DEBUG");
1041         if (env)
1042         {
1043             bDebug = atoi (env);
1044             TBM_EXYNOS4412_LOG ("TBM_EXYNOS4412_DEBUG=%s\n", env);
1045         }
1046         else
1047         {
1048             bDebug = 0;
1049         }
1050     }
1051 #endif
1052
1053     DBG ("[libtbm-exynos4412:%d] %s DMABUF FENCE is %s\n", getpid(),
1054          __FUNCTION__, bufmgr_exynos4412->use_dma_fence ? "supported!" : "NOT supported!");
1055
1056     DBG ("[libtbm-exynos4412:%d] %s fd:%d\n", getpid(),
1057          __FUNCTION__, bufmgr_exynos4412->fd);
1058
1059     return 1;
1060 }
1061
1062