Re: [RFC PATCH] dmaengine: xilinx_dma: Fix per-channel direction reporting via device_caps
From: Folker Schwesinger
Date: Tue Mar 03 2026 - 15:10:13 EST
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