From bf72f4d92f3c347a46fd90f31c74896b9ef3fed3 Mon Sep 17 00:00:00 2001 From: Gauri Joshi Date: Thu, 21 Jan 2021 11:26:19 +0530 Subject: [PATCH] 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 Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 118 ++++++++++++++++++++--------- drivers/platform/msm/mhi_dev/mhi.h | 2 + 2 files changed, 84 insertions(+), 36 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 3bc4d448d8bd..c2d9d1921414 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -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"); diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 7fec5e68a001..c477bfa7686b 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -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 */