[PATCH 16/58] mtd: rawnand: mtk: retain chips across controller removal
James Hilliard
james.hilliard1 at gmail.com
Sat Nov 7 02:16:13 PST 2026
Give scanned chips their own storage lifetime and retain the shared
controller until all chip references have been dropped. Unregister and
disconnect each chip before releasing the ECC provider and clocks.
Unlink chips before the final put and unwind unpublished allocations
directly.
Fixes: 1d6b1e464950 ("mtd: mediatek: driver for MTK Smart Device")
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
drivers/mtd/nand/raw/mtk_nand.c | 44 +++++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 10 deletions(-)
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 21c7e1102746..bdc3d1519631 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -1336,6 +1336,11 @@ static const struct nand_controller_ops mtk_nfc_controller_ops = {
.exec_op = mtk_nfc_exec_op,
};
+static void mtk_nfc_nand_release(struct nand_chip *nand)
+{
+ kfree(container_of(nand, struct mtk_nfc_nand_chip, nand));
+}
+
static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
struct device_node *np)
{
@@ -1356,8 +1361,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
return -EINVAL;
}
- chip = devm_kzalloc(dev, struct_size(chip, sels, nsels),
- GFP_KERNEL);
+ chip = kzalloc(struct_size(chip, sels, nsels), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -1366,17 +1370,19 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
ret = of_property_read_u32_index(np, "reg", i, &tmp);
if (ret) {
dev_err(dev, "reg property failure : %d\n", ret);
- return ret;
+ goto free_chip;
}
if (tmp >= MTK_NAND_MAX_NSELS) {
dev_err(dev, "invalid CS: %u\n", tmp);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}
if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
dev_err(dev, "CS %u already assigned\n", tmp);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_chip;
}
chip->sels[i] = tmp;
@@ -1415,18 +1421,28 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
ret = nand_scan(nand, nsels);
if (ret)
- return ret;
+ goto free_chip;
+ ret = nand_set_release(nand, mtk_nfc_nand_release);
+ if (ret) {
+ nand_cleanup(nand);
+ goto free_chip;
+ }
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "mtd parse partition error\n");
- nand_cleanup(nand);
+ nand_disconnect(nand);
+ mtd_put_master(mtd);
return ret;
}
list_add_tail(&chip->node, &nfc->chips);
return 0;
+
+free_chip:
+ kfree(chip);
+ return ret;
}
static void mtk_nfc_nand_chips_cleanup(struct mtk_nfc *nfc)
@@ -1441,8 +1457,9 @@ static void mtk_nfc_nand_chips_cleanup(struct mtk_nfc *nfc)
chip = &mtk_chip->nand;
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);
list_del(&mtk_chip->node);
+ mtd_put_master(nand_to_mtd(chip));
}
}
@@ -1504,6 +1521,11 @@ static const struct of_device_id mtk_nfc_id_table[] = {
};
MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
+static void mtk_nfc_release(struct nand_controller *controller)
+{
+ kfree(container_of(controller, struct mtk_nfc, controller));
+}
+
static int mtk_nfc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1511,11 +1533,13 @@ static int mtk_nfc_probe(struct platform_device *pdev)
struct mtk_nfc *nfc;
int ret, irq;
- nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+ nfc = kzalloc_obj(*nfc);
if (!nfc)
return -ENOMEM;
- nand_controller_init(&nfc->controller);
+ ret = devm_nand_controller_init(dev, &nfc->controller, mtk_nfc_release);
+ if (ret)
+ return ret;
INIT_LIST_HEAD(&nfc->chips);
nfc->controller.ops = &mtk_nfc_controller_ops;
--
2.53.0
More information about the linux-mtd
mailing list