[PATCH 35/58] mtd: rawnand: marvell: retain open-handle state on removal
From: James Hilliard
Date: Sat Nov 07 2026 - 15:14:49 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.
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/marvell_nand.c | 54 ++++++++++++++++++++++++++-----------
1 file changed, 39 insertions(+), 15 deletions(-)
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index 38b7eb5b992c..f3967024411c 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2600,6 +2600,11 @@ static const struct nand_controller_ops marvell_nand_controller_ops = {
.setup_interface = marvell_nfc_setup_interface,
};
+static void marvell_nand_release(struct nand_chip *chip)
+{
+ kfree(container_of(chip, struct marvell_nand_chip, chip));
+}
+
static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
struct device_node *np)
{
@@ -2630,9 +2635,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 +2657,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 +2693,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 +2708,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 +2744,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_release(chip, marvell_nand_release);
+ 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 +2759,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 +2783,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));
}
}
@@ -2932,6 +2950,11 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
return 0;
}
+static void marvell_nfc_release(struct nand_controller *controller)
+{
+ kfree(container_of(controller, struct marvell_nfc, controller));
+}
+
static int marvell_nfc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -2939,13 +2962,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, marvell_nfc_release);
+ 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