Re: [PATCH v4 03/12] dmaengine: switchtec-dma: always clear DMA base registers on chan_stop()

[email protected] Tue, 28 Jul 2026 17:34:51 +0000
Newsgroups org.kernel.vger.dmaengine,org.kernel.vger.linux-pci
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unintentional memory leak of DMA descriptor rings during device hot-unplug or driver unbind.
- [High] Zeroing DMA base registers on an unhalted channel directs ongoing DMA to physical address 0, causing memory corruption.
--

--- Patch [3]: [PATCH v4 03/12] dmaengine: switchtec-dma: always clear DMA base registers on chan_stop() ---
commit ba435d6b93a5b911f612d1880a59068a9e918427
Author: Logan Gunthorpe <[email protected]>

dmaengine: switchtec-dma: always clear DMA base registers on chan_stop()

This patch modifies switchtec_dma_chan_stop() to clear DMA base registers
even if the hardware halt times out. It also updates callers to check the
halt result and skip freeing descriptor rings if the halt was unconfirmed.

Link: https://lore.kernel.org/dmaengine/[email protected]

> diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
> index f77da31aeb65e..cbbc9ad082471 100644
> --- a/drivers/dma/switchtec_dma.c
> +++ b/drivers/dma/switchtec_dma.c

[ ... ]

> @@ -543,26 +543,33 @@ switchtec_dma_abort_desc(struct switchtec_dma_chan *swdma_chan, int force)
>  	spin_unlock_bh(&swdma_chan->complete_lock);
>  }
>  
> -static void switchtec_dma_chan_stop(struct switchtec_dma_chan *swdma_chan)
> +static int switchtec_dma_chan_stop(struct switchtec_dma_chan *swdma_chan)
>  {
> +	struct pci_dev *pdev;
>  	int rc;
>  
>  	rc = halt_channel(swdma_chan);
> -	if (rc)
> -		return;
>  
>  	rcu_read_lock();
> -	if (!rcu_dereference(swdma_chan->swdma_dev->pdev)) {
> +	pdev = rcu_dereference(swdma_chan->swdma_dev->pdev);
> +	if (!pdev) {
>  		rcu_read_unlock();
> -		return;
> +		return rc;
>  	}
>  
> +	if (rc)
> +		pci_err(pdev,
> +			"Channel %d halt timed out, clearing DMA base registers anyway\n",
> +			swdma_chan->index);
> +
>  	writel(0, &swdma_chan->mmio_chan_fw->sq_base_lo);
>  	writel(0, &swdma_chan->mmio_chan_fw->sq_base_hi);
>  	writel(0, &swdma_chan->mmio_chan_fw->cq_base_lo);
>  	writel(0, &swdma_chan->mmio_chan_fw->cq_base_hi);
>  
>  	rcu_read_unlock();
> +
> +	return rc;
>  }

[Severity: High]
If the channel failed to halt and is still actively processing transactions,
could writing 0 to the base address registers redirect ongoing DMA to physical 
address 0x0?

The commit message states the descriptor rings are intentionally leaked so
the hardware can safely continue to write into them. However, by clearing
the base addresses here while the hardware is active, it appears the active
DMA is instead pointed at address 0x0, which might lead to memory corruption.

[ ... ]

> @@ -1050,6 +1057,7 @@ static void switchtec_dma_free_chan_resources(struct dma_chan *chan)
>  {
>  	struct switchtec_dma_chan *swdma_chan =
>  		container_of(chan, struct switchtec_dma_chan, dma_chan);
> +	int rc;
>  
>  	spin_lock_bh(&swdma_chan->submit_lock);
>  	swdma_chan->ring_active = false;
> @@ -1059,9 +1067,10 @@ static void switchtec_dma_free_chan_resources(struct dma_chan *chan)
>  	swdma_chan->comp_ring_active = false;
>  	spin_unlock_bh(&swdma_chan->complete_lock);
>  
> -	switchtec_dma_chan_stop(swdma_chan);
> +	rc = switchtec_dma_chan_stop(swdma_chan);
>  	switchtec_dma_abort_desc(swdma_chan, 0);
> -	switchtec_dma_free_desc(swdma_chan);
> +	if (!rc)
> +		switchtec_dma_free_desc(swdma_chan);
>  
>  	disable_channel(swdma_chan);
>  }

[Severity: High]
Does this logic skip freeing the descriptor rings during normal device unplug?

When a device is hot-unplugged and the driver unbinds, swdma_dev->pdev is set
to NULL. This causes halt_channel() and switchtec_dma_chan_stop() to return
-ENODEV.

Because rc is -ENODEV (non-zero) on a standard unplug, the condition if (!rc)
evaluates to false. This seems to unintentionally bypass
switchtec_dma_free_desc() and permanently leak the descriptor rings and
coherent memory. A similar bypass happens in the error paths of
switchtec_dma_alloc_chan_resources().

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=3