summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2018-07-25 17:04:08 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2018-07-25 17:04:07 -0700
commit3fbf4c7216af0f002752d4f802a2fb1488eee129 (patch)
tree84374ee14d351bd6525882532d01a830a1584b2e
parent4e72dda7209a9ef1883778665ad55c080de5b704 (diff)
parentbf9dde89b8b843bfe27232307380c4a30b00bd28 (diff)
Merge "drm/sde: report MDP underrun error only if not stabilized"
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c65
1 files changed, 64 insertions, 1 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 77fdcd86c920..dde742014125 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -44,6 +44,13 @@
/* timeout in frames waiting for frame done */
#define SDE_ENCODER_FRAME_DONE_TIMEOUT 60
+/* timeout in msecs */
+#define SDE_ENCODER_UNDERRUN_TIMEOUT 200
+/* underrun count threshold value */
+#define SDE_ENCODER_UNDERRUN_CNT_MAX 10
+/* 3 vsync time period in msec, report underrun */
+#define SDE_ENCODER_UNDERRUN_DELTA 50
+
#define MISR_BUFF_SIZE 256
/*
@@ -155,6 +162,11 @@ static struct sde_csc_cfg sde_csc_10bit_convert[SDE_MAX_CSC] = {
* @crtc_frame_event: callback event
* @frame_done_timeout: frame done timeout in Hz
* @frame_done_timer: watchdog timer for frame done event
+ * @last_underrun_ts: variable to hold the last occurred underrun
+ * timestamp
+ * @underrun_cnt_dwork: underrun counter for delayed work
+ * @dwork: delayed work for deferring the reporting
+ * of underrun error
*/
struct sde_encoder_virt {
struct drm_encoder base;
@@ -181,6 +193,9 @@ struct sde_encoder_virt {
u32 crtc_frame_event;
atomic_t frame_done_timeout;
struct timer_list frame_done_timer;
+ atomic_t last_underrun_ts;
+ atomic_t underrun_cnt_dwork;
+ struct delayed_work dwork;
};
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -597,14 +612,28 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc,
static void sde_encoder_underrun_callback(struct drm_encoder *drm_enc,
struct sde_encoder_phys *phy_enc)
{
+ struct sde_encoder_virt *sde_enc = NULL;
+
if (!phy_enc)
return;
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
SDE_ATRACE_BEGIN("encoder_underrun_callback");
atomic_inc(&phy_enc->underrun_cnt);
SDE_EVT32(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt));
- sde_recovery_set_events(SDE_UNDERRUN);
+ /* schedule delayed work if it has not scheduled or executed earlier */
+ if ((!atomic_read(&sde_enc->last_underrun_ts)) &&
+ (!atomic_read(&sde_enc->underrun_cnt_dwork))) {
+ schedule_delayed_work(&sde_enc->dwork,
+ msecs_to_jiffies(SDE_ENCODER_UNDERRUN_TIMEOUT));
+ }
+
+ /* take snapshot of current underrun and increment the count */
+ atomic_set(&sde_enc->last_underrun_ts, jiffies);
+ atomic_inc(&sde_enc->underrun_cnt_dwork);
+
trace_sde_encoder_underrun(DRMID(drm_enc),
atomic_read(&phy_enc->underrun_cnt));
SDE_DBG_CTRL("stop_ftrace");
@@ -1391,6 +1420,37 @@ static void sde_encoder_frame_done_timeout(unsigned long data)
SDE_ENCODER_FRAME_EVENT_ERROR);
}
+static void sde_encoder_underrun_work_func(struct work_struct *work)
+{
+ struct sde_encoder_virt *sde_enc =
+ container_of(work, struct sde_encoder_virt, dwork.work);
+
+ unsigned long delta, time;
+
+ if (!sde_enc) {
+ SDE_ERROR("invalid parameters\n");
+ return;
+ }
+
+ delta = jiffies - atomic_read(&sde_enc->last_underrun_ts);
+ time = jiffies_to_msecs(delta);
+
+ /*
+ * report underrun error when it exceeds the threshold count
+ * and the occurrence of last underrun error is less than 3
+ * vsync period.
+ */
+ if (atomic_read(&sde_enc->underrun_cnt_dwork) >
+ SDE_ENCODER_UNDERRUN_CNT_MAX &&
+ time < SDE_ENCODER_UNDERRUN_DELTA) {
+ sde_recovery_set_events(SDE_UNDERRUN);
+ }
+
+ /* reset underrun last timestamp and counter */
+ atomic_set(&sde_enc->last_underrun_ts, 0);
+ atomic_set(&sde_enc->underrun_cnt_dwork, 0);
+}
+
struct drm_encoder *sde_encoder_init(
struct drm_device *dev,
struct msm_display_info *disp_info)
@@ -1421,8 +1481,11 @@ struct drm_encoder *sde_encoder_init(
drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs);
atomic_set(&sde_enc->frame_done_timeout, 0);
+ atomic_set(&sde_enc->last_underrun_ts, 0);
+ atomic_set(&sde_enc->underrun_cnt_dwork, 0);
setup_timer(&sde_enc->frame_done_timer, sde_encoder_frame_done_timeout,
(unsigned long) sde_enc);
+ INIT_DELAYED_WORK(&sde_enc->dwork, sde_encoder_underrun_work_func);
_sde_encoder_init_debugfs(drm_enc, sde_enc, sde_kms);