/*
|
* Copyright (C) 2013, 2017 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) */
|