xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/mali400/mali/common/mali_timeline_fence_wait.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2013-2014, 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_fence_wait.h"
12 #include "mali_osk.h"
13 #include "mali_kernel_common.h"
14 #include "mali_spinlock_reentrant.h"
15 
16 /**
17  * Allocate a fence waiter tracker.
18  *
19  * @return New fence waiter if successful, NULL if not.
20  */
mali_timeline_fence_wait_tracker_alloc(void)21 static struct mali_timeline_fence_wait_tracker *mali_timeline_fence_wait_tracker_alloc(void)
22 {
23 	return (struct mali_timeline_fence_wait_tracker *) _mali_osk_calloc(1, sizeof(struct mali_timeline_fence_wait_tracker));
24 }
25 
26 /**
27  * Free fence waiter tracker.
28  *
29  * @param wait Fence wait tracker to free.
30  */
mali_timeline_fence_wait_tracker_free(struct mali_timeline_fence_wait_tracker * wait)31 static void mali_timeline_fence_wait_tracker_free(struct mali_timeline_fence_wait_tracker *wait)
32 {
33 	MALI_DEBUG_ASSERT_POINTER(wait);
34 	_mali_osk_atomic_term(&wait->refcount);
35 	_mali_osk_free(wait);
36 }
37 
38 /**
39  * Check if fence wait tracker has been activated.  Used as a wait queue condition.
40  *
41  * @param data Fence waiter.
42  * @return MALI_TRUE if tracker has been activated, MALI_FALSE if not.
43  */
mali_timeline_fence_wait_tracker_is_activated(void * data)44 static mali_bool mali_timeline_fence_wait_tracker_is_activated(void *data)
45 {
46 	struct mali_timeline_fence_wait_tracker *wait;
47 
48 	wait = (struct mali_timeline_fence_wait_tracker *) data;
49 	MALI_DEBUG_ASSERT_POINTER(wait);
50 
51 	return wait->activated;
52 }
53 
54 /**
55  * Check if fence has been signaled.
56  *
57  * @param system Timeline system.
58  * @param fence Timeline fence.
59  * @return MALI_TRUE if fence is signaled, MALI_FALSE if not.
60  */
mali_timeline_fence_wait_check_status(struct mali_timeline_system * system,struct mali_timeline_fence * fence)61 static mali_bool mali_timeline_fence_wait_check_status(struct mali_timeline_system *system, struct mali_timeline_fence *fence)
62 {
63 	int i;
64 	u32 tid = _mali_osk_get_tid();
65 	mali_bool ret = MALI_TRUE;
66 #if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE)
67 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
68 	struct sync_fence *sync_fence = NULL;
69 #else
70 	struct mali_internal_sync_fence *sync_fence = NULL;
71 #endif
72 #endif
73 
74 	MALI_DEBUG_ASSERT_POINTER(system);
75 	MALI_DEBUG_ASSERT_POINTER(fence);
76 
77 	mali_spinlock_reentrant_wait(system->spinlock, tid);
78 
79 	for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
80 		struct mali_timeline *timeline;
81 		mali_timeline_point   point;
82 
83 		point = fence->points[i];
84 
85 		if (likely(MALI_TIMELINE_NO_POINT == point)) {
86 			/* Fence contains no point on this timeline. */
87 			continue;
88 		}
89 
90 		timeline = system->timelines[i];
91 		MALI_DEBUG_ASSERT_POINTER(timeline);
92 
93 		if (unlikely(!mali_timeline_is_point_valid(timeline, point))) {
94 			MALI_PRINT_ERROR(("Mali Timeline: point %d is not valid (oldest=%d, next=%d)\n", point, timeline->point_oldest, timeline->point_next));
95 		}
96 
97 		if (!mali_timeline_is_point_released(timeline, point)) {
98 			ret = MALI_FALSE;
99 			goto exit;
100 		}
101 	}
102 
103 #if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE)
104 	if (-1 != fence->sync_fd) {
105 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
106 		sync_fence = sync_fence_fdget(fence->sync_fd);
107 #else
108 		sync_fence = mali_internal_sync_fence_fdget(fence->sync_fd);
109 #endif
110 		if (likely(NULL != sync_fence)) {
111 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
112 			if (0 == sync_fence->status) {
113 #elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
114 			if (0 < atomic_read(&sync_fence->status)) {
115 #else
116 			if (0 == sync_fence->fence->ops->signaled(sync_fence->fence)) {
117 #endif
118 				ret = MALI_FALSE;
119 
120 			} else {
121 				ret = MALI_TRUE;
122 			}
123 		} else {
124 			MALI_PRINT_ERROR(("Mali Timeline: failed to get sync fence from fd %d\n", fence->sync_fd));
125 		}
126 	}
127 #endif /* defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) */
128 
129 exit:
130 	mali_spinlock_reentrant_signal(system->spinlock, tid);
131 
132 #if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE)
133 	if (NULL != sync_fence) {
134 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
135 		sync_fence_put(sync_fence);
136 #else
137 		fput(sync_fence->file);
138 #endif
139 	}
140 #endif /* defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) */
141 
142 	return ret;
143 }
144 
145 mali_bool mali_timeline_fence_wait(struct mali_timeline_system *system, struct mali_timeline_fence *fence, u32 timeout)
146 {
147 	struct mali_timeline_fence_wait_tracker *wait;
148 	mali_timeline_point point;
149 	mali_bool ret;
150 
151 	MALI_DEBUG_ASSERT_POINTER(system);
152 	MALI_DEBUG_ASSERT_POINTER(fence);
153 
154 	MALI_DEBUG_PRINT(4, ("Mali Timeline: wait on fence\n"));
155 
156 	if (MALI_TIMELINE_FENCE_WAIT_TIMEOUT_IMMEDIATELY == timeout) {
157 		return mali_timeline_fence_wait_check_status(system, fence);
158 	}
159 
160 	wait = mali_timeline_fence_wait_tracker_alloc();
161 	if (unlikely(NULL == wait)) {
162 		MALI_PRINT_ERROR(("Mali Timeline: failed to allocate data for fence wait\n"));
163 		return MALI_FALSE;
164 	}
165 
166 	wait->activated = MALI_FALSE;
167 	wait->system = system;
168 
169 	/* Initialize refcount to two references.  The reference first will be released by this
170 	 * function after the wait is over.  The second reference will be released when the tracker
171 	 * is activated. */
172 	_mali_osk_atomic_init(&wait->refcount, 2);
173 
174 	/* Add tracker to timeline system, but not to a timeline. */
175 	mali_timeline_tracker_init(&wait->tracker, MALI_TIMELINE_TRACKER_WAIT, fence, wait);
176 	point = mali_timeline_system_add_tracker(system, &wait->tracker, MALI_TIMELINE_NONE);
177 	MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT == point);
178 	MALI_IGNORE(point);
179 
180 	/* Wait for the tracker to be activated or time out. */
181 	if (MALI_TIMELINE_FENCE_WAIT_TIMEOUT_NEVER == timeout) {
182 		_mali_osk_wait_queue_wait_event(system->wait_queue, mali_timeline_fence_wait_tracker_is_activated, (void *) wait);
183 	} else {
184 		_mali_osk_wait_queue_wait_event_timeout(system->wait_queue, mali_timeline_fence_wait_tracker_is_activated, (void *) wait, timeout);
185 	}
186 
187 	ret = wait->activated;
188 
189 	if (0 == _mali_osk_atomic_dec_return(&wait->refcount)) {
190 		mali_timeline_fence_wait_tracker_free(wait);
191 	}
192 
193 	return ret;
194 }
195 
196 void mali_timeline_fence_wait_activate(struct mali_timeline_fence_wait_tracker *wait)
197 {
198 	mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
199 
200 	MALI_DEBUG_ASSERT_POINTER(wait);
201 	MALI_DEBUG_ASSERT_POINTER(wait->system);
202 
203 	MALI_DEBUG_PRINT(4, ("Mali Timeline: activation for fence wait tracker\n"));
204 
205 	MALI_DEBUG_ASSERT(MALI_FALSE == wait->activated);
206 	wait->activated = MALI_TRUE;
207 
208 	_mali_osk_wait_queue_wake_up(wait->system->wait_queue);
209 
210 	/* Nothing can wait on this tracker, so nothing to schedule after release. */
211 	schedule_mask = mali_timeline_tracker_release(&wait->tracker);
212 	MALI_DEBUG_ASSERT(MALI_SCHEDULER_MASK_EMPTY == schedule_mask);
213 	MALI_IGNORE(schedule_mask);
214 
215 	if (0 == _mali_osk_atomic_dec_return(&wait->refcount)) {
216 		mali_timeline_fence_wait_tracker_free(wait);
217 	}
218 }
219