[PATCH v2 14/58] mtd: rawnand: intel: retain open-handle state on removal
From: James Hilliard
Date: Tue Nov 10 2026 - 02:51:06 EST
Disconnect NAND operations after unregistering MTD and before disabling
the controller or releasing DMA channels. Retain the embedded chip,
controller lock and NAND metadata until the last MTD reference is
released, including references obtained during a partially successful
probe.
Fixes: 0b1039f016e8 ("mtd: rawnand: Add NAND controller support on Intel LGM SoC")
Cc: Ramuthevar Vadivel Murugan <vadivel.muruganx.ramuthevar@xxxxxxxxxxxxxxx>
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/intel-nand-controller.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c
index 97c82e9c1af2..19c54d3fc260 100644
--- a/drivers/mtd/nand/raw/intel-nand-controller.c
+++ b/drivers/mtd/nand/raw/intel-nand-controller.c
@@ -573,6 +573,11 @@ static void ebu_dma_cleanup(struct ebu_nand_controller *ebu_host)
dma_release_channel(ebu_host->dma_tx);
}
+static void ebu_nand_release(struct nand_controller *controller)
+{
+ kfree(container_of(controller, struct ebu_nand_controller, controller));
+}
+
static int ebu_nand_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -585,12 +590,14 @@ static int ebu_nand_probe(struct platform_device *pdev)
int ret;
u32 cs;
- ebu_host = devm_kzalloc(dev, sizeof(*ebu_host), GFP_KERNEL);
+ ebu_host = kzalloc_obj(*ebu_host);
if (!ebu_host)
return -ENOMEM;
+ ret = devm_nand_controller_init(dev, &ebu_host->controller, ebu_nand_release);
+ if (ret)
+ return ret;
ebu_host->dev = dev;
- nand_controller_init(&ebu_host->controller);
ebu_host->ebu = devm_platform_ioremap_resource_byname(pdev, "ebunand");
if (IS_ERR(ebu_host->ebu))
@@ -692,9 +699,16 @@ static int ebu_nand_probe(struct platform_device *pdev)
if (ret)
goto err_disable_nand;
- ret = mtd_device_register(mtd, NULL, 0);
+ ret = nand_set_release(nand, NULL);
if (ret)
goto err_clean_nand;
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ nand_disconnect(nand);
+ ebu_nand_disable(nand);
+ mtd_put_master(mtd);
+ goto err_cleanup_dma;
+ }
return 0;
@@ -717,9 +731,10 @@ static void ebu_nand_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(&ebu_host->chip));
WARN_ON(ret);
- nand_cleanup(&ebu_host->chip);
+ nand_disconnect(&ebu_host->chip);
ebu_nand_disable(&ebu_host->chip);
ebu_dma_cleanup(ebu_host);
+ mtd_put_master(nand_to_mtd(&ebu_host->chip));
}
static const struct of_device_id ebu_nand_match[] = {
--
2.53.0