summaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2022-12-28 21:47:03 +0530
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-03-10 09:34:31 +0100
commit69cc38576293507668ad7f936c2b5f5a37fbbbf5 (patch)
tree42e74e01203cd153856589efd73919d6fef76489 /drivers/bus
parent353aea15d6edbd4e69e039356a1bd3e641f7d952 (diff)
downloadlinux-stable-69cc38576293507668ad7f936c2b5f5a37fbbbf5.tar.gz
linux-stable-69cc38576293507668ad7f936c2b5f5a37fbbbf5.tar.bz2
linux-stable-69cc38576293507668ad7f936c2b5f5a37fbbbf5.zip
bus: mhi: ep: Move chan->lock to the start of processing queued ch ring
commit 8d6a1fea53864cd9545741f48f4ae4df804db557 upstream. There is a good chance that while the channel ring gets processed, the STOP or RESET command for the channel might be received from the MHI host. In those cases, the entire channel ring processing needs to be protected by chan->lock to prevent the race where the corresponding channel ring might be reset. While at it, let's also add a sanity check to make sure that the ring is started before processing it. Because, if the STOP/RESET command gets processed while mhi_ep_ch_ring_worker() waited for chan->lock, the ring would've been reset. Cc: <stable@vger.kernel.org> # 5.19 Fixes: 03c0bb8ec983 ("bus: mhi: ep: Add support for processing channel rings") Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com> Link: https://lore.kernel.org/r/20221228161704.255268-6-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/mhi/ep/main.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index 2b3a3b56e280..883bf79be57e 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -723,24 +723,37 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work)
list_del(&itr->node);
ring = itr->ring;
+ chan = &mhi_cntrl->mhi_chan[ring->ch_id];
+ mutex_lock(&chan->lock);
+
+ /*
+ * The ring could've stopped while we waited to grab the (chan->lock), so do
+ * a sanity check before going further.
+ */
+ if (!ring->started) {
+ mutex_unlock(&chan->lock);
+ kfree(itr);
+ continue;
+ }
+
/* Update the write offset for the ring */
ret = mhi_ep_update_wr_offset(ring);
if (ret) {
dev_err(dev, "Error updating write offset for ring\n");
+ mutex_unlock(&chan->lock);
kfree(itr);
continue;
}
/* Sanity check to make sure there are elements in the ring */
if (ring->rd_offset == ring->wr_offset) {
+ mutex_unlock(&chan->lock);
kfree(itr);
continue;
}
el = &ring->ring_cache[ring->rd_offset];
- chan = &mhi_cntrl->mhi_chan[ring->ch_id];
- mutex_lock(&chan->lock);
dev_dbg(dev, "Processing the ring for channel (%u)\n", ring->ch_id);
ret = mhi_ep_process_ch_ring(ring, el);
if (ret) {