]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mtd: rawnand: lpc32xx_slc: fail DMA transfer on completion timeout
authorPengpeng Hou <pengpeng@iscas.ac.cn>
Fri, 3 Jul 2026 07:39:43 +0000 (15:39 +0800)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Fri, 3 Jul 2026 13:45:55 +0000 (15:45 +0200)
lpc32xx_xmit_dma() waits for the DMA completion callback but ignores
wait_for_completion_timeout(). A timed out DMA transfer is therefore
unmapped and reported as successful to the NAND read/write path.

Return -ETIMEDOUT when the completion wait expires. Terminate the DMA
channel before unmapping the scatterlist so the timed out transfer cannot
continue to access the buffer after the error is returned.

Fixes: 2944a44da09e ("mtd: add LPC32xx SLC NAND driver")
Cc: stable@vger.kernel.org
Reviewed-by: Vladimir Zapolskiy <vz@kernel.org>
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/nand/raw/lpc32xx_slc.c

index 3ca30e7dce33694e7d9acd4a1b1134172d21886b..10c8080207f4959a7e40fb52696d77e8e324f3be 100644 (file)
@@ -430,6 +430,7 @@ static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
        struct dma_async_tx_descriptor *desc;
        int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
        int res;
+       unsigned long time_left;
 
        host->dma_slave_config.direction = dir;
        host->dma_slave_config.src_addr = dma;
@@ -467,12 +468,19 @@ static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
        dmaengine_submit(desc);
        dma_async_issue_pending(host->dma_chan);
 
-       wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
+       time_left = wait_for_completion_timeout(&host->comp,
+                                               msecs_to_jiffies(1000));
+       if (!time_left) {
+               dmaengine_terminate_sync(host->dma_chan);
+               res = -ETIMEDOUT;
+       } else {
+               res = 0;
+       }
 
        dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
                     DMA_BIDIRECTIONAL);
 
-       return 0;
+       return res;
 out1:
        dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
                     DMA_BIDIRECTIONAL);