2 * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
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.
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.
11 #include "mali_timeline.h"
12 #include "mali_kernel_common.h"
13 #include "mali_osk_mali.h"
14 #include "mali_scheduler.h"
15 #include "mali_soft_job.h"
16 #include "mali_timeline_fence_wait.h"
17 #include "mali_timeline_sync_fence.h"
19 #define MALI_TIMELINE_SYSTEM_LOCKED(system) (mali_spinlock_reentrant_is_held((system)->spinlock, _mali_osk_get_tid()))
21 static mali_scheduler_mask mali_timeline_system_release_waiter(struct mali_timeline_system *system,
22 struct mali_timeline_waiter *waiter);
24 #if defined(CONFIG_SYNC)
25 /* Callback that is called when a sync fence a tracker is waiting on is signaled. */
26 static void mali_timeline_sync_fence_callback(struct sync_fence *sync_fence, struct sync_fence_waiter *sync_fence_waiter)
28 struct mali_timeline_system *system;
29 struct mali_timeline_waiter *waiter;
30 struct mali_timeline_tracker *tracker;
31 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
32 u32 tid = _mali_osk_get_tid();
33 mali_bool is_aborting = MALI_FALSE;
34 int fence_status = sync_fence->status;
36 MALI_DEBUG_ASSERT_POINTER(sync_fence);
37 MALI_DEBUG_ASSERT_POINTER(sync_fence_waiter);
39 tracker = _MALI_OSK_CONTAINER_OF(sync_fence_waiter, struct mali_timeline_tracker, sync_fence_waiter);
40 MALI_DEBUG_ASSERT_POINTER(tracker);
42 system = tracker->system;
43 MALI_DEBUG_ASSERT_POINTER(system);
44 MALI_DEBUG_ASSERT_POINTER(system->session);
46 mali_spinlock_reentrant_wait(system->spinlock, tid);
48 is_aborting = system->session->is_aborting;
49 if (!is_aborting && (0 > fence_status)) {
50 MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, fence_status));
51 tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT;
54 waiter = tracker->waiter_sync;
55 MALI_DEBUG_ASSERT_POINTER(waiter);
57 tracker->sync_fence = NULL;
58 schedule_mask |= mali_timeline_system_release_waiter(system, waiter);
60 /* If aborting, wake up sleepers that are waiting for sync fence callbacks to complete. */
62 _mali_osk_wait_queue_wake_up(system->wait_queue);
65 mali_spinlock_reentrant_signal(system->spinlock, tid);
67 sync_fence_put(sync_fence);
70 mali_scheduler_schedule_from_mask(schedule_mask, MALI_TRUE);
73 #endif /* defined(CONFIG_SYNC) */
75 static mali_scheduler_mask mali_timeline_tracker_time_out(struct mali_timeline_tracker *tracker)
77 MALI_DEBUG_ASSERT_POINTER(tracker);
78 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_SOFT == tracker->type);
80 return mali_soft_job_system_timeout_job((struct mali_soft_job *) tracker->job);
83 static void mali_timeline_timer_callback(void *data)
85 struct mali_timeline_system *system;
86 struct mali_timeline_tracker *tracker;
87 struct mali_timeline *timeline;
88 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
89 u32 tid = _mali_osk_get_tid();
91 timeline = (struct mali_timeline *) data;
92 MALI_DEBUG_ASSERT_POINTER(timeline);
94 system = timeline->system;
95 MALI_DEBUG_ASSERT_POINTER(system);
97 mali_spinlock_reentrant_wait(system->spinlock, tid);
99 if (!system->timer_enabled) {
100 mali_spinlock_reentrant_signal(system->spinlock, tid);
104 tracker = timeline->tracker_tail;
105 timeline->timer_active = MALI_FALSE;
107 if (NULL != tracker && MALI_TRUE == tracker->timer_active) {
108 /* This is likely the delayed work that has been schedule out before cancelled. */
109 if (MALI_TIMELINE_TIMEOUT_HZ > (_mali_osk_time_tickcount() - tracker->os_tick_activate)) {
110 mali_spinlock_reentrant_signal(system->spinlock, tid);
114 schedule_mask = mali_timeline_tracker_time_out(tracker);
115 tracker->timer_active = MALI_FALSE;
117 MALI_PRINT_ERROR(("Mali Timeline: Soft job timer callback without a waiting tracker.\n"));
120 mali_spinlock_reentrant_signal(system->spinlock, tid);
122 mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
125 void mali_timeline_system_stop_timer(struct mali_timeline_system *system)
128 u32 tid = _mali_osk_get_tid();
130 MALI_DEBUG_ASSERT_POINTER(system);
132 mali_spinlock_reentrant_wait(system->spinlock, tid);
133 system->timer_enabled = MALI_FALSE;
134 mali_spinlock_reentrant_signal(system->spinlock, tid);
136 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
137 struct mali_timeline *timeline = system->timelines[i];
139 MALI_DEBUG_ASSERT_POINTER(timeline);
141 if (NULL != timeline->delayed_work) {
142 _mali_osk_wq_delayed_cancel_work_sync(timeline->delayed_work);
143 timeline->timer_active = MALI_FALSE;
148 static void mali_timeline_destroy(struct mali_timeline *timeline)
150 MALI_DEBUG_ASSERT_POINTER(timeline);
151 if (NULL != timeline) {
152 /* Assert that the timeline object has been properly cleaned up before destroying it. */
153 MALI_DEBUG_ASSERT(timeline->point_oldest == timeline->point_next);
154 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head);
155 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail);
156 MALI_DEBUG_ASSERT(NULL == timeline->waiter_head);
157 MALI_DEBUG_ASSERT(NULL == timeline->waiter_tail);
158 MALI_DEBUG_ASSERT(NULL != timeline->system);
159 MALI_DEBUG_ASSERT(MALI_TIMELINE_MAX > timeline->id);
161 #if defined(CONFIG_SYNC)
162 if (NULL != timeline->sync_tl) {
163 sync_timeline_destroy(timeline->sync_tl);
165 #endif /* defined(CONFIG_SYNC) */
167 if (NULL != timeline->delayed_work) {
168 _mali_osk_wq_delayed_cancel_work_sync(timeline->delayed_work);
169 _mali_osk_wq_delayed_delete_work_nonflush(timeline->delayed_work);
172 _mali_osk_free(timeline);
176 static struct mali_timeline *mali_timeline_create(struct mali_timeline_system *system, enum mali_timeline_id id)
178 struct mali_timeline *timeline;
180 MALI_DEBUG_ASSERT_POINTER(system);
181 MALI_DEBUG_ASSERT(id < MALI_TIMELINE_MAX);
183 timeline = (struct mali_timeline *) _mali_osk_calloc(1, sizeof(struct mali_timeline));
184 if (NULL == timeline) {
188 /* Initially the timeline is empty. */
189 #if defined(MALI_TIMELINE_DEBUG_START_POINT)
190 /* Start the timeline a bit before wrapping when debugging. */
191 timeline->point_next = UINT_MAX - MALI_TIMELINE_MAX_POINT_SPAN - 128;
193 timeline->point_next = 1;
195 timeline->point_oldest = timeline->point_next;
197 /* The tracker and waiter lists will initially be empty. */
199 timeline->system = system;
202 timeline->delayed_work = _mali_osk_wq_delayed_create_work(mali_timeline_timer_callback, timeline);
203 if (NULL == timeline->delayed_work) {
204 mali_timeline_destroy(timeline);
208 timeline->timer_active = MALI_FALSE;
210 #if defined(CONFIG_SYNC)
212 char timeline_name[32];
215 case MALI_TIMELINE_GP:
216 _mali_osk_snprintf(timeline_name, 32, "mali-%u-gp", _mali_osk_get_pid());
218 case MALI_TIMELINE_PP:
219 _mali_osk_snprintf(timeline_name, 32, "mali-%u-pp", _mali_osk_get_pid());
221 case MALI_TIMELINE_SOFT:
222 _mali_osk_snprintf(timeline_name, 32, "mali-%u-soft", _mali_osk_get_pid());
225 MALI_PRINT_ERROR(("Mali Timeline: Invalid timeline id %d\n", id));
226 mali_timeline_destroy(timeline);
230 timeline->sync_tl = mali_sync_timeline_create(timeline_name);
231 if (NULL == timeline->sync_tl) {
232 mali_timeline_destroy(timeline);
236 #endif /* defined(CONFIG_SYNC) */
241 static void mali_timeline_insert_tracker(struct mali_timeline *timeline, struct mali_timeline_tracker *tracker)
243 MALI_DEBUG_ASSERT_POINTER(timeline);
244 MALI_DEBUG_ASSERT_POINTER(tracker);
246 if (mali_timeline_is_full(timeline)) {
247 /* Don't add tracker if timeline is full. */
248 tracker->point = MALI_TIMELINE_NO_POINT;
252 tracker->timeline = timeline;
253 tracker->point = timeline->point_next;
255 /* Find next available point. */
256 timeline->point_next++;
257 if (MALI_TIMELINE_NO_POINT == timeline->point_next) {
258 timeline->point_next++;
261 MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline));
263 /* Add tracker as new head on timeline's tracker list. */
264 if (NULL == timeline->tracker_head) {
265 /* Tracker list is empty. */
266 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail);
268 timeline->tracker_tail = tracker;
270 MALI_DEBUG_ASSERT(NULL == tracker->timeline_next);
271 MALI_DEBUG_ASSERT(NULL == tracker->timeline_prev);
273 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head->timeline_next);
275 tracker->timeline_prev = timeline->tracker_head;
276 timeline->tracker_head->timeline_next = tracker;
278 MALI_DEBUG_ASSERT(NULL == tracker->timeline_next);
280 timeline->tracker_head = tracker;
282 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head->timeline_next);
283 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail->timeline_prev);
286 /* Inserting the waiter object into the given timeline */
287 static void mali_timeline_insert_waiter(struct mali_timeline *timeline, struct mali_timeline_waiter *waiter_new)
289 struct mali_timeline_waiter *waiter_prev;
290 struct mali_timeline_waiter *waiter_next;
292 /* Waiter time must be between timeline head and tail, and there must
293 * be less than MALI_TIMELINE_MAX_POINT_SPAN elements between */
294 MALI_DEBUG_ASSERT(( waiter_new->point - timeline->point_oldest) < MALI_TIMELINE_MAX_POINT_SPAN);
295 MALI_DEBUG_ASSERT((-waiter_new->point + timeline->point_next) < MALI_TIMELINE_MAX_POINT_SPAN);
297 /* Finding out where to put this waiter, in the linked waiter list of the given timeline **/
298 waiter_prev = timeline->waiter_head; /* Insert new after waiter_prev */
299 waiter_next = NULL; /* Insert new before waiter_next */
301 /* Iterating backwards from head (newest) to tail (oldest) until we
302 * find the correct spot to insert the new waiter */
303 while (waiter_prev && mali_timeline_point_after(waiter_prev->point, waiter_new->point)) {
304 waiter_next = waiter_prev;
305 waiter_prev = waiter_prev->timeline_prev;
308 if (NULL == waiter_prev && NULL == waiter_next) {
310 timeline->waiter_head = waiter_new;
311 timeline->waiter_tail = waiter_new;
312 } else if (NULL == waiter_next) {
314 waiter_new->timeline_prev = timeline->waiter_head;
315 timeline->waiter_head->timeline_next = waiter_new;
316 timeline->waiter_head = waiter_new;
317 } else if (NULL == waiter_prev) {
319 waiter_new->timeline_next = timeline->waiter_tail;
320 timeline->waiter_tail->timeline_prev = waiter_new;
321 timeline->waiter_tail = waiter_new;
324 waiter_new->timeline_next = waiter_next;
325 waiter_new->timeline_prev = waiter_prev;
326 waiter_next->timeline_prev = waiter_new;
327 waiter_prev->timeline_next = waiter_new;
331 static void mali_timeline_update_delayed_work(struct mali_timeline *timeline)
333 struct mali_timeline_system *system;
334 struct mali_timeline_tracker *oldest_tracker;
336 MALI_DEBUG_ASSERT_POINTER(timeline);
337 MALI_DEBUG_ASSERT(MALI_TIMELINE_SOFT == timeline->id);
339 system = timeline->system;
340 MALI_DEBUG_ASSERT_POINTER(system);
342 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
344 /* Timer is disabled, early out. */
345 if (!system->timer_enabled) return;
347 oldest_tracker = timeline->tracker_tail;
348 if (NULL != oldest_tracker && 0 == oldest_tracker->trigger_ref_count) {
349 if (MALI_FALSE == oldest_tracker->timer_active) {
350 if (MALI_TRUE == timeline->timer_active) {
351 _mali_osk_wq_delayed_cancel_work_async(timeline->delayed_work);
353 _mali_osk_wq_delayed_schedule_work(timeline->delayed_work, MALI_TIMELINE_TIMEOUT_HZ);
354 oldest_tracker->timer_active = MALI_TRUE;
355 timeline->timer_active = MALI_TRUE;
357 } else if (MALI_TRUE == timeline->timer_active) {
358 _mali_osk_wq_delayed_cancel_work_async(timeline->delayed_work);
359 timeline->timer_active = MALI_FALSE;
363 static mali_scheduler_mask mali_timeline_update_oldest_point(struct mali_timeline *timeline)
365 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
367 MALI_DEBUG_ASSERT_POINTER(timeline);
370 struct mali_timeline_system *system = timeline->system;
371 MALI_DEBUG_ASSERT_POINTER(system);
373 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
376 if (NULL != timeline->tracker_tail) {
377 /* Set oldest point to oldest tracker's point */
378 timeline->point_oldest = timeline->tracker_tail->point;
380 /* No trackers, mark point list as empty */
381 timeline->point_oldest = timeline->point_next;
384 /* Release all waiters no longer on the timeline's point list.
385 * Releasing a waiter can trigger this function to be called again, so
386 * we do not store any pointers on stack. */
387 while (NULL != timeline->waiter_tail) {
388 u32 waiter_time_relative;
389 u32 time_head_relative;
390 struct mali_timeline_waiter *waiter = timeline->waiter_tail;
392 time_head_relative = timeline->point_next - timeline->point_oldest;
393 waiter_time_relative = waiter->point - timeline->point_oldest;
395 if (waiter_time_relative < time_head_relative) {
396 /* This and all following waiters are on the point list, so we are done. */
400 /* Remove waiter from timeline's waiter list. */
401 if (NULL != waiter->timeline_next) {
402 waiter->timeline_next->timeline_prev = NULL;
404 /* This was the last waiter */
405 timeline->waiter_head = NULL;
407 timeline->waiter_tail = waiter->timeline_next;
409 /* Release waiter. This could activate a tracker, if this was
410 * the last waiter for the tracker. */
411 schedule_mask |= mali_timeline_system_release_waiter(timeline->system, waiter);
414 return schedule_mask;
417 void mali_timeline_tracker_init(struct mali_timeline_tracker *tracker,
418 mali_timeline_tracker_type type,
419 struct mali_timeline_fence *fence,
422 MALI_DEBUG_ASSERT_POINTER(tracker);
423 MALI_DEBUG_ASSERT_POINTER(job);
425 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAX > type);
427 /* Zero out all tracker members. */
428 _mali_osk_memset(tracker, 0, sizeof(*tracker));
430 tracker->type = type;
432 tracker->trigger_ref_count = 1; /* Prevents any callback from trigging while adding it */
433 tracker->os_tick_create = _mali_osk_time_tickcount();
434 MALI_DEBUG_CODE(tracker->magic = MALI_TIMELINE_TRACKER_MAGIC);
436 tracker->activation_error = MALI_TIMELINE_ACTIVATION_ERROR_NONE;
440 _mali_osk_memcpy(&tracker->fence, fence, sizeof(struct mali_timeline_fence));
444 mali_scheduler_mask mali_timeline_tracker_release(struct mali_timeline_tracker *tracker)
446 struct mali_timeline *timeline;
447 struct mali_timeline_system *system;
448 struct mali_timeline_tracker *tracker_next, *tracker_prev;
449 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
450 u32 tid = _mali_osk_get_tid();
452 /* Upon entry a group lock will be held, but not a scheduler lock. */
453 MALI_DEBUG_ASSERT_POINTER(tracker);
454 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic);
456 /* Tracker should have been triggered */
457 MALI_DEBUG_ASSERT(0 == tracker->trigger_ref_count);
459 /* All waiters should have been released at this point */
460 MALI_DEBUG_ASSERT(NULL == tracker->waiter_head);
461 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
463 MALI_DEBUG_PRINT(3, ("Mali Timeline: releasing tracker for job 0x%08X\n", tracker->job));
465 timeline = tracker->timeline;
466 if (NULL == timeline) {
467 /* Tracker was not on a timeline, there is nothing to release. */
468 return MALI_SCHEDULER_MASK_EMPTY;
471 system = timeline->system;
472 MALI_DEBUG_ASSERT_POINTER(system);
474 mali_spinlock_reentrant_wait(system->spinlock, tid);
476 /* Tracker should still be on timeline */
477 MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline));
478 MALI_DEBUG_ASSERT( mali_timeline_is_point_on(timeline, tracker->point));
480 /* Tracker is no longer valid. */
481 MALI_DEBUG_CODE(tracker->magic = 0);
483 tracker_next = tracker->timeline_next;
484 tracker_prev = tracker->timeline_prev;
485 tracker->timeline_next = NULL;
486 tracker->timeline_prev = NULL;
488 /* Removing tracker from timeline's tracker list */
489 if (NULL == tracker_next) {
490 /* This tracker was the head */
491 timeline->tracker_head = tracker_prev;
493 tracker_next->timeline_prev = tracker_prev;
496 if (NULL == tracker_prev) {
497 /* This tracker was the tail */
498 timeline->tracker_tail = tracker_next;
499 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
500 /* Update the timeline's oldest time and release any waiters */
501 schedule_mask |= mali_timeline_update_oldest_point(timeline);
502 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
504 tracker_prev->timeline_next = tracker_next;
507 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
509 /* Update delayed work only when it is the soft job timeline */
510 if (MALI_TIMELINE_SOFT == tracker->timeline->id) {
511 mali_timeline_update_delayed_work(tracker->timeline);
514 mali_spinlock_reentrant_signal(system->spinlock, tid);
516 return schedule_mask;
519 void mali_timeline_system_release_waiter_list(struct mali_timeline_system *system,
520 struct mali_timeline_waiter *tail,
521 struct mali_timeline_waiter *head)
523 MALI_DEBUG_ASSERT_POINTER(system);
524 MALI_DEBUG_ASSERT_POINTER(head);
525 MALI_DEBUG_ASSERT_POINTER(tail);
526 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
528 head->tracker_next = system->waiter_empty_list;
529 system->waiter_empty_list = tail;
532 static mali_scheduler_mask mali_timeline_tracker_activate(struct mali_timeline_tracker *tracker)
534 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
535 struct mali_timeline_system *system;
536 struct mali_timeline *timeline;
537 u32 tid = _mali_osk_get_tid();
539 MALI_DEBUG_ASSERT_POINTER(tracker);
540 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic);
542 system = tracker->system;
543 MALI_DEBUG_ASSERT_POINTER(system);
544 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
546 tracker->os_tick_activate = _mali_osk_time_tickcount();
548 if (NULL != tracker->waiter_head) {
549 mali_timeline_system_release_waiter_list(system, tracker->waiter_tail, tracker->waiter_head);
550 tracker->waiter_head = NULL;
551 tracker->waiter_tail = NULL;
554 switch (tracker->type) {
555 case MALI_TIMELINE_TRACKER_GP:
556 schedule_mask = mali_gp_scheduler_activate_job((struct mali_gp_job *) tracker->job);
558 case MALI_TIMELINE_TRACKER_PP:
559 schedule_mask = mali_pp_scheduler_activate_job((struct mali_pp_job *) tracker->job);
561 case MALI_TIMELINE_TRACKER_SOFT:
562 timeline = tracker->timeline;
563 MALI_DEBUG_ASSERT_POINTER(timeline);
565 mali_soft_job_system_activate_job((struct mali_soft_job *) tracker->job);
567 /* Start a soft timer to make sure the soft job be released in a limited time */
568 mali_spinlock_reentrant_wait(system->spinlock, tid);
569 mali_timeline_update_delayed_work(timeline);
570 mali_spinlock_reentrant_signal(system->spinlock, tid);
572 case MALI_TIMELINE_TRACKER_WAIT:
573 mali_timeline_fence_wait_activate((struct mali_timeline_fence_wait_tracker *) tracker->job);
575 case MALI_TIMELINE_TRACKER_SYNC:
576 #if defined(CONFIG_SYNC)
577 mali_timeline_sync_fence_activate((struct mali_timeline_sync_fence_tracker *) tracker->job);
579 MALI_PRINT_ERROR(("Mali Timeline: sync tracker not supported\n", tracker->type));
580 #endif /* defined(CONFIG_SYNC) */
583 MALI_PRINT_ERROR(("Mali Timeline - Illegal tracker type: %d\n", tracker->type));
587 return schedule_mask;
590 void mali_timeline_system_tracker_get(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker)
592 u32 tid = _mali_osk_get_tid();
594 MALI_DEBUG_ASSERT_POINTER(tracker);
595 MALI_DEBUG_ASSERT_POINTER(system);
597 mali_spinlock_reentrant_wait(system->spinlock, tid);
599 MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count);
600 tracker->trigger_ref_count++;
602 mali_spinlock_reentrant_signal(system->spinlock, tid);
605 mali_scheduler_mask mali_timeline_system_tracker_put(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker, mali_timeline_activation_error activation_error)
607 u32 tid = _mali_osk_get_tid();
608 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
610 MALI_DEBUG_ASSERT_POINTER(tracker);
611 MALI_DEBUG_ASSERT_POINTER(system);
613 mali_spinlock_reentrant_wait(system->spinlock, tid);
615 MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count);
616 tracker->trigger_ref_count--;
618 tracker->activation_error |= activation_error;
620 if (0 == tracker->trigger_ref_count) {
621 schedule_mask |= mali_timeline_tracker_activate(tracker);
625 mali_spinlock_reentrant_signal(system->spinlock, tid);
627 return schedule_mask;
630 void mali_timeline_fence_copy_uk_fence(struct mali_timeline_fence *fence, _mali_uk_fence_t *uk_fence)
634 MALI_DEBUG_ASSERT_POINTER(fence);
635 MALI_DEBUG_ASSERT_POINTER(uk_fence);
637 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
638 fence->points[i] = uk_fence->points[i];
641 fence->sync_fd = uk_fence->sync_fd;
644 struct mali_timeline_system *mali_timeline_system_create(struct mali_session_data *session)
647 struct mali_timeline_system *system;
649 MALI_DEBUG_ASSERT_POINTER(session);
650 MALI_DEBUG_PRINT(4, ("Mali Timeline: creating timeline system\n"));
652 system = (struct mali_timeline_system *) _mali_osk_calloc(1, sizeof(struct mali_timeline_system));
653 if (NULL == system) {
657 system->spinlock = mali_spinlock_reentrant_init(_MALI_OSK_LOCK_ORDER_TIMELINE_SYSTEM);
658 if (NULL == system->spinlock) {
659 mali_timeline_system_destroy(system);
663 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
664 system->timelines[i] = mali_timeline_create(system, (enum mali_timeline_id)i);
665 if (NULL == system->timelines[i]) {
666 mali_timeline_system_destroy(system);
671 #if defined(CONFIG_SYNC)
672 system->signaled_sync_tl = mali_sync_timeline_create("mali-always-signaled");
673 if (NULL == system->signaled_sync_tl) {
674 mali_timeline_system_destroy(system);
677 #endif /* defined(CONFIG_SYNC) */
679 system->waiter_empty_list = NULL;
680 system->session = session;
681 system->timer_enabled = MALI_TRUE;
683 system->wait_queue = _mali_osk_wait_queue_init();
684 if (NULL == system->wait_queue) {
685 mali_timeline_system_destroy(system);
692 #if defined(CONFIG_SYNC)
695 * Check if there are any trackers left on timeline.
697 * Used as a wait queue conditional.
699 * @param data Timeline.
700 * @return MALI_TRUE if there are no trackers on timeline, MALI_FALSE if not.
702 static mali_bool mali_timeline_has_no_trackers(void *data)
704 struct mali_timeline *timeline = (struct mali_timeline *) data;
706 MALI_DEBUG_ASSERT_POINTER(timeline);
708 return mali_timeline_is_empty(timeline);
712 * Cancel sync fence waiters waited upon by trackers on all timelines.
714 * Will return after all timelines have no trackers left.
716 * @param system Timeline system.
718 static void mali_timeline_cancel_sync_fence_waiters(struct mali_timeline_system *system)
721 u32 tid = _mali_osk_get_tid();
722 struct mali_timeline_tracker *tracker, *tracker_next;
723 _MALI_OSK_LIST_HEAD_STATIC_INIT(tracker_list);
725 MALI_DEBUG_ASSERT_POINTER(system);
726 MALI_DEBUG_ASSERT_POINTER(system->session);
727 MALI_DEBUG_ASSERT(system->session->is_aborting);
729 mali_spinlock_reentrant_wait(system->spinlock, tid);
731 /* Cancel sync fence waiters. */
732 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
733 struct mali_timeline *timeline = system->timelines[i];
735 MALI_DEBUG_ASSERT_POINTER(timeline);
737 tracker_next = timeline->tracker_tail;
738 while (NULL != tracker_next) {
739 tracker = tracker_next;
740 tracker_next = tracker->timeline_next;
742 if (NULL == tracker->sync_fence) continue;
744 MALI_DEBUG_PRINT(3, ("Mali Timeline: Cancelling sync fence wait for tracker 0x%08X.\n", tracker));
746 /* Cancel sync fence waiter. */
747 if (0 == sync_fence_cancel_async(tracker->sync_fence, &tracker->sync_fence_waiter)) {
748 /* Callback was not called, move tracker to local list. */
749 _mali_osk_list_add(&tracker->sync_fence_cancel_list, &tracker_list);
754 mali_spinlock_reentrant_signal(system->spinlock, tid);
756 /* Manually call sync fence callback in order to release waiter and trigger activation of tracker. */
757 _MALI_OSK_LIST_FOREACHENTRY(tracker, tracker_next, &tracker_list, struct mali_timeline_tracker, sync_fence_cancel_list) {
758 mali_timeline_sync_fence_callback(tracker->sync_fence, &tracker->sync_fence_waiter);
761 /* Sleep until all sync fence callbacks are done and all timelines are empty. */
762 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
763 struct mali_timeline *timeline = system->timelines[i];
765 MALI_DEBUG_ASSERT_POINTER(timeline);
767 _mali_osk_wait_queue_wait_event(system->wait_queue, mali_timeline_has_no_trackers, (void *) timeline);
771 #endif /* defined(CONFIG_SYNC) */
773 void mali_timeline_system_abort(struct mali_timeline_system *system)
775 MALI_DEBUG_CODE(u32 tid = _mali_osk_get_tid(););
777 MALI_DEBUG_ASSERT_POINTER(system);
778 MALI_DEBUG_ASSERT_POINTER(system->session);
779 MALI_DEBUG_ASSERT(system->session->is_aborting);
781 MALI_DEBUG_PRINT(3, ("Mali Timeline: Aborting timeline system for session 0x%08X.\n", system->session));
783 #if defined(CONFIG_SYNC)
784 mali_timeline_cancel_sync_fence_waiters(system);
785 #endif /* defined(CONFIG_SYNC) */
787 /* Should not be any waiters or trackers left at this point. */
790 mali_spinlock_reentrant_wait(system->spinlock, tid);
791 for (i = 0; i < MALI_TIMELINE_MAX; ++i)
793 struct mali_timeline *timeline = system->timelines[i];
794 MALI_DEBUG_ASSERT_POINTER(timeline);
795 MALI_DEBUG_ASSERT(timeline->point_oldest == timeline->point_next);
796 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head);
797 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail);
798 MALI_DEBUG_ASSERT(NULL == timeline->waiter_head);
799 MALI_DEBUG_ASSERT(NULL == timeline->waiter_tail);
801 mali_spinlock_reentrant_signal(system->spinlock, tid);
805 void mali_timeline_system_destroy(struct mali_timeline_system *system)
808 struct mali_timeline_waiter *waiter, *next;
810 MALI_DEBUG_ASSERT_POINTER(system);
811 MALI_DEBUG_ASSERT_POINTER(system->session);
813 MALI_DEBUG_PRINT(4, ("Mali Timeline: destroying timeline system\n"));
815 if (NULL != system) {
816 /* There should be no waiters left on this queue. */
817 if (NULL != system->wait_queue) {
818 _mali_osk_wait_queue_term(system->wait_queue);
819 system->wait_queue = NULL;
822 /* Free all waiters in empty list */
823 waiter = system->waiter_empty_list;
824 while (NULL != waiter) {
825 next = waiter->tracker_next;
826 _mali_osk_free(waiter);
830 #if defined(CONFIG_SYNC)
831 if (NULL != system->signaled_sync_tl) {
832 sync_timeline_destroy(system->signaled_sync_tl);
834 #endif /* defined(CONFIG_SYNC) */
836 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
837 if (NULL != system->timelines[i]) {
838 mali_timeline_destroy(system->timelines[i]);
841 if (NULL != system->spinlock) {
842 mali_spinlock_reentrant_term(system->spinlock);
845 _mali_osk_free(system);
850 * Find how many waiters are needed for a given fence.
852 * @param fence The fence to check.
853 * @return Number of waiters needed for fence.
855 static u32 mali_timeline_fence_num_waiters(struct mali_timeline_fence *fence)
857 u32 i, num_waiters = 0;
859 MALI_DEBUG_ASSERT_POINTER(fence);
861 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
862 if (MALI_TIMELINE_NO_POINT != fence->points[i]) {
867 #if defined(CONFIG_SYNC)
868 if (-1 != fence->sync_fd) ++num_waiters;
869 #endif /* defined(CONFIG_SYNC) */
874 static struct mali_timeline_waiter *mali_timeline_system_get_zeroed_waiter(struct mali_timeline_system *system)
876 struct mali_timeline_waiter *waiter;
878 MALI_DEBUG_ASSERT_POINTER(system);
879 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
881 waiter = system->waiter_empty_list;
882 if (NULL != waiter) {
883 /* Remove waiter from empty list and zero it */
884 system->waiter_empty_list = waiter->tracker_next;
885 _mali_osk_memset(waiter, 0, sizeof(*waiter));
888 /* Return NULL if list was empty. */
892 static void mali_timeline_system_allocate_waiters(struct mali_timeline_system *system,
893 struct mali_timeline_waiter **tail,
894 struct mali_timeline_waiter **head,
897 u32 i, tid = _mali_osk_get_tid();
899 struct mali_timeline_waiter *waiter;
901 MALI_DEBUG_ASSERT_POINTER(system);
902 MALI_DEBUG_ASSERT_POINTER(tail);
903 MALI_DEBUG_ASSERT_POINTER(head);
905 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
907 *head = *tail = NULL;
908 do_alloc = MALI_FALSE;
910 while (i < max_num_waiters) {
911 if (MALI_FALSE == do_alloc) {
912 waiter = mali_timeline_system_get_zeroed_waiter(system);
913 if (NULL == waiter) {
914 do_alloc = MALI_TRUE;
915 mali_spinlock_reentrant_signal(system->spinlock, tid);
919 waiter = _mali_osk_calloc(1, sizeof(struct mali_timeline_waiter));
920 if (NULL == waiter) break;
927 (*head)->tracker_next = waiter;
931 if (MALI_TRUE == do_alloc) {
932 mali_spinlock_reentrant_wait(system->spinlock, tid);
937 * Create waiters for the given tracker. The tracker is activated when all waiters are release.
939 * @note Tracker can potentially be activated before this function returns.
941 * @param system Timeline system.
942 * @param tracker Tracker we will create waiters for.
943 * @param waiter_tail List of pre-allocated waiters.
944 * @param waiter_head List of pre-allocated waiters.
946 static void mali_timeline_system_create_waiters_and_unlock(struct mali_timeline_system *system,
947 struct mali_timeline_tracker *tracker,
948 struct mali_timeline_waiter *waiter_tail,
949 struct mali_timeline_waiter *waiter_head)
952 u32 tid = _mali_osk_get_tid();
953 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
954 #if defined(CONFIG_SYNC)
955 struct sync_fence *sync_fence = NULL;
956 #endif /* defined(CONFIG_SYNC) */
958 MALI_DEBUG_ASSERT_POINTER(system);
959 MALI_DEBUG_ASSERT_POINTER(tracker);
961 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
963 MALI_DEBUG_ASSERT(NULL == tracker->waiter_head);
964 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
965 MALI_DEBUG_ASSERT(NULL != tracker->job);
967 /* Creating waiter object for all the timelines the fence is put on. Inserting this waiter
968 * into the timelines sorted list of waiters */
969 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
970 mali_timeline_point point;
971 struct mali_timeline *timeline;
972 struct mali_timeline_waiter *waiter;
974 /* Get point on current timeline from tracker's fence. */
975 point = tracker->fence.points[i];
977 if (likely(MALI_TIMELINE_NO_POINT == point)) {
978 /* Fence contains no point on this timeline so we don't need a waiter. */
982 timeline = system->timelines[i];
983 MALI_DEBUG_ASSERT_POINTER(timeline);
985 if (unlikely(!mali_timeline_is_point_valid(timeline, point))) {
986 MALI_PRINT_ERROR(("Mali Timeline: point %d is not valid (oldest=%d, next=%d)\n",
987 point, timeline->point_oldest, timeline->point_next));
991 if (likely(mali_timeline_is_point_released(timeline, point))) {
992 /* Tracker representing the point has been released so we don't need a
997 /* The point is on timeline. */
998 MALI_DEBUG_ASSERT(mali_timeline_is_point_on(timeline, point));
1000 /* Get a new zeroed waiter object. */
1001 if (likely(NULL != waiter_tail)) {
1002 waiter = waiter_tail;
1003 waiter_tail = waiter_tail->tracker_next;
1005 MALI_PRINT_ERROR(("Mali Timeline: failed to allocate memory for waiter\n"));
1009 /* Yanking the trigger ref count of the tracker. */
1010 tracker->trigger_ref_count++;
1012 waiter->point = point;
1013 waiter->tracker = tracker;
1015 /* Insert waiter on tracker's singly-linked waiter list. */
1016 if (NULL == tracker->waiter_head) {
1018 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
1019 tracker->waiter_tail = waiter;
1021 tracker->waiter_head->tracker_next = waiter;
1023 tracker->waiter_head = waiter;
1025 /* Add waiter to timeline. */
1026 mali_timeline_insert_waiter(timeline, waiter);
1028 #if defined(CONFIG_SYNC)
1029 if (-1 != tracker->fence.sync_fd) {
1031 struct mali_timeline_waiter *waiter;
1033 sync_fence = sync_fence_fdget(tracker->fence.sync_fd);
1034 if (unlikely(NULL == sync_fence)) {
1035 MALI_PRINT_ERROR(("Mali Timeline: failed to get sync fence from fd %d\n", tracker->fence.sync_fd));
1039 /* Check if we have a zeroed waiter object available. */
1040 if (unlikely(NULL == waiter_tail)) {
1041 MALI_PRINT_ERROR(("Mali Timeline: failed to allocate memory for waiter\n"));
1045 /* Start asynchronous wait that will release waiter when the fence is signaled. */
1046 sync_fence_waiter_init(&tracker->sync_fence_waiter, mali_timeline_sync_fence_callback);
1047 ret = sync_fence_wait_async(sync_fence, &tracker->sync_fence_waiter);
1049 /* Fence already signaled, no waiter needed. */
1051 } else if (0 != ret) {
1052 MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, ret));
1053 tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT;
1057 /* Grab new zeroed waiter object. */
1058 waiter = waiter_tail;
1059 waiter_tail = waiter_tail->tracker_next;
1061 /* Increase the trigger ref count of the tracker. */
1062 tracker->trigger_ref_count++;
1064 waiter->point = MALI_TIMELINE_NO_POINT;
1065 waiter->tracker = tracker;
1067 /* Insert waiter on tracker's singly-linked waiter list. */
1068 if (NULL == tracker->waiter_head) {
1070 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
1071 tracker->waiter_tail = waiter;
1073 tracker->waiter_head->tracker_next = waiter;
1075 tracker->waiter_head = waiter;
1077 /* Also store waiter in separate field for easy access by sync callback. */
1078 tracker->waiter_sync = waiter;
1080 /* Store the sync fence in tracker so we can retrieve in abort session, if needed. */
1081 tracker->sync_fence = sync_fence;
1086 #endif /* defined(CONFIG_SYNC) */
1088 if (NULL != waiter_tail) {
1089 mali_timeline_system_release_waiter_list(system, waiter_tail, waiter_head);
1092 /* Release the initial trigger ref count. */
1093 tracker->trigger_ref_count--;
1095 /* If there were no waiters added to this tracker we activate immediately. */
1096 if (0 == tracker->trigger_ref_count) {
1097 schedule_mask |= mali_timeline_tracker_activate(tracker);
1100 mali_spinlock_reentrant_signal(system->spinlock, tid);
1102 #if defined(CONFIG_SYNC)
1103 if (NULL != sync_fence) {
1104 sync_fence_put(sync_fence);
1106 #endif /* defined(CONFIG_SYNC) */
1108 mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
1111 mali_timeline_point mali_timeline_system_add_tracker(struct mali_timeline_system *system,
1112 struct mali_timeline_tracker *tracker,
1113 enum mali_timeline_id timeline_id)
1115 int num_waiters = 0;
1116 struct mali_timeline_waiter *waiter_tail, *waiter_head;
1117 u32 tid = _mali_osk_get_tid();
1118 mali_timeline_point point = MALI_TIMELINE_NO_POINT;
1120 MALI_DEBUG_ASSERT_POINTER(system);
1121 MALI_DEBUG_ASSERT_POINTER(system->session);
1122 MALI_DEBUG_ASSERT_POINTER(tracker);
1124 MALI_DEBUG_ASSERT(MALI_FALSE == system->session->is_aborting);
1125 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAX > tracker->type);
1126 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic);
1128 MALI_DEBUG_PRINT(4, ("Mali Timeline: adding tracker for job %p, timeline: %d\n", tracker->job, timeline_id));
1130 MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count);
1131 tracker->system = system;
1133 mali_spinlock_reentrant_wait(system->spinlock, tid);
1135 num_waiters = mali_timeline_fence_num_waiters(&tracker->fence);
1137 /* Allocate waiters. */
1138 mali_timeline_system_allocate_waiters(system, &waiter_tail, &waiter_head, num_waiters);
1139 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
1141 /* Add tracker to timeline. This will allocate a point for the tracker on the timeline. If
1142 * timeline ID is MALI_TIMELINE_NONE the tracker will NOT be added to a timeline and the
1143 * point will be MALI_TIMELINE_NO_POINT.
1145 * NOTE: the tracker can fail to be added if the timeline is full. If this happens, the
1146 * point will be MALI_TIMELINE_NO_POINT. */
1147 MALI_DEBUG_ASSERT(timeline_id < MALI_TIMELINE_MAX || timeline_id == MALI_TIMELINE_NONE);
1148 if (likely(timeline_id < MALI_TIMELINE_MAX)) {
1149 struct mali_timeline *timeline = system->timelines[timeline_id];
1150 mali_timeline_insert_tracker(timeline, tracker);
1151 MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline));
1154 point = tracker->point;
1156 /* Create waiters for tracker based on supplied fence. Each waiter will increase the
1157 * trigger ref count. */
1158 mali_timeline_system_create_waiters_and_unlock(system, tracker, waiter_tail, waiter_head);
1161 /* At this point the tracker object might have been freed so we should no longer
1165 /* The tracker will always be activated after calling add_tracker, even if NO_POINT is
1170 static mali_scheduler_mask mali_timeline_system_release_waiter(struct mali_timeline_system *system,
1171 struct mali_timeline_waiter *waiter)
1173 struct mali_timeline_tracker *tracker;
1174 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
1176 MALI_DEBUG_ASSERT_POINTER(system);
1177 MALI_DEBUG_ASSERT_POINTER(waiter);
1179 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
1181 tracker = waiter->tracker;
1182 MALI_DEBUG_ASSERT_POINTER(tracker);
1184 /* At this point the waiter has been removed from the timeline's waiter list, but it is
1185 * still on the tracker's waiter list. All of the tracker's waiters will be released when
1186 * the tracker is activated. */
1188 waiter->point = MALI_TIMELINE_NO_POINT;
1189 waiter->tracker = NULL;
1191 tracker->trigger_ref_count--;
1192 if (0 == tracker->trigger_ref_count) {
1193 /* This was the last waiter; activate tracker */
1194 schedule_mask |= mali_timeline_tracker_activate(tracker);
1198 return schedule_mask;
1201 mali_timeline_point mali_timeline_system_get_latest_point(struct mali_timeline_system *system,
1202 enum mali_timeline_id timeline_id)
1204 mali_timeline_point point;
1205 struct mali_timeline *timeline;
1206 u32 tid = _mali_osk_get_tid();
1208 MALI_DEBUG_ASSERT_POINTER(system);
1210 if (MALI_TIMELINE_MAX <= timeline_id) {
1211 return MALI_TIMELINE_NO_POINT;
1214 mali_spinlock_reentrant_wait(system->spinlock, tid);
1216 timeline = system->timelines[timeline_id];
1217 MALI_DEBUG_ASSERT_POINTER(timeline);
1219 point = MALI_TIMELINE_NO_POINT;
1220 if (timeline->point_oldest != timeline->point_next) {
1221 point = timeline->point_next - 1;
1222 if (MALI_TIMELINE_NO_POINT == point) point--;
1225 mali_spinlock_reentrant_signal(system->spinlock, tid);
1230 #if defined(MALI_TIMELINE_DEBUG_FUNCTIONS)
1232 static mali_bool is_waiting_on_timeline(struct mali_timeline_tracker *tracker, enum mali_timeline_id id)
1234 struct mali_timeline *timeline;
1235 struct mali_timeline_system *system;
1237 MALI_DEBUG_ASSERT_POINTER(tracker);
1239 MALI_DEBUG_ASSERT_POINTER(tracker->timeline);
1240 timeline = tracker->timeline;
1242 MALI_DEBUG_ASSERT_POINTER(timeline->system);
1243 system = timeline->system;
1245 if (MALI_TIMELINE_MAX > id) {
1246 return mali_timeline_is_point_on(system->timelines[id], tracker->fence.points[id]);
1248 MALI_DEBUG_ASSERT(MALI_TIMELINE_NONE == id);
1253 static const char *timeline_id_to_string(enum mali_timeline_id id)
1256 case MALI_TIMELINE_GP:
1258 case MALI_TIMELINE_PP:
1260 case MALI_TIMELINE_SOFT:
1267 static const char *timeline_tracker_type_to_string(enum mali_timeline_tracker_type type)
1270 case MALI_TIMELINE_TRACKER_GP:
1272 case MALI_TIMELINE_TRACKER_PP:
1274 case MALI_TIMELINE_TRACKER_SOFT:
1276 case MALI_TIMELINE_TRACKER_WAIT:
1278 case MALI_TIMELINE_TRACKER_SYNC:
1285 mali_timeline_tracker_state mali_timeline_debug_get_tracker_state(struct mali_timeline_tracker *tracker)
1287 struct mali_timeline *timeline = NULL;
1289 MALI_DEBUG_ASSERT_POINTER(tracker);
1290 timeline = tracker->timeline;
1292 if (0 != tracker->trigger_ref_count) {
1293 return MALI_TIMELINE_TS_WAITING;
1296 if (timeline && (timeline->tracker_tail == tracker || NULL != tracker->timeline_prev)) {
1297 return MALI_TIMELINE_TS_ACTIVE;
1300 if (timeline && (MALI_TIMELINE_NO_POINT == tracker->point)) {
1301 return MALI_TIMELINE_TS_INIT;
1304 return MALI_TIMELINE_TS_FINISH;
1307 void mali_timeline_debug_print_tracker(struct mali_timeline_tracker *tracker)
1309 const char *tracker_state = "IWAF";
1311 MALI_DEBUG_ASSERT_POINTER(tracker);
1313 if (0 != tracker->trigger_ref_count) {
1314 MALI_PRINTF(("TL: %s %u %c - ref_wait:%u [%s%u,%s%u,%s%u,%d] (0x%08X)\n",
1315 timeline_tracker_type_to_string(tracker->type), tracker->point,
1316 *(tracker_state + mali_timeline_debug_get_tracker_state(tracker)),
1317 tracker->trigger_ref_count,
1318 is_waiting_on_timeline(tracker, MALI_TIMELINE_GP) ? "W" : " ", tracker->fence.points[0],
1319 is_waiting_on_timeline(tracker, MALI_TIMELINE_PP) ? "W" : " ", tracker->fence.points[1],
1320 is_waiting_on_timeline(tracker, MALI_TIMELINE_SOFT) ? "W" : " ", tracker->fence.points[2],
1321 tracker->fence.sync_fd, tracker->job));
1323 MALI_PRINTF(("TL: %s %u %c (0x%08X)\n",
1324 timeline_tracker_type_to_string(tracker->type), tracker->point,
1325 *(tracker_state + mali_timeline_debug_get_tracker_state(tracker)),
1330 void mali_timeline_debug_print_timeline(struct mali_timeline *timeline)
1332 struct mali_timeline_tracker *tracker = NULL;
1335 MALI_DEBUG_ASSERT_POINTER(timeline);
1337 tracker = timeline->tracker_tail;
1338 while (NULL != tracker && 0 < --i_max) {
1339 mali_timeline_debug_print_tracker(tracker);
1340 tracker = tracker->timeline_next;
1344 MALI_PRINTF(("TL: Too many trackers in list to print\n"));
1348 void mali_timeline_debug_print_system(struct mali_timeline_system *system)
1351 int num_printed = 0;
1353 MALI_DEBUG_ASSERT_POINTER(system);
1355 /* Print all timelines */
1356 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
1357 struct mali_timeline *timeline = system->timelines[i];
1359 MALI_DEBUG_ASSERT_POINTER(timeline);
1361 if (NULL == timeline->tracker_head) continue;
1363 MALI_PRINTF(("TL: Timeline %s:\n",
1364 timeline_id_to_string((enum mali_timeline_id)i)));
1365 mali_timeline_debug_print_timeline(timeline);
1369 if (0 == num_printed) {
1370 MALI_PRINTF(("TL: All timelines empty\n"));
1374 #endif /* defined(MALI_TIMELINE_DEBUG_FUNCTIONS) */