* [PATCH v3] spi: atmel: fix DMA channel and bounce buffer leaks
@ 2026-05-22 12:40 Felix Gu
2026-06-01 14:03 ` Mark Brown
0 siblings, 1 reply; 2+ messages in thread
From: Felix Gu @ 2026-05-22 12:40 UTC (permalink / raw)
To: Ryan Wanner, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Radu Pirea, Richard Genoud
Cc: linux-spi, linux-arm-kernel, linux-kernel, Felix Gu
The original code set use_dma to false when dma_alloc_coherent() for
bounce buffers failed, but DMA channels acquired earlier via
atmel_spi_configure_dma() were never freed.
When devm_request_irq() or clk_prepare_enable() failed later in probe,
the driver also did not release DMA channels or bounce buffers already
allocated.
The out_free_dma error path released DMA channels but did not free the
bounce buffers.
Fix by moving bounce buffer allocation into atmel_spi_configure_dma()
and registering the devres cleanup for DMA channels and bounce buffers.
Fixes: a9889ed62d06 ("spi: atmel: Implements transfers with bounce buffer")
Signed-off-by: Felix Gu <ustc.gu@gmail•com>
---
Changes in v3:
- Fix Mark's comment.
- Link to v2: https://patch.msgid.link/20260517-atmel-v2-1-36c836be6345@gmail.com
Changes in v2:
- Switch to devm-managed variants to fix Claudiu Beznea's comment.
- Link to v1: https://patch.msgid.link/20260516-atmel-v1-0-674fb4707af6@gmail.com
To: Ryan Wanner <ryan.wanner@microchip•com>
To: Mark Brown <broonie@kernel•org>
To: Nicolas Ferre <nicolas.ferre@microchip•com>
To: Alexandre Belloni <alexandre.belloni@bootlin•com>
To: Claudiu Beznea <claudiu.beznea@tuxon•dev>
To: Radu Pirea <radu.pirea@microchip•com>
Cc: linux-spi@vger•kernel.org
Cc: linux-arm-kernel@lists•infradead.org
Cc: linux-kernel@vger•kernel.org
---
drivers/spi/spi-atmel.c | 133 +++++++++++++++++++++++++-----------------------
1 file changed, 68 insertions(+), 65 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 25aa294631c8..c8012c82c3a7 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -559,6 +559,38 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
return err;
}
+static void atmel_spi_release_dma(void *data)
+{
+ struct spi_controller *host = data;
+ struct atmel_spi *as = spi_controller_get_devdata(host);
+ struct device *dev = &as->pdev->dev;
+
+ if (host->dma_tx) {
+ dma_release_channel(host->dma_tx);
+ host->dma_tx = NULL;
+ }
+
+ if (host->dma_rx) {
+ dma_release_channel(host->dma_rx);
+ host->dma_rx = NULL;
+ }
+
+ if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
+ if (as->addr_tx_bbuf) {
+ dma_free_coherent(dev, SPI_MAX_DMA_XFER,
+ as->addr_tx_bbuf,
+ as->dma_addr_tx_bbuf);
+ as->addr_tx_bbuf = NULL;
+ }
+ if (as->addr_rx_bbuf) {
+ dma_free_coherent(dev, SPI_MAX_DMA_XFER,
+ as->addr_rx_bbuf,
+ as->dma_addr_rx_bbuf);
+ as->addr_rx_bbuf = NULL;
+ }
+ }
+}
+
static int atmel_spi_configure_dma(struct spi_controller *host,
struct atmel_spi *as)
{
@@ -569,7 +601,8 @@ static int atmel_spi_configure_dma(struct spi_controller *host,
if (IS_ERR(host->dma_tx)) {
err = PTR_ERR(host->dma_tx);
dev_dbg(dev, "No TX DMA channel, DMA is disabled\n");
- goto error_clear;
+ host->dma_tx = NULL;
+ return err;
}
host->dma_rx = dma_request_chan(dev, "rx");
@@ -580,26 +613,45 @@ static int atmel_spi_configure_dma(struct spi_controller *host,
* requested tx channel.
*/
dev_dbg(dev, "No RX DMA channel, DMA is disabled\n");
- goto error;
+ host->dma_rx = NULL;
+ goto err_release_dma;
}
err = atmel_spi_dma_slave_config(as, 8);
if (err)
- goto error;
+ goto err_release_dma;
+
+ if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
+ as->addr_tx_bbuf = dma_alloc_coherent(dev, SPI_MAX_DMA_XFER,
+ &as->dma_addr_tx_bbuf,
+ GFP_KERNEL | GFP_DMA);
+ if (!as->addr_tx_bbuf) {
+ err = -ENOMEM;
+ goto err_release_dma;
+ }
+
+ as->addr_rx_bbuf = dma_alloc_coherent(dev, SPI_MAX_DMA_XFER,
+ &as->dma_addr_rx_bbuf,
+ GFP_KERNEL | GFP_DMA);
+ if (!as->addr_rx_bbuf) {
+ err = -ENOMEM;
+ goto err_release_dma;
+ }
+ }
+
+ err = devm_add_action_or_reset(dev, atmel_spi_release_dma, host);
+ if (err)
+ return err;
dev_info(&as->pdev->dev,
- "Using %s (tx) and %s (rx) for DMA transfers\n",
- dma_chan_name(host->dma_tx),
- dma_chan_name(host->dma_rx));
+ "Using %s (tx) and %s (rx) for DMA transfers\n",
+ dma_chan_name(host->dma_tx), dma_chan_name(host->dma_rx));
return 0;
-error:
- if (!IS_ERR(host->dma_rx))
- dma_release_channel(host->dma_rx);
- if (!IS_ERR(host->dma_tx))
- dma_release_channel(host->dma_tx);
-error_clear:
- host->dma_tx = host->dma_rx = NULL;
+
+err_release_dma:
+ atmel_spi_release_dma(host);
+
return err;
}
@@ -611,18 +663,6 @@ static void atmel_spi_stop_dma(struct spi_controller *host)
dmaengine_terminate_all(host->dma_tx);
}
-static void atmel_spi_release_dma(struct spi_controller *host)
-{
- if (host->dma_rx) {
- dma_release_channel(host->dma_rx);
- host->dma_rx = NULL;
- }
- if (host->dma_tx) {
- dma_release_channel(host->dma_tx);
- host->dma_tx = NULL;
- }
-}
-
/* This function is called by the DMA driver from tasklet context */
static void dma_callback(void *data)
{
@@ -1581,30 +1621,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
as->use_pdc = true;
}
- if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
- as->addr_rx_bbuf = dma_alloc_coherent(&pdev->dev,
- SPI_MAX_DMA_XFER,
- &as->dma_addr_rx_bbuf,
- GFP_KERNEL | GFP_DMA);
- if (!as->addr_rx_bbuf) {
- as->use_dma = false;
- } else {
- as->addr_tx_bbuf = dma_alloc_coherent(&pdev->dev,
- SPI_MAX_DMA_XFER,
- &as->dma_addr_tx_bbuf,
- GFP_KERNEL | GFP_DMA);
- if (!as->addr_tx_bbuf) {
- as->use_dma = false;
- dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
- as->addr_rx_bbuf,
- as->dma_addr_rx_bbuf);
- }
- }
- if (!as->use_dma)
- dev_info(host->dev.parent,
- " can not allocate dma coherent memory\n");
- }
-
if (as->caps.has_dma_support && !as->use_dma)
dev_info(&pdev->dev, "Atmel SPI Controller using PIO only\n");
@@ -1664,13 +1680,10 @@ static int atmel_spi_probe(struct platform_device *pdev)
out_free_dma:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
-
- if (as->use_dma)
- atmel_spi_release_dma(host);
-
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
- clk_disable_unprepare(as->gclk);
+ if (as->gclk)
+ clk_disable_unprepare(as->gclk);
out_disable_clk:
clk_disable_unprepare(clk);
@@ -1687,18 +1700,8 @@ static void atmel_spi_remove(struct platform_device *pdev)
spi_unregister_controller(host);
/* reset the hardware and block queue progress */
- if (as->use_dma) {
+ if (as->use_dma)
atmel_spi_stop_dma(host);
- atmel_spi_release_dma(host);
- if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
- dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
- as->addr_tx_bbuf,
- as->dma_addr_tx_bbuf);
- dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
- as->addr_rx_bbuf,
- as->dma_addr_rx_bbuf);
- }
- }
spin_lock_irq(&as->lock);
spi_writel(as, CR, SPI_BIT(SWRST));
---
base-commit: e98d21c170b01ddef366f023bbfcf6b31509fa83
change-id: 20260516-atmel-6d6b0150eb7e
Best regards,
--
Felix Gu <ustc.gu@gmail•com>
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v3] spi: atmel: fix DMA channel and bounce buffer leaks
2026-05-22 12:40 [PATCH v3] spi: atmel: fix DMA channel and bounce buffer leaks Felix Gu
@ 2026-06-01 14:03 ` Mark Brown
0 siblings, 0 replies; 2+ messages in thread
From: Mark Brown @ 2026-06-01 14:03 UTC (permalink / raw)
To: Ryan Wanner, Nicolas Ferre, Alexandre Belloni, Claudiu Beznea,
Radu Pirea, Richard Genoud, Felix Gu
Cc: linux-spi, linux-arm-kernel, linux-kernel
On Fri, 22 May 2026 20:40:48 +0800, Felix Gu wrote:
> spi: atmel: fix DMA channel and bounce buffer leaks
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-7.2
Thanks!
[1/1] spi: atmel: fix DMA channel and bounce buffer leaks
https://git.kernel.org/broonie/spi/c/bd7e9843ec95
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
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-02 12:07 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-22 12:40 [PATCH v3] spi: atmel: fix DMA channel and bounce buffer leaks Felix Gu
2026-06-01 14:03 ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox