[PATCH v9 06/18] mtd: rawnand: sunxi: stop failed program operations and disable ECC
From: James Hilliard
Date: Sat Oct 17 2026 - 15:48:20 EST
A page program has three stages: send the setup command and address,
transfer the data with ECC, then send PAGEPROG to commit it and check
the NAND status. The PIO page/subpage and DMA page writers ignore the
return from nand_prog_page_begin_op(). A FIFO or command-completion
timeout can therefore be followed by data transfers and PAGEPROG, with a
later success hiding the original setup failure.
Check setup before enabling ECC or transferring data. DMA preparation
occurs before setup and may already have queued a descriptor and mapped
the buffer, so use its existing abort and cleanup helpers before
returning that error.
The PIO writers also return directly when a chunk reports failure,
leaving ECC enabled for the next controller operation. Route those exits
through ECC disable, preserve the reported error and skip program-end.
Keep the successful setup/transfer/confirm sequence unchanged; this
patch does not add a new controller-reset or NAND-abort policy.
Fixes: 1fef62c1423b ("mtd: nand: add sunxi NAND flash controller support")
Fixes: 25f815f66a14 ("mtd: nand: force drivers to explicitly send READ/PROG commands")
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/sunxi_nand.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 5b736a4a7fe9..1db6ee18594a 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1614,11 +1614,13 @@ static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand,
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct mtd_info *mtd = nand_to_mtd(nand);
struct nand_ecc_ctrl *ecc = &nand->ecc;
- int ret, i, cur_off = 0;
+ int ret = 0, i, cur_off = 0;
sunxi_nfc_select_chip(nand, nand->cur_cs);
- nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+ ret = nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+ if (ret)
+ return ret;
sunxi_nfc_hw_ecc_enable(nand);
@@ -1633,14 +1635,17 @@ static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand,
oob_off + mtd->writesize,
&cur_off, i, page);
if (ret)
- return ret;
+ goto out;
}
if (oob_required || (nand->options & NAND_NEED_SCRAMBLING))
sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi,
&cur_off, page);
+out:
sunxi_nfc_hw_ecc_disable(nand);
+ if (ret)
+ return ret;
return nand_prog_page_end_op(nand);
}
@@ -1654,11 +1659,13 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *nand,
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct mtd_info *mtd = nand_to_mtd(nand);
struct nand_ecc_ctrl *ecc = &nand->ecc;
- int ret, i, cur_off = 0;
+ int ret = 0, i, cur_off = 0;
sunxi_nfc_select_chip(nand, nand->cur_cs);
- nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+ ret = nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+ if (ret)
+ return ret;
sunxi_nfc_hw_ecc_enable(nand);
@@ -1674,10 +1681,13 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *nand,
oob_off + mtd->writesize,
&cur_off, i, page);
if (ret)
- return ret;
+ goto out;
}
+out:
sunxi_nfc_hw_ecc_disable(nand);
+ if (ret)
+ return ret;
return nand_prog_page_end_op(nand);
}
@@ -1718,7 +1728,12 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
reg_index += user_data_sz / 4;
}
- nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+ ret = nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+ if (ret) {
+ sunxi_nfc_dma_op_abort(nfc);
+ sunxi_nfc_dma_op_cleanup(nfc, DMA_TO_DEVICE, &sg);
+ return ret;
+ }
sunxi_nfc_hw_ecc_enable(nand);
sunxi_nfc_randomizer_config(nand, page, false);
--
2.53.0