mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 07:03:09 -04:00
msm: ipa: fix race condition between USB connect and modem SSR
This fix solves the race conditions between USB connect and modem SSR by using mutex protection. Change-Id: If97264a7c875f3e0c66b34b1b02e48b21c99e319 Acked-by: Jyothi J <jyothij@qti.qualcomm.com> Signed-off-by: Michael Adisumarta <madisuma@codeaurora.org>
This commit is contained in:
parent
9930b32e86
commit
3d5ac78337
1 changed files with 49 additions and 25 deletions
|
|
@ -375,12 +375,6 @@ struct ipa_mpm_mhi_driver {
|
|||
bool init_complete;
|
||||
/* General MPM mutex to protect concurrent update of MPM GSI states */
|
||||
struct mutex mutex;
|
||||
/*
|
||||
* Mutex to protect IPA clock vote/unvote to make sure IPA isn't double
|
||||
* devoted for concurrency scenarios such as SSR and LPM mode CB
|
||||
* concurrency.
|
||||
*/
|
||||
struct mutex lpm_mutex;
|
||||
/*
|
||||
* Mutex to protect mhi_dev update/ access, for concurrency such as
|
||||
* 5G SSR and USB disconnect/connect.
|
||||
|
|
@ -1357,7 +1351,6 @@ static void ipa_mpm_mhip_shutdown(int mhip_idx)
|
|||
|
||||
ipa_mpm_clean_mhip_chan(mhip_idx, dl_cons_chan);
|
||||
|
||||
mutex_lock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
|
||||
if (!ipa_mpm_ctx->md[mhip_idx].in_lpm) {
|
||||
ipa_mpm_vote_unvote_ipa_clk(CLK_OFF, mhip_idx);
|
||||
/* while in modem shutdown scenarios such as SSR, no explicit
|
||||
|
|
@ -1365,10 +1358,8 @@ static void ipa_mpm_mhip_shutdown(int mhip_idx)
|
|||
*/
|
||||
ipa_mpm_ctx->md[mhip_idx].in_lpm = true;
|
||||
}
|
||||
mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
|
||||
mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
|
||||
ipa_mpm_ctx->md[mhip_idx].mhi_dev = NULL;
|
||||
ipa_mpm_ctx->md[mhip_idx].init_complete = false;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
|
||||
IPA_MPM_FUNC_EXIT();
|
||||
}
|
||||
|
|
@ -1399,6 +1390,18 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!ipa_mpm_ctx->md[probe_id].init_complete) {
|
||||
/*
|
||||
* SSR might be in progress, dont have to vote/unvote for
|
||||
* IPA clocks as it will be taken care in remove_cb/subsequent
|
||||
* probe.
|
||||
*/
|
||||
IPA_MPM_DBG("SSR in progress, return\n");
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
return 0;
|
||||
}
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
|
||||
IPA_MPM_ERR("PCIe clock vote/unvote = %d probe_id = %d clk_cnt = %d\n",
|
||||
vote, probe_id,
|
||||
atomic_read(&ipa_mpm_ctx->md[probe_id].clk_cnt.pcie_clk_cnt));
|
||||
|
|
@ -1409,7 +1412,6 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
|
|||
if (result) {
|
||||
IPA_MPM_ERR("mhi_sync_get failed for probe_id %d\n",
|
||||
result, probe_id);
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1423,7 +1425,6 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
|
|||
IPA_MPM_DBG("probe_id %d PCIE clock already devoted\n",
|
||||
probe_id);
|
||||
WARN_ON(1);
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
return 0;
|
||||
}
|
||||
mhi_device_put(ipa_mpm_ctx->md[probe_id].mhi_dev, MHI_VOTE_BUS);
|
||||
|
|
@ -1431,8 +1432,6 @@ static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
|
|||
atomic_dec(&ipa_mpm_ctx->md[probe_id].clk_cnt.pcie_clk_cnt);
|
||||
atomic_dec(&ipa_mpm_ctx->pcie_clk_total_cnt);
|
||||
}
|
||||
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1482,11 +1481,9 @@ static int ipa_mpm_start_stop_remote_mhip_chan(
|
|||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
/* For error state, expect modem SSR to recover from error */
|
||||
if (ipa_mpm_ctx->md[probe_id].remote_state == MPM_MHIP_REMOTE_ERR) {
|
||||
IPA_MPM_ERR("Remote channels in err state for %d\n", probe_id);
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
|
@ -1497,12 +1494,14 @@ static int ipa_mpm_start_stop_remote_mhip_chan(
|
|||
probe_id);
|
||||
} else {
|
||||
ret = mhi_resume_transfer(mhi_dev);
|
||||
mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
if (ret)
|
||||
ipa_mpm_ctx->md[probe_id].remote_state =
|
||||
MPM_MHIP_REMOTE_ERR;
|
||||
else
|
||||
ipa_mpm_ctx->md[probe_id].remote_state =
|
||||
MPM_MHIP_REMOTE_START;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
}
|
||||
} else {
|
||||
if (ipa_mpm_ctx->md[probe_id].remote_state ==
|
||||
|
|
@ -1511,15 +1510,16 @@ static int ipa_mpm_start_stop_remote_mhip_chan(
|
|||
probe_id);
|
||||
} else {
|
||||
ret = mhi_pause_transfer(mhi_dev);
|
||||
mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
if (ret)
|
||||
ipa_mpm_ctx->md[probe_id].remote_state =
|
||||
MPM_MHIP_REMOTE_ERR;
|
||||
else
|
||||
ipa_mpm_ctx->md[probe_id].remote_state =
|
||||
MPM_MHIP_REMOTE_STOP;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1563,6 +1563,15 @@ static enum mhip_status_type ipa_mpm_start_stop_mhip_chan(
|
|||
IPA_MPM_ERR("fail to get EP# for idx %d\n", ipa_ep_idx);
|
||||
return MHIP_STATUS_EP_NOT_FOUND;
|
||||
}
|
||||
|
||||
mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
if (!ipa_mpm_ctx->md[probe_id].init_complete) {
|
||||
IPA_MPM_ERR("MHIP probe %d not initialized\n", probe_id);
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
return MHIP_STATUS_EP_NOT_READY;
|
||||
}
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
|
||||
ep = &ipa3_ctx->ep[ipa_ep_idx];
|
||||
|
||||
if (mhip_chan == IPA_MPM_MHIP_CHAN_UL) {
|
||||
|
|
@ -1951,10 +1960,8 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
|
|||
ipa_mpm_ctx->md[probe_id].remote_state = MPM_MHIP_REMOTE_STOP;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
ipa_mpm_vote_unvote_pcie_clk(CLK_ON, probe_id);
|
||||
mutex_lock(&ipa_mpm_ctx->md[probe_id].lpm_mutex);
|
||||
ipa_mpm_vote_unvote_ipa_clk(CLK_ON, probe_id);
|
||||
ipa_mpm_ctx->md[probe_id].in_lpm = false;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].lpm_mutex);
|
||||
IPA_MPM_DBG("ul chan = %d, dl_chan = %d\n", ul_prod, dl_cons);
|
||||
|
||||
/*
|
||||
|
|
@ -2089,8 +2096,10 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
|
|||
* to MHI driver. remove_cb will be called eventually when
|
||||
* Device side comes from where pending cleanup happens.
|
||||
*/
|
||||
mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
atomic_inc(&ipa_mpm_ctx->probe_cnt);
|
||||
ipa_mpm_ctx->md[probe_id].init_complete = true;
|
||||
ipa_mpm_ctx->md[probe_id].init_complete = false;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
IPA_MPM_FUNC_EXIT();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2271,8 +2280,6 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
|
|||
}
|
||||
|
||||
atomic_inc(&ipa_mpm_ctx->probe_cnt);
|
||||
ipa_mpm_ctx->md[probe_id].init_complete = true;
|
||||
|
||||
/* Check if ODL pipe is connected to MHIP DPL pipe before probe */
|
||||
if (probe_id == IPA_MPM_MHIP_CH_ID_2 &&
|
||||
ipa3_is_odl_connected()) {
|
||||
|
|
@ -2280,7 +2287,9 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
|
|||
ret = ipa_mpm_set_dma_mode(IPA_CLIENT_MHI_PRIME_DPL_PROD,
|
||||
IPA_CLIENT_USB_DPL_CONS, false);
|
||||
}
|
||||
|
||||
mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
ipa_mpm_ctx->md[probe_id].init_complete = true;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex);
|
||||
IPA_MPM_FUNC_EXIT();
|
||||
return 0;
|
||||
|
||||
|
|
@ -2349,6 +2358,11 @@ static void ipa_mpm_mhi_remove_cb(struct mhi_device *mhi_dev)
|
|||
}
|
||||
|
||||
IPA_MPM_DBG("remove_cb for mhip_idx = %d", mhip_idx);
|
||||
|
||||
mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
|
||||
ipa_mpm_ctx->md[mhip_idx].init_complete = false;
|
||||
mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
|
||||
|
||||
ipa_mpm_mhip_shutdown(mhip_idx);
|
||||
|
||||
atomic_dec(&ipa_mpm_ctx->probe_cnt);
|
||||
|
|
@ -2387,7 +2401,19 @@ static void ipa_mpm_mhi_status_cb(struct mhi_device *mhi_dev,
|
|||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
|
||||
mutex_lock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
|
||||
if (!ipa_mpm_ctx->md[mhip_idx].init_complete) {
|
||||
/*
|
||||
* SSR might be in progress, dont have to vote/unvote for
|
||||
* IPA clocks as it will be taken care in remove_cb/subsequent
|
||||
* probe.
|
||||
*/
|
||||
IPA_MPM_DBG("SSR in progress, return\n");
|
||||
mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex);
|
||||
|
||||
switch (mhi_cb) {
|
||||
case MHI_CB_IDLE:
|
||||
break;
|
||||
|
|
@ -2424,7 +2450,6 @@ static void ipa_mpm_mhi_status_cb(struct mhi_device *mhi_dev,
|
|||
IPA_MPM_ERR("unexpected event %d\n", mhi_cb);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].lpm_mutex);
|
||||
}
|
||||
|
||||
static void ipa_mpm_mhip_map_prot(enum ipa_usb_teth_prot prot,
|
||||
|
|
@ -2777,7 +2802,6 @@ static int ipa_mpm_probe(struct platform_device *pdev)
|
|||
for (i = 0; i < IPA_MPM_MHIP_CH_ID_MAX; i++) {
|
||||
mutex_init(&ipa_mpm_ctx->md[i].mutex);
|
||||
mutex_init(&ipa_mpm_ctx->md[i].mhi_mutex);
|
||||
mutex_init(&ipa_mpm_ctx->md[i].lpm_mutex);
|
||||
}
|
||||
|
||||
ipa_mpm_ctx->dev_info.pdev = pdev;
|
||||
|
|
|
|||
Loading…
Reference in a new issue