[PATCH v10 19/26] mtd: rawnand: sunxi: scan all chips before registering MTD devices
James Hilliard
james.hilliard1 at gmail.com
Thu Nov 5 10:55:35 PST 2026
sunxi_nand_chips_init() scans and registers each NAND child before
starting the next one. Registering the first MTD device allows users to
access it while the next child is being identified on the same NFC.
Normal NAND I/O holds the controller mutex, but nand_scan_ident() does
not take it. Its RESET and READ ID operations can therefore change the
shared chip select and timing while an operation on an already
registered chip is in progress. The normal I/O can likewise interfere
with identification.
Scan all chips before registering any MTD devices. Add each successfully
scanned chip to the controller's list and track whether its MTD has been
registered, so a scan or registration failure cleans up every scanned
chip and unregisters only the devices that were successfully registered.
Fixes: 1fef62c1423b ("mtd: nand: add sunxi NAND flash controller support")
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
drivers/mtd/nand/raw/sunxi_nand.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 3de9ed6795fe..e1306d14ab3a 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -298,6 +298,7 @@ struct sunxi_nfc_oob_ops {
* @nsels: number of CS lines required by the NAND chip
* @sels: array of CS lines descriptions
* @user_data_bytes: array of user data lengths for all ECC steps
+ * @registered: whether the MTD device has been registered
*/
struct sunxi_nand_chip {
struct list_head node;
@@ -308,6 +309,7 @@ struct sunxi_nand_chip {
u32 timing_cfg;
u32 timing_ctl;
u8 *user_data_bytes;
+ bool registered;
int nsels;
struct sunxi_nand_chip_sel sels[] __counted_by(nsels);
};
@@ -2672,8 +2674,10 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
struct sunxi_nand_chip,
node);
chip = &sunxi_nand->nand;
- ret = mtd_device_unregister(nand_to_mtd(chip));
- WARN_ON(ret);
+ if (sunxi_nand->registered) {
+ ret = mtd_device_unregister(nand_to_mtd(chip));
+ WARN_ON(ret);
+ }
nand_cleanup(chip);
list_del(&sunxi_nand->node);
}
@@ -2754,13 +2758,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
if (ret)
return ret;
- ret = mtd_device_register(mtd, NULL, 0);
- if (ret) {
- dev_err(dev, "failed to register mtd device: %d\n", ret);
- nand_cleanup(nand);
- return ret;
- }
-
list_add_tail(&sunxi_nand->node, &nfc->chips);
return 0;
@@ -2768,6 +2765,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
{
+ struct sunxi_nand_chip *sunxi_nand;
struct device_node *np = dev->of_node;
int ret;
@@ -2779,6 +2777,18 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
}
}
+ /* NAND identification must finish before MTD users can access the NFC. */
+ list_for_each_entry(sunxi_nand, &nfc->chips, node) {
+ ret = mtd_device_register(nand_to_mtd(&sunxi_nand->nand), NULL, 0);
+ if (ret) {
+ dev_err(dev, "failed to register mtd device: %d\n", ret);
+ sunxi_nand_chips_cleanup(nfc);
+ return ret;
+ }
+
+ sunxi_nand->registered = true;
+ }
+
return 0;
}
--
2.53.0
More information about the linux-mtd
mailing list