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

From: James Hilliard

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

Free DMA memory in the synchronous NAND detach callback while the PCI
resources are available.

Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/cafe_nand.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
index e936c9807bf8..be29e78d6408 100644
--- a/drivers/mtd/nand/raw/cafe_nand.c
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -683,6 +683,10 @@ static int cafe_nand_probe(struct pci_dev *pdev,
err = -ENOMEM;
goto out_disable_device;
}
+ cafe->nand.controller = &cafe->nand.legacy.dummy_controller;
+ err = devm_nand_controller_init(&pdev->dev, cafe->nand.controller, cafe);
+ if (err)
+ goto out_disable_device;

mtd = nand_to_mtd(&cafe->nand);
mtd->parent_dev = &pdev->dev;
@@ -693,7 +697,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
if (!cafe->mmio) {
dev_warn(&pdev->dev, "failed to iomap\n");
err = -ENOMEM;
- goto out_free_mtd;
+ goto out_disable_device;
}

cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
@@ -785,9 +789,15 @@ static int cafe_nand_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mtd);

mtd->name = "cafe_nand";
- err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+ err = nand_set_lifetime(&cafe->nand, NULL);
if (err)
goto out_cleanup_nand;
+ err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+ if (err) {
+ nand_disconnect(&cafe->nand);
+ mtd_put_master(mtd);
+ goto out_irq;
+ }

goto out;

@@ -801,8 +811,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
free_rs(cafe->rs);
out_ior:
pci_iounmap(pdev, cafe->mmio);
- out_free_mtd:
- kfree(cafe);
out_disable_device:
pci_disable_device(pdev);
out:
@@ -816,17 +824,16 @@ static void cafe_nand_remove(struct pci_dev *pdev)
struct cafe_priv *cafe = nand_get_controller_data(chip);
int ret;

+ ret = mtd_device_unregister(mtd);
+ WARN_ON(ret);
+ nand_disconnect(chip);
/* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
free_irq(pdev->irq, mtd);
- ret = mtd_device_unregister(mtd);
- WARN_ON(ret);
- nand_cleanup(chip);
free_rs(cafe->rs);
pci_iounmap(pdev, cafe->mmio);
- dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
- kfree(cafe);
pci_disable_device(pdev);
+ mtd_put_master(mtd);
}

static const struct pci_device_id cafe_nand_tbl[] = {

--
2.53.0