mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 21:22:09 -04:00
msm: mhi_dev: stop reading host CH ring when CH is reset
The host can asynchronously reset the channel and this can happen when there are pending ch interrupts to process on the EP. The change is to prevent processing the old DB rung by the host by adding delaying channel reset cmd ack. Change-Id: I020a9961196867a7cc1ac8e4f309d0a75c38f6f5 Signed-off-by: Subramanian Ananthanarayanan <skananth@codeaurora.org> Signed-off-by: Gauri Joshi <gaurjosh@codeaurora.org>
This commit is contained in:
parent
24bf1e88dd
commit
bf72f4d92f
2 changed files with 83 additions and 35 deletions
|
|
@ -1829,6 +1829,44 @@ static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id,
|
|||
MHI_CMD_COMPL_CODE_SUCCESS);
|
||||
}
|
||||
|
||||
static void mhi_dev_process_reset_cmd(struct mhi_dev *mhi, int ch_id)
|
||||
{
|
||||
int rc = 0;
|
||||
struct mhi_dev_channel *ch;
|
||||
struct mhi_addr host_addr;
|
||||
|
||||
ch = &mhi->ch[ch_id];
|
||||
/* hard stop and set the channel to stop */
|
||||
mhi->ch_ctx_cache[ch_id].ch_state =
|
||||
MHI_DEV_CH_STATE_DISABLED;
|
||||
mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
|
||||
|
||||
if (mhi->use_ipa)
|
||||
host_addr.host_pa =
|
||||
mhi->ch_ctx_shadow.host_pa +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
else
|
||||
host_addr.device_va =
|
||||
mhi->ch_ctx_shadow.device_va +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
|
||||
host_addr.virt_addr =
|
||||
&mhi->ch_ctx_cache[ch_id].ch_state;
|
||||
host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
|
||||
|
||||
/* update the channel state in the host */
|
||||
mhi_ctx->write_to_host(mhi, &host_addr, NULL,
|
||||
MHI_DEV_DMA_SYNC);
|
||||
|
||||
/* send the completion event to the host */
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_SUCCESS);
|
||||
if (rc)
|
||||
pr_err("Error sending command completion event\n");
|
||||
|
||||
ch->reset_pending = false;
|
||||
}
|
||||
|
||||
static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
|
||||
union mhi_dev_ring_element_type *el, void *ctx)
|
||||
{
|
||||
|
|
@ -2046,38 +2084,19 @@ send_start_completion_event:
|
|||
pr_err("Channel not opened for %d\n", ch_id);
|
||||
return;
|
||||
}
|
||||
|
||||
ch = &mhi->ch[ch_id];
|
||||
|
||||
mutex_lock(&ch->ch_lock);
|
||||
mutex_lock(&ch->ring->event_lock);
|
||||
|
||||
/* hard stop and set the channel to stop */
|
||||
mhi->ch_ctx_cache[ch_id].ch_state =
|
||||
MHI_DEV_CH_STATE_DISABLED;
|
||||
mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED;
|
||||
if (MHI_USE_DMA(mhi))
|
||||
host_addr.host_pa =
|
||||
mhi->ch_ctx_shadow.host_pa +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
else
|
||||
host_addr.device_va =
|
||||
mhi->ch_ctx_shadow.device_va +
|
||||
(sizeof(struct mhi_dev_ch_ctx) * ch_id);
|
||||
|
||||
host_addr.virt_addr =
|
||||
&mhi->ch_ctx_cache[ch_id].ch_state;
|
||||
host_addr.size = sizeof(enum mhi_dev_ch_ctx_state);
|
||||
|
||||
/* update the channel state in the host */
|
||||
mhi_ctx->write_to_host(mhi, &host_addr, NULL,
|
||||
MHI_DEV_DMA_SYNC);
|
||||
|
||||
/* send the completion event to the host */
|
||||
rc = mhi_dev_send_cmd_comp_event(mhi,
|
||||
MHI_CMD_COMPL_CODE_SUCCESS);
|
||||
if (rc)
|
||||
pr_err("Error sending command completion event\n");
|
||||
if (ch->db_pending) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"skipping reset cmd ack for channel %d\n",
|
||||
ch_id);
|
||||
ch->reset_pending = true;
|
||||
mutex_unlock(&ch->ring->event_lock);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
return;
|
||||
}
|
||||
mhi_dev_process_reset_cmd(mhi, ch_id);
|
||||
mutex_unlock(&ch->ring->event_lock);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
mhi_update_state_info_ch(ch_id, MHI_STATE_DISCONNECTED);
|
||||
|
|
@ -2126,9 +2145,10 @@ static void mhi_dev_process_ring_pending(struct work_struct *work)
|
|||
struct list_head *cp, *q;
|
||||
struct mhi_dev_ring *ring;
|
||||
struct mhi_dev_channel *ch;
|
||||
int rc = 0;
|
||||
int rc = 0, ch_id;
|
||||
|
||||
mutex_lock(&mhi_ctx->mhi_lock);
|
||||
|
||||
rc = mhi_dev_process_ring(&mhi->ring[mhi->cmd_ring_idx]);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR, "error processing command ring\n");
|
||||
|
|
@ -2139,12 +2159,6 @@ static void mhi_dev_process_ring_pending(struct work_struct *work)
|
|||
ring = list_entry(cp, struct mhi_dev_ring, list);
|
||||
list_del(cp);
|
||||
mhi_log(MHI_MSG_VERBOSE, "processing ring %d\n", ring->id);
|
||||
rc = mhi_dev_process_ring(ring);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"error processing ring %d\n", ring->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ring->id < mhi->ch_ring_start) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
|
|
@ -2153,12 +2167,39 @@ static void mhi_dev_process_ring_pending(struct work_struct *work)
|
|||
}
|
||||
|
||||
ch = &mhi->ch[ring->id - mhi->ch_ring_start];
|
||||
mutex_lock(&ch->ch_lock);
|
||||
|
||||
rc = mhi_dev_process_ring(ring);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"error processing ring %d\n", ring->id);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
goto exit;
|
||||
}
|
||||
ch->db_pending = false;
|
||||
|
||||
if (ch->reset_pending) {
|
||||
/*
|
||||
* The channel might be reset asynchronously by the
|
||||
* host, below reset ack is in case the channel
|
||||
* was stopped/reset with pending DB.
|
||||
*/
|
||||
ch_id = ch->ch_id;
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"processing pending ch:%d reset\n", ch_id);
|
||||
mutex_lock(&ch->ring->event_lock);
|
||||
mhi_dev_process_reset_cmd(mhi, ch_id);
|
||||
mutex_unlock(&ch->ring->event_lock);
|
||||
}
|
||||
|
||||
rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch->ch_id);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"error enabling chdb interrupt for %d\n", ch->ch_id);
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
goto exit;
|
||||
}
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
|
@ -2195,6 +2236,7 @@ static void mhi_dev_queue_channel_db(struct mhi_dev *mhi,
|
|||
uint32_t chintr_value, uint32_t ch_num)
|
||||
{
|
||||
struct mhi_dev_ring *ring;
|
||||
struct mhi_dev_channel *ch;
|
||||
int rc = 0;
|
||||
|
||||
for (; chintr_value; ch_num++, chintr_value >>= 1) {
|
||||
|
|
@ -2206,6 +2248,10 @@ static void mhi_dev_queue_channel_db(struct mhi_dev *mhi,
|
|||
}
|
||||
mhi_ring_set_state(ring, RING_STATE_PENDING);
|
||||
list_add(&ring->list, &mhi->process_ring_list);
|
||||
ch = &mhi->ch[ch_num];
|
||||
mutex_lock(&ch->ch_lock);
|
||||
ch->db_pending = true;
|
||||
mutex_unlock(&ch->ch_lock);
|
||||
rc = mhi_dev_mmio_disable_chdb_a7(mhi, ch_num);
|
||||
if (rc) {
|
||||
pr_err("Error disabling chdb\n");
|
||||
|
|
|
|||
|
|
@ -509,6 +509,8 @@ struct mhi_dev_channel {
|
|||
uint32_t msi_cnt;
|
||||
uint32_t flush_req_cnt;
|
||||
bool skip_td;
|
||||
bool db_pending;
|
||||
bool reset_pending;
|
||||
};
|
||||
|
||||
/* Structure device for mhi dev */
|
||||
|
|
|
|||
Loading…
Reference in a new issue