[PATCH v4 10/58] mtd: rawnand: stm32_fmc2: retain open-handle state on removal

From: James Hilliard

Date: Fri Nov 13 2026 - 14:07:47 EST


Keep the embedded NAND chip and controller serialization state alive for
MTD references that survive unbind. Disconnect operations before
releasing DMA channels and scatterlists and asserting write protection;
run NAND cleanup during disconnection and retain the core-owned layout
and controller storage until the final reference.

Preserve immediate cleanup before publication and use the retained
lifetime after MTD registration has been attempted.

Fixes: 2cd457f328c1 ("mtd: rawnand: stm32_fmc2: add STM32 FMC2 NAND flash controller driver")
Cc: Alexandre Torgue <alexandre.torgue@xxxxxxxxxxx>
Cc: Boris Brezillon <bbrezillon@xxxxxxxxxx>
Cc: Christophe Kerello <christophe.kerello@xxxxxx>
Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
Cc: Maxime Coquelin <mcoquelin.stm32@xxxxxxxxx>
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/stm32_fmc2_nand.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
index 78af58d87960..2b8c0b467f7b 100644
--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
@@ -1915,12 +1915,14 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
int chip_cs, mem_region, ret, irq;
int start_region = 0;

- nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+ nfc = kzalloc_obj(*nfc);
if (!nfc)
return -ENOMEM;
+ ret = devm_nand_controller_init(dev, &nfc->base, nfc);
+ if (ret)
+ return ret;

nfc->dev = dev;
- nand_controller_init(&nfc->base);
nfc->base.ops = &stm32_fmc2_nfc_controller_ops;

nfc->data = of_device_get_match_data(dev);
@@ -2024,9 +2026,15 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
if (ret)
goto err_wp_enable;

- ret = mtd_device_register(mtd, NULL, 0);
+ ret = nand_set_lifetime(chip, NULL);
if (ret)
goto err_nand_cleanup;
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ nand_disconnect(chip);
+ mtd_put_master(mtd);
+ goto err_wp_enable;
+ }

platform_set_drvdata(pdev, nfc);

@@ -2061,7 +2069,7 @@ static void stm32_fmc2_nfc_remove(struct platform_device *pdev)

ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);

if (nfc->dma_ecc_ch)
dma_release_channel(nfc->dma_ecc_ch);
@@ -2074,6 +2082,7 @@ static void stm32_fmc2_nfc_remove(struct platform_device *pdev)
sg_free_table(&nfc->dma_ecc_sg);

stm32_fmc2_nfc_wp_enable(nand);
+ mtd_put_master(nand_to_mtd(chip));
}

static int stm32_fmc2_nfc_suspend(struct device *dev)

--
2.53.0