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

From: James Hilliard

Date: Fri Nov 13 2026 - 16:03:38 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.

Retain the layout metadata used by OOB queries and unlink before put.

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/marvell_nand.c | 44 ++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index 56350209f7e0..7bd5537d6b62 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2630,9 +2630,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
}

/* Alloc the nand chip structure */
- marvell_nand = devm_kzalloc(dev,
- struct_size(marvell_nand, sels, nsels),
- GFP_KERNEL);
+ marvell_nand = kzalloc(struct_size(marvell_nand, sels, nsels), GFP_KERNEL);
if (!marvell_nand) {
dev_err(dev, "could not allocate chip structure\n");
return -ENOMEM;
@@ -2654,19 +2652,21 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
if (ret) {
dev_err(dev, "could not retrieve reg property: %d\n",
ret);
- return ret;
+ goto free_chip;
}
}

if (cs >= nfc->caps->max_cs_nb) {
dev_err(dev, "invalid reg value: %u (max CS = %d)\n",
cs, nfc->caps->max_cs_nb);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}

if (test_and_set_bit(cs, &nfc->assigned_cs)) {
dev_err(dev, "CS %d already assigned\n", cs);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}

/*
@@ -2688,7 +2688,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
marvell_nand->sels[i].ndcb0_csel = NDCB0_CSEL;
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}

/* Retrieve RB id */
@@ -2702,14 +2703,15 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
dev_err(dev,
"could not retrieve RB property: %d\n",
ret);
- return ret;
+ goto free_chip;
}
}

if (rb >= nfc->caps->max_rb_nb) {
dev_err(dev, "invalid reg value: %u (max RB = %d)\n",
rb, nfc->caps->max_rb_nb);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}

marvell_nand->sels[i].rb = rb;
@@ -2737,9 +2739,14 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
ret = nand_scan(chip, marvell_nand->nsels);
if (ret) {
dev_err(dev, "could not scan the nand chip\n");
- return ret;
+ goto free_chip;
}

+ ret = nand_set_lifetime(chip, container_of(chip, struct marvell_nand_chip, chip));
+ if (ret) {
+ nand_cleanup(chip);
+ goto free_chip;
+ }
if (pdata)
/* Legacy bindings support only one chip */
ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
@@ -2747,13 +2754,18 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);
+ mtd_put_master(mtd);
return ret;
}

list_add_tail(&marvell_nand->node, &nfc->chips);

return 0;
+
+free_chip:
+ kfree(marvell_nand);
+ return ret;
}

static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
@@ -2766,8 +2778,9 @@ static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
chip = &entry->chip;
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);
list_del(&entry->node);
+ mtd_put_master(nand_to_mtd(chip));
}
}

@@ -2939,13 +2952,14 @@ static int marvell_nfc_probe(struct platform_device *pdev)
int ret;
int irq;

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

nfc->dev = dev;
- nand_controller_init(&nfc->controller);
nfc->controller.ops = &marvell_nand_controller_ops;
INIT_LIST_HEAD(&nfc->chips);


--
2.53.0