msm: mdss: fix new and used pipe config in layer validation
Pipes present in destroy and cleanup list are considers as used pipes during layer validation. This assumption is wrong. Async update should not be supported for such pipes because they are not stagged in current draw cycle. These pipes should also go through destroy cleanup process if any layer validation fails during the atomic ioctl check. Change-Id: I11ba16db40634e32e7f55af4e19f6cb42530b1f4 Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
This commit is contained in:
parent
e22c8ccbee
commit
6d9fcf1aba
1 changed files with 69 additions and 38 deletions
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue