diff options
author | Ujwal Patel <ujwalp@codeaurora.org> | 2015-04-22 14:51:12 -0700 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:40:48 -0700 |
commit | 26bebe99120ebfa202a9be8b37e3c96f2829195b (patch) | |
tree | 2821b581e28a734ad6df652a6d68ad3da22296e5 | |
parent | 3425b351bd3c3bbc456078da54c3a82a04e34c61 (diff) |
msm: mdss: handle timeouts from pan_idle and wait_for_kickoff
mdss_fb_pan_idle and mdss_fb_wait_for_kickoff are used to hold the
current context until it is safe to proceed. Unless shutdown is going on,
these contexts are woken up by corresponding display thread responsible
for committing a frame to display. Display thread has various delays like
waiting for fences to be signalled, waiting for previous frame to finish
or waiting for a vsync etc. Under normal circumstances, these delays are
very negligible and different threads work in good harmony. However in a
heavily loaded system or some bad thread which disables interrupts for a
long time, these delays can become very large. Increase timeout to
arbitrarily derived value and add error messaging when the timeout is
observed. Remove panic from the timeout to let the system recover by
itself.
Change-Id: I58fe4c0d8b0c43998f87384035a1eacc24d7230a
Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
-rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 86 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 11 |
2 files changed, 71 insertions, 26 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 0e509ff4f28b..6177df1b40a0 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -628,7 +628,13 @@ static int mdss_fb_blanking_mode_switch(struct msm_fb_data_type *mfd, int mode) pdata = dev_get_platdata(&mfd->pdev->dev); pdata->panel_info.dynamic_switch_pending = true; - mdss_fb_pan_idle(mfd); + ret = mdss_fb_pan_idle(mfd); + if (ret) { + pr_err("mdss_fb_pan_idle for fb%d failed. ret=%d\n", + mfd->index, ret); + pdata->panel_info.dynamic_switch_pending = false; + return ret; + } mutex_lock(&mfd->bl_lock); bl_lvl = mfd->bl_level; @@ -995,11 +1001,17 @@ static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd) pr_debug("mdss_fb suspend index=%d\n", mfd->index); - mdss_fb_pan_idle(mfd); + ret = mdss_fb_pan_idle(mfd); + if (ret) { + pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d\n", + mfd->index, ret); + goto exit; + } + ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_SUSPEND, NULL); if (ret) { pr_warn("unable to suspend fb%d (%d)\n", mfd->index, ret); - return ret; + goto exit; } mfd->suspend.op_enable = mfd->op_enable; @@ -1017,14 +1029,14 @@ static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd) mfd->suspend.op_enable); if (ret) { pr_err("can't turn off display!\n"); - return ret; + goto exit; } } mfd->op_enable = false; fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED); } - - return 0; +exit: + return ret; } static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd) @@ -1038,7 +1050,13 @@ static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd) mfd->is_power_setting = true; pr_debug("mdss_fb resume index=%d\n", mfd->index); - mdss_fb_pan_idle(mfd); + ret = mdss_fb_pan_idle(mfd); + if (ret) { + pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d\n", + mfd->index, ret); + return ret; + } + ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_RESUME, NULL); if (ret) { pr_warn("unable to resume fb%d (%d)\n", mfd->index, ret); @@ -1530,10 +1548,17 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, static int mdss_fb_blank(int blank_mode, struct fb_info *info) { + int ret; struct mdss_panel_data *pdata; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; - mdss_fb_pan_idle(mfd); + ret = mdss_fb_pan_idle(mfd); + if (ret) { + pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d\n", + mfd->index, ret); + return ret; + } + if (mfd->op_enable == 0) { if (blank_mode == FB_BLANK_UNBLANK) mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON; @@ -2367,8 +2392,12 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all) mfd->index); /* wait only for the last release */ - if (release_all || (mfd->ref_cnt == 1)) - mdss_fb_pan_idle(mfd); + if (release_all || (mfd->ref_cnt == 1)) { + ret = mdss_fb_pan_idle(mfd); + if (ret && (ret != -ESHUTDOWN)) + pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d ignoring.\n", + mfd->index, ret); + } pr_debug("release_all = %s\n", release_all ? "true" : "false"); @@ -2730,13 +2759,16 @@ static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd) pr_err("%pS: wait for idle timeout commits=%d\n", __builtin_return_address(0), atomic_read(&mfd->commits_pending)); - MDSS_XLOG_TOUT_HANDLER("mdp", "panic"); + MDSS_XLOG_TOUT_HANDLER("mdp"); + ret = -ETIMEDOUT; } else if (mfd->shutdown_pending) { pr_debug("Shutdown signalled\n"); - return -ESHUTDOWN; + ret = -ESHUTDOWN; + } else { + ret = 0; } - return 0; + return ret; } static int mdss_fb_wait_for_kickoff(struct msm_fb_data_type *mfd) @@ -2755,13 +2787,16 @@ static int mdss_fb_wait_for_kickoff(struct msm_fb_data_type *mfd) __builtin_return_address(0), atomic_read(&mfd->kickoff_pending), atomic_read(&mfd->commits_pending)); - MDSS_XLOG_TOUT_HANDLER("mdp", "panic"); + MDSS_XLOG_TOUT_HANDLER("mdp"); + ret = -ETIMEDOUT; } else if (mfd->shutdown_pending) { pr_debug("Shutdown signalled\n"); - return -ESHUTDOWN; + ret = -ESHUTDOWN; + } else { + ret = 0; } - return 0; + return ret; } static int mdss_fb_pan_display_ex(struct fb_info *info, @@ -2788,7 +2823,7 @@ static int mdss_fb_pan_display_ex(struct fb_info *info, ret = mdss_fb_wait_for_kickoff(mfd); if (ret) { - pr_err("Shutdown pending. Aborting operation\n"); + pr_err("wait_for_kick failed. rc=%d\n", ret); return ret; } @@ -2818,8 +2853,11 @@ static int mdss_fb_pan_display_ex(struct fb_info *info, atomic_inc(&mfd->kickoff_pending); wake_up_all(&mfd->commit_wait_q); mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex); - if (wait_for_finish) - mdss_fb_pan_idle(mfd); + if (wait_for_finish) { + ret = mdss_fb_pan_idle(mfd); + if (ret) + pr_err("mdss_fb_pan_idle failed. rc=%d\n", ret); + } return ret; } @@ -3136,7 +3174,10 @@ static int __mdss_fb_display_thread(void *data) if (kthread_should_stop()) break; + MDSS_XLOG(mfd->index, XLOG_FUNC_ENTRY); ret = __mdss_fb_perform_commit(mfd); + MDSS_XLOG(mfd->index, XLOG_FUNC_EXIT); + atomic_dec(&mfd->commits_pending); wake_up_all(&mfd->idle_wait_q); } @@ -3268,7 +3309,7 @@ static int mdss_fb_set_par(struct fb_info *info) ret = mdss_fb_pan_idle(mfd); if (ret) { - pr_err("Shutdown pending. Aborting operation\n"); + pr_err("mdss_fb_pan_idle failed. rc=%d\n", ret); return ret; } @@ -3856,8 +3897,9 @@ static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd) ret = mdss_fb_pan_idle(mfd); } - if (ret) - pr_debug("Shutdown pending. Aborting operation %x\n", cmd); + if (ret && (ret != -ESHUTDOWN)) + pr_err("wait_idle failed. cmd=0x%x rc=%d\n", cmd, ret); + return ret; } diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 6466b1d21d4a..11d2f4cc2b39 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -37,11 +37,14 @@ #define WAIT_MAX_FENCE_TIMEOUT (WAIT_FENCE_FIRST_TIMEOUT + \ WAIT_FENCE_FINAL_TIMEOUT) #define WAIT_MIN_FENCE_TIMEOUT (1) -/* Display op timeout should be greater than the total timeout but not - * unreasonably large. Set to 1s more than first wait + final wait which - * are already quite long and proceed without any further waits. */ +/* + * Display op timeout should be greater than total time it can take for + * a display thread to commit one frame. One of the largest time consuming + * activity performed by display thread is waiting for fences. So keeping + * that as a reference and add additional 20s to sustain system holdups. + */ #define WAIT_DISP_OP_TIMEOUT (WAIT_FENCE_FIRST_TIMEOUT + \ - WAIT_FENCE_FINAL_TIMEOUT + MSEC_PER_SEC) + WAIT_FENCE_FINAL_TIMEOUT + (20 * MSEC_PER_SEC)) #ifndef MAX #define MAX(x, y) (((x) > (y)) ? (x) : (y)) |