diff options
| author | Rahul Sharma <rahsha@codeaurora.org> | 2018-07-19 15:15:55 +0530 |
|---|---|---|
| committer | Rahul Sharma <rahsha@codeaurora.org> | 2018-07-20 16:53:04 +0530 |
| commit | bf9dde89b8b843bfe27232307380c4a30b00bd28 (patch) | |
| tree | d0d0e56f2c7cb0da0ccd872bbe7de9155532e26b /drivers/gpu/drm | |
| parent | 80db82bdaffd91e52a302ab98587995fad935520 (diff) | |
drm/sde: report MDP underrun error only if not stabilized
MDP underrun error is being reported to recovery manager as and when they
are detected by the interrupt handler. Since most of the times errors are
recovered successfully and stabilizes and hence we do not need to report in
those scenarios.
This implementation uses a delayed work to figure out if the error is
stabilized. In case if error is still persists then it would be reported
to the recovery manager.
Change-Id: I3509484867d86dc946dd4be856d85de444c0aa60
Signed-off-by: Rahul Sharma <rahsha@codeaurora.org>
Diffstat (limited to 'drivers/gpu/drm')
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder.c | 65 |
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); |
