Skip to content

Commit f5225a3

Browse files
Sumit KumarManivannan Sadhasivam
authored andcommitted
bus: mhi: ep: Fix chained transfer handling in read path
The mhi_ep_read_channel function incorrectly assumes the End of Transfer (EOT) bit is present for each packet in a chained transactions, causing it to advance mhi_chan->rd_offset beyond wr_offset during host-to-device transfers when EOT has not yet arrived. This leads to access of unmapped host memory, causing IOMMU faults and processing of stale TREs. Modify the loop condition to ensure mhi_queue is not empty, allowing the function to process only valid TREs up to the current write pointer to prevent premature reads and ensure safe traversal of chained TREs. Due to this change, buf_left needs to be removed from the while loop condition to avoid exiting prematurely before reading the ring completely, and also remove write_offset since it will always be zero because the new cache buffer is allocated every time. Fixes: 5301258 ("bus: mhi: ep: Add support for reading from the host") Co-developed-by: Akhil Vinod <[email protected]> Signed-off-by: Akhil Vinod <[email protected]> Signed-off-by: Sumit Kumar <[email protected]> [mani: reworded description slightly] Signed-off-by: Manivannan Sadhasivam <[email protected]> Reviewed-by: Krishna Chaitanya Chundru <[email protected]> Cc: [email protected] Link: https://patch.msgid.link/[email protected]
1 parent d5411ed commit f5225a3

File tree

1 file changed

+12
-25
lines changed

1 file changed

+12
-25
lines changed

drivers/bus/mhi/ep/main.c

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -403,17 +403,13 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
403403
{
404404
struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id];
405405
struct device *dev = &mhi_cntrl->mhi_dev->dev;
406-
size_t tr_len, read_offset, write_offset;
406+
size_t tr_len, read_offset;
407407
struct mhi_ep_buf_info buf_info = {};
408408
u32 len = MHI_EP_DEFAULT_MTU;
409409
struct mhi_ring_element *el;
410-
bool tr_done = false;
411410
void *buf_addr;
412-
u32 buf_left;
413411
int ret;
414412

415-
buf_left = len;
416-
417413
do {
418414
/* Don't process the transfer ring if the channel is not in RUNNING state */
419415
if (mhi_chan->state != MHI_CH_STATE_RUNNING) {
@@ -426,24 +422,23 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
426422
/* Check if there is data pending to be read from previous read operation */
427423
if (mhi_chan->tre_bytes_left) {
428424
dev_dbg(dev, "TRE bytes remaining: %u\n", mhi_chan->tre_bytes_left);
429-
tr_len = min(buf_left, mhi_chan->tre_bytes_left);
425+
tr_len = min(len, mhi_chan->tre_bytes_left);
430426
} else {
431427
mhi_chan->tre_loc = MHI_TRE_DATA_GET_PTR(el);
432428
mhi_chan->tre_size = MHI_TRE_DATA_GET_LEN(el);
433429
mhi_chan->tre_bytes_left = mhi_chan->tre_size;
434430

435-
tr_len = min(buf_left, mhi_chan->tre_size);
431+
tr_len = min(len, mhi_chan->tre_size);
436432
}
437433

438434
read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left;
439-
write_offset = len - buf_left;
440435

441436
buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL);
442437
if (!buf_addr)
443438
return -ENOMEM;
444439

445440
buf_info.host_addr = mhi_chan->tre_loc + read_offset;
446-
buf_info.dev_addr = buf_addr + write_offset;
441+
buf_info.dev_addr = buf_addr;
447442
buf_info.size = tr_len;
448443
buf_info.cb = mhi_ep_read_completion;
449444
buf_info.cb_buf = buf_addr;
@@ -459,16 +454,12 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
459454
goto err_free_buf_addr;
460455
}
461456

462-
buf_left -= tr_len;
463457
mhi_chan->tre_bytes_left -= tr_len;
464458

465-
if (!mhi_chan->tre_bytes_left) {
466-
if (MHI_TRE_DATA_GET_IEOT(el))
467-
tr_done = true;
468-
459+
if (!mhi_chan->tre_bytes_left)
469460
mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size;
470-
}
471-
} while (buf_left && !tr_done);
461+
/* Read until the some buffer is left or the ring becomes not empty */
462+
} while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE));
472463

473464
return 0;
474465

@@ -502,15 +493,11 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring)
502493
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
503494
} else {
504495
/* UL channel */
505-
do {
506-
ret = mhi_ep_read_channel(mhi_cntrl, ring);
507-
if (ret < 0) {
508-
dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
509-
return ret;
510-
}
511-
512-
/* Read until the ring becomes empty */
513-
} while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE));
496+
ret = mhi_ep_read_channel(mhi_cntrl, ring);
497+
if (ret < 0) {
498+
dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
499+
return ret;
500+
}
514501
}
515502

516503
return 0;

0 commit comments

Comments
 (0)