[PATCH 57/58] mtd: rawnand: cs553x: retain chip state across removal

From: James Hilliard

Date: Sat Nov 07 2026 - 15:22:32 EST


Keep chip metadata alive while MTD device references remain after module
removal unregisters the device. Disconnect before unmapping the
controller, and release the backing allocation at the final MTD put.

Check registration failures and release the corresponding controller
without leaving it in the registered-device array.

Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/cs553x_nand.c | 46 ++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
index 0b872b1e3b04..7419308a740d 100644
--- a/drivers/mtd/nand/raw/cs553x_nand.c
+++ b/drivers/mtd/nand/raw/cs553x_nand.c
@@ -257,12 +257,18 @@ static const struct nand_controller_ops cs553x_nand_controller_ops = {
.attach_chip = cs553x_attach_chip,
};

+static void cs553x_chip_release(struct nand_chip *chip)
+{
+ kfree(container_of(chip, struct cs553x_nand_controller, chip));
+}
+
static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
{
struct cs553x_nand_controller *controller;
int err = 0;
struct nand_chip *this;
struct mtd_info *new_mtd;
+ const char *name;

pr_notice("Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n",
cs, mmio ? "MM" : "P", adr);
@@ -309,6 +315,13 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
err = nand_scan(this, 1);
if (err)
goto out_free;
+ name = new_mtd->name;
+ err = nand_set_release(this, cs553x_chip_release);
+ if (err) {
+ nand_cleanup(this);
+ goto out_free;
+ }
+ kfree(name);

controllers[cs] = controller;
goto out;
@@ -344,6 +357,7 @@ static int __init cs553x_init(void)
{
int err = -ENXIO;
int i;
+ int registered = 0;
uint64_t val;

/* If the CPU isn't a Geode GX or LX, abort */
@@ -374,14 +388,22 @@ static int __init cs553x_init(void)
do mtdconcat etc. if we want to. */
for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
if (controllers[i]) {
- /* If any devices registered, return success. Else the last error. */
- mtd_device_register(nand_to_mtd(&controllers[i]->chip),
- NULL, 0);
- err = 0;
+ struct cs553x_nand_controller *controller = controllers[i];
+ struct mtd_info *mtd = nand_to_mtd(&controller->chip);
+
+ err = mtd_device_register(mtd, NULL, 0);
+ if (err) {
+ nand_disconnect(&controller->chip);
+ iounmap(controller->mmio);
+ controllers[i] = NULL;
+ mtd_put_master(mtd);
+ } else {
+ registered++;
+ }
}
}

- return err;
+ return registered ? 0 : err;
}

module_init(cs553x_init);
@@ -392,25 +414,25 @@ static void __exit cs553x_cleanup(void)

for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
struct cs553x_nand_controller *controller = controllers[i];
- struct nand_chip *this = &controller->chip;
- struct mtd_info *mtd = nand_to_mtd(this);
+ struct nand_chip *this;
+ struct mtd_info *mtd;
int ret;

- if (!mtd)
+ if (!controller)
continue;
+ this = &controller->chip;
+ mtd = nand_to_mtd(this);

/* Release resources, unregister device */
ret = mtd_device_unregister(mtd);
WARN_ON(ret);
- nand_cleanup(this);
- kfree(mtd->name);
+ nand_disconnect(this);
controllers[i] = NULL;

/* unmap physical address */
iounmap(controller->mmio);

- /* Free the MTD device structure */
- kfree(controller);
+ mtd_put_master(mtd);
}
}


--
2.53.0