[PATCH v2] mtd: rawnand: lpc32xx_mlc: fail DMA transfers on timeout
From: Pengpeng Hou <hidden>
Date: 2026-07-03 07:38:16
Also in:
lkml, stable
Subsystem:
memory technology devices (mtd), nand flash subsystem, the rest · Maintainers:
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra, Linus Torvalds
lpc32xx_xmit_dma() starts a DMA transfer and waits up to one second
for its completion, but it ignores the wait result and returns success
after unmapping the buffer.
A timed out read can therefore return success with incomplete data, and
a timed out write can continue the NAND operation without proof that the
DMA payload reached the controller.
Terminate the DMA channel on timeout, unmap the scatterlist through the
existing cleanup path, and return -ETIMEDOUT to the NAND read/write
callers. Initialize the shared cleanup-path result before using it for
dmaengine_prep_slave_sg() failures.
Fixes: 70f7cb78ec53 ("mtd: add LPC32xx MLC NAND driver")
Cc: stable@vger.kernel.org
Reviewed-by: Vladimir Zapolskiy <vz@kernel.org>
Signed-off-by: Pengpeng Hou <redacted>
---
Changes since v1: https://lore.kernel.org/all/20260625003327.11060-1-pengpeng@iscas.ac.cn/ (local)
- add Fixes and Cc stable tags as requested by Miquel
- carry Vladimir's Reviewed-by tag
drivers/mtd/nand/raw/lpc32xx_mlc.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index 19b13ae536d4..8f6a89d9ba83 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c@@ -396,6 +396,7 @@ static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len, struct lpc32xx_nand_host *host = nand_get_controller_data(chip); struct dma_async_tx_descriptor *desc; int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + unsigned long time_left; int res; sg_init_one(&host->sgl, mem, len);
@@ -410,6 +411,7 @@ static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len, flags); if (!desc) { dev_err(mtd->dev.parent, "Failed to prepare slave sg\n"); + res = -ENXIO; goto out1; }
@@ -420,7 +422,13 @@ static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len, dmaengine_submit(desc); dma_async_issue_pending(host->dma_chan); - wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000)); + time_left = wait_for_completion_timeout(&host->comp_dma, + msecs_to_jiffies(1000)); + if (!time_left) { + dmaengine_terminate_sync(host->dma_chan); + res = -ETIMEDOUT; + goto out1; + } dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, DMA_BIDIRECTIONAL);
@@ -428,7 +436,7 @@ static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len, out1: dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, DMA_BIDIRECTIONAL); - return -ENXIO; + return res; } static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf,
--
2.53.0