msm: mdss: fix deadlock during early wake up

Resource control lock mutex should not be held while
driver is waiting for the power work items to finish
since this can result in a deadlock.
Fix this by moving the mutex to only the area that
needs to be protected.

Change-Id: I91c440845a379a1e141178b043ad7adb33989ef2
Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
This commit is contained in:
Ingrid Gallardo 2015-08-13 10:48:35 -07:00 committed by David Keitel
parent ba55276d8c
commit a16cf3827e

View file

@ -683,12 +683,12 @@ int mdss_mdp_resource_control(struct mdss_mdp_ctl *ctl, u32 sw_event)
break;
case MDP_RSRC_CTL_EVENT_EARLY_WAKE_UP:
/*
* 1. If the current state is ON, stay in ON and cancel any
* pending GATE work item.
* 2. If the current state is GATED, stay at GATED and cancel
* any pending POWER-OFF work item.
* 3. If the current state is POWER-OFF, Schedule a work item to
* POWER-ON.
* Cancel any work item pending and:
* 1. If the current state is ON, stay in ON.
* 2. If the current state is GATED, stay at GATED.
* 3. If the current state is POWER-OFF, POWER-ON and
* schedule a work item to POWER-OFF if no
* kickoffs get scheduled.
*/
/* if panels are off, do not process early wake up */
@ -696,17 +696,19 @@ int mdss_mdp_resource_control(struct mdss_mdp_ctl *ctl, u32 sw_event)
(sctx && __mdss_mdp_cmd_is_panel_power_off(sctx)))
break;
mutex_lock(&ctl->rsrc_lock);
if (mdp5_data->resources_state != MDP_RSRC_CTL_STATE_OFF) {
if (cancel_work_sync(&ctx->gate_clk_work))
pr_debug("%s: %s - gate_work cancelled\n",
__func__, get_sw_event_name(sw_event));
/* Cancel GATE Work Item */
if (cancel_work_sync(&ctx->gate_clk_work))
pr_debug("%s: %s - gate_work cancelled\n",
__func__, get_sw_event_name(sw_event));
if (cancel_delayed_work_sync(
&ctx->delayed_off_clk_work))
pr_debug("%s: %s - off work cancelled\n",
__func__, get_sw_event_name(sw_event));
} else {
/* Cancel OFF Work Item */
if (cancel_delayed_work_sync(
&ctx->delayed_off_clk_work))
pr_debug("%s: %s - off work cancelled\n",
__func__, get_sw_event_name(sw_event));
mutex_lock(&ctl->rsrc_lock);
if (mdp5_data->resources_state == MDP_RSRC_CTL_STATE_OFF) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
mdss_mdp_ctl_intf_event(ctx->ctl,
MDSS_EVENT_PANEL_CLK_CTRL,
@ -963,11 +965,15 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work)
get_clk_pwr_state_name
(mdp5_data->resources_state));
mutex_lock(&ctl->rsrc_lock);
if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
mutex_lock(&cmd_clk_mtx);
if (mdss_mdp_get_split_display_ctls(&ctl, &sctl)) {
/* error when getting both controllers, just returnr */
pr_err("cannot get both controllers for the split display\n");
return;
goto exit;
}
/* re-assign to have the correct order in the context */
@ -976,13 +982,10 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work)
if (!ctx || !sctx) {
pr_err("invalid %s %s\n",
ctx?"":"ctx", sctx?"":"sctx");
return;
goto exit;
}
mutex_lock(&cmd_clk_mtx);
}
mutex_lock(&ctl->rsrc_lock);
if (ctx->autorefresh_init) {
/*
* Driver shouldn't have scheduled this work item if
@ -1017,12 +1020,12 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work)
mdp5_data->resources_state = MDP_RSRC_CTL_STATE_OFF;
exit:
mutex_unlock(&ctl->rsrc_lock);
/* do this at the end, so we can also protect the global power state*/
if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY)
mutex_unlock(&cmd_clk_mtx);
mutex_unlock(&ctl->rsrc_lock);
ATRACE_END(__func__);
}
@ -1056,12 +1059,16 @@ static void clk_ctrl_gate_work(struct work_struct *work)
ctl->num, get_clk_pwr_state_name
(mdp5_data->resources_state));
mutex_lock(&ctl->rsrc_lock);
if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
mutex_lock(&cmd_clk_mtx);
if (mdss_mdp_get_split_display_ctls(&ctl, &sctl)) {
/* error when getting both controllers, just return */
pr_err("%s cannot get both cts for the split display\n",
__func__);
return;
goto exit;
}
/* re-assign to have the correct order in the context */
@ -1070,13 +1077,10 @@ static void clk_ctrl_gate_work(struct work_struct *work)
if (!ctx || !sctx) {
pr_err("%s ERROR invalid %s %s\n", __func__,
ctx?"":"ctx", sctx?"":"sctx");
return;
goto exit;
}
mutex_lock(&cmd_clk_mtx);
}
mutex_lock(&ctl->rsrc_lock);
if (ctx->autorefresh_init) {
/*
* Driver shouldn't have scheduled this work item if
@ -1107,12 +1111,12 @@ static void clk_ctrl_gate_work(struct work_struct *work)
mdp5_data->resources_state = MDP_RSRC_CTL_STATE_GATE;
exit:
mutex_unlock(&ctl->rsrc_lock);
/* unlock mutex needed for split display */
if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY)
mutex_unlock(&cmd_clk_mtx);
mutex_unlock(&ctl->rsrc_lock);
ATRACE_END(__func__);
}