From d0a4940862ff9cbd5b50aa8eec24e7170f0b7df7 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 19 Dec 2019 18:01:57 -0800 Subject: [PATCH] mhi: core: fix fast forward recycling of event rings Some low priority event rings operate on a fast forwarding mechanism where only the latest event is processed and the rest are skipped. The recycle API only handles updating the context write pointer in sequence which causes an out of bounds doorbell issued to the device due to mismatched values. Add another API to support handling updates for context write pointer separately with the fast forwarding use case. Change-Id: If628b49e063d14920fe734ebd113c9c4c733204b Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_main.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 0cd40bf99786..47e26304ee16 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -292,6 +292,29 @@ static void mhi_recycle_ev_ring_element(struct mhi_controller *mhi_cntrl, smp_wmb(); } +static void mhi_recycle_fwd_ev_ring_element(struct mhi_controller *mhi_cntrl, + struct mhi_ring *ring) +{ + dma_addr_t ctxt_wp; + + /* update the WP */ + ring->wp += ring->el_size; + if (ring->wp >= (ring->base + ring->len)) + ring->wp = ring->base; + + /* update the context WP based on the RP to support fast forwarding */ + ctxt_wp = ring->iommu_base + (ring->wp - ring->base); + *ring->ctxt_wp = ctxt_wp; + + /* update the RP */ + ring->rp += ring->el_size; + if (ring->rp >= (ring->base + ring->len)) + ring->rp = ring->base; + + /* visible to other cores */ + smp_wmb(); +} + static bool mhi_is_ring_full(struct mhi_controller *mhi_cntrl, struct mhi_ring *ring) { @@ -1451,7 +1474,7 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, ev_ring->wp = dev_rp - 1; if (ev_ring->wp < ev_ring->base) ev_ring->wp = ev_ring->base + ev_ring->len - ev_ring->el_size; - mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); + mhi_recycle_fwd_ev_ring_element(mhi_cntrl, ev_ring); read_lock_bh(&mhi_cntrl->pm_lock); if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))