spi: fsl-qspi: use devm function instead of driver remove
authorHan Xu <han.xu@nxp.com>
Wed, 26 Mar 2025 22:41:51 +0000 (17:41 -0500)
committerMark Brown <broonie@kernel.org>
Thu, 27 Mar 2025 19:02:29 +0000 (19:02 +0000)
Driver use devm APIs to manage clk/irq/resources and register the spi
controller, but the legacy remove function will be called first during
device detach and trigger kernel panic. Drop the remove function and use
devm_add_action_or_reset() for driver cleanup to ensure the release
sequence.

Trigger kernel panic on i.MX8MQ by
echo 30bb0000.spi >/sys/bus/platform/drivers/fsl-quadspi/unbind

Cc: stable@vger.kernel.org
Fixes: 8fcb830a00f0 ("spi: spi-fsl-qspi: use devm_spi_register_controller")
Reported-by: Kevin Hao <haokexin@gmail.com>
Signed-off-by: Han Xu <han.xu@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20250326224152.2147099-1-han.xu@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-fsl-qspi.c

index 355e6a39fb41896f460e2474a90b8f0b42068ff3..5c59fddb32c1b9cc030e7abb49484662ec7b382c 100644 (file)
@@ -844,6 +844,19 @@ static const struct spi_controller_mem_caps fsl_qspi_mem_caps = {
        .per_op_freq = true,
 };
 
+static void fsl_qspi_cleanup(void *data)
+{
+       struct fsl_qspi *q = data;
+
+       /* disable the hardware */
+       qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+       qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
+
+       fsl_qspi_clk_disable_unprep(q);
+
+       mutex_destroy(&q->lock);
+}
+
 static int fsl_qspi_probe(struct platform_device *pdev)
 {
        struct spi_controller *ctlr;
@@ -934,6 +947,10 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 
        ctlr->dev.of_node = np;
 
+       ret = devm_add_action_or_reset(dev, fsl_qspi_cleanup, q);
+       if (ret)
+               goto err_destroy_mutex;
+
        ret = devm_spi_register_controller(dev, ctlr);
        if (ret)
                goto err_destroy_mutex;
@@ -953,19 +970,6 @@ err_put_ctrl:
        return ret;
 }
 
-static void fsl_qspi_remove(struct platform_device *pdev)
-{
-       struct fsl_qspi *q = platform_get_drvdata(pdev);
-
-       /* disable the hardware */
-       qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
-       qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
-
-       fsl_qspi_clk_disable_unprep(q);
-
-       mutex_destroy(&q->lock);
-}
-
 static int fsl_qspi_suspend(struct device *dev)
 {
        return 0;
@@ -1003,7 +1007,6 @@ static struct platform_driver fsl_qspi_driver = {
                .pm =   &fsl_qspi_pm_ops,
        },
        .probe          = fsl_qspi_probe,
-       .remove         = fsl_qspi_remove,
 };
 module_platform_driver(fsl_qspi_driver);