Skip to content

Commit

Permalink
bus: mhi: ep: Move chan->lock to the start of processing queued ch ring
Browse files Browse the repository at this point in the history
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: 03c0bb8 ("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>
  • Loading branch information
Manivannan Sadhasivam committed Jan 27, 2023
1 parent 8e697fc commit 8d6a1fe
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions drivers/bus/mhi/ep/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,24 +730,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) {
Expand Down

0 comments on commit 8d6a1fe

Please sign in to comment.