1 /*
2 * Copyright (C) 2013, 2017 ARM Limited. All rights reserved.
3 *
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6 *
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
9 */
10 #include <linux/file.h>
11 #include "mali_timeline_sync_fence.h"
12
13 #include "mali_osk.h"
14 #include "mali_kernel_common.h"
15 #include "mali_sync.h"
16
17 #if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE)
18 /**
19 * Creates a sync fence tracker and a sync fence. Adds sync fence tracker to Timeline system and
20 * returns sync fence. The sync fence will be signaled when the sync fence tracker is activated.
21 *
22 * @param timeline Timeline.
23 * @param point Point on timeline.
24 * @return Sync fence that will be signaled when tracker is activated.
25 */
26 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
mali_timeline_sync_fence_create_and_add_tracker(struct mali_timeline * timeline,mali_timeline_point point)27 static struct sync_fence *mali_timeline_sync_fence_create_and_add_tracker(struct mali_timeline *timeline, mali_timeline_point point)
28 #else
29 static struct mali_internal_sync_fence *mali_timeline_sync_fence_create_and_add_tracker(struct mali_timeline *timeline, mali_timeline_point point)
30 #endif
31 {
32 struct mali_timeline_sync_fence_tracker *sync_fence_tracker;
33 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
34 struct sync_fence *sync_fence;
35 #else
36 struct mali_internal_sync_fence *sync_fence;
37 #endif
38 struct mali_timeline_fence fence;
39
40 MALI_DEBUG_ASSERT_POINTER(timeline);
41 MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT != point);
42
43 /* Allocate sync fence tracker. */
44 sync_fence_tracker = _mali_osk_calloc(1, sizeof(struct mali_timeline_sync_fence_tracker));
45 if (NULL == sync_fence_tracker) {
46 MALI_PRINT_ERROR(("Mali Timeline: sync_fence_tracker allocation failed\n"));
47 return NULL;
48 }
49
50 /* Create sync flag. */
51 MALI_DEBUG_ASSERT_POINTER(timeline->sync_tl);
52 sync_fence_tracker->flag = mali_sync_flag_create(timeline->sync_tl, point);
53 if (NULL == sync_fence_tracker->flag) {
54 MALI_PRINT_ERROR(("Mali Timeline: sync_flag creation failed\n"));
55 _mali_osk_free(sync_fence_tracker);
56 return NULL;
57 }
58
59 /* Create sync fence from sync flag. */
60 sync_fence = mali_sync_flag_create_fence(sync_fence_tracker->flag);
61 if (NULL == sync_fence) {
62 MALI_PRINT_ERROR(("Mali Timeline: sync_fence creation failed\n"));
63 mali_sync_flag_put(sync_fence_tracker->flag);
64 _mali_osk_free(sync_fence_tracker);
65 return NULL;
66 }
67
68 /* Setup fence for tracker. */
69 _mali_osk_memset(&fence, 0, sizeof(struct mali_timeline_fence));
70 fence.sync_fd = -1;
71 fence.points[timeline->id] = point;
72
73 /* Finally, add the tracker to Timeline system. */
74 mali_timeline_tracker_init(&sync_fence_tracker->tracker, MALI_TIMELINE_TRACKER_SYNC, &fence, sync_fence_tracker);
75 point = mali_timeline_system_add_tracker(timeline->system, &sync_fence_tracker->tracker, MALI_TIMELINE_NONE);
76 MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT == point);
77
78 return sync_fence;
79 }
80
mali_timeline_sync_fence_create(struct mali_timeline_system * system,struct mali_timeline_fence * fence)81 s32 mali_timeline_sync_fence_create(struct mali_timeline_system *system, struct mali_timeline_fence *fence)
82 {
83 u32 i;
84 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
85 struct sync_fence *sync_fence_acc = NULL;
86 #else
87 struct mali_internal_sync_fence *sync_fence_acc = NULL;
88 #endif
89 MALI_DEBUG_ASSERT_POINTER(system);
90 MALI_DEBUG_ASSERT_POINTER(fence);
91
92 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
93 struct mali_timeline *timeline;
94 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
95 struct sync_fence *sync_fence;
96 #else
97 struct mali_internal_sync_fence *sync_fence;
98 #endif
99 if (MALI_TIMELINE_NO_POINT == fence->points[i]) continue;
100
101 timeline = system->timelines[i];
102 MALI_DEBUG_ASSERT_POINTER(timeline);
103
104 sync_fence = mali_timeline_sync_fence_create_and_add_tracker(timeline, fence->points[i]);
105 if (NULL == sync_fence) goto error;
106
107 if (NULL != sync_fence_acc) {
108 /* Merge sync fences. */
109 sync_fence_acc = mali_sync_fence_merge(sync_fence_acc, sync_fence);
110 if (NULL == sync_fence_acc) goto error;
111 } else {
112 /* This was the first sync fence created. */
113 sync_fence_acc = sync_fence;
114 }
115 }
116
117 if (-1 != fence->sync_fd) {
118 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
119 struct sync_fence *sync_fence;
120 sync_fence = sync_fence_fdget(fence->sync_fd);
121 #else
122 struct mali_internal_sync_fence *sync_fence;
123 sync_fence = mali_internal_sync_fence_fdget(fence->sync_fd);
124 #endif
125
126 if (NULL == sync_fence) goto error;
127
128 if (NULL != sync_fence_acc) {
129 sync_fence_acc = mali_sync_fence_merge(sync_fence_acc, sync_fence);
130 if (NULL == sync_fence_acc) goto error;
131 } else {
132 sync_fence_acc = sync_fence;
133 }
134 }
135
136 if (NULL == sync_fence_acc) {
137 MALI_DEBUG_ASSERT_POINTER(system->signaled_sync_tl);
138
139 /* There was nothing to wait on, so return an already signaled fence. */
140
141 sync_fence_acc = mali_sync_timeline_create_signaled_fence(system->signaled_sync_tl);
142 if (NULL == sync_fence_acc) goto error;
143 }
144
145 /* Return file descriptor for the accumulated sync fence. */
146 return mali_sync_fence_fd_alloc(sync_fence_acc);
147
148 error:
149 if (NULL != sync_fence_acc) {
150 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
151 sync_fence_put(sync_fence_acc);
152 #else
153 fput(sync_fence_acc->file);
154 #endif
155 }
156
157 return -1;
158 }
159
mali_timeline_sync_fence_activate(struct mali_timeline_sync_fence_tracker * sync_fence_tracker)160 void mali_timeline_sync_fence_activate(struct mali_timeline_sync_fence_tracker *sync_fence_tracker)
161 {
162 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
163
164 MALI_DEBUG_ASSERT_POINTER(sync_fence_tracker);
165 MALI_DEBUG_ASSERT_POINTER(sync_fence_tracker->flag);
166
167 MALI_DEBUG_PRINT(4, ("Mali Timeline: activation for sync fence tracker\n"));
168
169 /* Signal flag and release reference. */
170 mali_sync_flag_signal(sync_fence_tracker->flag, 0);
171 mali_sync_flag_put(sync_fence_tracker->flag);
172
173 /* Nothing can wait on this tracker, so nothing to schedule after release. */
174 schedule_mask = mali_timeline_tracker_release(&sync_fence_tracker->tracker);
175 MALI_DEBUG_ASSERT(MALI_SCHEDULER_MASK_EMPTY == schedule_mask);
176
177 _mali_osk_free(sync_fence_tracker);
178 }
179 #endif /* defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) */
180