Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 5301258899773 ("bus: mhi: ep: Add support for reading from the host")
Co-developed-by: Akhil Vinod <akhil.vinod@oss.qualcomm.com>
Signed-off-by: Akhil Vinod <akhil.vinod@oss.qualcomm.com>
Signed-off-by: Sumit Kumar <sumit.kumar@oss.qualcomm.com>
[mani: reworded description slightly]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Reviewed-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20250910-final_chained-v3-1-ec77c9d88ace@oss.qualcomm.com

authored by

Sumit Kumar and committed by
Manivannan Sadhasivam
f5225a34 d5411ed6

+12 -25
+12 -25
drivers/bus/mhi/ep/main.c
··· 403 403 { 404 404 struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id]; 405 405 struct device *dev = &mhi_cntrl->mhi_dev->dev; 406 - size_t tr_len, read_offset, write_offset; 406 + size_t tr_len, read_offset; 407 407 struct mhi_ep_buf_info buf_info = {}; 408 408 u32 len = MHI_EP_DEFAULT_MTU; 409 409 struct mhi_ring_element *el; 410 - bool tr_done = false; 411 410 void *buf_addr; 412 - u32 buf_left; 413 411 int ret; 414 - 415 - buf_left = len; 416 412 417 413 do { 418 414 /* Don't process the transfer ring if the channel is not in RUNNING state */ ··· 422 426 /* Check if there is data pending to be read from previous read operation */ 423 427 if (mhi_chan->tre_bytes_left) { 424 428 dev_dbg(dev, "TRE bytes remaining: %u\n", mhi_chan->tre_bytes_left); 425 - tr_len = min(buf_left, mhi_chan->tre_bytes_left); 429 + tr_len = min(len, mhi_chan->tre_bytes_left); 426 430 } else { 427 431 mhi_chan->tre_loc = MHI_TRE_DATA_GET_PTR(el); 428 432 mhi_chan->tre_size = MHI_TRE_DATA_GET_LEN(el); 429 433 mhi_chan->tre_bytes_left = mhi_chan->tre_size; 430 434 431 - tr_len = min(buf_left, mhi_chan->tre_size); 435 + tr_len = min(len, mhi_chan->tre_size); 432 436 } 433 437 434 438 read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left; 435 - write_offset = len - buf_left; 436 439 437 440 buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL); 438 441 if (!buf_addr) 439 442 return -ENOMEM; 440 443 441 444 buf_info.host_addr = mhi_chan->tre_loc + read_offset; 442 - buf_info.dev_addr = buf_addr + write_offset; 445 + buf_info.dev_addr = buf_addr; 443 446 buf_info.size = tr_len; 444 447 buf_info.cb = mhi_ep_read_completion; 445 448 buf_info.cb_buf = buf_addr; ··· 454 459 goto err_free_buf_addr; 455 460 } 456 461 457 - buf_left -= tr_len; 458 462 mhi_chan->tre_bytes_left -= tr_len; 459 463 460 - if (!mhi_chan->tre_bytes_left) { 461 - if (MHI_TRE_DATA_GET_IEOT(el)) 462 - tr_done = true; 463 - 464 + if (!mhi_chan->tre_bytes_left) 464 465 mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size; 465 - } 466 - } while (buf_left && !tr_done); 466 + /* Read until the some buffer is left or the ring becomes not empty */ 467 + } while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE)); 467 468 468 469 return 0; 469 470 ··· 493 502 mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); 494 503 } else { 495 504 /* UL channel */ 496 - do { 497 - ret = mhi_ep_read_channel(mhi_cntrl, ring); 498 - if (ret < 0) { 499 - dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n"); 500 - return ret; 501 - } 502 - 503 - /* Read until the ring becomes empty */ 504 - } while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE)); 505 + ret = mhi_ep_read_channel(mhi_cntrl, ring); 506 + if (ret < 0) { 507 + dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n"); 508 + return ret; 509 + } 505 510 } 506 511 507 512 return 0;