Commit | Line | Data |
---|---|---|
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 | */ | |
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)) { | |
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 | ||
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 | } |