Merge tag 'spi-fix-v7.1-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "This is quite a big set of fixes, almost all from Johan Hovold who is
  on an ongoing quest to clean up issues with probe and removal handling
  in drivers.

  There isn't anything too concerning here especially with the
  deregistration stuff which will very rarely get run in production
  systems since this is all platform devices in the SoC on embedded
  hardware, but it's all real issues which should be fixed. There's more
  in flight here.

  We also have a few other minor fixes, one from Felix Gu along the same
  lines as Johan's work and a couple of documentation things"

* tag 'spi-fix-v7.1-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (23 commits)
  spi: fix controller cleanup() documentation
  spi: fix resource leaks on device setup failure
  spi: axiado: clean up probe return value
  spi: axiado: rename probe error labels
  spi: axiado: fix runtime pm imbalance on probe failure
  spi: orion: clean up probe return value
  spi: orion: fix clock imbalance on registration failure
  spi: orion: fix runtime pm leak on unbind
  spi: imx: fix runtime pm leak on probe deferral
  spi: mpc52xx: fix use-after-free on registration failure
  spi: Fix the error description in the `ptp_sts_word_post` comment
  spi: topcliff-pch: fix use-after-free on unbind
  spi: topcliff-pch: fix controller deregistration
  spi: orion: fix controller deregistration
  spi: mxic: fix controller deregistration
  spi: mpc52xx: fix use-after-free on unbind
  spi: mpc52xx: fix controller deregistration
  spi: cadence-quadspi: fix controller deregistration
  spi: cadence: fix controller deregistration
  spi: mtk-snfi: fix memory leak in probe
  ...
This commit is contained in:
Linus Torvalds
2026-04-24 13:16:36 -07:00
13 changed files with 110 additions and 58 deletions

View File

@@ -59,7 +59,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
spi@4c0 {
compatible = "fsl,spi";
@@ -67,8 +67,8 @@ examples:
cell-index = <0>;
interrupts = <82 0>;
mode = "cpu";
cs-gpios = <&gpio 18 IRQ_TYPE_EDGE_RISING // device reg=<0>
&gpio 19 IRQ_TYPE_EDGE_RISING>; // device reg=<1>
cs-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>, // device reg=<0>
<&gpio 19 GPIO_ACTIVE_HIGH>; // device reg=<1>
};
...

View File

@@ -24655,8 +24655,8 @@ F: Documentation/devicetree/bindings/net/socionext,synquacer-netsec.yaml
F: drivers/net/ethernet/socionext/netsec.c
SOCIONEXT (SNI) Synquacer SPI DRIVER
M: Masahisa Kojima <masahisa.kojima@linaro.org>
M: Jassi Brar <jaswinder.singh@linaro.org>
M: Masahisa Kojima <kojima.masahisa@socionext.com>
M: Jassi Brar <jassisinghbrar@gmail.com>
L: linux-spi@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/spi/socionext,synquacer-spi.yaml

View File

@@ -751,9 +751,9 @@ static const struct spi_controller_mem_ops ax_spi_mem_ops = {
*/
static int ax_spi_probe(struct platform_device *pdev)
{
int ret = 0, irq;
struct spi_controller *ctlr;
struct ax_spi *xspi;
int ret, irq;
u32 num_cs;
ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*xspi));
@@ -785,7 +785,7 @@ static int ax_spi_probe(struct platform_device *pdev)
ret = clk_prepare_enable(xspi->ref_clk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable device clock.\n");
goto clk_dis_apb;
goto err_disable_apb;
}
pm_runtime_use_autosuspend(&pdev->dev);
@@ -815,7 +815,7 @@ static int ax_spi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
ret = -ENXIO;
goto clk_dis_all;
goto err_disable_rpm;
}
ret = devm_request_irq(&pdev->dev, irq, ax_spi_irq,
@@ -823,7 +823,7 @@ static int ax_spi_probe(struct platform_device *pdev)
if (ret != 0) {
ret = -ENXIO;
dev_err(&pdev->dev, "request_irq failed\n");
goto clk_dis_all;
goto err_disable_rpm;
}
ctlr->use_gpio_descriptors = true;
@@ -842,23 +842,26 @@ static int ax_spi_probe(struct platform_device *pdev)
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
pm_runtime_put_autosuspend(&pdev->dev);
ctlr->mem_ops = &ax_spi_mem_ops;
ret = spi_register_controller(ctlr);
if (ret) {
dev_err(&pdev->dev, "spi_register_controller failed\n");
goto clk_dis_all;
goto err_disable_rpm;
}
return ret;
pm_runtime_put_autosuspend(&pdev->dev);
clk_dis_all:
pm_runtime_set_suspended(&pdev->dev);
return 0;
err_disable_rpm:
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
clk_disable_unprepare(xspi->ref_clk);
clk_dis_apb:
err_disable_apb:
clk_disable_unprepare(xspi->pclk);
return ret;
@@ -877,10 +880,14 @@ static void ax_spi_remove(struct platform_device *pdev)
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct ax_spi *xspi = spi_controller_get_devdata(ctlr);
pm_runtime_get_sync(&pdev->dev);
spi_unregister_controller(ctlr);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
clk_disable_unprepare(xspi->ref_clk);
clk_disable_unprepare(xspi->pclk);

View File

@@ -2016,13 +2016,13 @@ static void cqspi_remove(struct platform_device *pdev)
ddata = of_device_get_match_data(dev);
spi_unregister_controller(cqspi->host);
refcount_set(&cqspi->refcount, 0);
if (!refcount_dec_and_test(&cqspi->inflight_ops))
cqspi_wait_idle(cqspi);
spi_unregister_controller(cqspi->host);
if (cqspi->rx_chan)
dma_release_channel(cqspi->rx_chan);

View File

@@ -777,6 +777,10 @@ static void cdns_spi_remove(struct platform_device *pdev)
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct cdns_spi *xspi = spi_controller_get_devdata(ctlr);
spi_controller_get(ctlr);
spi_unregister_controller(ctlr);
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
if (!spi_controller_is_target(ctlr)) {
@@ -784,7 +788,7 @@ static void cdns_spi_remove(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
}
spi_unregister_controller(ctlr);
spi_controller_put(ctlr);
}
/**

View File

@@ -2373,6 +2373,7 @@ static int spi_imx_probe(struct platform_device *pdev)
out_runtime_pm_put:
pm_runtime_dont_use_autosuspend(spi_imx->dev);
pm_runtime_disable(spi_imx->dev);
pm_runtime_put_noidle(spi_imx->dev);
pm_runtime_set_suspended(&pdev->dev);
clk_disable_unprepare(spi_imx->clk_ipg);

View File

@@ -498,6 +498,9 @@ static int mpc52xx_spi_probe(struct platform_device *op)
err_register:
dev_err(&ms->host->dev, "initialization failed\n");
free_irq(ms->irq0, ms);
free_irq(ms->irq1, ms);
cancel_work_sync(&ms->work);
err_gpio:
while (i-- > 0)
gpiod_put(ms->gpio_cs[i]);
@@ -517,15 +520,17 @@ static void mpc52xx_spi_remove(struct platform_device *op)
struct mpc52xx_spi *ms = spi_controller_get_devdata(host);
int i;
cancel_work_sync(&ms->work);
spi_unregister_controller(host);
free_irq(ms->irq0, ms);
free_irq(ms->irq1, ms);
cancel_work_sync(&ms->work);
for (i = 0; i < ms->gpio_cs_count; i++)
gpiod_put(ms->gpio_cs[i]);
kfree(ms->gpio_cs);
spi_unregister_controller(host);
iounmap(ms->regs);
spi_controller_put(host);
}

View File

@@ -1447,14 +1447,14 @@ static int mtk_snand_probe(struct platform_device *pdev)
ret = nand_ecc_register_on_host_hw_engine(&ms->ecc_eng);
if (ret) {
dev_err(&pdev->dev, "failed to register ecc engine.\n");
goto release_ecc;
goto free_buf;
}
ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine,
&ms->ecc_eng);
if (ret) {
dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n");
goto release_ecc;
goto free_buf;
}
ctlr->num_chipselect = 1;
@@ -1465,10 +1465,12 @@ static int mtk_snand_probe(struct platform_device *pdev)
ret = spi_register_controller(ctlr);
if (ret) {
dev_err(&pdev->dev, "spi_register_controller failed.\n");
goto release_ecc;
goto free_buf;
}
return 0;
free_buf:
kfree(ms->buf);
release_ecc:
mtk_ecc_release(ms->ecc);
return ret;

View File

@@ -832,9 +832,10 @@ static void mxic_spi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct mxic_spi *mxic = spi_controller_get_devdata(host);
spi_unregister_controller(host);
pm_runtime_disable(&pdev->dev);
mxic_spi_mem_ecc_remove(mxic);
spi_unregister_controller(host);
}
static const struct of_device_id mxic_spi_of_ids[] = {

View File

@@ -648,8 +648,8 @@ static int orion_spi_probe(struct platform_device *pdev)
struct orion_spi *spi;
struct resource *r;
unsigned long tclk_hz;
int status = 0;
struct device_node *np;
int status;
host = spi_alloc_host(&pdev->dev, sizeof(*spi));
if (host == NULL) {
@@ -774,6 +774,7 @@ static int orion_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev);
status = orion_spi_reset(spi);
@@ -784,10 +785,15 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status < 0)
goto out_rel_pm;
return status;
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
out_rel_pm:
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
out_rel_axi_clk:
clk_disable_unprepare(spi->axi_clk);
out:
@@ -801,11 +807,19 @@ static void orion_spi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct orion_spi *spi = spi_controller_get_devdata(host);
spi_controller_get(host);
spi_unregister_controller(host);
pm_runtime_get_sync(&pdev->dev);
clk_disable_unprepare(spi->axi_clk);
spi_unregister_controller(host);
spi_controller_put(host);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
}
MODULE_ALIAS("platform:" DRIVER_NAME);

View File

@@ -1406,8 +1406,9 @@ static void pch_spi_pd_remove(struct platform_device *plat_dev)
dev_dbg(&plat_dev->dev, "%s:[ch%d] irq=%d\n",
__func__, plat_dev->id, board_dat->pdev->irq);
if (use_dma)
pch_free_dma_buf(board_dat, data);
spi_controller_get(data->host);
spi_unregister_controller(data->host);
/* check for any pending messages; no action is taken if the queue
* is still full; but at least we tried. Unload anyway */
@@ -1432,8 +1433,12 @@ static void pch_spi_pd_remove(struct platform_device *plat_dev)
free_irq(board_dat->pdev->irq, data);
}
if (use_dma)
pch_free_dma_buf(board_dat, data);
pci_iounmap(board_dat->pdev, data->io_remap_addr);
spi_unregister_controller(data->host);
spi_controller_put(data->host);
}
#ifdef CONFIG_PM
static int pch_spi_pd_suspend(struct platform_device *pd_dev,

View File

@@ -43,6 +43,8 @@ EXPORT_TRACEPOINT_SYMBOL(spi_transfer_stop);
#include "internals.h"
static int __spi_setup(struct spi_device *spi, bool initial_setup);
static DEFINE_IDR(spi_controller_idr);
static void spidev_release(struct device *dev)
@@ -743,7 +745,7 @@ static int __spi_add_device(struct spi_device *spi, struct spi_device *parent)
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
status = spi_setup(spi);
status = __spi_setup(spi, true);
if (status < 0) {
dev_err(dev, "can't setup %s, status %d\n",
dev_name(&spi->dev), status);
@@ -4049,27 +4051,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
return status;
}
/**
* spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified
* Context: can sleep, and no requests are queued to the device
*
* SPI protocol drivers may need to update the transfer mode if the
* device doesn't work with its default. They may likewise need
* to update clock rates or word sizes from initial values. This function
* changes those settings, and must be called from a context that can sleep.
* Except for SPI_CS_HIGH, which takes effect immediately, the changes take
* effect the next time the device is selected and data is transferred to
* or from it. When this function returns, the SPI device is deselected.
*
* Note that this call will fail if the protocol driver specifies an option
* that the underlying controller or its driver does not support. For
* example, not all hardware supports wire transfers using nine bit words,
* LSB-first wire encoding, or active-high chipselects.
*
* Return: zero on success, else a negative error code.
*/
int spi_setup(struct spi_device *spi)
static int __spi_setup(struct spi_device *spi, bool initial_setup)
{
unsigned bad_bits, ugly_bits;
int status;
@@ -4154,7 +4136,7 @@ int spi_setup(struct spi_device *spi)
status = spi_set_cs_timing(spi);
if (status) {
mutex_unlock(&spi->controller->io_mutex);
return status;
goto err_cleanup;
}
if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
@@ -4163,7 +4145,7 @@ int spi_setup(struct spi_device *spi)
mutex_unlock(&spi->controller->io_mutex);
dev_err(&spi->controller->dev, "Failed to power device: %d\n",
status);
return status;
goto err_cleanup;
}
/*
@@ -4199,6 +4181,37 @@ int spi_setup(struct spi_device *spi)
status);
return status;
err_cleanup:
if (initial_setup)
spi_cleanup(spi);
return status;
}
/**
* spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified
* Context: can sleep, and no requests are queued to the device
*
* SPI protocol drivers may need to update the transfer mode if the
* device doesn't work with its default. They may likewise need
* to update clock rates or word sizes from initial values. This function
* changes those settings, and must be called from a context that can sleep.
* Except for SPI_CS_HIGH, which takes effect immediately, the changes take
* effect the next time the device is selected and data is transferred to
* or from it. When this function returns, the SPI device is deselected.
*
* Note that this call will fail if the protocol driver specifies an option
* that the underlying controller or its driver does not support. For
* example, not all hardware supports wire transfers using nine bit words,
* LSB-first wire encoding, or active-high chipselects.
*
* Return: zero on success, else a negative error code.
*/
int spi_setup(struct spi_device *spi)
{
return __spi_setup(spi, false);
}
EXPORT_SYMBOL_GPL(spi_setup);

View File

@@ -701,7 +701,7 @@ struct spi_controller {
int (*transfer)(struct spi_device *spi,
struct spi_message *mesg);
/* Called on release() to free memory provided by spi_controller */
/* Called on deregistration to free memory provided by spi_controller */
void (*cleanup)(struct spi_device *spi);
/*
@@ -1019,7 +1019,7 @@ struct spi_res {
* this value may have changed compared to what was requested, depending
* on the available snapshotting resolution (DMA transfer,
* @ptp_sts_supported is false, etc).
* @ptp_sts_word_post: See @ptp_sts_word_post. The two can be equal (meaning
* @ptp_sts_word_post: See @ptp_sts_word_pre. The two can be equal (meaning
* that a single byte should be snapshotted).
* If the core takes care of the timestamp (if @ptp_sts_supported is false
* for this controller), it will set @ptp_sts_word_pre to 0, and