mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 01:08:13 -04:00
mtd: rawnand: lpc32xx_mlc: fail DMA transfers on timeout
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: 70f7cb78ec ("mtd: add LPC32xx MLC 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>
This commit is contained in:
committed by
Miquel Raynal
parent
9d4af746af
commit
dbf590b662
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user