| From cb9c4ef2cdebd6e556ad080d2c14555449da11d3 Mon Sep 17 00:00:00 2001 |
| From: Lukas Wunner <lukas@wunner.de> |
| Date: Fri, 15 May 2020 17:58:03 +0200 |
| Subject: [PATCH] spi: bcm2835aux: Fix controller unregister order |
| |
| commit b9dd3f6d417258ad0beeb292a1bc74200149f15d upstream. |
| |
| The BCM2835aux SPI driver uses devm_spi_register_master() on bind. |
| As a consequence, on unbind, __device_release_driver() first invokes |
| bcm2835aux_spi_remove() before unregistering the SPI controller via |
| devres_release_all(). |
| |
| This order is incorrect: bcm2835aux_spi_remove() turns off the SPI |
| controller, including its interrupts and clock. The SPI controller |
| is thus no longer usable. |
| |
| When the SPI controller is subsequently unregistered, it unbinds all |
| its slave devices. If their drivers need to access the SPI bus, |
| e.g. to quiesce their interrupts, unbinding will fail. |
| |
| As a rule, devm_spi_register_master() must not be used if the |
| ->remove() hook performs teardown steps which shall be performed |
| after unbinding of slaves. |
| |
| Fix by using the non-devm variant spi_register_master(). Note that the |
| struct spi_master as well as the driver-private data are not freed until |
| after bcm2835aux_spi_remove() has finished, so accessing them is safe. |
| |
| Fixes: 1ea29b39f4c8 ("spi: bcm2835aux: add bcm2835 auxiliary spi device driver") |
| Signed-off-by: Lukas Wunner <lukas@wunner.de> |
| Cc: stable@vger.kernel.org # v4.4+ |
| Cc: Martin Sperl <kernel@martin.sperl.org> |
| Link: https://lore.kernel.org/r/32f27f4d8242e4d75f9a53f7e8f1f77483b08669.1589557526.git.lukas@wunner.de |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c |
| index 40dfb7f58efe..bc2a85ad8e89 100644 |
| --- a/drivers/spi/spi-bcm2835aux.c |
| +++ b/drivers/spi/spi-bcm2835aux.c |
| @@ -574,7 +574,7 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev) |
| goto out_clk_disable; |
| } |
| |
| - err = devm_spi_register_master(&pdev->dev, master); |
| + err = spi_register_master(master); |
| if (err) { |
| dev_err(&pdev->dev, "could not register SPI master: %d\n", err); |
| goto out_clk_disable; |
| @@ -598,6 +598,8 @@ static int bcm2835aux_spi_remove(struct platform_device *pdev) |
| |
| bcm2835aux_debugfs_remove(bs); |
| |
| + spi_unregister_master(master); |
| + |
| bcm2835aux_spi_reset_hw(bs); |
| |
| /* disable the HW block by releasing the clock */ |
| -- |
| 2.27.0 |
| |