mali mess
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / mt8127 / mali / mali / common / mali_timeline_fence_wait.c
CommitLineData
6fa3eb70
S
1/*
2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
02af6beb 4 * (C) COPYRIGHT 2013-2015 ARM Limited
6fa3eb70
S
5 * ALL RIGHTS RESERVED
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
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 */
22static 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 */
32static 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 */
45static 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 */
62static 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)) {
02af6beb 104#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
6fa3eb70 105 if (0 == sync_fence->status) {
02af6beb
S
106#else
107 if (0 == atomic_read(&sync_fence->status)) {
108#endif
6fa3eb70
S
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
117exit:
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
129mali_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
180void 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}