diff options
| author | Adrian Salido-Moreno <adrianm@codeaurora.org> | 2013-07-24 13:13:10 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:20:18 -0700 |
| commit | 710843adf53e568841f98cc1b37b8fb48cc1f2c6 (patch) | |
| tree | fd8d16d0032ee18bc90cbd91a7f85f9070b64649 | |
| parent | b18026410901fe57d342a8c0b6cf2b06d7ac11ea (diff) | |
msm: mdss: delay freeing buffers for additional vsync
There are cases where if commit happens very close to vsync or in other
uncommon conditions, where MDP will continue fetching from old buffer
address when unmap of the buffer happens. In order to avoid such
scenarios keep a reference of buffers for an additional commit before
unmapping to avoid potential iommu page fault.
Change-Id: Ied61b4851e2d410d71360ad0c119ef21009f91a1
Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 47 |
2 files changed, 49 insertions, 2 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index d38adfa86997..9fc7e11fe87d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -40,6 +40,7 @@ #define MAX_UPSCALE_RATIO 20 #define MAX_DECIMATION 4 #define MDP_MIN_VBP 4 +#define MAX_FREE_LIST_SIZE 12 #define C3_ALPHA 3 /* alpha */ #define C2_R_Cr 2 /* R/Cr */ @@ -385,6 +386,9 @@ struct mdss_overlay_private { struct list_head pipes_cleanup; struct list_head rot_proc_list; bool mixer_swap; + + struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE]; + int free_list_size; }; struct mdss_mdp_perf_params { diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index ef39bb26e401..abf429d8f00f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -709,6 +709,45 @@ static inline int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data) return 0; } +/** + * __mdss_mdp_overlay_free_list_purge() - clear free list of buffers + * @mfd: Msm frame buffer data structure for the associated fb + * + * Frees memory and clears current list of buffers which are pending free + */ +static void __mdss_mdp_overlay_free_list_purge(struct msm_fb_data_type *mfd) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + int i; + + pr_debug("purging fb%d free list\n", mfd->index); + for (i = 0; i < mdp5_data->free_list_size; i++) + mdss_mdp_overlay_free_buf(&mdp5_data->free_list[i]); + mdp5_data->free_list_size = 0; +} + +/** + * __mdss_mdp_overlay_free_list_add() - add a buffer to free list + * @mfd: Msm frame buffer data structure for the associated fb + */ +static void __mdss_mdp_overlay_free_list_add(struct msm_fb_data_type *mfd, + struct mdss_mdp_data *buf) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + int i; + + /* if holding too many buffers free current list */ + if (mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE) { + pr_warn("max free list size for fb%d, purging\n", mfd->index); + __mdss_mdp_overlay_free_list_purge(mfd); + } + + BUG_ON(mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE); + i = mdp5_data->free_list_size++; + mdp5_data->free_list[i] = *buf; + memset(buf, 0, sizeof(*buf)); +} + static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd) { struct mdss_mdp_pipe *pipe, *tmp; @@ -716,18 +755,20 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd) LIST_HEAD(destroy_pipes); mutex_lock(&mfd->lock); + __mdss_mdp_overlay_free_list_purge(mfd); + list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup, cleanup_list) { list_move(&pipe->cleanup_list, &destroy_pipes); mdss_mdp_overlay_free_buf(&pipe->back_buf); - mdss_mdp_overlay_free_buf(&pipe->front_buf); + __mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf); pipe->mfd = NULL; } list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) { if (pipe->back_buf.num_planes) { /* make back buffer active */ - mdss_mdp_overlay_free_buf(&pipe->front_buf); + __mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf); swap(pipe->back_buf, pipe->front_buf); } } @@ -2106,6 +2147,8 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) rc = mdss_mdp_ctl_stop(mdp5_data->ctl); if (rc == 0) { + __mdss_mdp_overlay_free_list_purge(mfd); + if (!mfd->ref_cnt) { mdp5_data->borderfill_enable = false; mdss_mdp_ctl_destroy(mdp5_data->ctl); |
