[PATCH v4 09/58] mtd: rawnand: gpio: retain open-handle state on removal
From: James Hilliard
Date: Fri Nov 13 2026 - 15:27:14 EST
A retained MTD handle can outlive GPIO NAND unbind. Drain and disconnect
NAND operations before disabling the chip, and keep the chip metadata
and controller lock alive until the final MTD reference is released.
GPIO and MMIO resources are still released during unbind.
Also release scanned NAND metadata when MTD registration fails, using
retained ownership once a device could have been published.
Run NAND cleanup during disconnection; the final core-owned put only
releases retained allocation and layout data.
Fixes: aaf7ea200004 ("[MTD] [NAND] GPIO NAND flash driver")
Cc: David Woodhouse <David.Woodhouse@xxxxxxxxx>
Cc: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx>
Cc: Mike Rapoport <rppt@xxxxxxxxxx>
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/gpio.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
index d17fb2244923..2a8c44865636 100644
--- a/drivers/mtd/nand/raw/gpio.c
+++ b/drivers/mtd/nand/raw/gpio.c
@@ -273,13 +273,14 @@ static void gpio_nand_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);
/* Enable write protection and disable the chip */
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
gpiod_set_value(gpiomtd->nwp, 0);
if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
gpiod_set_value(gpiomtd->nce, 0);
+ mtd_put_master(nand_to_mtd(chip));
}
static int gpio_nand_probe(struct platform_device *pdev)
@@ -294,9 +295,12 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (!dev->of_node && !dev_get_platdata(dev))
return -EINVAL;
- gpiomtd = devm_kzalloc(dev, sizeof(*gpiomtd), GFP_KERNEL);
+ gpiomtd = kzalloc_obj(*gpiomtd);
if (!gpiomtd)
return -ENOMEM;
+ ret = devm_nand_controller_init(dev, &gpiomtd->base, gpiomtd);
+ if (ret)
+ return ret;
chip = &gpiomtd->nand_chip;
@@ -345,7 +349,6 @@ static int gpio_nand_probe(struct platform_device *pdev)
goto out_ce;
}
- nand_controller_init(&gpiomtd->base);
gpiomtd->base.ops = &gpio_nand_ops;
nand_set_flash_node(chip, pdev->dev.of_node);
@@ -374,11 +377,18 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (gpiomtd->plat.adjust_parts)
gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
+ ret = nand_set_lifetime(chip, NULL);
+ if (ret) {
+ nand_cleanup(chip);
+ goto err_wp;
+ }
ret = mtd_device_register(mtd, gpiomtd->plat.parts,
gpiomtd->plat.num_parts);
if (!ret)
return 0;
+ nand_disconnect(chip);
+ mtd_put_master(mtd);
err_wp:
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
--
2.53.0