From: Cho KyongHo Date: Fri, 19 Jan 2018 03:20:34 +0000 (+0900) Subject: g2d: fix fence timeout handling X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=7aff7071722c20674478d7bf654d6bed7f71a022;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git g2d: fix fence timeout handling If an fence timeout is caused by unsignaled fences, G2D driver forcefully schedules the task to H/W because it is not a good idea that a driver waits for a fence to be signaled undefinitely. Sometimes fence timeout is happened when a task queued in the workqueue is pended too long. We don't need to restart the fence timer again because is has no meaning to recover the situation. Moreover, it may corrupt the timer initialized for H/W timeouts if the restarting timer for fence happens later than initializing the timer for H/W. In the most cases, fence timeout is happened by unsigned fences. The counter task.starter is not zeroed when the expired task is forcefully started. It makes confusing when debugging problems related to timeouts. Change-Id: I2bdcc9df1b891cdeaf315b3380f41a99cc5a3ce0 Signed-off-by: Cho KyongHo --- diff --git a/drivers/gpu/exynos/g2d/g2d_fence.c b/drivers/gpu/exynos/g2d/g2d_fence.c index eda8056daa7a..d95eee05d11c 100644 --- a/drivers/gpu/exynos/g2d/g2d_fence.c +++ b/drivers/gpu/exynos/g2d/g2d_fence.c @@ -75,13 +75,14 @@ void g2d_fence_timeout_handler(unsigned long arg) */ if (atomic_read(&task->starter.refcount.refs) == 0) { spin_unlock_irqrestore(&task->fence_timeout_lock, flags); - pr_err("All fences have been signaled. (work_busy? %d)\n", - work_busy(&task->work)); - /* If this happens again, the problem is obviously caused by the - * workqueue that does not schedule the work of this context. + pr_err("All fences are signaled. (work_busy? %d, state %#lx)\n", + work_busy(&task->work), task->state); + /* + * If this happens, there is racing between + * g2d_fence_timeout_handler() and g2d_queuework_task(). Once + * g2d_queuework_task() is invoked, it is guaranteed that the + * task is to be scheduled to H/W. */ - mod_timer(&task->timer, - jiffies + msecs_to_jiffies(G2D_FENCE_TIMEOUT_MSEC)); return; } @@ -105,6 +106,12 @@ void g2d_fence_timeout_handler(unsigned long arg) if (fence) dma_fence_remove_callback(fence, &task->target.fence_cb); + /* + * Now it is OK to init kref for g2d_start_task() below. + * All fences waiters are removed + */ + kref_init(&task->starter); + /* check compressed buffer because crashed buffer makes recovery */ for (i = 0; i < task->num_source; i++) { if (IS_AFBC( @@ -117,7 +124,7 @@ void g2d_fence_timeout_handler(unsigned long arg) g2d_stamp_task(task, G2D_STAMP_STATE_TIMEOUT_FENCE, afbc); - g2d_queuework_task(&task->starter); + kref_put(&task->starter, g2d_queuework_task); }; static const char *g2d_fence_get_driver_name(struct dma_fence *fence)