[PATCH v5 04/12] dmaengine: switchtec-dma: halt channel on alloc_chan_resources error

From: Logan Gunthorpe

Date: Mon Aug 31 2026 - 16:10:10 EST


The error-unwind path called disable_channel() before freeing the
descriptor rings, but that only clears the enable bit with an
unflushed write -- it doesn't halt the channel or clear its DMA base
address registers. If unhalt_channel() timed out, the channel's actual
state is unknown at that point, so nothing guarantees the hardware
isn't still touching the rings when they're freed.

Call switchtec_dma_chan_stop() first, matching what
switchtec_dma_free_chan_resources() already does before freeing
descriptors on the normal teardown path: it synchronously halts the
channel and zeroes the DMA base registers. If the halt itself can't be
confirmed, skip freeing the descriptor rings (leaking them instead).

All this is hardening that is pretty unlikely to be hit in the real
world. However, it is correct and the best thing to do against buggy
hardware that doesn't tear down correctly and could still write to
memory. In this unlikely situation it is better to leak the memory
than have hardware randomly trash memory that has already been used
for something else.

Fixes: 30eba9df76ad ("dmaengine: switchtec-dma: Implement hardware initialization and cleanup")
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Link: https://lore.kernel.org/dmaengine/20260717223647.F0A051F000E9@xxxxxxxxxxxxxxx
Link: https://lore.kernel.org/dmaengine/20260727185101.D221C1F000E9@xxxxxxxxxxxxxxx
Signed-off-by: Logan Gunthorpe <logang@xxxxxxxxxxxx>
---
drivers/dma/switchtec_dma.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
index e2bb65237d2c..2d5ba194c99a 100644
--- a/drivers/dma/switchtec_dma.c
+++ b/drivers/dma/switchtec_dma.c
@@ -1047,6 +1047,10 @@ static int switchtec_dma_alloc_chan_resources(struct dma_chan *chan)
swdma_chan->comp_ring_active = false;
spin_unlock_bh(&swdma_chan->complete_lock);
err_disable_channel:
+ if (switchtec_dma_chan_stop(swdma_chan)) {
+ disable_channel(swdma_chan);
+ return rc;
+ }
disable_channel(swdma_chan);
err_free_desc:
switchtec_dma_free_desc(swdma_chan);
--
2.47.3