/* * Copyright (C) 2013, 2015 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 "mali_timeline_sync_fence.h" #include "mali_osk.h" #include "mali_kernel_common.h" #include "mali_sync.h" #if defined(CONFIG_SYNC) /** * 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. */ static struct sync_fence *mali_timeline_sync_fence_create_and_add_tracker(struct mali_timeline *timeline, mali_timeline_point point) { struct mali_timeline_sync_fence_tracker *sync_fence_tracker; struct sync_fence *sync_fence; 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; struct sync_fence *sync_fence_acc = NULL; MALI_DEBUG_ASSERT_POINTER(system); MALI_DEBUG_ASSERT_POINTER(fence); for (i = 0; i < MALI_TIMELINE_MAX; ++i) { struct mali_timeline *timeline; struct sync_fence *sync_fence; 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) { struct sync_fence *sync_fence; sync_fence = sync_fence_fdget(fence->sync_fd); 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) { sync_fence_put(sync_fence_acc); } 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) */