#define MALI_TIMELINE_SYSTEM_LOCKED(system) (mali_spinlock_reentrant_is_held((system)->spinlock, _mali_osk_get_tid()))
+#if defined(CONFIG_SYNC)
+_mali_osk_wq_work_t *sync_fence_callback_work_t = NULL;
+_mali_osk_spinlock_irq_t *sync_fence_callback_list_lock = NULL;
+static _MALI_OSK_LIST_HEAD_STATIC_INIT(sync_fence_callback_queue);
+#endif
+
/*
* Following three elements are used to record how many
* gp, physical pp or virtual pp jobs are delayed in the whole
/* Callback that is called when a sync fence a tracker is waiting on is signaled. */
static void mali_timeline_sync_fence_callback(struct sync_fence *sync_fence, struct sync_fence_waiter *sync_fence_waiter)
{
- struct mali_timeline_system *system;
- struct mali_timeline_waiter *waiter;
struct mali_timeline_tracker *tracker;
- mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
- u32 tid = _mali_osk_get_tid();
- mali_bool is_aborting = MALI_FALSE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
- int fence_status = sync_fence->status;
-#else
- int fence_status = atomic_read(&sync_fence->status);
-#endif
-
- MALI_DEBUG_ASSERT_POINTER(sync_fence);
+ MALI_IGNORE(sync_fence);
MALI_DEBUG_ASSERT_POINTER(sync_fence_waiter);
tracker = _MALI_OSK_CONTAINER_OF(sync_fence_waiter, struct mali_timeline_tracker, sync_fence_waiter);
MALI_DEBUG_ASSERT_POINTER(tracker);
- system = tracker->system;
- MALI_DEBUG_ASSERT_POINTER(system);
- MALI_DEBUG_ASSERT_POINTER(system->session);
-
- mali_spinlock_reentrant_wait(system->spinlock, tid);
-
- is_aborting = system->session->is_aborting;
- if (!is_aborting && (0 > fence_status)) {
- MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, fence_status));
- tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT;
- }
-
- waiter = tracker->waiter_sync;
- MALI_DEBUG_ASSERT_POINTER(waiter);
-
- tracker->sync_fence = NULL;
- tracker->fence.sync_fd = -1;
-
- schedule_mask |= mali_timeline_system_release_waiter(system, waiter);
-
- /* If aborting, wake up sleepers that are waiting for sync fence callbacks to complete. */
- if (is_aborting) {
- _mali_osk_wait_queue_wake_up(system->wait_queue);
- }
-
- mali_spinlock_reentrant_signal(system->spinlock, tid);
-
- /*
- * Older versions of Linux, before 3.5, doesn't support fput() in interrupt
- * context. For those older kernels, allocate a list object and put the
- * fence object on that and defer the call to sync_fence_put() to a workqueue.
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
- {
- struct mali_deferred_fence_put_entry *obj;
-
- obj = kzalloc(sizeof(struct mali_deferred_fence_put_entry), GFP_ATOMIC);
- if (obj) {
- unsigned long flags;
- mali_bool schedule = MALI_FALSE;
-
- obj->fence = sync_fence;
-
- spin_lock_irqsave(&mali_timeline_sync_fence_to_free_lock, flags);
- if (hlist_empty(&mali_timeline_sync_fence_to_free_list))
- schedule = MALI_TRUE;
- hlist_add_head(&obj->list, &mali_timeline_sync_fence_to_free_list);
- spin_unlock_irqrestore(&mali_timeline_sync_fence_to_free_lock, flags);
+ _mali_osk_spinlock_irq_lock(sync_fence_callback_list_lock);
+ _mali_osk_list_addtail(&tracker->sync_fence_signal_list, &sync_fence_callback_queue);
+ _mali_osk_spinlock_irq_unlock(sync_fence_callback_list_lock);
- if (schedule)
- schedule_delayed_work(&delayed_sync_fence_put, 0);
- }
- }
-#else
- sync_fence_put(sync_fence);
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) */
-
- if (!is_aborting) {
- mali_executor_schedule_from_mask(schedule_mask, MALI_TRUE);
- }
+ _mali_osk_wq_schedule_work(sync_fence_callback_work_t);
}
#endif /* defined(CONFIG_SYNC) */
return point;
}
-void mali_timeline_initialize(void)
+#if defined(CONFIG_SYNC)
+static void mali_timeline_do_sync_fence_callback(void *arg)
+{
+ _MALI_OSK_LIST_HEAD_STATIC_INIT(list);
+ struct mali_timeline_tracker *tracker;
+ struct mali_timeline_tracker *tmp_tracker;
+ u32 tid = _mali_osk_get_tid();
+
+ MALI_IGNORE(arg);
+
+ /*
+ * Quickly "unhook" the jobs pending to be deleted, so we can release
+ * the lock before we start deleting the job objects
+ * (without any locks held)
+ */
+ _mali_osk_spinlock_irq_lock(sync_fence_callback_list_lock);
+ _mali_osk_list_move_list(&sync_fence_callback_queue, &list);
+ _mali_osk_spinlock_irq_unlock(sync_fence_callback_list_lock);
+
+ _MALI_OSK_LIST_FOREACHENTRY(tracker, tmp_tracker, &list,
+ struct mali_timeline_tracker, sync_fence_signal_list) {
+ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
+ mali_bool is_aborting = MALI_FALSE;
+ int fence_status = 0;
+ struct sync_fence *sync_fence = NULL;
+ struct mali_timeline_system *system = NULL;
+ struct mali_timeline_waiter *waiter = NULL;
+
+ _mali_osk_list_delinit(&tracker->sync_fence_signal_list);
+
+ sync_fence = tracker->sync_fence;
+ MALI_DEBUG_ASSERT_POINTER(sync_fence);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
+ fence_status = sync_fence->status;
+#else
+ fence_status = atomic_read(&sync_fence->status);
+#endif
+
+ system = tracker->system;
+ MALI_DEBUG_ASSERT_POINTER(system);
+ MALI_DEBUG_ASSERT_POINTER(system->session);
+
+ mali_spinlock_reentrant_wait(system->spinlock, tid);
+
+ is_aborting = system->session->is_aborting;
+ if (!is_aborting && (0 > fence_status)) {
+ MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, fence_status));
+ tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT;
+ }
+
+ waiter = tracker->waiter_sync;
+ MALI_DEBUG_ASSERT_POINTER(waiter);
+
+ tracker->sync_fence = NULL;
+ tracker->fence.sync_fd = -1;
+
+ schedule_mask |= mali_timeline_system_release_waiter(system, waiter);
+
+ /* If aborting, wake up sleepers that are waiting for sync fence callbacks to complete. */
+ if (is_aborting) {
+ _mali_osk_wait_queue_wake_up(system->wait_queue);
+ }
+
+ mali_spinlock_reentrant_signal(system->spinlock, tid);
+
+ /*
+ * Older versions of Linux, before 3.5, doesn't support fput() in interrupt
+ * context. For those older kernels, allocate a list object and put the
+ * fence object on that and defer the call to sync_fence_put() to a workqueue.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+ {
+ struct mali_deferred_fence_put_entry *obj;
+
+ obj = kzalloc(sizeof(struct mali_deferred_fence_put_entry), GFP_ATOMIC);
+ if (obj) {
+ unsigned long flags;
+ mali_bool schedule = MALI_FALSE;
+
+ obj->fence = sync_fence;
+
+ spin_lock_irqsave(&mali_timeline_sync_fence_to_free_lock, flags);
+ if (hlist_empty(&mali_timeline_sync_fence_to_free_list))
+ schedule = MALI_TRUE;
+ hlist_add_head(&obj->list, &mali_timeline_sync_fence_to_free_list);
+ spin_unlock_irqrestore(&mali_timeline_sync_fence_to_free_lock, flags);
+
+ if (schedule)
+ schedule_delayed_work(&delayed_sync_fence_put, 0);
+ }
+ }
+#else
+ sync_fence_put(sync_fence);
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) */
+
+ if (!is_aborting) {
+ mali_executor_schedule_from_mask(schedule_mask, MALI_TRUE);
+ }
+ }
+}
+#endif /* defined(CONFIG_SYNC) */
+
+_mali_osk_errcode_t mali_timeline_initialize(void)
{
_mali_osk_atomic_init(&gp_tracker_count, 0);
_mali_osk_atomic_init(&phy_pp_tracker_count, 0);
_mali_osk_atomic_init(&virt_pp_tracker_count, 0);
+#if defined(CONFIG_SYNC)
+ sync_fence_callback_list_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_UNORDERED, _MALI_OSK_LOCK_ORDER_FIRST);
+ if (NULL == sync_fence_callback_list_lock) {
+ return _MALI_OSK_ERR_NOMEM;
+ }
+
+ sync_fence_callback_work_t = _mali_osk_wq_create_work(
+ mali_timeline_do_sync_fence_callback, NULL);
+
+ if (NULL == sync_fence_callback_work_t) {
+ return _MALI_OSK_ERR_FAULT;
+ }
+#endif
+ return _MALI_OSK_ERR_OK;
}
void mali_timeline_terminate(void)
_mali_osk_atomic_term(&gp_tracker_count);
_mali_osk_atomic_term(&phy_pp_tracker_count);
_mali_osk_atomic_term(&virt_pp_tracker_count);
+#if defined(CONFIG_SYNC)
+ if (NULL != sync_fence_callback_list_lock) {
+ _mali_osk_spinlock_irq_term(sync_fence_callback_list_lock);
+ sync_fence_callback_list_lock = NULL;
+ }
+
+ if (NULL != sync_fence_callback_work_t) {
+ _mali_osk_wq_delete_work(sync_fence_callback_work_t);
+ sync_fence_callback_work_t = NULL;
+ }
+#endif
}
#if defined(MALI_TIMELINE_DEBUG_FUNCTIONS)