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