Merge "msm: mdss: fix race condition in dsi clk off request"

This commit is contained in:
Linux Build Service Account 2016-11-18 01:54:47 -08:00 committed by Gerrit - the friendly Code Review server
commit db18e6f95e
7 changed files with 84 additions and 27 deletions

View file

@ -2985,6 +2985,12 @@ static int mdss_dsi_cont_splash_config(struct mdss_panel_info *pinfo,
mdss_dsi_panel_pwm_enable(ctrl_pdata); mdss_dsi_panel_pwm_enable(ctrl_pdata);
ctrl_pdata->ctrl_state |= (CTRL_STATE_PANEL_INIT | ctrl_pdata->ctrl_state |= (CTRL_STATE_PANEL_INIT |
CTRL_STATE_MDP_ACTIVE | CTRL_STATE_DSI_ACTIVE); CTRL_STATE_MDP_ACTIVE | CTRL_STATE_DSI_ACTIVE);
/*
* MDP client removes this extra vote during splash reconfigure
* for command mode panel from interface. DSI removes the vote
* during suspend-resume for video mode panel.
*/
if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL)
clk_handle = ctrl_pdata->mdp_clk_handle; clk_handle = ctrl_pdata->mdp_clk_handle;
else else

View file

@ -557,7 +557,8 @@ struct mdss_dsi_ctrl_pdata {
void *clk_mngr; void *clk_mngr;
void *dsi_clk_handle; void *dsi_clk_handle;
void *mdp_clk_handle; void *mdp_clk_handle;
int m_vote_cnt; int m_dsi_vote_cnt;
int m_mdp_vote_cnt;
/* debugfs structure */ /* debugfs structure */
struct mdss_dsi_debugfs_info *debugfs_info; struct mdss_dsi_debugfs_info *debugfs_info;

View file

@ -795,8 +795,29 @@ error:
return rc; return rc;
} }
bool is_dsi_clk_in_ecg_state(void *client)
{
struct mdss_dsi_clk_client_info *c = client;
struct mdss_dsi_clk_mngr *mngr;
bool is_ecg = false;
if (!client) {
pr_err("Invalid client params\n");
goto end;
}
mngr = c->mngr;
mutex_lock(&mngr->clk_mutex);
is_ecg = (c->core_clk_state == MDSS_DSI_CLK_EARLY_GATE);
mutex_unlock(&mngr->clk_mutex);
end:
return is_ecg;
}
int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk, int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
enum mdss_dsi_clk_state state) enum mdss_dsi_clk_state state, u32 index)
{ {
int rc = 0; int rc = 0;
struct mdss_dsi_clk_client_info *c = client; struct mdss_dsi_clk_client_info *c = client;
@ -817,7 +838,7 @@ int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
c->name, mngr->name, clk, state, c->core_clk_state, c->name, mngr->name, clk, state, c->core_clk_state,
c->link_clk_state); c->link_clk_state);
MDSS_XLOG(clk, state, c->core_clk_state, c->link_clk_state); MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state);
/* /*
* Refcount handling rules: * Refcount handling rules:
* 1. Increment refcount whenever ON is called * 1. Increment refcount whenever ON is called
@ -883,7 +904,7 @@ int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
pr_debug("[%s]%s: change=%d, Core (ref=%d, state=%d), Link (ref=%d, state=%d)\n", pr_debug("[%s]%s: change=%d, Core (ref=%d, state=%d), Link (ref=%d, state=%d)\n",
c->name, mngr->name, changed, c->core_refcount, c->name, mngr->name, changed, c->core_refcount,
c->core_clk_state, c->link_refcount, c->link_clk_state); c->core_clk_state, c->link_refcount, c->link_clk_state);
MDSS_XLOG(clk, state, c->core_clk_state, c->link_clk_state); MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state);
if (changed) { if (changed) {
rc = dsi_recheck_clk_state(mngr); rc = dsi_recheck_clk_state(mngr);

View file

@ -197,6 +197,7 @@ int mdss_dsi_clk_deregister(void *client);
* @client: client handle. * @client: client handle.
* @clk: Type of clock requested (enum mdss_dsi_clk_type). * @clk: Type of clock requested (enum mdss_dsi_clk_type).
* @state: clock state requested. * @state: clock state requested.
* @index: controller index.
* *
* This routine is used to request a new clock state for a specific clock. If * This routine is used to request a new clock state for a specific clock. If
* turning ON the clocks, this guarantees that clocks will be on before * turning ON the clocks, this guarantees that clocks will be on before
@ -206,7 +207,7 @@ int mdss_dsi_clk_deregister(void *client);
* @return: error code. * @return: error code.
*/ */
int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk, int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
enum mdss_dsi_clk_state state); enum mdss_dsi_clk_state state, u32 index);
/** /**
* mdss_dsi_clk_set_link_rate() - set clock rate for link clocks * mdss_dsi_clk_set_link_rate() - set clock rate for link clocks
@ -238,4 +239,16 @@ int mdss_dsi_clk_set_link_rate(void *client, enum mdss_dsi_link_clk_type clk,
* @return:error code. * @return:error code.
*/ */
int mdss_dsi_clk_force_toggle(void *client, u32 clk); int mdss_dsi_clk_force_toggle(void *client, u32 clk);
/**
* is_dsi_clk_in_ecg_state() - Checks the current state of clocks
* @client: client handle.
*
* This routine returns checks the clocks status for client and return
* success code based on it.
*
* @return:true: if clocks are in ECG state
* false: for all other cases
*/
bool is_dsi_clk_in_ecg_state(void *client);
#endif /* _MDSS_DSI_CLK_H_ */ #endif /* _MDSS_DSI_CLK_H_ */

View file

@ -2811,12 +2811,6 @@ static int dsi_event_thread(void *data)
pr_debug("%s: Handling underflow event\n", pr_debug("%s: Handling underflow event\n",
__func__); __func__);
__dsi_fifo_error_handler(ctrl, true); __dsi_fifo_error_handler(ctrl, true);
} else {
pr_err("%s: ctrl recovery not defined\n",
__func__);
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl",
"dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif",
"vbif_nrt", "dbg_bus", "vbif_dbg_bus", "panic");
} }
mutex_unlock(&ctrl->mutex); mutex_unlock(&ctrl->mutex);
} }

View file

@ -852,7 +852,7 @@ static int __validate_layer_reconfig(struct mdp_input_layer *layer,
*/ */
if (pipe->csc_coeff_set != layer->color_space) { if (pipe->csc_coeff_set != layer->color_space) {
src_fmt = mdss_mdp_get_format_params(layer->buffer.format); src_fmt = mdss_mdp_get_format_params(layer->buffer.format);
if (pipe->src_fmt->is_yuv && src_fmt->is_yuv) { if (pipe->src_fmt->is_yuv && src_fmt && src_fmt->is_yuv) {
status = -EPERM; status = -EPERM;
pr_err("csc change is not permitted on used pipe\n"); pr_err("csc change is not permitted on used pipe\n");
} }

View file

@ -2081,7 +2081,11 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
{ {
int rc = 0; int rc = 0;
struct mdss_dsi_ctrl_pdata *mctrl = NULL; struct mdss_dsi_ctrl_pdata *mctrl = NULL;
int i; int i, *vote_cnt;
void *m_clk_handle;
bool is_ecg = false;
int state = MDSS_DSI_CLK_OFF;
if (!ctrl) { if (!ctrl) {
pr_err("%s: Invalid arg\n", __func__); pr_err("%s: Invalid arg\n", __func__);
@ -2112,6 +2116,18 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
__func__); __func__);
} }
/*
* it should add and remove extra votes based on voting clients to avoid
* removal of legitimate vote from DSI client.
*/
if (mctrl && (clk_handle == ctrl->dsi_clk_handle)) {
m_clk_handle = mctrl->dsi_clk_handle;
vote_cnt = &mctrl->m_dsi_vote_cnt;
} else if (mctrl) {
m_clk_handle = mctrl->mdp_clk_handle;
vote_cnt = &mctrl->m_mdp_vote_cnt;
}
/* /*
* When DSI is used in split mode, the link clock for master controller * When DSI is used in split mode, the link clock for master controller
* has to be turned on first before the link clock for slave can be * has to be turned on first before the link clock for slave can be
@ -2124,18 +2140,24 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
__func__, ctrl->ndx, clk_type, clk_state, __func__, ctrl->ndx, clk_type, clk_state,
__builtin_return_address(0), mctrl ? 1 : 0); __builtin_return_address(0), mctrl ? 1 : 0);
if (mctrl && (clk_type & MDSS_DSI_LINK_CLK)) { if (mctrl && (clk_type & MDSS_DSI_LINK_CLK)) {
rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle, if (clk_state != MDSS_DSI_CLK_ON) {
MDSS_DSI_ALL_CLKS, /* preserve clk state; do not turn off forcefully */
MDSS_DSI_CLK_ON); is_ecg = is_dsi_clk_in_ecg_state(m_clk_handle);
if (is_ecg)
state = MDSS_DSI_CLK_EARLY_GATE;
}
rc = mdss_dsi_clk_req_state(m_clk_handle,
MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_ON, mctrl->ndx);
if (rc) { if (rc) {
pr_err("%s: failed to turn on mctrl clocks, rc=%d\n", pr_err("%s: failed to turn on mctrl clocks, rc=%d\n",
__func__, rc); __func__, rc);
goto error; goto error;
} }
ctrl->m_vote_cnt++; (*vote_cnt)++;
} }
rc = mdss_dsi_clk_req_state(clk_handle, clk_type, clk_state); rc = mdss_dsi_clk_req_state(clk_handle, clk_type, clk_state, ctrl->ndx);
if (rc) { if (rc) {
pr_err("%s: failed set clk state, rc = %d\n", __func__, rc); pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
goto error; goto error;
@ -2164,24 +2186,24 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle,
* for ON, since the previous ECG state must have * for ON, since the previous ECG state must have
* removed two votes to let clocks turn off. * removed two votes to let clocks turn off.
* *
* To satisfy the above requirement, m_vote_cnt keeps track of * To satisfy the above requirement, vote_cnt keeps track of
* the number of ON votes for master requested by slave. For * the number of ON votes for master requested by slave. For
* every OFF/ECG state request, Either 2 or m_vote_cnt number of * every OFF/ECG state request, Either 2 or vote_cnt number of
* votes are removed depending on which is lower. * votes are removed depending on which is lower.
*/ */
for (i = 0; (i < ctrl->m_vote_cnt && i < 2); i++) { for (i = 0; (i < *vote_cnt && i < 2); i++) {
rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle, rc = mdss_dsi_clk_req_state(m_clk_handle,
MDSS_DSI_ALL_CLKS, MDSS_DSI_ALL_CLKS, state, mctrl->ndx);
MDSS_DSI_CLK_OFF);
if (rc) { if (rc) {
pr_err("%s: failed to set mctrl clk state, rc = %d\n", pr_err("%s: failed to set mctrl clk state, rc = %d\n",
__func__, rc); __func__, rc);
goto error; goto error;
} }
} }
ctrl->m_vote_cnt -= i; (*vote_cnt) -= i;
pr_debug("%s: ctrl=%d, m_vote_cnt=%d\n", __func__, ctrl->ndx, pr_debug("%s: ctrl=%d, vote_cnt=%d dsi_vote_cnt=%d mdp_vote_cnt:%d\n",
ctrl->m_vote_cnt); __func__, ctrl->ndx, *vote_cnt, mctrl->m_dsi_vote_cnt,
mctrl->m_mdp_vote_cnt);
} }
error: error: