2 * Copyright (C) 2013-2014 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_scheduler.h"
14 #include "mali_soft_job.h"
15 #include "mali_timeline_fence_wait.h"
16 #include "mali_timeline_sync_fence.h"
17 #include "mali_executor.h"
18 #include "mali_pp_job.h"
20 #define MALI_TIMELINE_SYSTEM_LOCKED(system) (mali_spinlock_reentrant_is_held((system)->spinlock, _mali_osk_get_tid()))
23 * Following three elements are used to record how many
24 * gp, physical pp or virtual pp jobs are delayed in the whole
25 * timeline system, we can use these three value to decide
26 * if need to deactivate idle group.
28 _mali_osk_atomic_t gp_tracker_count;
29 _mali_osk_atomic_t phy_pp_tracker_count;
30 _mali_osk_atomic_t virt_pp_tracker_count;
32 static mali_scheduler_mask mali_timeline_system_release_waiter(struct mali_timeline_system *system,
33 struct mali_timeline_waiter *waiter);
35 #if defined(CONFIG_SYNC)
36 #include <linux/version.h>
37 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
38 #include <linux/list.h>
39 #include <linux/workqueue.h>
40 #include <linux/spinlock.h>
42 struct mali_deferred_fence_put_entry {
43 struct hlist_node list;
44 struct sync_fence *fence;
47 static HLIST_HEAD(mali_timeline_sync_fence_to_free_list);
48 static DEFINE_SPINLOCK(mali_timeline_sync_fence_to_free_lock);
50 static void put_sync_fences(struct work_struct *ignore)
52 struct hlist_head list;
53 struct hlist_node *tmp, *pos;
55 struct mali_deferred_fence_put_entry *o;
57 spin_lock_irqsave(&mali_timeline_sync_fence_to_free_lock, flags);
58 hlist_move_list(&mali_timeline_sync_fence_to_free_list, &list);
59 spin_unlock_irqrestore(&mali_timeline_sync_fence_to_free_lock, flags);
61 hlist_for_each_entry_safe(o, pos, tmp, &list, list) {
62 sync_fence_put(o->fence);
67 static DECLARE_DELAYED_WORK(delayed_sync_fence_put, put_sync_fences);
68 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) */
70 /* Callback that is called when a sync fence a tracker is waiting on is signaled. */
71 static void mali_timeline_sync_fence_callback(struct sync_fence *sync_fence, struct sync_fence_waiter *sync_fence_waiter)
73 struct mali_timeline_system *system;
74 struct mali_timeline_waiter *waiter;
75 struct mali_timeline_tracker *tracker;
76 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
77 u32 tid = _mali_osk_get_tid();
78 mali_bool is_aborting = MALI_FALSE;
79 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
80 int fence_status = sync_fence->status;
82 int fence_status = atomic_read(&sync_fence->status);
85 MALI_DEBUG_ASSERT_POINTER(sync_fence);
86 MALI_DEBUG_ASSERT_POINTER(sync_fence_waiter);
88 tracker = _MALI_OSK_CONTAINER_OF(sync_fence_waiter, struct mali_timeline_tracker, sync_fence_waiter);
89 MALI_DEBUG_ASSERT_POINTER(tracker);
91 system = tracker->system;
92 MALI_DEBUG_ASSERT_POINTER(system);
93 MALI_DEBUG_ASSERT_POINTER(system->session);
95 mali_spinlock_reentrant_wait(system->spinlock, tid);
97 is_aborting = system->session->is_aborting;
98 if (!is_aborting && (0 > fence_status)) {
99 MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, fence_status));
100 tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT;
103 waiter = tracker->waiter_sync;
104 MALI_DEBUG_ASSERT_POINTER(waiter);
106 tracker->sync_fence = NULL;
107 tracker->fence.sync_fd = -1;
109 schedule_mask |= mali_timeline_system_release_waiter(system, waiter);
111 /* If aborting, wake up sleepers that are waiting for sync fence callbacks to complete. */
113 _mali_osk_wait_queue_wake_up(system->wait_queue);
116 mali_spinlock_reentrant_signal(system->spinlock, tid);
118 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
120 struct mali_deferred_fence_put_entry *obj;
122 obj = kzalloc(sizeof(struct mali_deferred_fence_put_entry), GFP_ATOMIC);
125 mali_bool schedule = MALI_FALSE;
127 obj->fence = sync_fence;
129 spin_lock_irqsave(&mali_timeline_sync_fence_to_free_lock, flags);
130 if (hlist_empty(&mali_timeline_sync_fence_to_free_list))
131 schedule = MALI_TRUE;
132 hlist_add_head(&obj->list, &mali_timeline_sync_fence_to_free_list);
133 spin_unlock_irqrestore(&mali_timeline_sync_fence_to_free_lock, flags);
136 schedule_delayed_work(&delayed_sync_fence_put, 0);
140 sync_fence_put(sync_fence);
141 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) */
144 mali_executor_schedule_from_mask(schedule_mask, MALI_TRUE);
147 #endif /* defined(CONFIG_SYNC) */
149 static mali_scheduler_mask mali_timeline_tracker_time_out(struct mali_timeline_tracker *tracker)
151 MALI_DEBUG_ASSERT_POINTER(tracker);
152 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_SOFT == tracker->type);
154 return mali_soft_job_system_timeout_job((struct mali_soft_job *) tracker->job);
157 static void mali_timeline_timer_callback(void *data)
159 struct mali_timeline_system *system;
160 struct mali_timeline_tracker *tracker;
161 struct mali_timeline *timeline;
162 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
163 u32 tid = _mali_osk_get_tid();
165 timeline = (struct mali_timeline *) data;
166 MALI_DEBUG_ASSERT_POINTER(timeline);
168 system = timeline->system;
169 MALI_DEBUG_ASSERT_POINTER(system);
171 mali_spinlock_reentrant_wait(system->spinlock, tid);
173 if (!system->timer_enabled) {
174 mali_spinlock_reentrant_signal(system->spinlock, tid);
178 tracker = timeline->tracker_tail;
179 timeline->timer_active = MALI_FALSE;
181 if (NULL != tracker && MALI_TRUE == tracker->timer_active) {
182 /* This is likely the delayed work that has been schedule out before cancelled. */
183 if (MALI_TIMELINE_TIMEOUT_HZ > (_mali_osk_time_tickcount() - tracker->os_tick_activate)) {
184 mali_spinlock_reentrant_signal(system->spinlock, tid);
188 schedule_mask = mali_timeline_tracker_time_out(tracker);
189 tracker->timer_active = MALI_FALSE;
191 MALI_PRINT_ERROR(("Mali Timeline: Soft job timer callback without a waiting tracker.\n"));
194 mali_spinlock_reentrant_signal(system->spinlock, tid);
196 mali_executor_schedule_from_mask(schedule_mask, MALI_FALSE);
199 void mali_timeline_system_stop_timer(struct mali_timeline_system *system)
202 u32 tid = _mali_osk_get_tid();
204 MALI_DEBUG_ASSERT_POINTER(system);
206 mali_spinlock_reentrant_wait(system->spinlock, tid);
207 system->timer_enabled = MALI_FALSE;
208 mali_spinlock_reentrant_signal(system->spinlock, tid);
210 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
211 struct mali_timeline *timeline = system->timelines[i];
213 MALI_DEBUG_ASSERT_POINTER(timeline);
215 if (NULL != timeline->delayed_work) {
216 _mali_osk_wq_delayed_cancel_work_sync(timeline->delayed_work);
217 timeline->timer_active = MALI_FALSE;
222 static void mali_timeline_destroy(struct mali_timeline *timeline)
224 MALI_DEBUG_ASSERT_POINTER(timeline);
225 if (NULL != timeline) {
226 /* Assert that the timeline object has been properly cleaned up before destroying it. */
227 MALI_DEBUG_ASSERT(timeline->point_oldest == timeline->point_next);
228 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head);
229 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail);
230 MALI_DEBUG_ASSERT(NULL == timeline->waiter_head);
231 MALI_DEBUG_ASSERT(NULL == timeline->waiter_tail);
232 MALI_DEBUG_ASSERT(NULL != timeline->system);
233 MALI_DEBUG_ASSERT(MALI_TIMELINE_MAX > timeline->id);
235 #if defined(CONFIG_SYNC)
236 if (NULL != timeline->sync_tl) {
237 sync_timeline_destroy(timeline->sync_tl);
239 #endif /* defined(CONFIG_SYNC) */
241 if (NULL != timeline->delayed_work) {
242 _mali_osk_wq_delayed_cancel_work_sync(timeline->delayed_work);
243 _mali_osk_wq_delayed_delete_work_nonflush(timeline->delayed_work);
246 _mali_osk_free(timeline);
250 static struct mali_timeline *mali_timeline_create(struct mali_timeline_system *system, enum mali_timeline_id id)
252 struct mali_timeline *timeline;
254 MALI_DEBUG_ASSERT_POINTER(system);
255 MALI_DEBUG_ASSERT(id < MALI_TIMELINE_MAX);
257 timeline = (struct mali_timeline *) _mali_osk_calloc(1, sizeof(struct mali_timeline));
258 if (NULL == timeline) {
262 /* Initially the timeline is empty. */
263 #if defined(MALI_TIMELINE_DEBUG_START_POINT)
264 /* Start the timeline a bit before wrapping when debugging. */
265 timeline->point_next = UINT_MAX - MALI_TIMELINE_MAX_POINT_SPAN - 128;
267 timeline->point_next = 1;
269 timeline->point_oldest = timeline->point_next;
271 /* The tracker and waiter lists will initially be empty. */
273 timeline->system = system;
276 timeline->delayed_work = _mali_osk_wq_delayed_create_work(mali_timeline_timer_callback, timeline);
277 if (NULL == timeline->delayed_work) {
278 mali_timeline_destroy(timeline);
282 timeline->timer_active = MALI_FALSE;
284 #if defined(CONFIG_SYNC)
286 char timeline_name[32];
289 case MALI_TIMELINE_GP:
290 _mali_osk_snprintf(timeline_name, 32, "mali-%u-gp", _mali_osk_get_pid());
292 case MALI_TIMELINE_PP:
293 _mali_osk_snprintf(timeline_name, 32, "mali-%u-pp", _mali_osk_get_pid());
295 case MALI_TIMELINE_SOFT:
296 _mali_osk_snprintf(timeline_name, 32, "mali-%u-soft", _mali_osk_get_pid());
299 MALI_PRINT_ERROR(("Mali Timeline: Invalid timeline id %d\n", id));
300 mali_timeline_destroy(timeline);
304 timeline->sync_tl = mali_sync_timeline_create(timeline, timeline_name);
305 if (NULL == timeline->sync_tl) {
306 mali_timeline_destroy(timeline);
310 #endif /* defined(CONFIG_SYNC) */
315 static void mali_timeline_insert_tracker(struct mali_timeline *timeline, struct mali_timeline_tracker *tracker)
317 MALI_DEBUG_ASSERT_POINTER(timeline);
318 MALI_DEBUG_ASSERT_POINTER(tracker);
320 if (mali_timeline_is_full(timeline)) {
321 /* Don't add tracker if timeline is full. */
322 tracker->point = MALI_TIMELINE_NO_POINT;
326 tracker->timeline = timeline;
327 tracker->point = timeline->point_next;
329 /* Find next available point. */
330 timeline->point_next++;
331 if (MALI_TIMELINE_NO_POINT == timeline->point_next) {
332 timeline->point_next++;
335 MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline));
337 if (MALI_TIMELINE_TRACKER_GP == tracker->type) {
338 _mali_osk_atomic_inc(&gp_tracker_count);
339 } else if (MALI_TIMELINE_TRACKER_PP == tracker->type) {
340 if (mali_pp_job_is_virtual((struct mali_pp_job *)tracker->job)) {
341 _mali_osk_atomic_inc(&virt_pp_tracker_count);
343 _mali_osk_atomic_inc(&phy_pp_tracker_count);
347 /* Add tracker as new head on timeline's tracker list. */
348 if (NULL == timeline->tracker_head) {
349 /* Tracker list is empty. */
350 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail);
352 timeline->tracker_tail = tracker;
354 MALI_DEBUG_ASSERT(NULL == tracker->timeline_next);
355 MALI_DEBUG_ASSERT(NULL == tracker->timeline_prev);
357 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head->timeline_next);
359 tracker->timeline_prev = timeline->tracker_head;
360 timeline->tracker_head->timeline_next = tracker;
362 MALI_DEBUG_ASSERT(NULL == tracker->timeline_next);
364 timeline->tracker_head = tracker;
366 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head->timeline_next);
367 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail->timeline_prev);
370 /* Inserting the waiter object into the given timeline */
371 static void mali_timeline_insert_waiter(struct mali_timeline *timeline, struct mali_timeline_waiter *waiter_new)
373 struct mali_timeline_waiter *waiter_prev;
374 struct mali_timeline_waiter *waiter_next;
376 /* Waiter time must be between timeline head and tail, and there must
377 * be less than MALI_TIMELINE_MAX_POINT_SPAN elements between */
378 MALI_DEBUG_ASSERT((waiter_new->point - timeline->point_oldest) < MALI_TIMELINE_MAX_POINT_SPAN);
379 MALI_DEBUG_ASSERT((-waiter_new->point + timeline->point_next) < MALI_TIMELINE_MAX_POINT_SPAN);
381 /* Finding out where to put this waiter, in the linked waiter list of the given timeline **/
382 waiter_prev = timeline->waiter_head; /* Insert new after waiter_prev */
383 waiter_next = NULL; /* Insert new before waiter_next */
385 /* Iterating backwards from head (newest) to tail (oldest) until we
386 * find the correct spot to insert the new waiter */
387 while (waiter_prev && mali_timeline_point_after(waiter_prev->point, waiter_new->point)) {
388 waiter_next = waiter_prev;
389 waiter_prev = waiter_prev->timeline_prev;
392 if (NULL == waiter_prev && NULL == waiter_next) {
394 timeline->waiter_head = waiter_new;
395 timeline->waiter_tail = waiter_new;
396 } else if (NULL == waiter_next) {
398 waiter_new->timeline_prev = timeline->waiter_head;
399 timeline->waiter_head->timeline_next = waiter_new;
400 timeline->waiter_head = waiter_new;
401 } else if (NULL == waiter_prev) {
403 waiter_new->timeline_next = timeline->waiter_tail;
404 timeline->waiter_tail->timeline_prev = waiter_new;
405 timeline->waiter_tail = waiter_new;
408 waiter_new->timeline_next = waiter_next;
409 waiter_new->timeline_prev = waiter_prev;
410 waiter_next->timeline_prev = waiter_new;
411 waiter_prev->timeline_next = waiter_new;
415 static void mali_timeline_update_delayed_work(struct mali_timeline *timeline)
417 struct mali_timeline_system *system;
418 struct mali_timeline_tracker *oldest_tracker;
420 MALI_DEBUG_ASSERT_POINTER(timeline);
421 MALI_DEBUG_ASSERT(MALI_TIMELINE_SOFT == timeline->id);
423 system = timeline->system;
424 MALI_DEBUG_ASSERT_POINTER(system);
426 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
428 /* Timer is disabled, early out. */
429 if (!system->timer_enabled) return;
431 oldest_tracker = timeline->tracker_tail;
432 if (NULL != oldest_tracker && 0 == oldest_tracker->trigger_ref_count) {
433 if (MALI_FALSE == oldest_tracker->timer_active) {
434 if (MALI_TRUE == timeline->timer_active) {
435 _mali_osk_wq_delayed_cancel_work_async(timeline->delayed_work);
437 _mali_osk_wq_delayed_schedule_work(timeline->delayed_work, MALI_TIMELINE_TIMEOUT_HZ);
438 oldest_tracker->timer_active = MALI_TRUE;
439 timeline->timer_active = MALI_TRUE;
441 } else if (MALI_TRUE == timeline->timer_active) {
442 _mali_osk_wq_delayed_cancel_work_async(timeline->delayed_work);
443 timeline->timer_active = MALI_FALSE;
447 static mali_scheduler_mask mali_timeline_update_oldest_point(struct mali_timeline *timeline)
449 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
451 MALI_DEBUG_ASSERT_POINTER(timeline);
454 struct mali_timeline_system *system = timeline->system;
455 MALI_DEBUG_ASSERT_POINTER(system);
457 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
460 if (NULL != timeline->tracker_tail) {
461 /* Set oldest point to oldest tracker's point */
462 timeline->point_oldest = timeline->tracker_tail->point;
464 /* No trackers, mark point list as empty */
465 timeline->point_oldest = timeline->point_next;
468 /* Release all waiters no longer on the timeline's point list.
469 * Releasing a waiter can trigger this function to be called again, so
470 * we do not store any pointers on stack. */
471 while (NULL != timeline->waiter_tail) {
472 u32 waiter_time_relative;
473 u32 time_head_relative;
474 struct mali_timeline_waiter *waiter = timeline->waiter_tail;
476 time_head_relative = timeline->point_next - timeline->point_oldest;
477 waiter_time_relative = waiter->point - timeline->point_oldest;
479 if (waiter_time_relative < time_head_relative) {
480 /* This and all following waiters are on the point list, so we are done. */
484 /* Remove waiter from timeline's waiter list. */
485 if (NULL != waiter->timeline_next) {
486 waiter->timeline_next->timeline_prev = NULL;
488 /* This was the last waiter */
489 timeline->waiter_head = NULL;
491 timeline->waiter_tail = waiter->timeline_next;
493 /* Release waiter. This could activate a tracker, if this was
494 * the last waiter for the tracker. */
495 schedule_mask |= mali_timeline_system_release_waiter(timeline->system, waiter);
498 return schedule_mask;
501 void mali_timeline_tracker_init(struct mali_timeline_tracker *tracker,
502 mali_timeline_tracker_type type,
503 struct mali_timeline_fence *fence,
506 MALI_DEBUG_ASSERT_POINTER(tracker);
507 MALI_DEBUG_ASSERT_POINTER(job);
509 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAX > type);
511 /* Zero out all tracker members. */
512 _mali_osk_memset(tracker, 0, sizeof(*tracker));
514 tracker->type = type;
516 tracker->trigger_ref_count = 1; /* Prevents any callback from trigging while adding it */
517 tracker->os_tick_create = _mali_osk_time_tickcount();
518 MALI_DEBUG_CODE(tracker->magic = MALI_TIMELINE_TRACKER_MAGIC);
520 tracker->activation_error = MALI_TIMELINE_ACTIVATION_ERROR_NONE;
524 _mali_osk_memcpy(&tracker->fence, fence, sizeof(struct mali_timeline_fence));
528 mali_scheduler_mask mali_timeline_tracker_release(struct mali_timeline_tracker *tracker)
530 struct mali_timeline *timeline;
531 struct mali_timeline_system *system;
532 struct mali_timeline_tracker *tracker_next, *tracker_prev;
533 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
534 u32 tid = _mali_osk_get_tid();
536 /* Upon entry a group lock will be held, but not a scheduler lock. */
537 MALI_DEBUG_ASSERT_POINTER(tracker);
538 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic);
540 /* Tracker should have been triggered */
541 MALI_DEBUG_ASSERT(0 == tracker->trigger_ref_count);
543 /* All waiters should have been released at this point */
544 MALI_DEBUG_ASSERT(NULL == tracker->waiter_head);
545 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
547 MALI_DEBUG_PRINT(3, ("Mali Timeline: releasing tracker for job 0x%08X\n", tracker->job));
549 timeline = tracker->timeline;
550 if (NULL == timeline) {
551 /* Tracker was not on a timeline, there is nothing to release. */
552 return MALI_SCHEDULER_MASK_EMPTY;
555 system = timeline->system;
556 MALI_DEBUG_ASSERT_POINTER(system);
558 mali_spinlock_reentrant_wait(system->spinlock, tid);
560 /* Tracker should still be on timeline */
561 MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline));
562 MALI_DEBUG_ASSERT(mali_timeline_is_point_on(timeline, tracker->point));
564 /* Tracker is no longer valid. */
565 MALI_DEBUG_CODE(tracker->magic = 0);
567 tracker_next = tracker->timeline_next;
568 tracker_prev = tracker->timeline_prev;
569 tracker->timeline_next = NULL;
570 tracker->timeline_prev = NULL;
572 /* Removing tracker from timeline's tracker list */
573 if (NULL == tracker_next) {
574 /* This tracker was the head */
575 timeline->tracker_head = tracker_prev;
577 tracker_next->timeline_prev = tracker_prev;
580 if (NULL == tracker_prev) {
581 /* This tracker was the tail */
582 timeline->tracker_tail = tracker_next;
583 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
584 /* Update the timeline's oldest time and release any waiters */
585 schedule_mask |= mali_timeline_update_oldest_point(timeline);
586 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
588 tracker_prev->timeline_next = tracker_next;
591 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
593 /* Update delayed work only when it is the soft job timeline */
594 if (MALI_TIMELINE_SOFT == tracker->timeline->id) {
595 mali_timeline_update_delayed_work(tracker->timeline);
598 mali_spinlock_reentrant_signal(system->spinlock, tid);
600 return schedule_mask;
603 void mali_timeline_system_release_waiter_list(struct mali_timeline_system *system,
604 struct mali_timeline_waiter *tail,
605 struct mali_timeline_waiter *head)
607 MALI_DEBUG_ASSERT_POINTER(system);
608 MALI_DEBUG_ASSERT_POINTER(head);
609 MALI_DEBUG_ASSERT_POINTER(tail);
610 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
612 head->tracker_next = system->waiter_empty_list;
613 system->waiter_empty_list = tail;
616 static mali_scheduler_mask mali_timeline_tracker_activate(struct mali_timeline_tracker *tracker)
618 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
619 struct mali_timeline_system *system;
620 struct mali_timeline *timeline;
621 u32 tid = _mali_osk_get_tid();
623 MALI_DEBUG_ASSERT_POINTER(tracker);
624 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic);
626 system = tracker->system;
627 MALI_DEBUG_ASSERT_POINTER(system);
628 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
630 tracker->os_tick_activate = _mali_osk_time_tickcount();
632 if (NULL != tracker->waiter_head) {
633 mali_timeline_system_release_waiter_list(system, tracker->waiter_tail, tracker->waiter_head);
634 tracker->waiter_head = NULL;
635 tracker->waiter_tail = NULL;
638 switch (tracker->type) {
639 case MALI_TIMELINE_TRACKER_GP:
640 schedule_mask = mali_scheduler_activate_gp_job((struct mali_gp_job *) tracker->job);
642 _mali_osk_atomic_dec(&gp_tracker_count);
644 case MALI_TIMELINE_TRACKER_PP:
645 schedule_mask = mali_scheduler_activate_pp_job((struct mali_pp_job *) tracker->job);
647 if (mali_pp_job_is_virtual((struct mali_pp_job *)tracker->job)) {
648 _mali_osk_atomic_dec(&virt_pp_tracker_count);
650 _mali_osk_atomic_dec(&phy_pp_tracker_count);
653 case MALI_TIMELINE_TRACKER_SOFT:
654 timeline = tracker->timeline;
655 MALI_DEBUG_ASSERT_POINTER(timeline);
657 mali_soft_job_system_activate_job((struct mali_soft_job *) tracker->job);
659 /* Start a soft timer to make sure the soft job be released in a limited time */
660 mali_spinlock_reentrant_wait(system->spinlock, tid);
661 mali_timeline_update_delayed_work(timeline);
662 mali_spinlock_reentrant_signal(system->spinlock, tid);
664 case MALI_TIMELINE_TRACKER_WAIT:
665 mali_timeline_fence_wait_activate((struct mali_timeline_fence_wait_tracker *) tracker->job);
667 case MALI_TIMELINE_TRACKER_SYNC:
668 #if defined(CONFIG_SYNC)
669 mali_timeline_sync_fence_activate((struct mali_timeline_sync_fence_tracker *) tracker->job);
671 MALI_PRINT_ERROR(("Mali Timeline: sync tracker not supported\n", tracker->type));
672 #endif /* defined(CONFIG_SYNC) */
675 MALI_PRINT_ERROR(("Mali Timeline - Illegal tracker type: %d\n", tracker->type));
679 return schedule_mask;
682 void mali_timeline_system_tracker_get(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker)
684 u32 tid = _mali_osk_get_tid();
686 MALI_DEBUG_ASSERT_POINTER(tracker);
687 MALI_DEBUG_ASSERT_POINTER(system);
689 mali_spinlock_reentrant_wait(system->spinlock, tid);
691 MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count);
692 tracker->trigger_ref_count++;
694 mali_spinlock_reentrant_signal(system->spinlock, tid);
697 mali_scheduler_mask mali_timeline_system_tracker_put(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker, mali_timeline_activation_error activation_error)
699 u32 tid = _mali_osk_get_tid();
700 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
702 MALI_DEBUG_ASSERT_POINTER(tracker);
703 MALI_DEBUG_ASSERT_POINTER(system);
705 mali_spinlock_reentrant_wait(system->spinlock, tid);
707 MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count);
708 tracker->trigger_ref_count--;
710 tracker->activation_error |= activation_error;
712 if (0 == tracker->trigger_ref_count) {
713 schedule_mask |= mali_timeline_tracker_activate(tracker);
717 mali_spinlock_reentrant_signal(system->spinlock, tid);
719 return schedule_mask;
722 void mali_timeline_fence_copy_uk_fence(struct mali_timeline_fence *fence, _mali_uk_fence_t *uk_fence)
726 MALI_DEBUG_ASSERT_POINTER(fence);
727 MALI_DEBUG_ASSERT_POINTER(uk_fence);
729 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
730 fence->points[i] = uk_fence->points[i];
733 fence->sync_fd = uk_fence->sync_fd;
736 struct mali_timeline_system *mali_timeline_system_create(struct mali_session_data *session)
739 struct mali_timeline_system *system;
741 MALI_DEBUG_ASSERT_POINTER(session);
742 MALI_DEBUG_PRINT(4, ("Mali Timeline: creating timeline system\n"));
744 system = (struct mali_timeline_system *) _mali_osk_calloc(1, sizeof(struct mali_timeline_system));
745 if (NULL == system) {
749 system->spinlock = mali_spinlock_reentrant_init(_MALI_OSK_LOCK_ORDER_TIMELINE_SYSTEM);
750 if (NULL == system->spinlock) {
751 mali_timeline_system_destroy(system);
755 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
756 system->timelines[i] = mali_timeline_create(system, (enum mali_timeline_id)i);
757 if (NULL == system->timelines[i]) {
758 mali_timeline_system_destroy(system);
763 #if defined(CONFIG_SYNC)
764 system->signaled_sync_tl = mali_sync_timeline_create(NULL, "mali-always-signaled");
765 if (NULL == system->signaled_sync_tl) {
766 mali_timeline_system_destroy(system);
769 #endif /* defined(CONFIG_SYNC) */
771 system->waiter_empty_list = NULL;
772 system->session = session;
773 system->timer_enabled = MALI_TRUE;
775 system->wait_queue = _mali_osk_wait_queue_init();
776 if (NULL == system->wait_queue) {
777 mali_timeline_system_destroy(system);
784 #if defined(CONFIG_SYNC)
787 * Check if there are any trackers left on timeline.
789 * Used as a wait queue conditional.
791 * @param data Timeline.
792 * @return MALI_TRUE if there are no trackers on timeline, MALI_FALSE if not.
794 static mali_bool mali_timeline_has_no_trackers(void *data)
796 struct mali_timeline *timeline = (struct mali_timeline *) data;
798 MALI_DEBUG_ASSERT_POINTER(timeline);
800 return mali_timeline_is_empty(timeline);
804 * Cancel sync fence waiters waited upon by trackers on all timelines.
806 * Will return after all timelines have no trackers left.
808 * @param system Timeline system.
810 static void mali_timeline_cancel_sync_fence_waiters(struct mali_timeline_system *system)
813 u32 tid = _mali_osk_get_tid();
814 struct mali_timeline_tracker *tracker, *tracker_next;
815 _MALI_OSK_LIST_HEAD_STATIC_INIT(tracker_list);
817 MALI_DEBUG_ASSERT_POINTER(system);
818 MALI_DEBUG_ASSERT_POINTER(system->session);
819 MALI_DEBUG_ASSERT(system->session->is_aborting);
821 mali_spinlock_reentrant_wait(system->spinlock, tid);
823 /* Cancel sync fence waiters. */
824 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
825 struct mali_timeline *timeline = system->timelines[i];
827 MALI_DEBUG_ASSERT_POINTER(timeline);
829 tracker_next = timeline->tracker_tail;
830 while (NULL != tracker_next) {
831 tracker = tracker_next;
832 tracker_next = tracker->timeline_next;
834 if (NULL == tracker->sync_fence) continue;
836 MALI_DEBUG_PRINT(3, ("Mali Timeline: Cancelling sync fence wait for tracker 0x%08X.\n", tracker));
838 /* Cancel sync fence waiter. */
839 if (0 == sync_fence_cancel_async(tracker->sync_fence, &tracker->sync_fence_waiter)) {
840 /* Callback was not called, move tracker to local list. */
841 _mali_osk_list_add(&tracker->sync_fence_cancel_list, &tracker_list);
846 mali_spinlock_reentrant_signal(system->spinlock, tid);
848 /* Manually call sync fence callback in order to release waiter and trigger activation of tracker. */
849 _MALI_OSK_LIST_FOREACHENTRY(tracker, tracker_next, &tracker_list, struct mali_timeline_tracker, sync_fence_cancel_list) {
850 mali_timeline_sync_fence_callback(tracker->sync_fence, &tracker->sync_fence_waiter);
853 /* Sleep until all sync fence callbacks are done and all timelines are empty. */
854 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
855 struct mali_timeline *timeline = system->timelines[i];
857 MALI_DEBUG_ASSERT_POINTER(timeline);
859 _mali_osk_wait_queue_wait_event(system->wait_queue, mali_timeline_has_no_trackers, (void *) timeline);
863 #endif /* defined(CONFIG_SYNC) */
865 void mali_timeline_system_abort(struct mali_timeline_system *system)
867 MALI_DEBUG_CODE(u32 tid = _mali_osk_get_tid(););
869 MALI_DEBUG_ASSERT_POINTER(system);
870 MALI_DEBUG_ASSERT_POINTER(system->session);
871 MALI_DEBUG_ASSERT(system->session->is_aborting);
873 MALI_DEBUG_PRINT(3, ("Mali Timeline: Aborting timeline system for session 0x%08X.\n", system->session));
875 #if defined(CONFIG_SYNC)
876 mali_timeline_cancel_sync_fence_waiters(system);
877 #endif /* defined(CONFIG_SYNC) */
879 /* Should not be any waiters or trackers left at this point. */
882 mali_spinlock_reentrant_wait(system->spinlock, tid);
883 for (i = 0; i < MALI_TIMELINE_MAX; ++i)
885 struct mali_timeline *timeline = system->timelines[i];
886 MALI_DEBUG_ASSERT_POINTER(timeline);
887 MALI_DEBUG_ASSERT(timeline->point_oldest == timeline->point_next);
888 MALI_DEBUG_ASSERT(NULL == timeline->tracker_head);
889 MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail);
890 MALI_DEBUG_ASSERT(NULL == timeline->waiter_head);
891 MALI_DEBUG_ASSERT(NULL == timeline->waiter_tail);
893 mali_spinlock_reentrant_signal(system->spinlock, tid);
897 void mali_timeline_system_destroy(struct mali_timeline_system *system)
900 struct mali_timeline_waiter *waiter, *next;
902 MALI_DEBUG_ASSERT_POINTER(system);
903 MALI_DEBUG_ASSERT_POINTER(system->session);
905 MALI_DEBUG_PRINT(4, ("Mali Timeline: destroying timeline system\n"));
907 if (NULL != system) {
908 /* There should be no waiters left on this queue. */
909 if (NULL != system->wait_queue) {
910 _mali_osk_wait_queue_term(system->wait_queue);
911 system->wait_queue = NULL;
914 /* Free all waiters in empty list */
915 waiter = system->waiter_empty_list;
916 while (NULL != waiter) {
917 next = waiter->tracker_next;
918 _mali_osk_free(waiter);
922 #if defined(CONFIG_SYNC)
923 if (NULL != system->signaled_sync_tl) {
924 sync_timeline_destroy(system->signaled_sync_tl);
926 #endif /* defined(CONFIG_SYNC) */
928 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
929 if (NULL != system->timelines[i]) {
930 mali_timeline_destroy(system->timelines[i]);
933 if (NULL != system->spinlock) {
934 mali_spinlock_reentrant_term(system->spinlock);
937 _mali_osk_free(system);
942 * Find how many waiters are needed for a given fence.
944 * @param fence The fence to check.
945 * @return Number of waiters needed for fence.
947 static u32 mali_timeline_fence_num_waiters(struct mali_timeline_fence *fence)
949 u32 i, num_waiters = 0;
951 MALI_DEBUG_ASSERT_POINTER(fence);
953 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
954 if (MALI_TIMELINE_NO_POINT != fence->points[i]) {
959 #if defined(CONFIG_SYNC)
960 if (-1 != fence->sync_fd) ++num_waiters;
961 #endif /* defined(CONFIG_SYNC) */
966 static struct mali_timeline_waiter *mali_timeline_system_get_zeroed_waiter(struct mali_timeline_system *system)
968 struct mali_timeline_waiter *waiter;
970 MALI_DEBUG_ASSERT_POINTER(system);
971 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
973 waiter = system->waiter_empty_list;
974 if (NULL != waiter) {
975 /* Remove waiter from empty list and zero it */
976 system->waiter_empty_list = waiter->tracker_next;
977 _mali_osk_memset(waiter, 0, sizeof(*waiter));
980 /* Return NULL if list was empty. */
984 static void mali_timeline_system_allocate_waiters(struct mali_timeline_system *system,
985 struct mali_timeline_waiter **tail,
986 struct mali_timeline_waiter **head,
989 u32 i, tid = _mali_osk_get_tid();
991 struct mali_timeline_waiter *waiter;
993 MALI_DEBUG_ASSERT_POINTER(system);
994 MALI_DEBUG_ASSERT_POINTER(tail);
995 MALI_DEBUG_ASSERT_POINTER(head);
997 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
999 *head = *tail = NULL;
1000 do_alloc = MALI_FALSE;
1002 while (i < max_num_waiters) {
1003 if (MALI_FALSE == do_alloc) {
1004 waiter = mali_timeline_system_get_zeroed_waiter(system);
1005 if (NULL == waiter) {
1006 do_alloc = MALI_TRUE;
1007 mali_spinlock_reentrant_signal(system->spinlock, tid);
1011 waiter = _mali_osk_calloc(1, sizeof(struct mali_timeline_waiter));
1012 if (NULL == waiter) break;
1015 if (NULL == *tail) {
1019 (*head)->tracker_next = waiter;
1023 if (MALI_TRUE == do_alloc) {
1024 mali_spinlock_reentrant_wait(system->spinlock, tid);
1029 * Create waiters for the given tracker. The tracker is activated when all waiters are release.
1031 * @note Tracker can potentially be activated before this function returns.
1033 * @param system Timeline system.
1034 * @param tracker Tracker we will create waiters for.
1035 * @param waiter_tail List of pre-allocated waiters.
1036 * @param waiter_head List of pre-allocated waiters.
1038 static void mali_timeline_system_create_waiters_and_unlock(struct mali_timeline_system *system,
1039 struct mali_timeline_tracker *tracker,
1040 struct mali_timeline_waiter *waiter_tail,
1041 struct mali_timeline_waiter *waiter_head)
1044 u32 tid = _mali_osk_get_tid();
1045 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
1046 #if defined(CONFIG_SYNC)
1047 struct sync_fence *sync_fence = NULL;
1048 #endif /* defined(CONFIG_SYNC) */
1050 MALI_DEBUG_ASSERT_POINTER(system);
1051 MALI_DEBUG_ASSERT_POINTER(tracker);
1053 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
1055 MALI_DEBUG_ASSERT(NULL == tracker->waiter_head);
1056 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
1057 MALI_DEBUG_ASSERT(NULL != tracker->job);
1059 /* Creating waiter object for all the timelines the fence is put on. Inserting this waiter
1060 * into the timelines sorted list of waiters */
1061 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
1062 mali_timeline_point point;
1063 struct mali_timeline *timeline;
1064 struct mali_timeline_waiter *waiter;
1066 /* Get point on current timeline from tracker's fence. */
1067 point = tracker->fence.points[i];
1069 if (likely(MALI_TIMELINE_NO_POINT == point)) {
1070 /* Fence contains no point on this timeline so we don't need a waiter. */
1074 timeline = system->timelines[i];
1075 MALI_DEBUG_ASSERT_POINTER(timeline);
1077 if (unlikely(!mali_timeline_is_point_valid(timeline, point))) {
1078 MALI_PRINT_ERROR(("Mali Timeline: point %d is not valid (oldest=%d, next=%d)\n",
1079 point, timeline->point_oldest, timeline->point_next));
1083 if (likely(mali_timeline_is_point_released(timeline, point))) {
1084 /* Tracker representing the point has been released so we don't need a
1089 /* The point is on timeline. */
1090 MALI_DEBUG_ASSERT(mali_timeline_is_point_on(timeline, point));
1092 /* Get a new zeroed waiter object. */
1093 if (likely(NULL != waiter_tail)) {
1094 waiter = waiter_tail;
1095 waiter_tail = waiter_tail->tracker_next;
1097 MALI_PRINT_ERROR(("Mali Timeline: failed to allocate memory for waiter\n"));
1101 /* Yanking the trigger ref count of the tracker. */
1102 tracker->trigger_ref_count++;
1104 waiter->point = point;
1105 waiter->tracker = tracker;
1107 /* Insert waiter on tracker's singly-linked waiter list. */
1108 if (NULL == tracker->waiter_head) {
1110 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
1111 tracker->waiter_tail = waiter;
1113 tracker->waiter_head->tracker_next = waiter;
1115 tracker->waiter_head = waiter;
1117 /* Add waiter to timeline. */
1118 mali_timeline_insert_waiter(timeline, waiter);
1120 #if defined(CONFIG_SYNC)
1121 if (-1 != tracker->fence.sync_fd) {
1123 struct mali_timeline_waiter *waiter;
1125 sync_fence = sync_fence_fdget(tracker->fence.sync_fd);
1126 if (unlikely(NULL == sync_fence)) {
1127 MALI_PRINT_ERROR(("Mali Timeline: failed to get sync fence from fd %d\n", tracker->fence.sync_fd));
1131 /* Check if we have a zeroed waiter object available. */
1132 if (unlikely(NULL == waiter_tail)) {
1133 MALI_PRINT_ERROR(("Mali Timeline: failed to allocate memory for waiter\n"));
1137 /* Start asynchronous wait that will release waiter when the fence is signaled. */
1138 sync_fence_waiter_init(&tracker->sync_fence_waiter, mali_timeline_sync_fence_callback);
1139 ret = sync_fence_wait_async(sync_fence, &tracker->sync_fence_waiter);
1141 /* Fence already signaled, no waiter needed. */
1142 tracker->fence.sync_fd = -1;
1144 } else if (0 != ret) {
1145 MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, ret));
1146 tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT;
1150 /* Grab new zeroed waiter object. */
1151 waiter = waiter_tail;
1152 waiter_tail = waiter_tail->tracker_next;
1154 /* Increase the trigger ref count of the tracker. */
1155 tracker->trigger_ref_count++;
1157 waiter->point = MALI_TIMELINE_NO_POINT;
1158 waiter->tracker = tracker;
1160 /* Insert waiter on tracker's singly-linked waiter list. */
1161 if (NULL == tracker->waiter_head) {
1163 MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail);
1164 tracker->waiter_tail = waiter;
1166 tracker->waiter_head->tracker_next = waiter;
1168 tracker->waiter_head = waiter;
1170 /* Also store waiter in separate field for easy access by sync callback. */
1171 tracker->waiter_sync = waiter;
1173 /* Store the sync fence in tracker so we can retrieve in abort session, if needed. */
1174 tracker->sync_fence = sync_fence;
1179 #endif /* defined(CONFIG_SYNC) */
1181 if (NULL != waiter_tail) {
1182 mali_timeline_system_release_waiter_list(system, waiter_tail, waiter_head);
1185 /* Release the initial trigger ref count. */
1186 tracker->trigger_ref_count--;
1188 /* If there were no waiters added to this tracker we activate immediately. */
1189 if (0 == tracker->trigger_ref_count) {
1190 schedule_mask |= mali_timeline_tracker_activate(tracker);
1193 mali_spinlock_reentrant_signal(system->spinlock, tid);
1195 #if defined(CONFIG_SYNC)
1196 if (NULL != sync_fence) {
1197 sync_fence_put(sync_fence);
1199 #endif /* defined(CONFIG_SYNC) */
1201 mali_executor_schedule_from_mask(schedule_mask, MALI_FALSE);
1204 mali_timeline_point mali_timeline_system_add_tracker(struct mali_timeline_system *system,
1205 struct mali_timeline_tracker *tracker,
1206 enum mali_timeline_id timeline_id)
1208 int num_waiters = 0;
1209 struct mali_timeline_waiter *waiter_tail, *waiter_head;
1210 u32 tid = _mali_osk_get_tid();
1211 mali_timeline_point point = MALI_TIMELINE_NO_POINT;
1213 MALI_DEBUG_ASSERT_POINTER(system);
1214 MALI_DEBUG_ASSERT_POINTER(system->session);
1215 MALI_DEBUG_ASSERT_POINTER(tracker);
1217 MALI_DEBUG_ASSERT(MALI_FALSE == system->session->is_aborting);
1218 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAX > tracker->type);
1219 MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic);
1221 MALI_DEBUG_PRINT(4, ("Mali Timeline: adding tracker for job %p, timeline: %d\n", tracker->job, timeline_id));
1223 MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count);
1224 tracker->system = system;
1226 mali_spinlock_reentrant_wait(system->spinlock, tid);
1228 num_waiters = mali_timeline_fence_num_waiters(&tracker->fence);
1230 /* Allocate waiters. */
1231 mali_timeline_system_allocate_waiters(system, &waiter_tail, &waiter_head, num_waiters);
1232 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
1234 /* Add tracker to timeline. This will allocate a point for the tracker on the timeline. If
1235 * timeline ID is MALI_TIMELINE_NONE the tracker will NOT be added to a timeline and the
1236 * point will be MALI_TIMELINE_NO_POINT.
1238 * NOTE: the tracker can fail to be added if the timeline is full. If this happens, the
1239 * point will be MALI_TIMELINE_NO_POINT. */
1240 MALI_DEBUG_ASSERT(timeline_id < MALI_TIMELINE_MAX || timeline_id == MALI_TIMELINE_NONE);
1241 if (likely(timeline_id < MALI_TIMELINE_MAX)) {
1242 struct mali_timeline *timeline = system->timelines[timeline_id];
1243 mali_timeline_insert_tracker(timeline, tracker);
1244 MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline));
1247 point = tracker->point;
1249 /* Create waiters for tracker based on supplied fence. Each waiter will increase the
1250 * trigger ref count. */
1251 mali_timeline_system_create_waiters_and_unlock(system, tracker, waiter_tail, waiter_head);
1254 /* At this point the tracker object might have been freed so we should no longer
1258 /* The tracker will always be activated after calling add_tracker, even if NO_POINT is
1263 static mali_scheduler_mask mali_timeline_system_release_waiter(struct mali_timeline_system *system,
1264 struct mali_timeline_waiter *waiter)
1266 struct mali_timeline_tracker *tracker;
1267 mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
1269 MALI_DEBUG_ASSERT_POINTER(system);
1270 MALI_DEBUG_ASSERT_POINTER(waiter);
1272 MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system));
1274 tracker = waiter->tracker;
1275 MALI_DEBUG_ASSERT_POINTER(tracker);
1277 /* At this point the waiter has been removed from the timeline's waiter list, but it is
1278 * still on the tracker's waiter list. All of the tracker's waiters will be released when
1279 * the tracker is activated. */
1281 waiter->point = MALI_TIMELINE_NO_POINT;
1282 waiter->tracker = NULL;
1284 tracker->trigger_ref_count--;
1285 if (0 == tracker->trigger_ref_count) {
1286 /* This was the last waiter; activate tracker */
1287 schedule_mask |= mali_timeline_tracker_activate(tracker);
1291 return schedule_mask;
1294 mali_timeline_point mali_timeline_system_get_latest_point(struct mali_timeline_system *system,
1295 enum mali_timeline_id timeline_id)
1297 mali_timeline_point point;
1298 struct mali_timeline *timeline;
1299 u32 tid = _mali_osk_get_tid();
1301 MALI_DEBUG_ASSERT_POINTER(system);
1303 if (MALI_TIMELINE_MAX <= timeline_id) {
1304 return MALI_TIMELINE_NO_POINT;
1307 mali_spinlock_reentrant_wait(system->spinlock, tid);
1309 timeline = system->timelines[timeline_id];
1310 MALI_DEBUG_ASSERT_POINTER(timeline);
1312 point = MALI_TIMELINE_NO_POINT;
1313 if (timeline->point_oldest != timeline->point_next) {
1314 point = timeline->point_next - 1;
1315 if (MALI_TIMELINE_NO_POINT == point) point--;
1318 mali_spinlock_reentrant_signal(system->spinlock, tid);
1323 void mali_timeline_initialize(void)
1325 _mali_osk_atomic_init(&gp_tracker_count, 0);
1326 _mali_osk_atomic_init(&phy_pp_tracker_count, 0);
1327 _mali_osk_atomic_init(&virt_pp_tracker_count, 0);
1330 void mali_timeline_terminate(void)
1332 _mali_osk_atomic_term(&gp_tracker_count);
1333 _mali_osk_atomic_term(&phy_pp_tracker_count);
1334 _mali_osk_atomic_term(&virt_pp_tracker_count);
1337 #if defined(MALI_TIMELINE_DEBUG_FUNCTIONS)
1339 static mali_bool is_waiting_on_timeline(struct mali_timeline_tracker *tracker, enum mali_timeline_id id)
1341 struct mali_timeline *timeline;
1342 struct mali_timeline_system *system;
1344 MALI_DEBUG_ASSERT_POINTER(tracker);
1346 MALI_DEBUG_ASSERT_POINTER(tracker->timeline);
1347 timeline = tracker->timeline;
1349 MALI_DEBUG_ASSERT_POINTER(timeline->system);
1350 system = timeline->system;
1352 if (MALI_TIMELINE_MAX > id) {
1353 if (MALI_TIMELINE_NO_POINT != tracker->fence.points[id]) {
1354 return mali_timeline_is_point_on(system->timelines[id], tracker->fence.points[id]);
1359 MALI_DEBUG_ASSERT(MALI_TIMELINE_NONE == id);
1364 static const char *timeline_id_to_string(enum mali_timeline_id id)
1367 case MALI_TIMELINE_GP:
1369 case MALI_TIMELINE_PP:
1371 case MALI_TIMELINE_SOFT:
1378 static const char *timeline_tracker_type_to_string(enum mali_timeline_tracker_type type)
1381 case MALI_TIMELINE_TRACKER_GP:
1383 case MALI_TIMELINE_TRACKER_PP:
1385 case MALI_TIMELINE_TRACKER_SOFT:
1387 case MALI_TIMELINE_TRACKER_WAIT:
1389 case MALI_TIMELINE_TRACKER_SYNC:
1396 mali_timeline_tracker_state mali_timeline_debug_get_tracker_state(struct mali_timeline_tracker *tracker)
1398 struct mali_timeline *timeline = NULL;
1400 MALI_DEBUG_ASSERT_POINTER(tracker);
1401 timeline = tracker->timeline;
1403 if (0 != tracker->trigger_ref_count) {
1404 return MALI_TIMELINE_TS_WAITING;
1407 if (timeline && (timeline->tracker_tail == tracker || NULL != tracker->timeline_prev)) {
1408 return MALI_TIMELINE_TS_ACTIVE;
1411 if (timeline && (MALI_TIMELINE_NO_POINT == tracker->point)) {
1412 return MALI_TIMELINE_TS_INIT;
1415 return MALI_TIMELINE_TS_FINISH;
1418 void mali_timeline_debug_print_tracker(struct mali_timeline_tracker *tracker, _mali_osk_print_ctx *print_ctx)
1420 const char *tracker_state = "IWAF";
1421 char state_char = 'I';
1422 char tracker_type[32] = {0};
1424 MALI_DEBUG_ASSERT_POINTER(tracker);
1426 state_char = *(tracker_state + mali_timeline_debug_get_tracker_state(tracker));
1427 _mali_osk_snprintf(tracker_type, sizeof(tracker_type), "%s", timeline_tracker_type_to_string(tracker->type));
1429 #if defined(CONFIG_SYNC)
1430 if (0 != tracker->trigger_ref_count) {
1431 _mali_osk_ctxprintf(print_ctx, "TL: %s %u %c - ref_wait:%u [%s(%u),%s(%u),%s(%u), fd:%d, fence:(0x%08X)] job:(0x%08X)\n",
1432 tracker_type, tracker->point, state_char, tracker->trigger_ref_count,
1433 is_waiting_on_timeline(tracker, MALI_TIMELINE_GP) ? "WaitGP" : " ", tracker->fence.points[0],
1434 is_waiting_on_timeline(tracker, MALI_TIMELINE_PP) ? "WaitPP" : " ", tracker->fence.points[1],
1435 is_waiting_on_timeline(tracker, MALI_TIMELINE_SOFT) ? "WaitSOFT" : " ", tracker->fence.points[2],
1436 tracker->fence.sync_fd, tracker->sync_fence, tracker->job);
1438 _mali_osk_ctxprintf(print_ctx, "TL: %s %u %c fd:%d fence:(0x%08X) job:(0x%08X)\n",
1439 tracker_type, tracker->point, state_char,
1440 tracker->fence.sync_fd, tracker->sync_fence, tracker->job);
1443 if (0 != tracker->trigger_ref_count) {
1444 _mali_osk_ctxprintf(print_ctx, "TL: %s %u %c - ref_wait:%u [%s(%u),%s(%u),%s(%u)] job:(0x%08X)\n",
1445 tracker_type, tracker->point, state_char, tracker->trigger_ref_count,
1446 is_waiting_on_timeline(tracker, MALI_TIMELINE_GP) ? "WaitGP" : " ", tracker->fence.points[0],
1447 is_waiting_on_timeline(tracker, MALI_TIMELINE_PP) ? "WaitPP" : " ", tracker->fence.points[1],
1448 is_waiting_on_timeline(tracker, MALI_TIMELINE_SOFT) ? "WaitSOFT" : " ", tracker->fence.points[2],
1451 _mali_osk_ctxprintf(print_ctx, "TL: %s %u %c job:(0x%08X)\n",
1452 tracker_type, tracker->point, state_char,
1458 void mali_timeline_debug_print_timeline(struct mali_timeline *timeline, _mali_osk_print_ctx *print_ctx)
1460 struct mali_timeline_tracker *tracker = NULL;
1462 MALI_DEBUG_ASSERT_POINTER(timeline);
1464 tracker = timeline->tracker_tail;
1465 while (NULL != tracker) {
1466 mali_timeline_debug_print_tracker(tracker, print_ctx);
1467 tracker = tracker->timeline_next;
1471 void mali_timeline_debug_print_system(struct mali_timeline_system *system, _mali_osk_print_ctx *print_ctx)
1474 int num_printed = 0;
1475 u32 tid = _mali_osk_get_tid();
1477 MALI_DEBUG_ASSERT_POINTER(system);
1479 mali_spinlock_reentrant_wait(system->spinlock, tid);
1481 /* Print all timelines */
1482 for (i = 0; i < MALI_TIMELINE_MAX; ++i) {
1483 struct mali_timeline *timeline = system->timelines[i];
1485 MALI_DEBUG_ASSERT_POINTER(timeline);
1487 if (NULL == timeline->tracker_head) continue;
1489 _mali_osk_ctxprintf(print_ctx, "TL: Timeline %s:\n",
1490 timeline_id_to_string((enum mali_timeline_id)i));
1492 mali_timeline_debug_print_timeline(timeline, print_ctx);
1496 if (0 == num_printed) {
1497 _mali_osk_ctxprintf(print_ctx, "TL: All timelines empty\n");
1500 mali_spinlock_reentrant_signal(system->spinlock, tid);
1503 #endif /* defined(MALI_TIMELINE_DEBUG_FUNCTIONS) */