blob: 4541ca6108a1a57a7a873e388227f61ca3248ffc [file] [log] [blame]
/*
* Copyright (C) 2013, 2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/file.h>
#include "mali_timeline_sync_fence.h"
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_sync.h"
#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE)
/**
* Creates a sync fence tracker and a sync fence. Adds sync fence tracker to Timeline system and
* returns sync fence. The sync fence will be signaled when the sync fence tracker is activated.
*
* @param timeline Timeline.
* @param point Point on timeline.
* @return Sync fence that will be signaled when tracker is activated.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
static struct sync_fence *mali_timeline_sync_fence_create_and_add_tracker(struct mali_timeline *timeline, mali_timeline_point point)
#else
static struct mali_internal_sync_fence *mali_timeline_sync_fence_create_and_add_tracker(struct mali_timeline *timeline, mali_timeline_point point)
#endif
{
struct mali_timeline_sync_fence_tracker *sync_fence_tracker;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
struct sync_fence *sync_fence;
#else
struct mali_internal_sync_fence *sync_fence;
#endif
struct mali_timeline_fence fence;
MALI_DEBUG_ASSERT_POINTER(timeline);
MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT != point);
/* Allocate sync fence tracker. */
sync_fence_tracker = _mali_osk_calloc(1, sizeof(struct mali_timeline_sync_fence_tracker));
if (NULL == sync_fence_tracker) {
MALI_PRINT_ERROR(("Mali Timeline: sync_fence_tracker allocation failed\n"));
return NULL;
}
/* Create sync flag. */
MALI_DEBUG_ASSERT_POINTER(timeline->sync_tl);
sync_fence_tracker->flag = mali_sync_flag_create(timeline->sync_tl, point);
if (NULL == sync_fence_tracker->flag) {
MALI_PRINT_ERROR(("Mali Timeline: sync_flag creation failed\n"));
_mali_osk_free(sync_fence_tracker);
return NULL;
}
/* Create sync fence from sync flag. */
sync_fence = mali_sync_flag_create_fence(sync_fence_tracker->flag);
if (NULL == sync_fence) {
MALI_PRINT_ERROR(("Mali Timeline: sync_fence creation failed\n"));
mali_sync_flag_put(sync_fence_tracker->flag);
_mali_osk_free(sync_fence_tracker);
return NULL;
}
/* Setup fence for tracker. */
_mali_osk_memset(&fence, 0, sizeof(struct mali_timeline_fence));
fence.sync_fd = -1;
fence.points[timeline->id] = point;
/* Finally, add the tracker to Timeline system. */
mali_timeline_tracker_init(&sync_fence_tracker->tracker, MALI_TIMELINE_TRACKER_SYNC, &fence, sync_fence_tracker);
point = mali_timeline_system_add_tracker(timeline->system, &sync_fence_tracker->tracker, MALI_TIMELINE_NONE);
MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT == point);
return sync_fence;
}
s32 mali_timeline_sync_fence_create(struct mali_timeline_system *system, struct mali_timeline_fence *fence)
{
u32 i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
struct sync_fence *sync_fence_acc = NULL;
#else
struct mali_internal_sync_fence *sync_fence_acc = NULL;
#endif
MALI_DEBUG_ASSERT_POINTER(system);
MALI_DEBUG_ASSERT_POINTER(fence);
for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
struct mali_timeline *timeline;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
struct sync_fence *sync_fence;
#else
struct mali_internal_sync_fence *sync_fence;
#endif
if (MALI_TIMELINE_NO_POINT == fence->points[i]) continue;
timeline = system->timelines[i];
MALI_DEBUG_ASSERT_POINTER(timeline);
sync_fence = mali_timeline_sync_fence_create_and_add_tracker(timeline, fence->points[i]);
if (NULL == sync_fence) goto error;
if (NULL != sync_fence_acc) {
/* Merge sync fences. */
sync_fence_acc = mali_sync_fence_merge(sync_fence_acc, sync_fence);
if (NULL == sync_fence_acc) goto error;
} else {
/* This was the first sync fence created. */
sync_fence_acc = sync_fence;
}
}
if (-1 != fence->sync_fd) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
struct sync_fence *sync_fence;
sync_fence = sync_fence_fdget(fence->sync_fd);
#else
struct mali_internal_sync_fence *sync_fence;
sync_fence = mali_internal_sync_fence_fdget(fence->sync_fd);
#endif
if (NULL == sync_fence) goto error;
if (NULL != sync_fence_acc) {
sync_fence_acc = mali_sync_fence_merge(sync_fence_acc, sync_fence);
if (NULL == sync_fence_acc) goto error;
} else {
sync_fence_acc = sync_fence;
}
}
if (NULL == sync_fence_acc) {
MALI_DEBUG_ASSERT_POINTER(system->signaled_sync_tl);
/* There was nothing to wait on, so return an already signaled fence. */
sync_fence_acc = mali_sync_timeline_create_signaled_fence(system->signaled_sync_tl);
if (NULL == sync_fence_acc) goto error;
}
/* Return file descriptor for the accumulated sync fence. */
return mali_sync_fence_fd_alloc(sync_fence_acc);
error:
if (NULL != sync_fence_acc) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
sync_fence_put(sync_fence_acc);
#else
fput(sync_fence_acc->file);
#endif
}
return -1;
}
void mali_timeline_sync_fence_activate(struct mali_timeline_sync_fence_tracker *sync_fence_tracker)
{
mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
MALI_DEBUG_ASSERT_POINTER(sync_fence_tracker);
MALI_DEBUG_ASSERT_POINTER(sync_fence_tracker->flag);
MALI_DEBUG_PRINT(4, ("Mali Timeline: activation for sync fence tracker\n"));
/* Signal flag and release reference. */
mali_sync_flag_signal(sync_fence_tracker->flag, 0);
mali_sync_flag_put(sync_fence_tracker->flag);
/* Nothing can wait on this tracker, so nothing to schedule after release. */
schedule_mask = mali_timeline_tracker_release(&sync_fence_tracker->tracker);
MALI_DEBUG_ASSERT(MALI_SCHEDULER_MASK_EMPTY == schedule_mask);
_mali_osk_free(sync_fence_tracker);
}
#endif /* defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) */