[PATCH v4 32/58] mtd: rawnand: fsmc: retain open-handle state on removal
From: James Hilliard
Date: Fri Nov 13 2026 - 15:50:32 EST
Keep chip metadata and controller storage alive until the final MTD
reference is released. Unregister and disconnect each published chip
before releasing the resources used by its hardware operations.
Disconnect before controller disable and DMA channel release.
Run NAND cleanup during disconnection; the final core-owned put only
releases retained allocation and layout data.
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/fsmc_nand.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index 3cd25395d791..264a2570f40c 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -1037,9 +1037,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
int i;
/* Allocate memory for the device structure (and zero it) */
- host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+ host = kzalloc_obj(*host);
if (!host)
return -ENOMEM;
+ ret = devm_nand_controller_init(&pdev->dev, &host->base, host);
+ if (ret)
+ return ret;
nand = &host->nand;
@@ -1128,7 +1131,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
nand->options |= NAND_KEEP_TIMINGS;
}
- nand_controller_init(&host->base);
host->base.ops = &fsmc_nand_controller_ops;
nand->controller = &host->base;
@@ -1140,9 +1142,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
goto release_dma_write_chan;
mtd->name = "nand";
- ret = mtd_device_register(mtd, NULL, 0);
+ ret = nand_set_lifetime(nand, NULL);
if (ret)
goto cleanup_nand;
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ nand_disconnect(nand);
+ mtd_put_master(mtd);
+ goto release_dma_write_chan;
+ }
platform_set_drvdata(pdev, host);
dev_info(&pdev->dev, "FSMC NAND driver registration successful\n");
@@ -1176,13 +1184,14 @@ static void fsmc_nand_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);
fsmc_nand_disable(host);
if (host->mode == USE_DMA_ACCESS) {
dma_release_channel(host->write_dma_chan);
dma_release_channel(host->read_dma_chan);
}
+ mtd_put_master(nand_to_mtd(chip));
}
}
--
2.53.0