msm: mdss: synchronize recovery handler access
The recovery handler is used in the dsi event thread, and
the recovery handler variable was configured from a different
thread. Earlier, there is no synchronization between the two
threads accessing the recovery handler, causing kernel panics.
Change-Id: Iee990276fdabd65e2e1f2e3c21ad574fc0d8a7bc
Signed-off-by: Xiaoming Zhou <zhoux@codeaurora.org>
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e724d68..fcb8f50 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -952,6 +952,15 @@
return rc;
}
+int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct mdss_panel_recovery *recovery)
+{
+ mutex_lock(&ctrl->mutex);
+ ctrl->recovery = recovery;
+ mutex_unlock(&ctrl->mutex);
+ return 0;
+}
+
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@@ -1001,7 +1010,6 @@
mdss_dsi_clk_req(ctrl_pdata, (int)arg);
break;
case MDSS_EVENT_DSI_CMDLIST_KOFF:
- ctrl_pdata->recovery = (struct mdss_panel_recovery *)arg;
mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
break;
case MDSS_EVENT_PANEL_UPDATE_FPS:
@@ -1023,6 +1031,10 @@
case MDSS_EVENT_DSI_ULPS_CTRL:
rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg);
break;
+ case MDSS_EVENT_REGISTER_RECOVERY_HANDLER:
+ rc = mdss_dsi_register_recovery_handler(ctrl_pdata,
+ (struct mdss_panel_recovery *)arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index f79391a..5ab06e0 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -365,6 +365,9 @@
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
bool cmd_cfg_cont_splash);
+int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct mdss_panel_recovery *recovery);
+
static inline bool mdss_dsi_broadcast_mode_enabled(void)
{
return ctrl_list[DSI_CTRL_MASTER]->shared_pdata.broadcast_enable &&
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 72cb8d5..8e9f760 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1379,10 +1379,12 @@
mdss_dsi_pll_relock(ctrl);
if (todo & DSI_EV_MDP_FIFO_UNDERFLOW) {
+ mutex_lock(&ctrl->mutex);
if (ctrl->recovery) {
mdss_dsi_sw_reset_restore(ctrl);
ctrl->recovery->fxn(ctrl->recovery->data);
}
+ mutex_unlock(&ctrl->mutex);
}
if (todo & DSI_EV_DSI_FIFO_EMPTY)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 991eb06..ce94fcf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -592,6 +592,10 @@
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_ON, NULL);
WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
+
+ mdss_mdp_ctl_intf_event(ctl,
+ MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
+ (void *)&ctx->recovery);
}
MDSS_XLOG(ctl->num, ctl->roi.x, ctl->roi.y, ctl->roi.w,
@@ -609,8 +613,7 @@
/*
* tx dcs command if had any
*/
- mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF,
- (void *)&ctx->recovery);
+ mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
INIT_COMPLETION(ctx->pp_comp);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
@@ -679,6 +682,10 @@
if (cancel_delayed_work_sync(&ctx->ulps_work))
pr_debug("deleted pending ulps work\n");
+ mdss_mdp_ctl_intf_event(ctl,
+ MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
+ NULL);
+
ctx->panel_on = 0;
mdss_mdp_cmd_clk_off(ctx);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 52c3e71..8393bed 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -151,6 +151,7 @@
MDSS_EVENT_DSI_CMDLIST_KOFF,
MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
MDSS_EVENT_DSI_ULPS_CTRL,
+ MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
};
struct lcd_panel_info {