Re: [PATCH] dmaengine: switchtec-dma: preserve results for out-of-order completions
From: Frank Li
Date: Fri Oct 16 2026 - 12:20:59 EST
On Sat, Jul 18, 2026 at 10:32:57PM +0800, Hao-Qun Huang wrote:
> Switchtec completion entries can arrive out of submission order, and the
> driver handles that by marking the descriptor complete and deferring its
> callback until the ring tail catches up. The problem is that the
> per-transfer result (status and residue) is only kept in a stack variable
> while the completion entry is being read. Once the tail gap closes,
> cleanup retires the descriptor at the tail along with any already
> completed descriptors behind it, and hands the same stack result to every
> one of them.
>
> So a transfer that failed out of order can be reported as successful (or
> the other way round) depending on which completion happened to close the
> gap, and the residue can end up coming from the wrong transfer too.
>
> Keep the result in each descriptor instead of on the stack, and pass the
> descriptor's own saved result when it is retired. Cookie ordering, the
> CID-to-descriptor mapping and the completion locking are unchanged; only
> the result handed to each callback is corrected.
>
> Fixes: 30eba9df76ad ("dmaengine: switchtec-dma: Implement hardware initialization and cleanup")
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Hao-Qun Huang <alvinhuang0603@xxxxxxxxx>
> ---
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
> drivers/dma/switchtec_dma.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
> index 3ef928640615..681540836e73 100644
> --- a/drivers/dma/switchtec_dma.c
> +++ b/drivers/dma/switchtec_dma.c
> @@ -246,6 +246,7 @@ struct switchtec_dma_hw_ce {
> struct switchtec_dma_desc {
> struct dma_async_tx_descriptor txd;
> struct switchtec_dma_hw_se_desc *hw;
> + struct dmaengine_result result;
> u32 orig_size;
> bool completed;
> };
> @@ -409,7 +410,6 @@ switchtec_dma_cleanup_completed(struct switchtec_dma_chan *swdma_chan)
> struct device *chan_dev = &swdma_chan->dma_chan.dev->device;
> struct switchtec_dma_desc *desc;
> struct switchtec_dma_hw_ce *ce;
> - struct dmaengine_result res;
> int tail, cid, se_idx, i;
> __le16 phase_tag;
> u32 sts_code;
> @@ -439,17 +439,17 @@ switchtec_dma_cleanup_completed(struct switchtec_dma_chan *swdma_chan)
>
> tail = swdma_chan->tail;
>
> - res.residue = desc->orig_size - le32_to_cpu(ce->cpl_byte_cnt);
> + desc->result.residue = desc->orig_size - le32_to_cpu(ce->cpl_byte_cnt);
>
> sts_code = le32_to_cpu(ce->sts_code);
>
> if (!(sts_code & SWITCHTEC_CE_SC_MASK)) {
> - res.result = DMA_TRANS_NOERROR;
> + desc->result.result = DMA_TRANS_NOERROR;
> } else {
> if (sts_code & SWITCHTEC_CE_SC_D_RD_CTO)
> - res.result = DMA_TRANS_READ_FAILED;
> + desc->result.result = DMA_TRANS_READ_FAILED;
> else
> - res.result = DMA_TRANS_WRITE_FAILED;
> + desc->result.result = DMA_TRANS_WRITE_FAILED;
>
> dev_err(chan_dev, "CID 0x%04x failed, SC 0x%08x\n", cid,
> (u32)(sts_code & SWITCHTEC_CE_SC_MASK));
> @@ -488,7 +488,7 @@ switchtec_dma_cleanup_completed(struct switchtec_dma_chan *swdma_chan)
> do {
> dma_cookie_complete(&desc->txd);
> dma_descriptor_unmap(&desc->txd);
> - dmaengine_desc_get_callback_invoke(&desc->txd, &res);
> + dmaengine_desc_get_callback_invoke(&desc->txd, &desc->result);
> desc->txd.callback = NULL;
> desc->txd.callback_result = NULL;
> desc->completed = false;
> --
> 2.43.0
>