[PATCH v4 36/58] mtd: rawnand: renesas: retain open-handle state on removal
From: James Hilliard
Date: Fri Nov 13 2026 - 15:57:39 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.
Disconnect all chips before dropping runtime PM and transfer buffers.
Run NAND cleanup during disconnection; the final core-owned put only
releases retained allocation and layout data.
Cc: linux-renesas-soc@xxxxxxxxxxxxxxx
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/renesas-nand-controller.c | 35 +++++++++++++++++---------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/drivers/mtd/nand/raw/renesas-nand-controller.c b/drivers/mtd/nand/raw/renesas-nand-controller.c
index 135cdb67a472..8a2a55007148 100644
--- a/drivers/mtd/nand/raw/renesas-nand-controller.c
+++ b/drivers/mtd/nand/raw/renesas-nand-controller.c
@@ -1217,8 +1217,7 @@ static int rnandc_chip_init(struct rnandc *rnandc, struct device_node *np)
}
/* Alloc the driver's NAND chip structure */
- rnand = devm_kzalloc(rnandc->dev, struct_size(rnand, sels, nsels),
- GFP_KERNEL);
+ rnand = kzalloc(struct_size(rnand, sels, nsels), GFP_KERNEL);
if (!rnand)
return -ENOMEM;
@@ -1229,17 +1228,19 @@ static int rnandc_chip_init(struct rnandc *rnandc, struct device_node *np)
ret = of_property_read_u32_index(np, "reg", i, &cs);
if (ret) {
dev_err(rnandc->dev, "Incomplete reg property (%d)\n", ret);
- return ret;
+ goto free_chip;
}
if (cs >= RNANDC_CS_NUM) {
dev_err(rnandc->dev, "Invalid reg property (%d)\n", cs);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}
if (test_and_set_bit(cs, &rnandc->assigned_cs)) {
dev_err(rnandc->dev, "CS %d already assigned\n", cs);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}
/*
@@ -1257,23 +1258,29 @@ static int rnandc_chip_init(struct rnandc *rnandc, struct device_node *np)
mtd->parent_dev = rnandc->dev;
if (!mtd->name) {
dev_err(rnandc->dev, "Missing MTD label\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}
ret = nand_scan(chip, rnand->nsels);
if (ret) {
dev_err(rnandc->dev, "Failed to scan the NAND chip (%d)\n", ret);
- return ret;
+ goto free_chip;
}
ret = rnandc_alloc_dma_buf(rnandc, mtd);
if (ret)
goto cleanup_nand;
+ ret = nand_set_lifetime(chip, container_of(chip, struct rnand_chip, chip));
+ if (ret)
+ goto cleanup_nand;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(rnandc->dev, "Failed to register MTD device (%d)\n", ret);
- goto cleanup_nand;
+ nand_disconnect(chip);
+ mtd_put_master(mtd);
+ return ret;
}
list_add_tail(&rnand->node, &rnandc->chips);
@@ -1282,7 +1289,8 @@ static int rnandc_chip_init(struct rnandc *rnandc, struct device_node *np)
cleanup_nand:
nand_cleanup(chip);
-
+free_chip:
+ kfree(rnand);
return ret;
}
@@ -1296,8 +1304,9 @@ static void rnandc_chips_cleanup(struct rnandc *rnandc)
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));
}
}
@@ -1322,12 +1331,14 @@ static int rnandc_probe(struct platform_device *pdev)
struct clk *eclk;
int irq, ret;
- rnandc = devm_kzalloc(&pdev->dev, sizeof(*rnandc), GFP_KERNEL);
+ rnandc = kzalloc_obj(*rnandc);
if (!rnandc)
return -ENOMEM;
+ ret = devm_nand_controller_init(&pdev->dev, &rnandc->controller, rnandc);
+ if (ret)
+ return ret;
rnandc->dev = &pdev->dev;
- nand_controller_init(&rnandc->controller);
rnandc->controller.ops = &rnandc_ops;
INIT_LIST_HEAD(&rnandc->chips);
init_completion(&rnandc->complete);
--
2.53.0