summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUjwal Patel <ujwalp@codeaurora.org>2015-04-22 14:51:12 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:40:48 -0700
commit26bebe99120ebfa202a9be8b37e3c96f2829195b (patch)
tree2821b581e28a734ad6df652a6d68ad3da22296e5
parent3425b351bd3c3bbc456078da54c3a82a04e34c61 (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.c86
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h11
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))