| /* |
| * 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) */ |