Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 281fc6b6 authored by Alan Kwong's avatar Alan Kwong
Browse files

msm: sde: add support for sync file to sde rotator



Sync file is used for buffer synchronization between
user mode components and kernel mode drivers. Add support
to sde rotator to use sync file for synchronization of input
and output buffers.

CRs-Fixed: 2009709
Change-Id: Ib0453e2368f6c6c6d1b6bba2c16b111522e42748
Signed-off-by: default avatarAlan Kwong <akwong@codeaurora.org>
parent 900cea2a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ config MSM_SDE_ROTATOR
	depends on ARCH_QCOM && VIDEO_V4L2
	select V4L2_MEM2MEM_DEV
	select VIDEOBUF2_CORE
	select SW_SYNC if SYNC
	select SYNC_FILE
	---help---
	  Enable support of V4L2 rotator driver.

+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ obj-y += \
obj-y += \
		sde_rotator_r3.o

obj-$(CONFIG_SYNC) += \
obj-$(CONFIG_SYNC_FILE) += \
		sde_rotator_sync.o

obj-$(CONFIG_DEBUG_FS) += \
+257 −93
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -16,25 +16,179 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <sync.h>
#include <sw_sync.h>
#include <linux/spinlock.h>
#include <linux/fence.h>
#include <linux/sync_file.h>

#include "sde_rotator_util.h"
#include "sde_rotator_sync.h"

#define SDE_ROT_SYNC_NAME_SIZE		64
#define SDE_ROT_SYNC_DRIVER_NAME	"sde_rot"

/**
 * struct sde_rot_fence - sync fence context
 * @base: base sync fence object
 * @name: name of this sync fence
 * @fence_list: linked list of outstanding sync fence
 */
struct sde_rot_fence {
	struct fence base;
	char name[SDE_ROT_SYNC_NAME_SIZE];
	struct list_head fence_list;
};

/**
 * struct sde_rot_timeline - sync timeline context
 * @kref: reference count of timeline
 * @lock: serialization lock for timeline and fence update
 * @name: name of timeline
 * @fence_name: fence name prefix
 * @next_value: next commit sequence number
 * @curr_value: current retired sequence number
 * @context: fence context identifier
 * @fence_list_head: linked list of outstanding sync fence
 */
struct sde_rot_timeline {
	struct mutex lock;
	struct sw_sync_timeline *timeline;
	struct kref kref;
	spinlock_t lock;
	char name[SDE_ROT_SYNC_NAME_SIZE];
	char fence_name[SDE_ROT_SYNC_NAME_SIZE];
	u32 next_value;
	char fence_name[32];
	u32 curr_value;
	u64 context;
	struct list_head fence_list_head;
};

/*
 * to_sde_rot_fence - get rotator fence from fence base object
 * @fence: Pointer to fence base object
 */
static struct sde_rot_fence *to_sde_rot_fence(struct fence *fence)
{
	return container_of(fence, struct sde_rot_fence, base);
}

/*
 * to_sde_rot_timeline - get rotator timeline from fence base object
 * @fence: Pointer to fence base object
 */
static struct sde_rot_timeline *to_sde_rot_timeline(struct fence *fence)
{
	return container_of(fence->lock, struct sde_rot_timeline, lock);
}

/*
 * sde_rotator_free_timeline - Free the given timeline object
 * @kref: Pointer to timeline kref object.
 */
static void sde_rotator_free_timeline(struct kref *kref)
{
	struct sde_rot_timeline *tl =
		container_of(kref, struct sde_rot_timeline, kref);

	kfree(tl);
}

/*
 * sde_rotator_put_timeline - Put the given timeline object
 * @tl: Pointer to timeline object.
 */
static void sde_rotator_put_timeline(struct sde_rot_timeline *tl)
{
	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return;
	}

	kref_put(&tl->kref, sde_rotator_free_timeline);
}

/*
 * sde_rotator_get_timeline - Get the given timeline object
 * @tl: Pointer to timeline object.
 */
static void sde_rotator_get_timeline(struct sde_rot_timeline *tl)
{
	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return;
	}

	kref_get(&tl->kref);
}

static const char *sde_rot_fence_get_driver_name(struct fence *fence)
{
	return SDE_ROT_SYNC_DRIVER_NAME;
}

static const char *sde_rot_fence_get_timeline_name(struct fence *fence)
{
	struct sde_rot_timeline *tl = to_sde_rot_timeline(fence);

	return tl->name;
}

static bool sde_rot_fence_enable_signaling(struct fence *fence)
{
	return true;
}

static bool sde_rot_fence_signaled(struct fence *fence)
{
	struct sde_rot_timeline *tl = to_sde_rot_timeline(fence);
	bool status;

	status = ((s32) (tl->curr_value - fence->seqno)) >= 0;
	SDEROT_DBG("status:%d fence seq:%d and timeline:%d\n",
			status, fence->seqno, tl->curr_value);
	return status;
}

static void sde_rot_fence_release(struct fence *fence)
{
	struct sde_rot_fence *f = to_sde_rot_fence(fence);
	unsigned long flags;

	spin_lock_irqsave(fence->lock, flags);
	if (!list_empty(&f->fence_list))
		list_del(&f->fence_list);
	spin_unlock_irqrestore(fence->lock, flags);
	sde_rotator_put_timeline(to_sde_rot_timeline(fence));
	kfree_rcu(f, base.rcu);
}

static void sde_rot_fence_value_str(struct fence *fence, char *str, int size)
{
	snprintf(str, size, "%u", fence->seqno);
}

static void sde_rot_fence_timeline_value_str(struct fence *fence, char *str,
		int size)
{
	struct sde_rot_timeline *tl = to_sde_rot_timeline(fence);

	snprintf(str, size, "%u", tl->curr_value);
}

static struct fence_ops sde_rot_fence_ops = {
	.get_driver_name = sde_rot_fence_get_driver_name,
	.get_timeline_name = sde_rot_fence_get_timeline_name,
	.enable_signaling = sde_rot_fence_enable_signaling,
	.signaled = sde_rot_fence_signaled,
	.wait = fence_default_wait,
	.release = sde_rot_fence_release,
	.fence_value_str = sde_rot_fence_value_str,
	.timeline_value_str = sde_rot_fence_timeline_value_str,
};

/*
 * sde_rotator_create_timeline - Create timeline object with the given name
 * @name: Pointer to name character string.
 */
struct sde_rot_timeline *sde_rotator_create_timeline(const char *name)
{
	char tl_name[32];
	struct sde_rot_timeline *tl;

	if (!name) {
@@ -46,18 +200,12 @@ struct sde_rot_timeline *sde_rotator_create_timeline(const char *name)
	if (!tl)
		return NULL;

	snprintf(tl_name, sizeof(tl_name), "rot_timeline_%s", name);
	SDEROT_DBG("timeline name=%s\n", tl_name);
	tl->timeline = sw_sync_timeline_create(tl_name);
	if (!tl->timeline) {
		SDEROT_ERR("fail to allocate timeline\n");
		kfree(tl);
		return NULL;
	}

	kref_init(&tl->kref);
	snprintf(tl->name, sizeof(tl->name), "rot_timeline_%s", name);
	snprintf(tl->fence_name, sizeof(tl->fence_name), "rot_fence_%s", name);
	mutex_init(&tl->lock);
	tl->next_value = 0;
	spin_lock_init(&tl->lock);
	tl->context = fence_context_alloc(1);
	INIT_LIST_HEAD(&tl->fence_list_head);

	return tl;
}
@@ -68,15 +216,28 @@ struct sde_rot_timeline *sde_rotator_create_timeline(const char *name)
 */
void sde_rotator_destroy_timeline(struct sde_rot_timeline *tl)
{
	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return;
	sde_rotator_put_timeline(tl);
}

	if (tl->timeline)
		sync_timeline_destroy((struct sync_timeline *) tl->timeline);
/*
 * sde_rotator_inc_timeline_locked - Increment timeline by given amount
 * @tl: Pointer to timeline object.
 * @increment: the amount to increase the timeline by.
 */
static int sde_rotator_inc_timeline_locked(struct sde_rot_timeline *tl,
		int increment)
{
	struct sde_rot_fence *f, *next;

	kfree(tl);
	tl->curr_value += increment;
	list_for_each_entry_safe(f, next, &tl->fence_list_head, fence_list) {
		if (fence_is_signaled_locked(&f->base)) {
			SDEROT_DBG("%s signaled\n", f->name);
			list_del_init(&f->fence_list);
		}
	}

	return 0;
}

/*
@@ -85,19 +246,21 @@ void sde_rotator_destroy_timeline(struct sde_rot_timeline *tl)
 */
void sde_rotator_resync_timeline(struct sde_rot_timeline *tl)
{
	int val;
	unsigned long flags;
	s32 val;

	if (!tl || !tl->timeline) {
	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return;
	}
	mutex_lock(&tl->lock);
	val = tl->next_value - tl->timeline->value;

	spin_lock_irqsave(&tl->lock, flags);
	val = tl->next_value - tl->curr_value;
	if (val > 0) {
		SDEROT_WARN("flush %s:%d\n", tl->fence_name, val);
		sw_sync_timeline_inc(tl->timeline, val);
		SDEROT_WARN("flush %s:%d\n", tl->name, val);
		sde_rotator_inc_timeline_locked(tl, val);
	}
	mutex_unlock(&tl->lock);
	spin_unlock_irqrestore(&tl->lock, flags);
}

/*
@@ -108,64 +271,40 @@ void sde_rotator_resync_timeline(struct sde_rot_timeline *tl)
 * @timestamp: Pointer to timestamp of the returned fence. Null if not required.
 */
struct sde_rot_sync_fence *sde_rotator_get_sync_fence(
		struct sde_rot_timeline *tl, int *fence_fd,
		u32 *timestamp)
		struct sde_rot_timeline *tl, int *fence_fd, u32 *timestamp)
{
	struct sde_rot_fence *f;
	unsigned long flags;
	u32 val;
	struct sync_pt *sync_pt;
	struct sync_fence *fence;

	if (!tl || !tl->timeline) {
	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return NULL;
	}

	mutex_lock(&tl->lock);
	val = tl->next_value + 1;

	sync_pt = sw_sync_pt_create(tl->timeline, val);
	if (sync_pt == NULL) {
		SDEROT_ERR("cannot create sync point\n");
		goto sync_pt_create_err;
	}

	/* create fence */
	fence = sync_fence_create(tl->fence_name, sync_pt);
	if (fence == NULL) {
		SDEROT_ERR("%s: cannot create fence\n",
				tl->fence_name);
		goto sync_fence_create_err;
	}
	f = kzalloc(sizeof(struct sde_rot_fence), GFP_KERNEL);
	if (!f)
		return NULL;

	if (fence_fd) {
		int fd = get_unused_fd_flags(0);
	INIT_LIST_HEAD(&f->fence_list);
	spin_lock_irqsave(&tl->lock, flags);
	val = ++(tl->next_value);
	fence_init(&f->base, &sde_rot_fence_ops, &tl->lock, tl->context, val);
	list_add_tail(&f->fence_list, &tl->fence_list_head);
	sde_rotator_get_timeline(tl);
	spin_unlock_irqrestore(&tl->lock, flags);
	snprintf(f->name, sizeof(f->name), "%s_%u", tl->fence_name, val);

		if (fd < 0) {
			SDEROT_ERR("get_unused_fd_flags failed error:0x%x\n",
					fd);
			goto get_fd_err;
		}

		sync_fence_install(fence, fd);
		*fence_fd = fd;
	}
	if (fence_fd)
		*fence_fd = sde_rotator_get_sync_fence_fd(
				(struct sde_rot_sync_fence *) &f->base);

	if (timestamp)
		*timestamp = val;

	tl->next_value++;
	mutex_unlock(&tl->lock);
	SDEROT_DBG("output sync point created at val=%u\n", val);

	return (struct sde_rot_sync_fence *) fence;
get_fd_err:
	SDEROT_DBG("sys_fence_put c:%p\n", fence);
	sync_fence_put(fence);
sync_fence_create_err:
	sync_pt_free(sync_pt);
sync_pt_create_err:
	mutex_unlock(&tl->lock);
	return NULL;
	SDEROT_DBG("output sync fence created at val=%u\n", val);

	return (struct sde_rot_sync_fence *) &f->base;
}

/*
@@ -175,16 +314,19 @@ struct sde_rot_sync_fence *sde_rotator_get_sync_fence(
 */
int sde_rotator_inc_timeline(struct sde_rot_timeline *tl, int increment)
{
	if (!tl || !tl->timeline) {
	unsigned long flags;
	int rc;

	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return -EINVAL;
	}

	mutex_lock(&tl->lock);
	sw_sync_timeline_inc(tl->timeline, increment);
	mutex_unlock(&tl->lock);
	spin_lock_irqsave(&tl->lock, flags);
	rc = sde_rotator_inc_timeline_locked(tl, increment);
	spin_unlock_irqrestore(&tl->lock, flags);

	return 0;
	return rc;
}

/*
@@ -193,8 +335,10 @@ int sde_rotator_inc_timeline(struct sde_rot_timeline *tl, int increment)
 */
u32 sde_rotator_get_timeline_commit_ts(struct sde_rot_timeline *tl)
{
	if (!tl)
	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return 0;
	}

	return tl->next_value;
}
@@ -205,12 +349,12 @@ u32 sde_rotator_get_timeline_commit_ts(struct sde_rot_timeline *tl)
 */
u32 sde_rotator_get_timeline_retire_ts(struct sde_rot_timeline *tl)
{
	if (!tl || !tl->timeline) {
	if (!tl) {
		SDEROT_ERR("invalid parameters\n");
		return 0;
	}

	return tl->timeline->value;
	return tl->curr_value;
}

/*
@@ -224,7 +368,7 @@ void sde_rotator_put_sync_fence(struct sde_rot_sync_fence *fence)
		return;
	}

	sync_fence_put((struct sync_fence *) fence);
	fence_put((struct fence *) fence);
}

/*
@@ -235,10 +379,24 @@ void sde_rotator_put_sync_fence(struct sde_rot_sync_fence *fence)
int sde_rotator_wait_sync_fence(struct sde_rot_sync_fence *fence,
		long timeout)
{
	if (!fence)
	int rc;

	if (!fence) {
		SDEROT_ERR("invalid parameters\n");
		return -EINVAL;
	}

	rc = fence_wait_timeout((struct fence *) fence, false,
			msecs_to_jiffies(timeout));
	if (rc > 0) {
		SDEROT_DBG("fence signaled\n");
		rc = 0;
	} else if (rc == 0) {
		SDEROT_DBG("fence timeout\n");
		rc = -ETIMEDOUT;
	}

	return sync_fence_wait((struct sync_fence *) fence, timeout);
	return rc;
}

/*
@@ -247,7 +405,7 @@ int sde_rotator_wait_sync_fence(struct sde_rot_sync_fence *fence,
 */
struct sde_rot_sync_fence *sde_rotator_get_fd_sync_fence(int fd)
{
	return (struct sde_rot_sync_fence *) sync_fence_fdget(fd);
	return (struct sde_rot_sync_fence *) sync_file_get_fence(fd);
}

/*
@@ -257,21 +415,27 @@ struct sde_rot_sync_fence *sde_rotator_get_fd_sync_fence(int fd)
int sde_rotator_get_sync_fence_fd(struct sde_rot_sync_fence *fence)
{
	int fd;
	struct sync_file *sync_file;

	if (!fence) {
		SDEROT_ERR("invalid parameters\n");
		return -EINVAL;
	}

	fd = get_unused_fd_flags(0);

	fd = get_unused_fd_flags(O_CLOEXEC);
	if (fd < 0) {
		SDEROT_ERR("fail to get unused fd\n");
		return fd;
	}

	sync_fence_install((struct sync_fence *) fence, fd);
	sync_file = sync_file_create((struct fence *) fence);
	if (!sync_file) {
		put_unused_fd(fd);
		SDEROT_ERR("failed to create sync file\n");
		return -ENOMEM;
	}

	fd_install(fd, sync_file->file);

	return fd;
}
+2 −2
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -20,7 +20,7 @@
struct sde_rot_sync_fence;
struct sde_rot_timeline;

#if defined(CONFIG_SYNC) && defined(CONFIG_SW_SYNC)
#if defined(CONFIG_SYNC_FILE)
struct sde_rot_timeline *sde_rotator_create_timeline(const char *name);

void sde_rotator_destroy_timeline(struct sde_rot_timeline *tl);