summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Salido-Moreno <adrianm@codeaurora.org>2013-07-24 13:13:10 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:20:18 -0700
commit710843adf53e568841f98cc1b37b8fb48cc1f2c6 (patch)
treefd8d16d0032ee18bc90cbd91a7f85f9070b64649
parentb18026410901fe57d342a8c0b6cf2b06d7ac11ea (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.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c47
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);