summaryrefslogtreecommitdiff
path: root/drivers/gpu/ion/sprd/sprd_fence.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/gpu/ion/sprd/sprd_fence.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/gpu/ion/sprd/sprd_fence.c')
-rw-r--r--drivers/gpu/ion/sprd/sprd_fence.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/drivers/gpu/ion/sprd/sprd_fence.c b/drivers/gpu/ion/sprd/sprd_fence.c
new file mode 100644
index 00000000..0baafe89
--- /dev/null
+++ b/drivers/gpu/ion/sprd/sprd_fence.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sprd_fence.h"
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+
+#define WAIT_FENCE_TIMEOUT 200
+
+/*
+ * Porting from software sync
+ * (sw_sync.h sw_sync.c)
+ * */
+static int sprd_sync_cmp(u32 a, u32 b)
+{
+ if (a == b)
+ return 0;
+
+ return ((s32)a - (s32)b) < 0 ? -1 : 1;
+}
+
+struct sync_pt *sprd_sync_pt_create(struct sprd_sync_timeline *obj, u32 value)
+{
+ struct sprd_sync_pt *pt;
+
+ pt = (struct sprd_sync_pt *)
+ sync_pt_create(&obj->obj, sizeof(struct sprd_sync_pt));
+
+ pt->value = value;
+
+ return (struct sync_pt *)pt;
+}
+
+static struct sync_pt *sprd_sync_pt_dup(struct sync_pt *sync_pt)
+{
+ struct sprd_sync_pt *pt = (struct sprd_sync_pt *) sync_pt;
+ struct sprd_sync_timeline *obj =
+ (struct sprd_sync_timeline *)sync_pt->parent;
+
+ return (struct sync_pt *) sprd_sync_pt_create(obj, pt->value);
+}
+
+static int sprd_sync_pt_has_signaled(struct sync_pt *sync_pt)
+{
+ struct sprd_sync_pt *pt = (struct sprd_sync_pt *)sync_pt;
+ struct sprd_sync_timeline *obj =
+ (struct sprd_sync_timeline *)sync_pt->parent;
+
+ return sprd_sync_cmp(obj->value, pt->value) >= 0;
+}
+
+static int sprd_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
+{
+ struct sprd_sync_pt *pt_a = (struct sprd_sync_pt *)a;
+ struct sprd_sync_pt *pt_b = (struct sprd_sync_pt *)b;
+
+ return sprd_sync_cmp(pt_a->value, pt_b->value);
+}
+
+
+static int sprd_sync_fill_driver_data(struct sync_pt *sync_pt,
+ void *data, int size)
+{
+ struct sprd_sync_pt *pt = (struct sprd_sync_pt *)sync_pt;
+
+ if (size < sizeof(pt->value))
+ return -ENOMEM;
+
+ memcpy(data, &pt->value, sizeof(pt->value));
+
+ return sizeof(pt->value);
+}
+
+static void sprd_sync_timeline_value_str(struct sync_timeline *sync_timeline,
+ char *str, int size)
+{
+ struct sprd_sync_timeline *timeline =
+ (struct sprd_sync_timeline *)sync_timeline;
+ snprintf(str, size, "%d", timeline->value);
+}
+
+static void sprd_sync_pt_value_str(struct sync_pt *sync_pt,
+ char *str, int size)
+{
+ struct sprd_sync_pt *pt = (struct sprd_sync_pt *)sync_pt;
+ snprintf(str, size, "%d", pt->value);
+}
+
+static struct sync_timeline_ops sprd_sync_timeline_ops = {
+ .driver_name = "sprd_sync",
+ .dup = sprd_sync_pt_dup,
+ .has_signaled = sprd_sync_pt_has_signaled,
+ .compare = sprd_sync_pt_compare,
+ .fill_driver_data = sprd_sync_fill_driver_data,
+ .timeline_value_str = sprd_sync_timeline_value_str,
+ .pt_value_str = sprd_sync_pt_value_str,
+};
+
+struct sprd_sync_timeline *sprd_sync_timeline_create(const char *name)
+{
+ struct sprd_sync_timeline *obj = (struct sprd_sync_timeline *)
+ sync_timeline_create(&sprd_sync_timeline_ops,
+ sizeof(struct sprd_sync_timeline),
+ name);
+
+ return obj;
+}
+
+void sprd_sync_timeline_inc(struct sprd_sync_timeline *obj, u32 inc)
+{
+ obj->value += inc;
+
+ sync_timeline_signal(&obj->obj);
+}
+
+/*
+ * Porting software sync done
+ * */
+
+/*
+ * user interface
+ * */
+
+/*
+ * Now build two timeline,
+ * one for PrimaryDisplayDevice,
+ * the other for VirtualDisplayDevice.
+ * If we only use single timeline, the later Device will
+ * block the former Device.
+ * */
+static struct sync_timeline_data sprd_timeline;
+static struct sync_timeline_data sprd_timeline_virtual;
+int sprd_create_timeline(enum SPRD_DEVICE_SYNC_TYPE type)
+{
+ if (type == SPRD_DEVICE_PRIMARY_SYNC)
+ {
+ mutex_lock(&(sprd_timeline.sync_mutex));
+ if (sprd_timeline.timeline == NULL)
+ {
+ sprd_timeline.timeline = sprd_sync_timeline_create("sprd-timeline");
+ if (sprd_timeline.timeline == NULL)
+ {
+ printk(KERN_ERR "create_timeline, cannot create time line\n");
+ mutex_unlock(&(sprd_timeline.sync_mutex));
+ return -ENOMEM;
+ }
+ else
+ {
+ sprd_timeline.timeline_value = 0;
+ }
+ }
+ mutex_unlock(&(sprd_timeline.sync_mutex));
+ }
+ else if (type == SPRD_DEVICE_VIRTUAL_SYNC)
+ {
+ mutex_lock(&(sprd_timeline_virtual.sync_mutex));
+ if (sprd_timeline_virtual.timeline == NULL)
+ {
+ sprd_timeline_virtual.timeline = sprd_sync_timeline_create("sprd-timeline-virtual");
+ if (sprd_timeline_virtual.timeline == NULL)
+ {
+ printk(KERN_ERR "create_timeline, cannot create virtual time line\n");
+ mutex_unlock(&(sprd_timeline_virtual.sync_mutex));
+ return -ENOMEM;
+ }
+ else
+ {
+ sprd_timeline_virtual.timeline_value = 0;
+ }
+ }
+ mutex_unlock(&(sprd_timeline_virtual.sync_mutex));
+ }
+
+ return 0;
+}
+
+int sprd_destroy_timeline(struct sync_timeline_data *parent)
+{
+ struct sprd_sync_timeline *obj = NULL;
+
+ if (parent->timeline == NULL)
+ {
+ printk(KERN_ERR "sprd_fence timeline has been released\n");
+ return 0;
+ }
+
+ mutex_lock(&(parent->sync_mutex));
+ obj = parent->timeline;
+ sync_timeline_destroy(&obj->obj);
+ mutex_unlock(&(parent->sync_mutex));
+
+ return 0;
+}
+
+int open_sprd_sync_timeline(void)
+{
+ int ret = -1;
+ static int init = 0;
+
+ if (init == 0)
+ {
+ sprd_timeline.timeline_value = -1;
+ sprd_timeline.timeline = NULL;
+ mutex_init(&(sprd_timeline.sync_mutex));
+
+ sprd_timeline_virtual.timeline_value = -1;
+ sprd_timeline_virtual.timeline = NULL;
+ mutex_init(&(sprd_timeline_virtual.sync_mutex));
+
+ init = 1;
+ }
+
+ ret = sprd_create_timeline(SPRD_DEVICE_PRIMARY_SYNC);
+ if (ret < 0)
+ {
+ return ret;
+ }
+ ret = sprd_create_timeline(SPRD_DEVICE_VIRTUAL_SYNC);
+
+ return ret;
+}
+
+int close_sprd_sync_timeline(void)
+{
+ int ret = -1;
+
+ ret = sprd_destroy_timeline(&sprd_timeline);
+
+ ret = sprd_destroy_timeline(&sprd_timeline_virtual);
+
+ return ret;
+}
+
+int sprd_fence_create(struct ion_fence_data *data, char *name)
+{
+ int fd = get_unused_fd();
+ struct sync_pt *pt;
+ struct sync_fence *fence;
+ struct sync_timeline_data *parent = NULL;
+
+ if (data == NULL || name == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_create input para is NULL\n");
+ return -EFAULT;
+ }
+
+
+ if (fd < 0)
+ {
+ fd = get_unused_fd();
+ if (fd < 0)
+ {
+ printk(KERN_ERR "sprd_sync_pt_create failed to get fd\n");
+ }
+ return -EFAULT;
+ }
+
+ if (data->device_type == SPRD_DEVICE_PRIMARY_SYNC)
+ {
+ parent = &sprd_timeline;
+ }
+ else if (data->device_type == SPRD_DEVICE_VIRTUAL_SYNC)
+ {
+ parent = &sprd_timeline_virtual;
+ }
+
+ if (parent == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_create failed to get sync timeline\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&(parent->sync_mutex));
+
+ pt = sprd_sync_pt_create(parent->timeline, parent->timeline_value + data->life_value);
+ if (pt == NULL)
+ {
+ printk(KERN_ERR "sprd_sync_pt_create failed\n");
+ goto err;
+ }
+
+ fence = sync_fence_create(name, pt);
+ if (fence == NULL)
+ {
+ sync_pt_free(pt);
+ printk(KERN_ERR "sprd_create_fence failed\n");
+ goto err;
+ }
+
+ sync_fence_install(fence, fd);
+
+ mutex_unlock(&(parent->sync_mutex));
+
+ pr_debug("create a fence: %p, fd: %d, life_value: %d, name: %s\n",
+ (void *)fence, fd, data->life_value, name);
+
+ return fd;
+
+err:
+ put_unused_fd(fd);
+ mutex_unlock(&(parent->sync_mutex));
+ return -ENOMEM;
+}
+
+int sprd_fence_destroy(struct ion_fence_data *data)
+{
+ if (data == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_destroy parameters NULL\n");
+ return -EFAULT;
+ }
+
+ if (data->release_fence_fd >= 0)
+ {
+ struct sync_fence *fence = sync_fence_fdget(data->release_fence_fd);
+ if (fence == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_destroy failed fence == NULL\n");
+ return -EFAULT;
+ }
+ }
+ else if (data->retired_fence_fd >= 0)
+ {
+ struct sync_fence *fence = sync_fence_fdget(data->retired_fence_fd);
+ if (fence == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_destroy failed fence == NULL\n");
+ } return -EFAULT;
+ }
+
+ return 0;
+}
+int sprd_fence_build(struct ion_fence_data *data)
+{
+ if (data == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_build input para is NULL\n");
+ return -EFAULT;
+ }
+
+ data->release_fence_fd = sprd_fence_create(data, "HWCRelease");
+ if (data->release_fence_fd < 0)
+ {
+ printk(KERN_ERR "sprd_fence_build failed to create release fence\n");
+ return -ENOMEM;
+ }
+
+ data->retired_fence_fd = sprd_fence_create(data, "HWCRetire");
+ if (data->retired_fence_fd < 0)
+ {
+ printk(KERN_ERR "sprd_fence_build failed to create release fence\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int sprd_fence_signal_timeline(struct sync_timeline_data *parent)
+{
+ if (parent == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_signal_timeline timeline is NULL\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&(parent->sync_mutex));
+
+ if (parent->timeline)
+ {
+ sprd_sync_timeline_inc(parent->timeline, 1);
+ parent->timeline_value++;
+
+ /*
+ * For avoiding overflow
+ * */
+ if (parent->timeline_value < 0)
+ {
+ parent->timeline_value = 0;
+ }
+ }
+
+ mutex_unlock(&(parent->sync_mutex));
+
+ pr_debug("sprd_signal_fence value: %d\n", parent->timeline_value);
+
+ return 0;
+}
+int sprd_fence_signal(struct ion_fence_data *data)
+{
+ struct sync_timeline_data *parent = NULL;
+ enum SPRD_DEVICE_SYNC_TYPE device_type= SPRD_DEVICE_PRIMARY_SYNC;
+
+ if (data == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_signal parameter is NULL\n");
+ return -EFAULT;
+ }
+
+ if (data->device_type == SPRD_DEVICE_PRIMARY_SYNC)
+ {
+ parent = &sprd_timeline;
+ }
+ else if (data->device_type == SPRD_DEVICE_VIRTUAL_SYNC)
+ {
+ parent = &sprd_timeline_virtual;
+ }
+
+ if (parent == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_signal failed to get sync timeline\n");
+ return -EFAULT;
+ }
+
+ sprd_fence_signal_timeline(parent);
+ pr_debug("sprd_signal_fence device_type: %d\n", data->device_type);
+
+ return 0;
+}
+
+int sprd_fence_wait(int fence_fd)
+{
+ int ret = 0;
+
+ struct sync_fence *fence = NULL;
+
+ if (fence_fd < 0)
+ {
+ printk(KERN_ERR "sprd_wait_fence input parameters is NULL\n");
+ return -EFAULT;
+ }
+
+ fence = sync_fence_fdget(fence_fd);
+ if (fence == NULL)
+ {
+ printk(KERN_ERR "sprd_fence_wait failed fence == NULL\n");
+ return -EFAULT;
+ }
+
+ ret = sync_fence_wait(fence, WAIT_FENCE_TIMEOUT);
+ sync_fence_put(fence);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "sync_fence_wait failed, ret = %x\n", ret);
+ }
+
+ pr_debug("sprd_wait_fence wait fence: %p done\n", (void *)fence);
+
+ return ret;
+}
+
+struct sync_pt *sprd_fence_dup(struct sync_pt *sync_pt)
+{
+ struct sync_pt *pt = NULL;
+
+ pt = sprd_sync_pt_dup(sync_pt);
+
+ return pt;
+}