[PATCH v4 08/58] mtd: rawnand: plat_nand: retain open-handle state on removal
From: James Hilliard
Date: Fri Nov 13 2026 - 14:29:48 EST
Unregister MTD while notifier clients can finish their I/O, then
disconnect the NAND chip before invoking the platform hardware teardown.
Run NAND cleanup while the platform is bound. Keep the chip, controller
lock and copied layout until the last MTD reference is dropped.
Handle registration failures through the same reference-counted cleanup,
since partitions can have become visible before registration fails.
Fixes: 711fdf627ce1 ("[MTD] [NAND] platform NAND driver: add driver")
Cc: David Woodhouse <dwmw2@xxxxxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxx>
Cc: Vitaly Wool <vitalywool@xxxxxxxxx>
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/plat_nand.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
index a2775886e7c4..7963ca2d4557 100644
--- a/drivers/mtd/nand/raw/plat_nand.c
+++ b/drivers/mtd/nand/raw/plat_nand.c
@@ -65,10 +65,12 @@ static int plat_nand_probe(struct platform_device *pdev)
}
/* Allocate memory for the device structure (and zero it) */
- data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data),
- GFP_KERNEL);
+ data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
+ err = devm_nand_controller_init(&pdev->dev, &data->controller, data);
+ if (err)
+ return err;
data->ready_gpio = devm_gpiod_get_optional(&pdev->dev, "ready",
GPIOD_IN);
@@ -77,7 +79,6 @@ static int plat_nand_probe(struct platform_device *pdev)
"could not get READY GPIO\n");
data->controller.ops = &plat_nand_ops;
- nand_controller_init(&data->controller);
data->chip.controller = &data->controller;
chip = &data->chip;
nand_set_controller_data(chip, data);
@@ -126,6 +127,11 @@ static int plat_nand_probe(struct platform_device *pdev)
goto out;
part_types = pdata->chip.part_probe_types;
+ err = nand_set_lifetime(chip, NULL);
+ if (err) {
+ nand_cleanup(chip);
+ goto out;
+ }
err = mtd_device_parse_register(mtd, part_types, NULL,
pdata->chip.partitions,
@@ -134,7 +140,8 @@ static int plat_nand_probe(struct platform_device *pdev)
if (!err)
return err;
- nand_cleanup(&data->chip);
+ nand_disconnect(chip);
+ mtd_put_master(mtd);
out:
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
@@ -153,9 +160,10 @@ static void plat_nand_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
+ mtd_put_master(nand_to_mtd(chip));
}
static const struct of_device_id plat_nand_match[] = {
--
2.53.0