blob: 2990522735ab45fbe2321cdc117b9a0d926e76a6 [file] [log] [blame]
/* Copyright (c) 2015-2016, 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
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/sync.h>
#include <linux/sw_sync.h>
#include "sde_rotator_util.h"
#include "sde_rotator_sync.h"
struct sde_rot_timeline {
struct mutex lock;
struct sw_sync_timeline *timeline;
u32 next_value;
char fence_name[32];
};
/*
* 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) {
SDEROT_ERR("invalid parameters\n");
return NULL;
}
tl = kzalloc(sizeof(struct sde_rot_timeline), GFP_KERNEL);
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;
}
snprintf(tl->fence_name, sizeof(tl->fence_name), "rot_fence_%s", name);
mutex_init(&tl->lock);
tl->next_value = 0;
return tl;
}
/*
* sde_rotator_destroy_timeline - Destroy the given timeline object
* @tl: Pointer to timeline object.
*/
void sde_rotator_destroy_timeline(struct sde_rot_timeline *tl)
{
if (!tl) {
SDEROT_ERR("invalid parameters\n");
return;
}
if (tl->timeline)
sync_timeline_destroy((struct sync_timeline *) tl->timeline);
kfree(tl);
}
/*
* sde_rotator_resync_timeline - Resync timeline to last committed value
* @tl: Pointer to timeline object.
*/
void sde_rotator_resync_timeline(struct sde_rot_timeline *tl)
{
int val;
if (!tl || !tl->timeline) {
SDEROT_ERR("invalid parameters\n");
return;
}
mutex_lock(&tl->lock);
val = tl->next_value - tl->timeline->value;
if (val > 0) {
SDEROT_WARN("flush %s:%d\n", tl->fence_name, val);
sw_sync_timeline_inc(tl->timeline, val);
}
mutex_unlock(&tl->lock);
}
/*
* sde_rotator_get_sync_fence - Create fence object from the given timeline
* @tl: Pointer to timeline object
* @fence_fd: Pointer to file descriptor associated with the returned fence.
* Null if not required.
* @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)
{
u32 val;
struct sync_pt *sync_pt;
struct sync_fence *fence;
if (!tl || !tl->timeline) {
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;
}
if (fence_fd) {
int fd = get_unused_fd_flags(0);
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 (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;
}
/*
* sde_rotator_inc_timeline - Increment timeline by given amount
* @tl: Pointer to timeline object.
* @increment: the amount to increase the timeline by.
*/
int sde_rotator_inc_timeline(struct sde_rot_timeline *tl, int increment)
{
if (!tl || !tl->timeline) {
SDEROT_ERR("invalid parameters\n");
return -EINVAL;
}
mutex_lock(&tl->lock);
sw_sync_timeline_inc(tl->timeline, increment);
mutex_unlock(&tl->lock);
return 0;
}
/*
* sde_rotator_get_timeline_commit_ts - Return commit tick of given timeline
* @tl: Pointer to timeline object.
*/
u32 sde_rotator_get_timeline_commit_ts(struct sde_rot_timeline *tl)
{
if (!tl)
return 0;
return tl->next_value;
}
/*
* sde_rotator_get_timeline_retire_ts - Return retire tick of given timeline
* @tl: Pointer to timeline object.
*/
u32 sde_rotator_get_timeline_retire_ts(struct sde_rot_timeline *tl)
{
if (!tl || !tl->timeline) {
SDEROT_ERR("invalid parameters\n");
return 0;
}
return tl->timeline->value;
}
/*
* sde_rotator_put_sync_fence - Destroy given fence object
* @fence: Pointer to fence object.
*/
void sde_rotator_put_sync_fence(struct sde_rot_sync_fence *fence)
{
if (!fence) {
SDEROT_ERR("invalid parameters\n");
return;
}
sync_fence_put((struct sync_fence *) fence);
}
/*
* sde_rotator_wait_sync_fence - Wait until fence signal or timeout
* @fence: Pointer to fence object.
* @timeout: maximum wait time, in msec, for fence to signal.
*/
int sde_rotator_wait_sync_fence(struct sde_rot_sync_fence *fence,
long timeout)
{
if (!fence)
return -EINVAL;
return sync_fence_wait((struct sync_fence *) fence, timeout);
}
/*
* sde_rotator_get_sync_fence_fd - Get fence object of given file descriptor
* @fd: File description of fence object.
*/
struct sde_rot_sync_fence *sde_rotator_get_fd_sync_fence(int fd)
{
return (struct sde_rot_sync_fence *) sync_fence_fdget(fd);
}
/*
* sde_rotator_get_sync_fence_fd - Get file descriptor of given fence object
* @fence: Pointer to fence object.
*/
int sde_rotator_get_sync_fence_fd(struct sde_rot_sync_fence *fence)
{
int fd;
if (!fence) {
SDEROT_ERR("invalid parameters\n");
return -EINVAL;
}
fd = get_unused_fd_flags(0);
if (fd < 0) {
SDEROT_ERR("fail to get unused fd\n");
return fd;
}
sync_fence_install((struct sync_fence *) fence, fd);
return fd;
}