diff mbox series

spi: fsl-qspi: use devm function instead of driver remove

Message ID 20250326224152.2147099-1-han.xu@nxp.com (mailing list archive)
State Accepted
Commit 40369bfe717e96e26650eeecfa5a6363563df6e4
Headers show
Series spi: fsl-qspi: use devm function instead of driver remove | expand

Commit Message

Han Xu March 26, 2025, 10:41 p.m. UTC
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>
---
 drivers/spi/spi-fsl-qspi.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

Comments

Frank Li March 27, 2025, 3:45 p.m. UTC | #1
On Wed, Mar 26, 2025 at 05:41:51PM -0500, Han Xu wrote:
> 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>

> ---
>  drivers/spi/spi-fsl-qspi.c | 31 +++++++++++++++++--------------
>  1 file changed, 17 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
> index 355e6a39fb418..5c59fddb32c1b 100644
> --- a/drivers/spi/spi-fsl-qspi.c
> +++ b/drivers/spi/spi-fsl-qspi.c
> @@ -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;
> +

Look like needn't goto err_destroy_mutex. it should be enough

	if (ret)
		return ret;

Orginal error path:

err_destroy_mutex:
        mutex_destroy(&q->lock);    // already in fsl_qspi_cleanup()

err_disable_clk:
        fsl_qspi_clk_disable_unprep(q); // already in fsl_qspi_cleanup()

err_put_ctrl:
        spi_controller_put(ctlr); // suppose it is wrong, devm_spi_register_controller()
should consider it.


Frank

>  	ret = devm_spi_register_controller(dev, ctlr);
>  	if (ret)
>  		goto err_destroy_mutex;
> @@ -953,19 +970,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
>  	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);
>
> --
> 2.34.1
>
Mark Brown March 27, 2025, 9:11 p.m. UTC | #2
On Wed, 26 Mar 2025 17:41:51 -0500, Han Xu wrote:
> 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
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/1] spi: fsl-qspi: use devm function instead of driver remove
      commit: 40369bfe717e96e26650eeecfa5a6363563df6e4

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark
diff mbox series

Patch

diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
index 355e6a39fb418..5c59fddb32c1b 100644
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -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 @@  static int fsl_qspi_probe(struct platform_device *pdev)
 	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);