[PATCH 15/58] mtd: rawnand: tegra: retain open-handle state on removal
James Hilliard
james.hilliard1 at gmail.com
Sat Nov 7 02:16:12 PST 2026
Retain the chip and controller allocations until their final MTD
references are released. Disconnect the chip before suspending the
controller so retained handles cannot reach powered-down hardware. Leave
metadata cleanup to the final put, including registration-failure
unwinding.
Fixes: d7d9f8ec77fe ("mtd: rawnand: add NVIDIA Tegra NAND Flash controller driver")
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
drivers/mtd/nand/raw/tegra_nand.c | 37 ++++++++++++++++++++++++++++++-------
1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c
index 7f9eb5f042a7..da7791741b9d 100644
--- a/drivers/mtd/nand/raw/tegra_nand.c
+++ b/drivers/mtd/nand/raw/tegra_nand.c
@@ -1064,6 +1064,11 @@ static const struct nand_controller_ops tegra_nand_controller_ops = {
.setup_interface = tegra_nand_setup_interface,
};
+static void tegra_nand_chip_release(struct nand_chip *chip)
+{
+ kfree(container_of(chip, struct tegra_nand_chip, chip));
+}
+
static int tegra_nand_chips_init(struct device *dev,
struct tegra_nand_controller *ctrl)
{
@@ -1096,7 +1101,7 @@ static int tegra_nand_chips_init(struct device *dev,
return ret;
}
- nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
+ nand = kzalloc_obj(*nand);
if (!nand)
return -ENOMEM;
@@ -1107,7 +1112,7 @@ static int tegra_nand_chips_init(struct device *dev,
if (IS_ERR(nand->wp_gpio)) {
ret = PTR_ERR(nand->wp_gpio);
dev_err(dev, "Failed to request WP GPIO: %d\n", ret);
- return ret;
+ goto free_chip;
}
chip = &nand->chip;
@@ -1127,20 +1132,35 @@ static int tegra_nand_chips_init(struct device *dev,
ret = nand_scan(chip, 1);
if (ret)
- return ret;
+ goto free_chip;
mtd_ooblayout_ecc(mtd, 0, &nand->ecc);
+ ret = nand_set_release(chip, tegra_nand_chip_release);
+ if (ret) {
+ nand_cleanup(chip);
+ goto free_chip;
+ }
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;
}
ctrl->chip = chip;
return 0;
+
+free_chip:
+ kfree(nand);
+ return ret;
+}
+
+static void tegra_nand_release(struct nand_controller *controller)
+{
+ kfree(container_of(controller, struct tegra_nand_controller, controller));
}
static int tegra_nand_probe(struct platform_device *pdev)
@@ -1149,13 +1169,15 @@ static int tegra_nand_probe(struct platform_device *pdev)
struct tegra_nand_controller *ctrl;
int err = 0;
- ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
+ ctrl = kzalloc_obj(*ctrl);
if (!ctrl)
return -ENOMEM;
+ err = devm_nand_controller_init(&pdev->dev, &ctrl->controller, tegra_nand_release);
+ if (err)
+ return err;
ctrl->dev = &pdev->dev;
platform_set_drvdata(pdev, ctrl);
- nand_controller_init(&ctrl->controller);
ctrl->controller.ops = &tegra_nand_controller_ops;
ctrl->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -1232,10 +1254,11 @@ static void tegra_nand_remove(struct platform_device *pdev)
WARN_ON(mtd_device_unregister(mtd));
- nand_cleanup(chip);
+ nand_disconnect(chip);
pm_runtime_put_sync_suspend(ctrl->dev);
pm_runtime_force_suspend(ctrl->dev);
+ mtd_put_master(mtd);
}
static int __maybe_unused tegra_nand_runtime_resume(struct device *dev)
--
2.53.0
More information about the linux-mtd
mailing list