summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c107
1 files changed, 69 insertions, 38 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index bdd0416598c5..59e254c1011f 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -49,6 +49,12 @@ enum {
MDSS_MDP_RETIRE_FENCE,
};
+enum layer_pipe_q {
+ LAYER_USES_NEW_PIPE_Q = 0,
+ LAYER_USES_USED_PIPE_Q,
+ LAYER_USES_DESTROY_PIPE_Q,
+};
+
static inline bool is_layer_right_blend(struct mdp_rect *left_blend,
struct mdp_rect *right_blend, u32 left_lm_w)
{
@@ -950,50 +956,65 @@ static bool __find_pipe_in_list(struct list_head *head,
return false;
}
-static struct mdss_mdp_pipe *__find_used_pipe(struct msm_fb_data_type *mfd,
- u32 pipe_ndx)
+/*
+ * Search pipe from destroy and cleanup list to avoid validation failure.
+ * It is caller responsibility to hold the list lock before calling this API.
+ */
+static struct mdss_mdp_pipe *__find_and_move_cleanup_pipe(
+ struct mdss_overlay_private *mdp5_data, u32 pipe_ndx)
{
- struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe = NULL;
- bool found;
-
- mutex_lock(&mdp5_data->list_lock);
-
- found = __find_pipe_in_list(&mdp5_data->pipes_used, pipe_ndx, &pipe);
- /* check if the pipe is in the cleanup or destroy list */
- if (!found &&
- (__find_pipe_in_list(&mdp5_data->pipes_destroy, pipe_ndx, &pipe) ||
- __find_pipe_in_list(&mdp5_data->pipes_cleanup, pipe_ndx, &pipe))) {
- pr_debug("reuse pipe%d ndx:%d\n", pipe->num, pipe->ndx);
+ if (__find_pipe_in_list(&mdp5_data->pipes_destroy, pipe_ndx, &pipe)) {
+ pr_debug("reuse destroy pipe id:%d ndx:%d\n", pipe->num,
+ pipe_ndx);
+ list_move(&pipe->list, &mdp5_data->pipes_used);
+ } else if (__find_pipe_in_list(&mdp5_data->pipes_cleanup, pipe_ndx,
+ &pipe)) {
+ pr_debug("reuse cleanup pipe id:%d ndx:%d\n", pipe->num,
+ pipe_ndx);
+ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left);
+ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right);
+ pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
list_move(&pipe->list, &mdp5_data->pipes_used);
}
- mutex_unlock(&mdp5_data->list_lock);
return pipe;
}
/*
* __assign_pipe_for_layer() - get a pipe for layer
*
- * This function first searches the pipe from used list. On successful search,
- * it returns the same pipe for current layer. If pipe is switching mixer then
- * it will unstage it from current mixer. On failure search, it increments the
- * pipe refcount to allocate it for current cycle.
+ * This function first searches the pipe from used list, cleanup list and
+ * destroy list. On successful search, it returns the same pipe for current
+ * layer. It also un-stage the pipe from current mixer for used, cleanup,
+ * destroy pipes if they switches the mixer. On failure search, it returns
+ * the null pipe.
*/
static struct mdss_mdp_pipe *__assign_pipe_for_layer(
struct msm_fb_data_type *mfd,
struct mdss_mdp_mixer *mixer, u32 pipe_ndx,
- bool *new_pipe)
+ enum layer_pipe_q *pipe_q_type)
{
- struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_pipe *pipe = NULL;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
- pipe = __find_used_pipe(mfd, pipe_ndx);
- *new_pipe = pipe ? false : true;
+ mutex_lock(&mdp5_data->list_lock);
+ __find_pipe_in_list(&mdp5_data->pipes_used, pipe_ndx, &pipe);
+ if (IS_ERR_OR_NULL(pipe)) {
+ pipe = __find_and_move_cleanup_pipe(mdp5_data, pipe_ndx);
+ if (IS_ERR_OR_NULL(pipe))
+ *pipe_q_type = LAYER_USES_NEW_PIPE_Q;
+ else
+ *pipe_q_type = LAYER_USES_DESTROY_PIPE_Q;
+ } else {
+ *pipe_q_type = LAYER_USES_USED_PIPE_Q;
+ }
+ mutex_unlock(&mdp5_data->list_lock);
- if (!*new_pipe) {
+ /* found the pipe from used, destroy or cleanup list */
+ if (!IS_ERR_OR_NULL(pipe)) {
if (pipe->mixer_left != mixer) {
if (!mixer->ctl || (mixer->ctl->mfd != mfd)) {
pr_err("Can't switch mixer %d->%d pnum %d!\n",
@@ -1115,7 +1136,7 @@ static void __handle_free_list(struct mdss_overlay_private *mdp5_data,
static int __validate_layers(struct msm_fb_data_type *mfd,
struct file *file, struct mdp_layer_commit_v1 *commit)
{
- int ret, i, release_ndx = 0, inputndx = 0;
+ int ret, i, release_ndx = 0, inputndx = 0, destroy_ndx = 0;
u32 left_lm_layers = 0, right_lm_layers = 0;
u32 left_cnt = 0, right_cnt = 0;
u32 left_lm_w = left_lm_w_from_mfd(mfd);
@@ -1130,7 +1151,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
struct mdss_mdp_mixer *mixer = NULL;
struct mdp_input_layer *layer, *prev_layer, *layer_list;
bool is_single_layer = false;
- bool new_pipe = false;
+ enum layer_pipe_q pipe_q_type;
ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
if (ret)
@@ -1240,7 +1261,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
}
pipe = __assign_pipe_for_layer(mfd, mixer, layer->pipe_ndx,
- &new_pipe);
+ &pipe_q_type);
if (IS_ERR_OR_NULL(pipe)) {
pr_err("error assigning pipe id=0x%x rc:%ld\n",
layer->pipe_ndx, PTR_ERR(pipe));
@@ -1249,22 +1270,19 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
goto validate_exit;
}
+ if (pipe_q_type == LAYER_USES_NEW_PIPE_Q)
+ release_ndx |= pipe->ndx;
+ if (pipe_q_type == LAYER_USES_DESTROY_PIPE_Q)
+ destroy_ndx |= pipe->ndx;
+
ret = mdss_mdp_pipe_map(pipe);
if (IS_ERR_VALUE(ret)) {
pr_err("Unable to map used pipe%d ndx=%x\n",
pipe->num, pipe->ndx);
- if (new_pipe) {
- if (!list_empty(&pipe->list))
- list_del_init(&pipe->list);
- mdss_mdp_pipe_destroy(pipe);
- }
layer->error_code = ret;
goto validate_exit;
}
- if (new_pipe)
- release_ndx |= pipe->ndx;
-
ret = __configure_pipe_params(mfd, layer, pipe,
left_blend_pipe, is_single_layer, mixer_mux);
if (ret) {
@@ -1302,11 +1320,11 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
ret = __validate_secure_display(mdp5_data);
validate_exit:
- pr_debug("err=%d total_layer:%d left:%d right:%d release_ndx=0x%x processed=%d\n",
+ pr_debug("err=%d total_layer:%d left:%d right:%d release_ndx=0x%x destroy_ndx=0x%x processed=%d\n",
ret, layer_count, left_lm_layers, right_lm_layers,
- release_ndx, i);
+ release_ndx, destroy_ndx, i);
MDSS_XLOG(inputndx, layer_count, left_lm_layers, right_lm_layers,
- release_ndx, ret);
+ release_ndx, destroy_ndx, ret);
mutex_lock(&mdp5_data->list_lock);
list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_used, list) {
if (IS_ERR_VALUE(ret)) {
@@ -1317,6 +1335,15 @@ validate_exit:
if (!list_empty(&pipe->list))
list_del_init(&pipe->list);
mdss_mdp_pipe_destroy(pipe);
+ } else if (pipe->ndx & destroy_ndx) {
+ /*
+ * cleanup/destroy list pipes should move back
+ * to destroy list. Next/current kickoff cycle
+ * will release the pipe because validate also
+ * acquires ov_lock.
+ */
+ list_move(&pipe->list,
+ &mdp5_data->pipes_destroy);
}
} else {
pipe->file = file;
@@ -1591,13 +1618,17 @@ int mdss_mdp_async_position_update(struct msm_fb_data_type *mfd,
struct mdss_mdp_pipe *pipe = NULL;
struct mdp_async_layer *layer;
struct mdss_rect dst, src;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
u32 flush_bits = 0, inputndx = 0;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
for (i = 0; i < update_pos->input_layer_cnt; i++) {
layer = &update_pos->input_layers[i];
- pipe = __find_used_pipe(mfd, layer->pipe_ndx);
+ mutex_lock(&mdp5_data->list_lock);
+ __find_pipe_in_list(&mdp5_data->pipes_used, layer->pipe_ndx,
+ &pipe);
+ mutex_unlock(&mdp5_data->list_lock);
if (!pipe) {
pr_err("invalid pipe ndx=0x%x for async update\n",
layer->pipe_ndx);