From 10f4c14b87c90f2f2b90db53cc99e35258d69945 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 4 Dec 2019 16:53:51 -0800 Subject: [PATCH] mhi: core: Handle RSC minimum credit requirement After getting OOB driver checks for transfer ring empty condition and rings the channel ring doorbell without making sure if there are minimum 8 TREs queued for GSI to perform DMA. Otherwise there is a possibility of Host ringing doorbell after OOB with same write pointer which was already processed in polling mode. Change-Id: Idda28aadbd1af9b5857db71d98237ef4761427bd Signed-off-by: Hemant Kumar --- drivers/bus/mhi/core/mhi_internal.h | 2 ++ drivers/bus/mhi/core/mhi_main.c | 33 +++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 8edd644026af..79d276a5bb17 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -362,6 +362,8 @@ enum mhi_cmd_type { #define MHI_RSCTRE_DATA_DWORD0(cookie) (cookie) #define MHI_RSCTRE_DATA_DWORD1 (MHI_PKT_TYPE_COALESCING << 16) +#define MHI_RSC_MIN_CREDITS (8) + enum MHI_CMD { MHI_CMD_RESET_CHAN, MHI_CMD_START_CHAN, diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 8c0983231f37..50ed82dddf5e 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -499,6 +499,8 @@ int mhi_queue_dma(struct mhi_device *mhi_dev, struct mhi_ring *buf_ring = &mhi_chan->buf_ring; struct mhi_buf_info *buf_info; struct mhi_tre *mhi_tre; + bool ring_db = true; + int n_free_tre, n_queued_tre; if (mhi_is_ring_full(mhi_cntrl, tre_ring)) return -ENOMEM; @@ -538,6 +540,18 @@ int mhi_queue_dma(struct mhi_device *mhi_dev, mhi_tre->dword[0] = MHI_RSCTRE_DATA_DWORD0(buf_ring->wp - buf_ring->base); mhi_tre->dword[1] = MHI_RSCTRE_DATA_DWORD1; + /* + * on RSC channel IPA HW has a minimum credit requirement before + * switching to DB mode + */ + n_free_tre = mhi_get_no_free_descriptors(mhi_dev, + DMA_FROM_DEVICE); + n_queued_tre = tre_ring->elements - n_free_tre; + read_lock_bh(&mhi_chan->lock); + if (mhi_chan->db_cfg.db_mode && + n_queued_tre < MHI_RSC_MIN_CREDITS) + ring_db = false; + read_unlock_bh(&mhi_chan->lock); } else { mhi_tre->ptr = MHI_TRE_DATA_PTR(buf_info->p_addr); mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(buf_info->len); @@ -555,7 +569,7 @@ int mhi_queue_dma(struct mhi_device *mhi_dev, if (mhi_chan->dir == DMA_TO_DEVICE) atomic_inc(&mhi_cntrl->pending_pkts); - if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) { + if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)) && ring_db) { read_lock_bh(&mhi_chan->lock); mhi_ring_chan_db(mhi_cntrl, mhi_chan); read_unlock_bh(&mhi_chan->lock); @@ -972,6 +986,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, u32 ev_code; struct mhi_result result; unsigned long flags = 0; + bool ring_db = true; + int n_free_tre, n_queued_tre; ev_code = MHI_TRE_GET_EV_CODE(event); buf_ring = &mhi_chan->buf_ring; @@ -1067,9 +1083,22 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, MHI_VERB("DB_MODE/OOB Detected chan %d.\n", mhi_chan->chan); mhi_chan->db_cfg.db_mode = true; + + /* + * on RSC channel IPA HW has a minimum credit requirement before + * switching to DB mode + */ + if (mhi_chan->xfer_type == MHI_XFER_RSC_DMA) { + n_free_tre = mhi_get_no_free_descriptors( + mhi_chan->mhi_dev, DMA_FROM_DEVICE); + n_queued_tre = tre_ring->elements - n_free_tre; + if (n_queued_tre < MHI_RSC_MIN_CREDITS) + ring_db = false; + } + read_lock_irqsave(&mhi_cntrl->pm_lock, flags); if (tre_ring->wp != tre_ring->rp && - MHI_DB_ACCESS_VALID(mhi_cntrl)) { + MHI_DB_ACCESS_VALID(mhi_cntrl) && ring_db) { mhi_ring_chan_db(mhi_cntrl, mhi_chan); } read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);