drivers/dma/xilinx/xilinx_dma.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
Since commit 7e01511443c3 ("dmaengine: xilinx_dma: Set dma_device
directions") all channel directions are aggregated into
dma_device.directions so that dma_get_slave_caps() works for IIO
DMAEngine buffers.
However, this caused a regression in ASoC audio on ZynqMP platforms,
that causes cyclic playback to fail after the first buffer period,
because ASoC dmaengine PCM expects fixed per-channel direction reporting
from dma_get_slave_caps().
Implement optional device_caps() callback and override caps->directions
with the channel's fixed direction. This keeps device-wide direction
reporting for IIO intact while restoring correct per-channel semantics
for ASoC.
Other dma_slave_caps fields are left unchanged from their respective
values initialized from dma_get_slave_caps(). In case there should ever
be the need to override other fields, these can be added later.
Fixes: 7e01511443c3 ("dmaengine: xilinx_dma: Set dma_device directions")
Cc: stable@vger.kernel.org
Reported-by: Rahul Navale <rahul.navale@ifm.com>
Closes: https://lore.kernel.org/dmaengine/20260211140051.8177-1-rahulnavale04@gmail.com/T/#u
Closes: https://lore.kernel.org/dmaengine/CY1PR12MB96978AEBD6072FC469DFEAF1B762A@CY1PR12MB9697.namprd12.prod.outlook.com/T/#u
Signed-off-by: Folker Schwesinger <dev@folker-schwesinger.de>
---
Posting this as RFC because I can't verify this actually fixes the
regression as I don't have a ZynqMP. So Rahul, could you test if this
fixes the issue and report back? BR F.
---
drivers/dma/xilinx/xilinx_dma.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 64b3fba4e44f..bdd16173d762 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1711,6 +1711,19 @@ static void xilinx_dma_issue_pending(struct dma_chan *dchan)
spin_unlock_irqrestore(&chan->lock, flags);
}
+/**
+ * xilinx_dma_device_caps - Write channel-specific DMA slave capabilities
+ * @dchan: DMA channel
+ * @caps: DMA slave capabilities of DMA channel
+ */
+static void xilinx_dma_device_caps(struct dma_chan *dchan,
+ struct dma_slave_caps *caps)
+{
+ struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+
+ caps->directions = chan->direction;
+}
+
/**
* xilinx_dma_device_config - Configure the DMA channel
* @dchan: DMA channel
@@ -3292,6 +3305,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
xdev->common.device_tx_status = xilinx_dma_tx_status;
xdev->common.device_issue_pending = xilinx_dma_issue_pending;
xdev->common.device_config = xilinx_dma_device_config;
+ xdev->common.device_caps = xilinx_dma_device_caps;
if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
dma_cap_set(DMA_CYCLIC, xdev->common.cap_mask);
xdev->common.device_prep_peripheral_dma_vec = xilinx_dma_prep_peripheral_dma_vec;
base-commit: ab736ed52e3409b58a4888715e4425b6e8ac444f
--
2.53.0
From: Rahul Navale <rahul.navale@ifm.com> Hello Marek, >Can you please add [1] to the patch stack and let me know whether that >improves the behavior ? I added the patch to the patch stack and retested audio is working now. Thank you for your support.
From: Rahul Navale <rahul.navale@ifm.com>
@Xilinx/AMD maintainers:
Quick status: the ASoC playback regression is still present.
when 7e01511443c3 ("dmaengine: xilinx_dma: Set dma_device directions")
is present. Reverting 7e01511443c3 restores normal playback.
Could you please advice the next steps / preferred fix direction to address
this regression upstream?
Thanks,
Rahul
+Suraj,
On 3/25/26 15:22, Rahul Navale wrote:
> From: Rahul Navale <rahul.navale@ifm.com>
>
> @Xilinx/AMD maintainers:
>
> Quick status: the ASoC playback regression is still present.
> when 7e01511443c3 ("dmaengine: xilinx_dma: Set dma_device directions")
> is present. Reverting 7e01511443c3 restores normal playback.
>
> Could you please advice the next steps / preferred fix direction to address
> this regression upstream?
Suraj will take a look at it soon.
Thanks,
Michal
From: Rahul Navale <rahul.navale@ifm.com> Hi Marek, >If yes,make sure you only test these three I have confirmed no other pathes applied on xilinx dma driver. I have applied only three patches provided by you. and tested audio but facing same issue.
On 3/18/26 1:35 PM, Rahul Navale wrote: Hello Rahul, >> If yes,make sure you only test these three > I have confirmed no other pathes applied on xilinx dma driver. > I have applied only three patches provided by you. > and tested audio but facing same issue. Can you please add [1] to the patch stack and let me know whether that improves the behavior ? Thank you [1] https://lore.kernel.org/linux-sound/20260327143014.54867-1-marex@nabladev.com/
From: Rahul Navale <rahul.navale@ifm.com> Hi Folker, >Just to double check, and to make sure the regression you're seeing is >not a combination of any additional, yet unknown side-effects, could you >perform one more test? >In dmaengine_pcm_pointer() (the function we just patched), could you >replace the call to snd_dmaengine_pcm_pointer() with >snd_dmaengine_pcm_pointer_no_residue() while keeping 7e01511443c3 active >and test if this fixes your issue or not? I have performed the test (replace the call in dmaengine_pcm_pointer() function of provided patch) while keeping 7e01511443c3 active. I see issue is fixed audio is working with this. Hi Marek, >I came to the same conclusion, that the residue handling is broken in >the xilinx DMA driver for cyclic transfers, and the fix is below, with >two extra fixes in top: I have tested the provided patches the audio is not fixed with this.
On 3/17/26 11:49 AM, Rahul Navale wrote: > From: Rahul Navale <rahul.navale@ifm.com> > > Hi Folker, > >> Just to double check, and to make sure the regression you're seeing is >> not a combination of any additional, yet unknown side-effects, could you >> perform one more test? >> In dmaengine_pcm_pointer() (the function we just patched), could you >> replace the call to snd_dmaengine_pcm_pointer() with >> snd_dmaengine_pcm_pointer_no_residue() while keeping 7e01511443c3 active >> and test if this fixes your issue or not? > > I have performed the test (replace the call in dmaengine_pcm_pointer() > function of provided patch) while keeping 7e01511443c3 active. > I see issue is fixed audio is working with this. > > Hi Marek, > >> I came to the same conclusion, that the residue handling is broken in >> the xilinx DMA driver for cyclic transfers, and the fix is below, with >> two extra fixes in top: > > I have tested the provided patches the audio is not fixed with this. Do you have any other patches applied on the xilinx DMA driver by any chance ? If yes, make sure you only test these three.
On Tue Feb 17, 2026 at 7:49 PM CET, Folker Schwesinger wrote:
> Since commit 7e01511443c3 ("dmaengine: xilinx_dma: Set dma_device
> directions") all channel directions are aggregated into
> dma_device.directions so that dma_get_slave_caps() works for IIO
> DMAEngine buffers.
>
> However, this caused a regression in ASoC audio on ZynqMP platforms,
> that causes cyclic playback to fail after the first buffer period,
> because ASoC dmaengine PCM expects fixed per-channel direction reporting
> from dma_get_slave_caps().
>
> Implement optional device_caps() callback and override caps->directions
> with the channel's fixed direction. This keeps device-wide direction
> reporting for IIO intact while restoring correct per-channel semantics
> for ASoC.
> Other dma_slave_caps fields are left unchanged from their respective
> values initialized from dma_get_slave_caps(). In case there should ever
> be the need to override other fields, these can be added later.
>
> Fixes: 7e01511443c3 ("dmaengine: xilinx_dma: Set dma_device directions")
> Cc: stable@vger.kernel.org
> Reported-by: Rahul Navale <rahul.navale@ifm.com>
> Closes: https://lore.kernel.org/dmaengine/20260211140051.8177-1-rahulnavale04@gmail.com/T/#u
> Closes: https://lore.kernel.org/dmaengine/CY1PR12MB96978AEBD6072FC469DFEAF1B762A@CY1PR12MB9697.namprd12.prod.outlook.com/T/#u
> Signed-off-by: Folker Schwesinger <dev@folker-schwesinger.de>
@Xilinx/AMD maintainers:
Even though this patch does not fix the reported regression and there
may not be an immediate need for the implementation of the device_caps()
callback, it might be an improvement to the Xilinx DMA driver. In case
you see value in that addition, let me know and I resend the patch with
the necessary editorial changes.
Also during the debugging session, the following was identified:
> From a quick trace through the code I found that in the Xilinx DMA
> residue_granularity is set for AXIDMA independently from the SG setting
> of the DMA core [1].
> However, in xilinx_dma_tx_status() one of the conditions for residue
> calculations is that SG mode is enabled [2].
>
> [1]: https://elixir.bootlin.com/linux/v6.19.3/source/drivers/dma/xilinx/xilinx_dma.c#L3284
> [2]: https://elixir.bootlin.com/linux/v6.19.3/source/drivers/dma/xilinx/xilinx_dma.c#L1293
Not sure if this needs addressing, but this could have the potential for
subtle bugs...
Best regards
Folker
From: Rahul Navale <rahul.navale@ifm.com> >Please undo the latest Xilinx DMA patch I sent. >To get some more data, could you apply the following patch (keep RFC >patch and debug stuff) and rerun with 7e01511443c3 a) applied and b) >reverted and post logs for both cases: I have applied provided patch (with kept RFC patch and debug stuff) and with 7e01511443c3 applied. logs: root@pdm3:~# dmesg | grep xilinx_dma_device_caps [ 0.285057] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.285060] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.285759] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 0.285763] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 7.535143] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 7.535147] xilinx_dma_device_caps: caps->directions = 0x00000001 root@pdm3:~# dmesg | grep ptr_res root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo ^CAborted by signal Interrupt... aplay: pcm_write:2178: write error: Interrupted system call root@pdm3:~# root@pdm3:~# dmesg | grep ptr_res [ 198.997591] ptr_res: ptr = 0x00000000 [ 199.002885] ptr_res: ptr = 0x00000000 [ 199.002900] ptr_res: ptr = 0x00000000 [ 199.002925] ptr_res: ptr = 0x00000000 [ 199.002946] ptr_res: ptr = 0x00000000 [ 199.117775] ptr_res: ptr = 0x00000000 [ 199.117818] ptr_res: ptr = 0x00000000 [ 199.117839] ptr_res: ptr = 0x00000000 [ 199.242766] ptr_res: ptr = 0x00000000 [ 199.242800] ptr_res: ptr = 0x00000000 [ 199.242820] ptr_res: ptr = 0x00000000 Also I have applied provided patch (with kept RFC patch and debug stuff) and with 7e01511443c3 reverted. logs: root@pdm3:~# dmesg | grep xilinx_dma_device_caps root@pdm3:~# dmesg | grep ptr_res root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo ^CAborted by signal Interrupt... aplay: pcm_write:2178: write error: Interrupted system call root@pdm3:~# root@pdm3:~# dmesg | grep ptr_res [ 60.480754] ptr_res_no: ptr = 0x00000000 [ 60.486058] ptr_res_no: ptr = 0x00000000 [ 60.486070] ptr_res_no: ptr = 0x00000000 [ 60.486094] ptr_res_no: ptr = 0x00000000 [ 60.486113] ptr_res_no: ptr = 0x00000000 [ 60.600877] ptr_res_no: ptr = 0x00001770 [ 60.600920] ptr_res_no: ptr = 0x00001770 [ 60.600939] ptr_res_no: ptr = 0x00001770 [ 60.600948] ptr_res_no: ptr = 0x00001770 [ 60.600968] ptr_res_no: ptr = 0x00001770 [ 60.602739] ptr_res_no: ptr = 0x00001770 [ 60.602750] ptr_res_no: ptr = 0x00001770 [ 60.725869] ptr_res_no: ptr = 0x00002ee0 [ 60.725904] ptr_res_no: ptr = 0x00002ee0 [ 60.725921] ptr_res_no: ptr = 0x00002ee0 [ 60.725931] ptr_res_no: ptr = 0x00002ee0 [ 60.725949] ptr_res_no: ptr = 0x00002ee0 [ 60.727667] ptr_res_no: ptr = 0x00002ee0 [ 60.727677] ptr_res_no: ptr = 0x00002ee0 [ 60.850877] ptr_res_no: ptr = 0x00000000 [ 60.850939] ptr_res_no: ptr = 0x00000000 [ 60.850960] ptr_res_no: ptr = 0x00000000 [ 60.850969] ptr_res_no: ptr = 0x00000000 [ 60.851000] ptr_res_no: ptr = 0x00000000 [ 60.852750] ptr_res_no: ptr = 0x00000000 [ 60.852760] ptr_res_no: ptr = 0x00000000 [ 60.975869] ptr_res_no: ptr = 0x00001770 [ 60.975905] ptr_res_no: ptr = 0x00001770 [ 60.975923] ptr_res_no: ptr = 0x00001770 ... ...
On Mon Mar 9, 2026 at 8:28 AM CET, Rahul Navale wrote: > I have applied provided patch (with kept RFC patch and debug stuff) and with > 7e01511443c3 applied. logs: > > root@pdm3:~# dmesg | grep ptr_res > [ 198.997591] ptr_res: ptr = 0x00000000 > ... > [ 199.242820] ptr_res: ptr = 0x00000000 > > Also I have applied provided patch (with kept RFC patch and debug stuff) and with > 7e01511443c3 reverted. logs: > > root@pdm3:~# dmesg | grep ptr_res > [ 60.480754] ptr_res_no: ptr = 0x00000000 > ... > [ 60.600877] ptr_res_no: ptr = 0x00001770 > ... > [ 60.725869] ptr_res_no: ptr = 0x00002ee0 > ... > [ 60.850877] ptr_res_no: ptr = 0x00000000 > ... > [ 60.975869] ptr_res_no: ptr = 0x00001770 > ... This confirms that the residue_granularity field in dma_slave_caps, which gets properly set since 7e01511443c3 affects progress tracking in the PCM DMAEngine layer. Since Xilinx DMA advertises residue reporting with segment granularity [1], PCM DMAEngine switches from software based [2][3] progress tracking to hardware based progress tracking [4]. From my understanding however, residue reporting of the Xilinx DMA is incompatible with what the PCM DMAEngine expects. So the progression pointer is stuck at 0. As I'm neither an expert in the PCM subsystem nor very familiar with residue reporting of the AXIDMA (and its limitations), I can't propose a solution that fixes the issue for you. I did a quick check of the code to see, if there is any way to force the DMAEngine PCM layer into software tracking from your custom driver. But I think there's no API to force-set the SND_DMAENGINE_PCM_FLAG_NO_RESIDUE bit in dma_engine_pcm->flags from your custom driver. Maybe there's a way to establish compatibility between PCM and AIXDMA in this regard. But to figure that out, I think more eyes on the issue from the audio experts and Xilinx/AMD engineers familiar with AXIDMA residue reporting would be needed. Just to double check, and to make sure the regression you're seeing is not a combination of any additional, yet unknown side-effects, could you perform one more test? In dmaengine_pcm_pointer() (the function we just patched), could you replace the call to snd_dmaengine_pcm_pointer() with snd_dmaengine_pcm_pointer_no_residue() while keeping 7e01511443c3 active and test if this fixes your issue or not? [1]: https://elixir.bootlin.com/linux/v6.19.3/source/drivers/dma/xilinx/xilinx_dma.c#L3284 [2]: https://elixir.bootlin.com/linux/v7.0-rc3/source/sound/core/pcm_dmaengine.c#L136 [3]: https://elixir.bootlin.com/linux/v7.0-rc3/source/sound/core/pcm_dmaengine.c#L235 [4]: https://elixir.bootlin.com/linux/v7.0-rc3/source/sound/core/pcm_dmaengine.c#L251
On 3/14/26 9:35 AM, Folker Schwesinger wrote: > On Mon Mar 9, 2026 at 8:28 AM CET, Rahul Navale wrote: >> I have applied provided patch (with kept RFC patch and debug stuff) and with >> 7e01511443c3 applied. logs: >> >> root@pdm3:~# dmesg | grep ptr_res >> [ 198.997591] ptr_res: ptr = 0x00000000 >> ... >> [ 199.242820] ptr_res: ptr = 0x00000000 >> >> Also I have applied provided patch (with kept RFC patch and debug stuff) and with >> 7e01511443c3 reverted. logs: >> >> root@pdm3:~# dmesg | grep ptr_res >> [ 60.480754] ptr_res_no: ptr = 0x00000000 >> ... >> [ 60.600877] ptr_res_no: ptr = 0x00001770 >> ... >> [ 60.725869] ptr_res_no: ptr = 0x00002ee0 >> ... >> [ 60.850877] ptr_res_no: ptr = 0x00000000 >> ... >> [ 60.975869] ptr_res_no: ptr = 0x00001770 >> ... > > This confirms that the residue_granularity field in dma_slave_caps, > which gets properly set since 7e01511443c3 affects progress tracking in > the PCM DMAEngine layer. Since Xilinx DMA advertises residue reporting > with segment granularity [1], PCM DMAEngine switches from software based > [2][3] progress tracking to hardware based progress tracking [4]. > From my understanding however, residue reporting of the Xilinx DMA is > incompatible with what the PCM DMAEngine expects. So the progression > pointer is stuck at 0. > > As I'm neither an expert in the PCM subsystem nor very familiar with > residue reporting of the AXIDMA (and its limitations), I can't propose a > solution that fixes the issue for you. I did a quick check of the code to > see, if there is any way to force the DMAEngine PCM layer into software > tracking from your custom driver. But I think there's no API to > force-set the SND_DMAENGINE_PCM_FLAG_NO_RESIDUE bit in > dma_engine_pcm->flags from your custom driver. > Maybe there's a way to establish compatibility between PCM and AIXDMA in > this regard. But to figure that out, I think more eyes on the issue from > the audio experts and Xilinx/AMD engineers familiar with AXIDMA residue > reporting would be needed. > > Just to double check, and to make sure the regression you're seeing is > not a combination of any additional, yet unknown side-effects, could you > perform one more test? > In dmaengine_pcm_pointer() (the function we just patched), could you > replace the call to snd_dmaengine_pcm_pointer() with > snd_dmaengine_pcm_pointer_no_residue() while keeping 7e01511443c3 active > and test if this fixes your issue or not? > > [1]: https://elixir.bootlin.com/linux/v6.19.3/source/drivers/dma/xilinx/xilinx_dma.c#L3284 > [2]: https://elixir.bootlin.com/linux/v7.0-rc3/source/sound/core/pcm_dmaengine.c#L136 > [3]: https://elixir.bootlin.com/linux/v7.0-rc3/source/sound/core/pcm_dmaengine.c#L235 > [4]: https://elixir.bootlin.com/linux/v7.0-rc3/source/sound/core/pcm_dmaengine.c#L251 I came to the same conclusion, that the residue handling is broken in the Xilinx DMA driver for cyclic transfers, and the fix is below, with two extra fixes on top: https://lore.kernel.org/dmaengine/20260316221943.160375-1-marex@nabladev.com/ https://lore.kernel.org/dmaengine/20260316221728.160139-1-marex@nabladev.com/ https://lore.kernel.org/dmaengine/20260316222530.163815-1-marex@nabladev.com/
From: Rahul Navale <rahul.navale@ifm.com> >Could you confirm that the DMA IP core in your PL design operates in >scatter Gather mode? Yes, We confirmed that our DMA IP core in the PL design are configured for Scatter-Gather mode.
On Thu Mar 5, 2026 at 12:27 PM CET, Rahul Navale wrote:
> From: Rahul Navale <rahul.navale@ifm.com>
>
>>Could you confirm that the DMA IP core in your PL design operates in
>>scatter Gather mode?
>
> Yes, We confirmed that our DMA IP core in the PL design are configured
> for Scatter-Gather mode.
Thanks for confirming, this disproves the last theory. Please undo the
latest Xilinx DMA patch I sent.
To get some more data, could you apply the following patch (keep RFC
patch and debug stuff) and rerun with 7e01511443c3 a) applied and b)
reverted and post logs for both cases:
dmesg|grep ptr_res
<--8<-->
diff --git i/sound/soc/soc-generic-dmaengine-pcm.c w/sound/soc/soc-generic-dmaengine-pcm.c
index a63e942fdc0b..4635b199d020 100644
--- i/sound/soc/soc-generic-dmaengine-pcm.c
+++ w/sound/soc/soc-generic-dmaengine-pcm.c
@@ -280,11 +280,16 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
struct snd_pcm_substream *substream)
{
struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ snd_pcm_uframes_t ptr = 0;
- if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
- return snd_dmaengine_pcm_pointer_no_residue(substream);
- else
- return snd_dmaengine_pcm_pointer(substream);
+ if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) {
+ ptr = snd_dmaengine_pcm_pointer_no_residue(substream);
+ printk("ptr_res_no: ptr = 0x%08lx\n", ptr);
+ } else {
+ ptr = snd_dmaengine_pcm_pointer(substream);
+ printk("ptr_res: ptr = 0x%08lx\n", ptr);
+ }
+ return ptr;
}
static int dmaengine_copy(struct snd_soc_component *component,
<-->8-->
From: Rahul Navale <rahul.navale@ifm.com> >Could you show the debug output from dma_get_slave_caps()? logs: <4>[ 0.302360] dma_slave_caps: <4>[ 0.302364] src_addr_widths = 0x00000000 <4>[ 0.302368] dst_addr_widths = 0x00000000 <4>[ 0.302371] directions = 0x00000000 <4>[ 0.302374] min_burst = 0x00000000 <4>[ 0.302377] max_burst = 0x00000000 <4>[ 0.302380] max_sg_burst = 0x00000000 <4>[ 0.302383] cmd_pause = 0x00 <4>[ 0.302386] cmd_resume = 0x00 <4>[ 0.302388] cmd_terminate = 0x00 <4>[ 0.302391] residue_granularity= 0x00000000 <4>[ 0.302394] descriptor_reuse = 0x00 <4>[ 0.302398] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 0.302401] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 0.302404] dma_slave_caps: <4>[ 0.302406] src_addr_widths = 0x00000000 <4>[ 0.302409] dst_addr_widths = 0x00000000 <4>[ 0.302412] directions = 0x00000001 <4>[ 0.302415] min_burst = 0x00000000 <4>[ 0.302418] max_burst = 0x00000000 <4>[ 0.302421] max_sg_burst = 0x00000000 <4>[ 0.302423] cmd_pause = 0x00 <4>[ 0.302426] cmd_resume = 0x00 <4>[ 0.302429] cmd_terminate = 0x01 <4>[ 0.302431] residue_granularity= 0x00000001 <4>[ 0.302434] descriptor_reuse = 0x00
On Thu Mar 5, 2026 at 9:29 AM CET, Rahul Navale wrote: > logs: > <4>[ 0.302360] dma_slave_caps: > <4>[ 0.302364] src_addr_widths = 0x00000000 > <4>[ 0.302368] dst_addr_widths = 0x00000000 > <4>[ 0.302371] directions = 0x00000000 > <4>[ 0.302374] min_burst = 0x00000000 > <4>[ 0.302377] max_burst = 0x00000000 > <4>[ 0.302380] max_sg_burst = 0x00000000 > <4>[ 0.302383] cmd_pause = 0x00 > <4>[ 0.302386] cmd_resume = 0x00 > <4>[ 0.302388] cmd_terminate = 0x00 > <4>[ 0.302391] residue_granularity= 0x00000000 > <4>[ 0.302394] descriptor_reuse = 0x00 > <4>[ 0.302398] xilinx_dma_device_caps: caps->directions = 0x00000001 > <4>[ 0.302401] xilinx_dma_device_caps: caps->directions = 0x00000001 > <4>[ 0.302404] dma_slave_caps: > <4>[ 0.302406] src_addr_widths = 0x00000000 > <4>[ 0.302409] dst_addr_widths = 0x00000000 > <4>[ 0.302412] directions = 0x00000001 > <4>[ 0.302415] min_burst = 0x00000000 > <4>[ 0.302418] max_burst = 0x00000000 > <4>[ 0.302421] max_sg_burst = 0x00000000 > <4>[ 0.302423] cmd_pause = 0x00 > <4>[ 0.302426] cmd_resume = 0x00 > <4>[ 0.302429] cmd_terminate = 0x01 > <4>[ 0.302431] residue_granularity= 0x00000001 > <4>[ 0.302434] descriptor_reuse = 0x00 Could you confirm that the DMA IP core in your PL design operates in Scatter Gather mode?
From: Rahul Navale <rahul.navale@ifm.com> Hi Folker, >Could you test if this fixes your issue (and of course re-activate all the <caps->assignments in dma_get_slave_caps(), keep the debug stuff for now)? I applied the residue_granularity/has_sg gating patch you provided. I kept: 7e01511443c3 applied + RFC patch(xilinx_dma_device_caps + printk) + dmaengine.c debug patch applied (dma_slave_caps_printk() + dump_stack()) + all caps assignment in dma_get_slave_caps() enabled again. The audio issue is not fixed. Playback still fails after the first buffer period.
On Thu Mar 5, 2026 at 8:23 AM CET, Rahul Navale wrote: > I applied the residue_granularity/has_sg gating patch you provided. I kept: > 7e01511443c3 applied + RFC patch(xilinx_dma_device_caps + printk) + > dmaengine.c debug patch applied (dma_slave_caps_printk() + dump_stack()) + > all caps assignment in dma_get_slave_caps() enabled again. > > The audio issue is not fixed. Playback still fails after the first buffer period. Could you show the debug output from dma_get_slave_caps()? The stack traces are not needed.
From: Rahul Navale <rahul.navale@ifm.com> Hi Folker, Thanks — I followed your suggested debugging steps. >For the next debugging step I suggest that we focus on (2) but also on >getting some insight into the callers. Could you please reapply >7e01511443c3, keep the RFC patch in place and additionally apply the >below patch? >This will exercise your bad case, print the differences for caps, and >also print the call stacks for all calls to dma_get_slave_caps(). I have applied 7e01511443c3, kept RFC patch(xilinx_dma_device_caps + printk) and dmaengine.c debug patch applied (dma_slave_caps_printk() + dump_stack()) Observation: Issue still persists. cyclic playback fails after the first buffer period. logs: root@pdm3:~# dmesg | grep xilinx_dma_device_caps [ 0.302398] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.302401] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.303124] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 0.303128] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 7.762354] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 7.762358] xilinx_dma_device_caps: caps->directions = 0x00000001 root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo ^CAborted by signal Interrupt... aplay: pcm_write:2178: write error: Interrupted system call root@pdm3:~# ^C root@pdm3:~# ^C root@pdm3:~# dmesg | grep xilinx_dma_device_caps [ 0.302398] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.302401] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.303124] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 0.303128] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 7.762354] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 7.762358] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 44.792624] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 44.792628] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 0.302360] dma_slave_caps: <4>[ 0.302364] src_addr_widths = 0x00000000 <4>[ 0.302368] dst_addr_widths = 0x00000000 <4>[ 0.302371] directions = 0x00000000 <4>[ 0.302374] min_burst = 0x00000000 <4>[ 0.302377] max_burst = 0x00000000 <4>[ 0.302380] max_sg_burst = 0x00000000 <4>[ 0.302383] cmd_pause = 0x00 <4>[ 0.302386] cmd_resume = 0x00 <4>[ 0.302388] cmd_terminate = 0x00 <4>[ 0.302391] residue_granularity= 0x00000000 <4>[ 0.302394] descriptor_reuse = 0x00 <4>[ 0.302398] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 0.302401] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 0.302404] dma_slave_caps: <4>[ 0.302406] src_addr_widths = 0x00000000 <4>[ 0.302409] dst_addr_widths = 0x00000000 <4>[ 0.302412] directions = 0x00000001 <4>[ 0.302415] min_burst = 0x00000000 <4>[ 0.302418] max_burst = 0x00000000 <4>[ 0.302421] max_sg_burst = 0x00000000 <4>[ 0.302423] cmd_pause = 0x00 <4>[ 0.302426] cmd_resume = 0x00 <4>[ 0.302429] cmd_terminate = 0x01 <4>[ 0.302431] residue_granularity= 0x00000001 <4>[ 0.302434] descriptor_reuse = 0x00 <4>[ 0.302437] <stack> <4>[ 0.302442] CPU: 3 UID: 0 PID: 40 Comm: kworker/u20:0 Not tainted 6.12.74-stable-standard-00032-g4c3d957ee56f #1 <4>[ 0.302453] Hardware name: pdm3_10_001-2 (DT) <4>[ 0.302459] Workqueue: events_unbound deferred_probe_work_func <4>[ 0.302479] Call trace: <4>[ 0.302482] dump_backtrace+0xd0/0x108 <4>[ 0.302498] show_stack+0x14/0x1c <4>[ 0.302510] dump_stack_lvl+0x5c/0x78 <4>[ 0.302521] dump_stack+0x14/0x1c <4>[ 0.302530] dma_get_slave_caps+0xf8/0x114 <4>[ 0.302544] dmaengine_pcm_new+0x190/0x29c <4>[ 0.302557] snd_soc_pcm_component_new+0x50/0x88 <4>[ 0.302566] soc_new_pcm+0x520/0x618 <4>[ 0.302575] snd_soc_bind_card+0x6cc/0xa48 <4>[ 0.302585] snd_soc_register_card+0xec/0x100 <4>[ 0.302593] devm_snd_soc_register_card+0x48/0x88 <4>[ 0.302603] simple_probe+0x370/0x380 <4>[ 0.302611] platform_probe+0x64/0xb0 <4>[ 0.302623] really_probe+0x18c/0x32c <4>[ 0.302633] __driver_probe_device+0x120/0x138 <4>[ 0.302643] driver_probe_device+0x38/0xf0 <4>[ 0.302653] __device_attach_driver+0x100/0x114 <4>[ 0.302664] bus_for_each_drv+0xac/0xd4 <4>[ 0.302673] __device_attach+0xe4/0x164 <4>[ 0.302683] device_initial_probe+0x10/0x18 <4>[ 0.302693] bus_probe_device+0x38/0x9c <4>[ 0.302702] deferred_probe_work_func+0xc8/0xdc <4>[ 0.302712] process_scheduled_works+0x18c/0x23c <4>[ 0.302725] worker_thread+0x140/0x1c0 <4>[ 0.302736] kthread+0xd8/0xe8 <4>[ 0.302747] ret_from_fork+0x10/0x20 <4>[ 0.302756] </stack> <4>[ 0.303089] dma_slave_caps: <4>[ 0.303092] src_addr_widths = 0x00000000 <4>[ 0.303096] dst_addr_widths = 0x00000000 <4>[ 0.303099] directions = 0x00000000 <4>[ 0.303102] min_burst = 0x00000000 <4>[ 0.303105] max_burst = 0x00000000 <4>[ 0.303107] max_sg_burst = 0x00000000 <4>[ 0.303110] cmd_pause = 0x00 <4>[ 0.303113] cmd_resume = 0x00 <4>[ 0.303116] cmd_terminate = 0x00 <4>[ 0.303119] residue_granularity= 0x00000000 <4>[ 0.303121] descriptor_reuse = 0x00 <4>[ 0.303124] xilinx_dma_device_caps: caps->directions = 0x00000002 <4>[ 0.303128] xilinx_dma_device_caps: caps->directions = 0x00000002 <4>[ 0.303131] dma_slave_caps: <4>[ 0.303133] src_addr_widths = 0x00000000 <4>[ 0.303135] dst_addr_widths = 0x00000000 <4>[ 0.303138] directions = 0x00000002 <4>[ 0.303141] min_burst = 0x00000000 <4>[ 0.303144] max_burst = 0x00000000 <4>[ 0.303147] max_sg_burst = 0x00000000 <4>[ 0.303149] cmd_pause = 0x00 <4>[ 0.303152] cmd_resume = 0x00 <4>[ 0.303155] cmd_terminate = 0x01 <4>[ 0.303158] residue_granularity= 0x00000001 <4>[ 0.303161] descriptor_reuse = 0x00 <4>[ 0.303163] <stack> <4>[ 0.303176] Hardware name: pdm3_10_001-2 (DT) ..... ..... ..... <6>[ 7.102399] macb ff0c0000.ethernet eth1: Link is Up - 100Mbps/Full - flow control tx <3>[ 7.458535] lima fd4b0000.gpu: resume clk fail -13 <6>[ 7.683306] input: PDM3 virtual keyboard as /devices/virtual/input/input3 <4>[ 7.762300] dma_slave_caps: <4>[ 7.762316] src_addr_widths = 0x00000000 <4>[ 7.762322] dst_addr_widths = 0x00000000 <4>[ 7.762325] directions = 0x00000000 <4>[ 7.762328] min_burst = 0x00000000 <4>[ 7.762331] max_burst = 0x00000000 <4>[ 7.762334] max_sg_burst = 0x00000000 <4>[ 7.762337] cmd_pause = 0x00 <4>[ 7.762341] cmd_resume = 0x00 <4>[ 7.762344] cmd_terminate = 0x00 <4>[ 7.762347] residue_granularity= 0x00000000 <4>[ 7.762350] descriptor_reuse = 0x00 <4>[ 7.762354] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 7.762358] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 7.762361] dma_slave_caps: <4>[ 7.762364] src_addr_widths = 0x00000000 <4>[ 7.762366] dst_addr_widths = 0x00000000 <4>[ 7.762370] directions = 0x00000001 <4>[ 7.762373] min_burst = 0x00000000 <4>[ 7.762376] max_burst = 0x00000000 <4>[ 7.762379] max_sg_burst = 0x00000000 <4>[ 7.762382] cmd_pause = 0x00 <4>[ 7.762385] cmd_resume = 0x00 <4>[ 7.762387] cmd_terminate = 0x01 <4>[ 7.762390] residue_granularity= 0x00000001 <4>[ 7.762394] descriptor_reuse = 0x00 <4>[ 7.762397] <stack> <4>[ 7.762416] Hardware name: pdm3_10_001-2 (DT) <4>[ 7.762422] Call trace: <4>[ 7.762425] dump_backtrace+0xd0/0x108 <4>[ 7.762447] show_stack+0x14/0x1c <4>[ 7.762459] dump_stack_lvl+0x5c/0x78 <4>[ 7.762471] dump_stack+0x14/0x1c <4>[ 7.762480] dma_get_slave_caps+0xf8/0x114 <4>[ 7.762495] snd_dmaengine_pcm_refine_runtime_hwparams+0x60/0x15c <4>[ 7.762510] dmaengine_pcm_open+0x180/0x1a8 <4>[ 7.762524] snd_soc_component_open+0x50/0x5c <4>[ 7.762532] __soc_pcm_open+0x84/0x3a4 <4>[ 7.762542] soc_pcm_open+0x28/0x44 <4>[ 7.762550] snd_pcm_open_substream+0x4ec/0x750 <4>[ 7.762560] snd_pcm_open+0xb8/0x1ec <4>[ 7.762568] snd_pcm_playback_open+0x48/0x70 <4>[ 7.762576] snd_open+0x150/0x15c <4>[ 7.762587] chrdev_open+0x170/0x198 <4>[ 7.762601] do_dentry_open+0x2f8/0x3a4 <4>[ 7.762613] vfs_open+0x24/0x44 <4>[ 7.762621] path_openat+0x8cc/0xa04 <4>[ 7.762629] do_filp_open+0x60/0xd0 <4>[ 7.762636] do_sys_openat2+0xa0/0xec <4>[ 7.762644] do_sys_open+0x44/0x6c <4>[ 7.762652] __arm64_sys_openat+0x1c/0x24 <4>[ 7.762659] invoke_syscall+0x68/0xf0 <4>[ 7.762671] el0_svc_common.constprop.0+0xb0/0xcc <4>[ 7.762682] do_el0_svc+0x18/0x20 <4>[ 7.762693] el0_svc+0x18/0x44 <4>[ 7.762705] el0t_64_sync_handler+0x80/0x124 <4>[ 7.762717] el0t_64_sync+0x14c/0x150 <4>[ 7.762726] </stack> ..... ..... ..... <5>[ 40.293549] audit: type=1327 audit(1772610878.644:23): proctitle=737368643A20726F6F74205B707269765D <4>[ 44.792575] dma_slave_caps: <4>[ 44.792589] src_addr_widths = 0x00000000 <4>[ 44.792593] dst_addr_widths = 0x00000000 <4>[ 44.792596] directions = 0x00000000 <4>[ 44.792599] min_burst = 0x00000000 <4>[ 44.792602] max_burst = 0x00000000 <4>[ 44.792606] max_sg_burst = 0x00000000 <4>[ 44.792609] cmd_pause = 0x00 <4>[ 44.792612] cmd_resume = 0x00 <4>[ 44.792614] cmd_terminate = 0x00 <4>[ 44.792618] residue_granularity= 0x00000000 <4>[ 44.792621] descriptor_reuse = 0x00 <4>[ 44.792624] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 44.792628] xilinx_dma_device_caps: caps->directions = 0x00000001 <4>[ 44.792631] dma_slave_caps: <4>[ 44.792633] src_addr_widths = 0x00000000 <4>[ 44.792636] dst_addr_widths = 0x00000000 <4>[ 44.792639] directions = 0x00000001 <4>[ 44.792642] min_burst = 0x00000000 <4>[ 44.792645] max_burst = 0x00000000 <4>[ 44.792648] max_sg_burst = 0x00000000 <4>[ 44.792651] cmd_pause = 0x00 <4>[ 44.792654] cmd_resume = 0x00 <4>[ 44.792656] cmd_terminate = 0x01 <4>[ 44.792659] residue_granularity= 0x00000001 <4>[ 44.792662] descriptor_reuse = 0x00 <4>[ 44.792665] <stack> <4>[ 44.792671] CPU: 3 UID: 0 PID: 1225 Comm: aplay Not tainted 6.12.74-stable.. <4>[ 44.792684] Hardware name: pdm3_10_001-2 (DT) <4>[ 44.792689] Call trace: <4>[ 44.792692] dump_backtrace+0xd0/0x108 <4>[ 44.792713] show_stack+0x14/0x1c <4>[ 44.792725] dump_stack_lvl+0x5c/0x78 <4>[ 44.792737] dump_stack+0x14/0x1c <4>[ 44.792746] dma_get_slave_caps+0xf8/0x114 <4>[ 44.792761] snd_dmaengine_pcm_refine_runtime_hwparams+0x60/0x15c <4>[ 44.792775] dmaengine_pcm_open+0x180/0x1a8 <4>[ 44.792788] snd_soc_component_open+0x50/0x5c <4>[ 44.792796] __soc_pcm_open+0x84/0x3a4 <4>[ 44.792805] soc_pcm_open+0x28/0x44 <4>[ 44.792813] snd_pcm_open_substream+0x4ec/0x750 <4>[ 44.792822] snd_pcm_open+0xb8/0x1ec <4>[ 44.792830] snd_pcm_playback_open+0x48/0x70 <4>[ 44.792838] snd_open+0x150/0x15c <4>[ 44.792849] chrdev_open+0x170/0x198 <4>[ 44.792863] do_dentry_open+0x2f8/0x3a4 <4>[ 44.792875] vfs_open+0x24/0x44 <4>[ 44.792882] path_openat+0x8cc/0xa04 <4>[ 44.792890] do_filp_open+0x60/0xd0 <4>[ 44.792897] do_sys_openat2+0xa0/0xec <4>[ 44.792905] do_sys_open+0x44/0x6c <4>[ 44.792912] __arm64_sys_openat+0x1c/0x24 <4>[ 44.792920] invoke_syscall+0x68/0xf0 <4>[ 44.792931] el0_svc_common.constprop.0+0xb0/0xcc <4>[ 44.792942] do_el0_svc+0x18/0x20 <4>[ 44.792953] el0_svc+0x18/0x44 <4>[ 44.792964] el0t_64_sync_handler+0x80/0x124 <4>[ 44.792977] el0t_64_sync+0x14c/0x150 <4>[ 44.792985] </stack> >To quickly test theory (2), you could then comment out the caps-> >assignments in dma_get_slave_caps() and check if this fixes your issue >or not. I have applied 7e01511443c3, kept RFC patch(xilinx_dma_device_caps + printk) and dmaengine.c debug patch applied (dma_slave_caps_printk() + dump_stack()) and comment out the caps->assignments in dma_get_slave_caps() Observation:Audio works normally. logs: root@pdm3:~# dmesg | grep xilinx_dma_device_caps [ 0.301728] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 0.301731] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.302421] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 0.302424] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 5.882992] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 5.882996] xilinx_dma_device_caps: caps->directions = 0x00000001 root@pdm3:~# root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo ^X^X^CAborted by signal Interrupt... root@pdm3:~# dmesg | grep xilinx_dma_device_caps [ 0.301728] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 0.301731] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.302421] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 0.302424] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 5.882992] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 5.882996] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 324.413686] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 324.413689] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 348.022906] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 348.022910] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 402.654943] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 402.654946] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 423.598936] xilinx_dma_device_caps: caps->directions = 0x00000000 [ 423.598940] xilinx_dma_device_caps: caps->directions = 0x00000001
On Wed Mar 4, 2026 at 9:35 AM CET, Rahul Navale wrote:
>
> <4>[ 0.302360] dma_slave_caps:
> <4>[ 0.302364] src_addr_widths = 0x00000000
> <4>[ 0.302368] dst_addr_widths = 0x00000000
> <4>[ 0.302371] directions = 0x00000000
> <4>[ 0.302374] min_burst = 0x00000000
> <4>[ 0.302377] max_burst = 0x00000000
> <4>[ 0.302380] max_sg_burst = 0x00000000
> <4>[ 0.302383] cmd_pause = 0x00
> <4>[ 0.302386] cmd_resume = 0x00
> <4>[ 0.302388] cmd_terminate = 0x00
> <4>[ 0.302391] residue_granularity= 0x00000000
> <4>[ 0.302394] descriptor_reuse = 0x00
> <4>[ 0.302398] xilinx_dma_device_caps: caps->directions = 0x00000001
> <4>[ 0.302401] xilinx_dma_device_caps: caps->directions = 0x00000001
> <4>[ 0.302404] dma_slave_caps:
> <4>[ 0.302406] src_addr_widths = 0x00000000
> <4>[ 0.302409] dst_addr_widths = 0x00000000
> <4>[ 0.302412] directions = 0x00000001
> <4>[ 0.302415] min_burst = 0x00000000
> <4>[ 0.302418] max_burst = 0x00000000
> <4>[ 0.302421] max_sg_burst = 0x00000000
> <4>[ 0.302423] cmd_pause = 0x00
> <4>[ 0.302426] cmd_resume = 0x00
> <4>[ 0.302429] cmd_terminate = 0x01
> <4>[ 0.302431] residue_granularity= 0x00000001
> <4>[ 0.302434] descriptor_reuse = 0x00
I think the issue stems from the difference in residue_granularity
(directions is set in xilinx_dma_device_caps and playback is still fixed
and cmd_terminate is only referenced in the code by some unrelated
driver).
From a quick trace through the code I found that in the Xilinx DMA
residue_granularity is set for AXIDMA independently from the SG setting
of the DMA core [1].
However, in xilinx_dma_tx_status() one of the conditions for residue
calculations is that SG mode is enabled [2].
Here's a quick patch that defers setting residue_granularity for the
device into channel probe until chan->has_sg is available. Could you
test if this fixes your issue (and of course re-activate all the caps->
assignments in dma_get_slave_caps(), keep the debug stuff for now)?
<-->8-->
diff --git i/drivers/dma/xilinx/xilinx_dma.c w/drivers/dma/xilinx/xilinx_dma.c
index fabff602065f..adae1b37b533 100644
--- i/drivers/dma/xilinx/xilinx_dma.c
+++ w/drivers/dma/xilinx/xilinx_dma.c
@@ -3039,6 +3039,14 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
str_enabled_disabled(chan->has_sg));
}
+ /* Residue calculation is supported by only AXI DMA and CDMA */
+ if(chan->has_sg && (
+ xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA ||
+ xdev->dma_config->dmatype == XDMA_TYPE_CDMA)) {
+ xdev->common.residue_granularity =
+ DMA_RESIDUE_GRANULARITY_SEGMENT;
+ }
+
/* Initialize the tasklet */
tasklet_setup(&chan->tasklet, xilinx_dma_do_tasklet);
@@ -3277,15 +3285,9 @@ static int xilinx_dma_probe(struct platform_device *pdev)
xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg;
xdev->common.device_prep_dma_cyclic =
xilinx_dma_prep_dma_cyclic;
- /* Residue calculation is supported by only AXI DMA and CDMA */
- xdev->common.residue_granularity =
- DMA_RESIDUE_GRANULARITY_SEGMENT;
} else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy;
- /* Residue calculation is supported by only AXI DMA and CDMA */
- xdev->common.residue_granularity =
- DMA_RESIDUE_GRANULARITY_SEGMENT;
} else if (xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
xdev->common.device_prep_slave_sg = xilinx_mcdma_prep_slave_sg;
} else {
<--8<-->
[1]: https://elixir.bootlin.com/linux/v6.19.3/source/drivers/dma/xilinx/xilinx_dma.c#L3284
[2]: https://elixir.bootlin.com/linux/v6.19.3/source/drivers/dma/xilinx/xilinx_dma.c#L1293
From: Rahul Navale <rahul.navale@ifm.com>
Hi Folker,
>Could you confirm this from your DT?
DT for the audio AXI DMA is below. We indeed have two distinct
AXI DMA devices, each instantiated with a single fixed-direction channel:
axi_dma0: MM2S-only (playback / DMA_MEM_TO_DEV)
axi_dma1: S2MM-only (capture / DMA_DEV_TO_MEM)
axi_dma0: axidma@a0100000 {
compatible = "xlnx,axi-dma-1.00.a";
#dma-cells = <1>;
reg = <0 0xa0100000 0 0x10000>;
clocks = <&aclk>;
clock-names = "s_axi_lite_aclk";
xlnx,addrwidth = <32>;
dma-channel {
compatible = "xlnx,axi-dma-mm2s-channel";
interrupt-parent = <&axi_intc>;
interrupts = <14>;
xlnx,datawidth = <32>;
};
};
axi_dma1: axidma@a0110000 {
compatible = "xlnx,axi-dma-1.00.a";
#dma-cells = <1>;
reg = <0 0xa0110000 0 0x10000>;
clocks = <&aclk>;
clock-names = "s_axi_lite_aclk";
xlnx,addrwidth = <32>;
dma-channel {
compatible = "xlnx,axi-dma-s2mm-channel";
interrupt-parent = <&axi_intc>;
interrupts = <15>;
xlnx,datawidth = <32>;
};
};
This confirms your suspicion: direction aggregation via
xdev->common.directions |= chan->direction does not end up combining
different directions within a single dma_device instance in our setup,
because each dma_device only has one channel and one direction.
>There's however one other thing you could test: Could you keep the RFC
>patch with the printks in place, but revert 7e01511443c3, rerun and post
>the logs?
Debug results with your RFC patch kept, but 7e01511443c3 reverted:
- Audio playback works (aplay plays normally)
- No xilinx_dma_device_caps printk output at all:
# dmesg | grep xilinx_dma_device_caps
<no output>
On Mon Mar 2, 2026 at 8:24 AM CET, Rahul Navale wrote:
>
> DT for the audio AXI DMA is below. We indeed have two distinct
> AXI DMA devices, each instantiated with a single fixed-direction channel:
>
> axi_dma0: MM2S-only (playback / DMA_MEM_TO_DEV)
> axi_dma1: S2MM-only (capture / DMA_DEV_TO_MEM)
No surprises here, good.
> Debug results with your RFC patch kept, but 7e01511443c3 reverted:
> - Audio playback works (aplay plays normally)
> - No xilinx_dma_device_caps printk output at all:
> # dmesg | grep xilinx_dma_device_caps
> <no output>
From that observation we can conclude that in your good case
dma_get_slave_caps() returns early with -ENXIO [1] while in your bad
case it runs entirely returning 0.
So I think it's reasonable to assume that either (1) the change in
return value of dma_get_slave_caps() causes different behaviour in the
callers (possibly [2][3]; needs verification) or that (2) dma_slave_caps
*caps, whose fields now get populated in dma_get_slave_caps() cause
different behavior in downstream users of said caps.
For the next debugging step I suggest that we focus on (2) but also on
getting some insight into the callers. Could you please reapply
7e01511443c3, keep the RFC patch in place and additionally apply the
below patch?
This will exercise your bad case, print the differences for caps, and
also print the call stacks for all calls to dma_get_slave_caps().
Then, please extract & post the relevant dmesg logs.
<-->8-->
diff --git i/drivers/dma/dmaengine.c w/drivers/dma/dmaengine.c
index ca13cd39330b..710da870b8e9 100644
--- i/drivers/dma/dmaengine.c
+++ w/drivers/dma/dmaengine.c
@@ -570,6 +570,27 @@ void dma_issue_pending_all(void)
}
EXPORT_SYMBOL(dma_issue_pending_all);
+static void dma_slave_caps_printk(const struct dma_slave_caps *caps)
+{
+ if (!caps) {
+ printk("dma_slave_caps: (nil)\n");
+ return;
+ }
+
+ printk("dma_slave_caps:\n");
+ printk(" src_addr_widths = 0x%08x\n", caps->src_addr_widths);
+ printk(" dst_addr_widths = 0x%08x\n", caps->dst_addr_widths);
+ printk(" directions = 0x%08x\n", caps->directions);
+ printk(" min_burst = 0x%08x\n", caps->min_burst);
+ printk(" max_burst = 0x%08x\n", caps->max_burst);
+ printk(" max_sg_burst = 0x%08x\n", caps->max_sg_burst);
+ printk(" cmd_pause = 0x%02x\n", (u8)caps->cmd_pause);
+ printk(" cmd_resume = 0x%02x\n", (u8)caps->cmd_resume);
+ printk(" cmd_terminate = 0x%02x\n", (u8)caps->cmd_terminate);
+ printk(" residue_granularity= 0x%08x\n", (u32)caps->residue_granularity);
+ printk(" descriptor_reuse = 0x%02x\n", (u8)caps->descriptor_reuse);
+}
+
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
{
struct dma_device *device;
@@ -584,6 +605,8 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
test_bit(DMA_CYCLIC, device->cap_mask.bits)))
return -ENXIO;
+ dma_slave_caps_printk(caps);
+
/*
* Check whether it reports it uses the generic slave
* capabilities, if not, that means it doesn't support any
@@ -614,6 +637,11 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
if (device->device_caps)
device->device_caps(chan, caps);
+ dma_slave_caps_printk(caps);
+ printk("<stack>\n");
+ dump_stack();
+ printk("</stack>\n");
+
return 0;
}
EXPORT_SYMBOL_GPL(dma_get_slave_caps);
<--8<-->
[1]: https://elixir.bootlin.com/linux/v6.19.3/source/drivers/dma/dmaengine.c#L593
[2]: https://elixir.bootlin.com/linux/v6.19.3/source/sound/core/pcm_dmaengine.c#L421
[3]: https://elixir.bootlin.com/linux/v6.19.3/source/sound/soc/soc-generic-dmaengine-pcm.c#L206
On Tue Mar 3, 2026 at 9:09 PM CET, Folker Schwesinger wrote: > So I think it's reasonable to assume that either (1) the change in > return value of dma_get_slave_caps() causes different behaviour in the > callers (possibly [2][3]; needs verification) or that (2) dma_slave_caps > *caps, whose fields now get populated in dma_get_slave_caps() cause > different behavior in downstream users of said caps. > > For the next debugging step I suggest that we focus on (2) but also on > getting some insight into the callers. Could you please reapply > 7e01511443c3, keep the RFC patch in place... To quickly test theory (2), you could then comment out the caps-> assignments in dma_get_slave_caps() and check if this fixes your issue or not. <-->8--> diff --git i/drivers/dma/dmaengine.c w/drivers/dma/dmaengine.c index ca13cd39330b..91c5d7abb028 100644 --- i/drivers/dma/dmaengine.c +++ w/drivers/dma/dmaengine.c @@ -592,6 +592,7 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps) if (!device->directions) return -ENXIO; + /* caps->src_addr_widths = device->src_addr_widths; caps->dst_addr_widths = device->dst_addr_widths; caps->directions = device->directions; @@ -603,6 +604,7 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps) caps->cmd_pause = !!device->device_pause; caps->cmd_resume = !!device->device_resume; caps->cmd_terminate = !!device->device_terminate_all; + */ /* * DMA engine device might be configured with non-uniformly <--8<-->
From: Rahul Navale <rahul.navale@ifm.com>
Hi Folker,
>Could you confirm this from your DT?
DT for the audio AXI DMA is below. We indeed have two distinct
AXI DMA devices, each instantiated with a single fixed-direction channel:
axi_dma0: MM2S-only (playback / DMA_MEM_TO_DEV)
axi_dma1: S2MM-only (capture / DMA_DEV_TO_MEM)
axi_dma0: axidma@a0100000 {
compatible = "xlnx,axi-dma-1.00.a";
#dma-cells = <1>;
reg = <0 0xa0100000 0 0x10000>;
clocks = <&aclk>;
clock-names = "s_axi_lite_aclk";
xlnx,addrwidth = <32>;
dma-channel {
compatible = "xlnx,axi-dma-mm2s-channel";
interrupt-parent = <&axi_intc>;
interrupts = <14>;
xlnx,datawidth = <32>;
};
};
axi_dma1: axidma@a0110000 {
compatible = "xlnx,axi-dma-1.00.a";
#dma-cells = <1>;
reg = <0 0xa0110000 0 0x10000>;
clocks = <&aclk>;
clock-names = "s_axi_lite_aclk";
xlnx,addrwidth = <32>;
dma-channel {
compatible = "xlnx,axi-dma-s2mm-channel";
interrupt-parent = <&axi_intc>;
interrupts = <15>;
xlnx,datawidth = <32>;
};
};
This confirms your suspicion: direction aggregation via
xdev->common.directions |= chan->direction does not end up combining
different directions within a single dma_device instance in our setup,
because each dma_device only has one channel and one direction.
>There's however one other thing you could test: Could you keep the RFC
>patch with the printks in place, but revert 7e01511443c3, rerun and post
>the logs?
Debug results with your RFC patch kept, but 7e01511443c3 reverted:
- Audio playback works (aplay plays normally)
- No xilinx_dma_device_caps printk output at all:
# dmesg | grep xilinx_dma_device_caps
<no output>
From: Rahul Navale <rahul.navale@ifm.com> >in the RFC patch, rebuild and exercise your use case. Then please do >dmesg|grep xilinx_dma_device_caps Hi Folker, Thanks for the suggestion. I applied your RFC patch and added printk() in xilinx_dma_device_caps() around the assignment of caps->directions. After rebuilding and booting, I exercised the audio playback use case and collected the requested logs. The callback is reached and prints appear both during early boot and during playback. Issue still persists. cyclic playback fails after the first buffer period. Output of `dmesg | grep xilinx_dma_device_caps`: root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo ^CAborted by signal Interrupt... aplay: pcm_write:2178: write error: Interrupted system call root@pdm3:~# aplay closetoyou.wav root@pdm3:~# dmesg | grep xilinx_dma_device_caps [ 0.318827] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.318832] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.319170] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 0.319175] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 6.375745] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 6.375762] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 133.401497] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 133.401513] xilinx_dma_device_caps: caps->directions = 0x00000001 root@pdm3:~# root@pdm3:~# aplay closetoyou.wav Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo aplay: pcm_write:2178: write error: Interrupted system call root@pdm3:~# aplay closetoyou.wav root@pdm3:~# dmesg | grep xilinx_dma_device_caps [ 0.318827] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.318832] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 0.319170] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 0.319175] xilinx_dma_device_caps: caps->directions = 0x00000002 [ 6.375745] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 6.375762] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 133.401497] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 133.401513] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 167.802636] xilinx_dma_device_caps: caps->directions = 0x00000001 [ 167.802651] xilinx_dma_device_caps: caps->directions = 0x00000001
Hi Rahul, On Thu Feb 26, 2026 at 8:35 AM CET, Rahul Navale wrote: > root@pdm3:~# aplay closetoyou.wav > Playing WAVE 'closetoyou.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo > > aplay: pcm_write:2178: write error: Interrupted system call > root@pdm3:~# aplay closetoyou.wav root@pdm3:~# dmesg | grep xilinx_dma_device_caps > [ 0.318827] xilinx_dma_device_caps: caps->directions = 0x00000001 > [ 0.318832] xilinx_dma_device_caps: caps->directions = 0x00000001 > [ 0.319170] xilinx_dma_device_caps: caps->directions = 0x00000002 > [ 0.319175] xilinx_dma_device_caps: caps->directions = 0x00000002 > [ 6.375745] xilinx_dma_device_caps: caps->directions = 0x00000001 > [ 6.375762] xilinx_dma_device_caps: caps->directions = 0x00000001 > [ 133.401497] xilinx_dma_device_caps: caps->directions = 0x00000001 > [ 133.401513] xilinx_dma_device_caps: caps->directions = 0x00000001 > [ 167.802636] xilinx_dma_device_caps: caps->directions = 0x00000001 > [ 167.802651] xilinx_dma_device_caps: caps->directions = 0x00000001 Looks like direction aggregation does not actually happen in your case. Probably because you have two distinct DMA devices with a single channel each. Could you confirm this from your DT? This suggests, that direction aggregation is not the actual root cause of the regression you're seeing. Maybe 7e01511443c3 exposes/triggers another subtle flaw in the ASoC or DMA layers or your driver. But that's speculation at this point. I'm not sure how to proceed from here. I think the patch itself is functional, but it does not address the actual issue. There's however one other thing you could test: Could you keep the RFC patch with the printks in place, but revert 7e01511443c3, rerun and post the logs?
From: Rahul Navale <rahul.navale@ifm.com> >this is an important bit of information. Could you verify that your >customized driver uses dmaengine's dma_get_slave_caps() to obtain >channel capabilities and that the newly introduced >xilinx_dma_device_caps() is actually called? Hi Folker, Thanks for the clarification — I misunderstood about custom drivers. I have confirmed that we are using the upstream xilinx DMA driver (drivers/dma/xilinx/xilinx_dma.c) and using AXI DMA for audio. We use separate fixed-direction channels: MM2S for playback (DMA_MEM_TO_DEV) and S2MM for capture (DMA_DEV_TO_MEM), referenced via device tree. Thanks, Rahul Navale
On Tue Feb 24, 2026 at 10:30 AM CET, Rahul Navale wrote:
> From: Rahul Navale <rahul.navale@ifm.com>
>
>>this is an important bit of information. Could you verify that your
>>customized driver uses dmaengine's dma_get_slave_caps() to obtain
>>channel capabilities and that the newly introduced
>>xilinx_dma_device_caps() is actually called?
>
> Hi Folker,
>
> Thanks for the clarification — I misunderstood about custom drivers.
>
> I have confirmed that we are using the upstream xilinx DMA driver (drivers/dma/xilinx/xilinx_dma.c)
> and using AXI DMA for audio. We use separate fixed-direction channels:
> MM2S for playback (DMA_MEM_TO_DEV) and S2MM for capture (DMA_DEV_TO_MEM), referenced
> via device tree.
>
Ok good, but this does not say anything about whether
xilinx_dma_device_caps() is actually called or not. Could you please add
printk("xilinx_dma_device_caps: dirs = 0x%08x\n", caps->direction);
before and after
caps->direction = chan->direction;
in the RFC patch, rebuild and exercise your use case. Then please do
dmesg|grep xilinx_dma_device_caps
and post the output.
In case there isn't any output, your driver does not reach
xilinx_dma_device_caps(). In that case the proposed patch is uneffective
for your custom driver.
From: Rahul Navale <rahul.navale@ifm.com> Hi Folker, > Can you help reproduce the issue at our end. How does your setup > looks like? Is it dependent on PL design ? Unless there is some > dependency I can try and triage it. Our setup uses a custom FPGA design with a custom XSA file for the PL. The multimedia drivers (audio/video) are also customized for our platform. Regards, Rahul Navale
Hi Rahul, On Fri Feb 20, 2026 at 2:28 PM CET, Rahul Navale wrote: > From: Rahul Navale <rahul.navale@ifm.com> > > Our setup uses a custom FPGA design with a custom XSA file for the PL. > The multimedia drivers (audio/video) are also customized for our platform. > this is an important bit of information. Could you verify that your customized driver uses dmaengine's dma_get_slave_caps() to obtain channel capabilities and that the newly introduced xilinx_dma_device_caps() is actually called?
From: Rahul Navale <rahul.navale@ifm.com> Hi Folker, > Posting this as RFC because I can't verify this actually fixes the > regression as I don't have a ZynqMP. So Rahul, could you test if this > fixes the issue and report back? I tested this patch on my ZynqMP platform. Unfortunately, the issue still persists. Cyclic playback fails after the first buffer period. Regards, Rahul Navale
© 2016 - 2026 Red Hat, Inc.