[PATCH v4 08/12] dmaengine: switchtec-dma: disable channels before freeing on registration failure
From: Logan Gunthorpe
Date: Tue Jul 28 2026 - 13:32:26 EST
When switchtec_dma_create() fails after channels have been added to
dma_dev->channels (either from switchtec_dma_chans_enumerate()'s own
error path, or from dma_async_device_register() failing), the channel
status IRQ is still live while the channels are released and freed,
so it can fire mid-teardown against channels that are only partially
torn down.
Add switchtec_dma_chans_disable(), which frees the channel status IRQ
before releasing and freeing channels in both error paths.
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Link: https://lore.kernel.org/dmaengine/20260717223431.625EE1F000E9@xxxxxxxxxxxxxxx
Link: https://lore.kernel.org/dmaengine/20260721162822.05CDD1F000E9@xxxxxxxxxxxxxxx
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
Signed-off-by: Logan Gunthorpe <logang@xxxxxxxxxxxx>
---
drivers/dma/switchtec_dma.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
index 6ab2c62b52fd..ecf3a44d4dcc 100644
--- a/drivers/dma/switchtec_dma.c
+++ b/drivers/dma/switchtec_dma.c
@@ -1198,6 +1198,15 @@ static void switchtec_dma_chans_free(struct switchtec_dma_dev *swdma_dev)
kfree(swdma_dev->swdma_chans);
}
+static void switchtec_dma_chans_disable(struct pci_dev *pdev,
+ struct switchtec_dma_dev *swdma_dev)
+{
+ if (swdma_dev->chan_status_irq >= 0) {
+ pci_free_irq(pdev, swdma_dev->chan_status_irq, swdma_dev);
+ swdma_dev->chan_status_irq = -1;
+ }
+}
+
static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
struct pci_dev *pdev, int chan_cnt)
{
@@ -1231,6 +1240,7 @@ static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
return chan_cnt;
err_exit:
+ switchtec_dma_chans_disable(pdev, swdma_dev);
switchtec_dma_chans_release(pdev, swdma_dev);
switchtec_dma_chans_free(swdma_dev);
@@ -1334,6 +1344,7 @@ static int switchtec_dma_create(struct pci_dev *pdev)
return 0;
err_chans_release_exit:
+ switchtec_dma_chans_disable(pdev, swdma_dev);
switchtec_dma_chans_release(pdev, swdma_dev);
switchtec_dma_chans_free(swdma_dev);
--
2.47.3