MA-10827 Fix SystemUI crash issue on imx8

SystemUI crash issue on imx8 when switch between Gallery preview
and Settings through overview button. Fix the issue through add
reference count for Vivante bo.

Error log before crash:
v_egl : _GetVivanteDrmBoType: failed to get bo tiling
OpenGLRenderer: GL error: GL_INVALID_OPERATION
OpenGLRenderer: glEGLImageTargetTexture2DOES error! GL_INVALID_OPERATION (0x502)

Change-Id: I23888bcd73f12ed7ef378e017dd7a7a3a87c796f
Signed-off-by: Richard Liu <xuegang.liu@nxp.com>
Signed-off-by: ivan.liu <xiaowen.liu@nxp.com>
diff --git a/vivante/vivante_bo.c b/vivante/vivante_bo.c
index fe74384..c594e48 100644
--- a/vivante/vivante_bo.c
+++ b/vivante/vivante_bo.c
@@ -34,6 +34,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
+#include <pthread.h>
 
 #include <sys/mman.h>
 
@@ -47,6 +48,9 @@
 {
     /* driver fd. */
     int fd;
+
+    struct drm_vivante_bo *bo_list;
+    pthread_mutex_t mutex;
 };
 
 struct drm_vivante_bo
@@ -62,8 +66,12 @@
     uint32_t size;
 
     void *vaddr;
+
+    int refcount;
+    struct drm_vivante_bo *next;
 };
 
+
 int drm_vivante_create(int fd, struct drm_vivante **drmp)
 {
     int supported = 0;
@@ -87,8 +95,10 @@
         return -ENOMEM;
 
     drm->fd = fd;
-    *drmp = drm;
+    drm->bo_list = NULL;
+    pthread_mutex_init(&drm->mutex, NULL);
 
+    *drmp = drm;
     return 0;
 }
 
@@ -97,6 +107,67 @@
     free(drm);
 }
 
+static inline void drm_vivante_bo_add_locked(struct drm_vivante *drm,
+                    struct drm_vivante_bo *bo)
+{
+    bo->refcount = 1;
+    bo->next = drm->bo_list;
+    drm->bo_list = bo;
+}
+
+static void drm_vivante_bo_add(struct drm_vivante *drm,
+                    struct drm_vivante_bo *bo)
+{
+    pthread_mutex_lock(&drm->mutex);
+    drm_vivante_bo_add_locked(drm, bo);
+    pthread_mutex_unlock(&drm->mutex);
+}
+
+static struct drm_vivante_bo *drm_vivante_bo_lookup(
+                    struct drm_vivante *drm, uint32_t handle)
+{
+    struct drm_vivante_bo *bo;
+    int err;
+
+    for (bo = drm->bo_list; bo != NULL; bo = bo->next) {
+        if (bo->handle == handle)
+            break;
+    }
+    if (bo)
+        bo->refcount++;
+    return bo;
+}
+
+/* returns refcount. */
+static int drm_vivante_bo_decref(struct drm_vivante *drm,
+                struct drm_vivante_bo *bo)
+{
+    int ret;
+
+    pthread_mutex_lock(&drm->mutex);
+    ret = --bo->refcount;
+
+    if (ret > 0)
+        goto out;
+
+    /* unlink bo. */
+    if (bo == drm->bo_list)
+        drm->bo_list = bo->next;
+    else {
+        struct drm_vivante_bo *prev = NULL;
+        for (prev = drm->bo_list; prev != NULL; prev = prev->next) {
+            if (prev->next == bo) {
+                prev->next = bo->next;
+                break;
+            }
+        }
+    }
+
+out:
+    pthread_mutex_unlock(&drm->mutex);
+    return ret;
+}
+
 static int drm_vivante_bo_init(struct drm_vivante *drm,
                 struct drm_vivante_bo **bop)
 {
@@ -143,6 +214,7 @@
     bo->flags = flags;
     bo->size = size;
 
+    drm_vivante_bo_add(drm, bo);
     *bop = bo;
     return 0;
 }
@@ -205,6 +277,7 @@
     bo->flags = flags;
     bo->size = size;
 
+    drm_vivante_bo_add(drm, bo);
     *bop = bo;
     return 0;
 
@@ -251,14 +324,23 @@
     if (!drm || !bop || fd < 0)
         return -EINVAL;
 
-    err = drm_vivante_bo_init(drm, &bo);
-    if (err)
-        return err;
+    pthread_mutex_lock(&drm->mutex);
 
     if (drmPrimeFDToHandle(drm->fd, fd, &handle)) {
         err = -errno;
         goto err_close;
     }
+
+    bo = drm_vivante_bo_lookup(drm, handle);
+    if (bo) {
+        pthread_mutex_unlock(&drm->mutex);
+        *bop = bo;
+        return 0;
+    }
+
+    err = drm_vivante_bo_init(drm, &bo);
+    if (err)
+        goto err_close;
     bo->handle = handle;
 
     err = drm_vivante_bo_query(bo, DRM_VIV_GEM_PARAM_SIZE, &size);
@@ -266,10 +348,15 @@
         goto err_close;
     bo->size = (uint32_t)size;
 
+    drm_vivante_bo_add_locked(drm, bo);
+    pthread_mutex_unlock(&drm->mutex);
+
     *bop = bo;
     return 0;
 
 err_close:
+    pthread_mutex_unlock(&drm->mutex);
+
     if (handle > 0) {
         struct drm_gem_close close_args = {
             .handle = handle,
@@ -288,6 +375,9 @@
     if (!bo)
         return;
 
+    if (drm_vivante_bo_decref(bo->drm, bo) != 0)
+        return;
+
     if (bo->vaddr) {
         drm_vivante_bo_munmap(bo);
     }