Linux DMA Slave Channel Request
Free Linux Kernel Development Course — Linux Device Drivers, DMA Engine Chapter, Lecture 7
free linux kernel development course
free linux device drivers course
free embedded systems course
free embedded linux course
Every linux dma slave channel request in a real driver eventually comes down to one line of code: the call that asks the DMA engine framework for a channel. In this lecture of our free Linux kernel development course we look closely at that one line, because the kernel history around it is messy — there is an old wrapper, an even older Device Tree helper, and a modern unified function, and mixing them up is one of the most common bugs in DMA client drivers. This lecture also closes out our DMA engine mini-series (lectures 1 to 6) with a full recap of the slave DMA API.
What You Will Learn
- Why
dma_request_slave_channel()exists and why it is deprecated - How the old
of_dma_request_slave_channel()Device Tree helper worked - Doing a correct linux dma slave channel request with
dma_request_chan() - Why deferred probing (
-EPROBE_DEFER) breaks with the legacy API - A complete, original probe-based demo driver
- Common mistakes, best practices, and a full DMA chapter summary
Prerequisites
Before this lecture, you should already be comfortable with:
- Writing a basic platform driver (probe/remove)
- DMA channel setup from our earlier lecture on DT bindings
- struct dma_slave_config and transfer descriptors
- A Linux 6.x kernel source tree or headers for module builds
Recap: The DMA Slave API Journey So Far
Across this DMA engine chapter we built a complete mental model of the slave DMA API step by step: coherent DMA mapping, streaming DMA mapping with scatter/gather, transaction submission with completion callbacks, slave channel configuration, filter functions, and Device Tree bindings. Every one of those lectures needed a DMA channel handle before anything else could happen. This lecture finally opens up that very first call and asks: what does “request a channel” actually mean to the kernel, and which function should you use to do a linux dma slave channel request the right way in 2026?
Why dma_request_slave_channel() Exists
Long before the current dmaengine core matured, driver authors requested a named DMA channel with a small helper:
struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
It looked simple and many older drivers still call it. But look at what it actually does internally in the current kernel source — it is nothing more than a thin wrapper:
/* Deprecated, please use dma_request_chan() directly */
static inline struct dma_chan *__deprecated
dma_request_slave_channel(struct device *dev, const char *name)
{
struct dma_chan *ch = dma_request_chan(dev, name);
return IS_ERR(ch) ? NULL : ch;
}
That single line return IS_ERR(ch) ? NULL : ch; is the whole problem. dma_request_chan() returns a proper error pointer (for example -EPROBE_DEFER when the DMA controller driver has not loaded yet), but the legacy wrapper throws that information away and always hands back a plain NULL. Your probe function can no longer tell the difference between “no such channel exists” and “try again later.”
Inside of_dma_request_slave_channel(): The Old Device Tree Helper
Before dma_request_chan() became the single unified entry point, Device Tree-based platforms used a dedicated OF-only helper:
struct dma_chan *of_dma_request_slave_channel(struct device_node *np, const char *name);
This function parsed the consuming device’s node directly, read the dmas and dma-names properties we studied in the previous lecture, matched the requested name against the list, and called into the DMA controller’s of_dma_xlate callback to translate the specifier into a channel. It only understood Device Tree — nothing else. If your platform used ACPI or the old board-file dma_slave_map table instead, this function was useless to you, which is exactly why the kernel folded its logic into the generic dma_request_chan() path so one function works everywhere.
The Modern Way: dma_request_chan() and Deferred Probing
The current, recommended API for any linux dma slave channel request is:
struct dma_chan *dma_request_chan(struct device *dev, const char *name);
Internally this single call tries, in order, the Device Tree dmas/dma-names lookup, an ACPI DMA lookup, and finally the legacy dma_slave_map table — whichever mechanism your platform actually uses. Because it returns a real pointer-or-error value, your probe function can react correctly:
chan = dma_request_chan(dev, "tx");
if (IS_ERR(chan)) {
if (PTR_ERR(chan) == -EPROBE_DEFER)
return -EPROBE_DEFER; /* DMA controller not ready yet, try again */
return PTR_ERR(chan);
}
That one if (PTR_ERR(chan) == -EPROBE_DEFER) check is the entire reason the kernel community deprecated the older helpers. A probe deferral simply means the driver core will retry your probe() once the DMA controller driver has finished loading — something that is impossible to do correctly if all you have is a bare NULL.
Comparison: Legacy vs Modern Slave Channel Request APIs
| Function | Lookup source | Error reporting | Status in kernel 6.x |
|---|---|---|---|
| dma_request_slave_channel() | Delegates to dma_request_chan() | Always NULL on failure | Deprecated wrapper |
| of_dma_request_slave_channel() | Device Tree only | Error pointer, but DT-only | Superseded, DT logic merged into dma_request_chan() |
| dma_request_chan() | DT, ACPI, or dma_slave_map | Full error pointer incl. -EPROBE_DEFER | Current recommended API |
Hands-On Example: ep_dma_request_demo Driver
The following original platform driver demonstrates a correct linux dma slave channel request with proper deferred-probe handling. It is written for kernel 6.x and requests a single “tx” channel described in a matching Device Tree node.
// ep_dma_request_demo.c
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/dmaengine.h>
struct ep_dma_request_priv {
struct dma_chan *tx_chan;
};
static int ep_dma_request_probe(struct platform_device *pdev)
{
struct ep_dma_request_priv *priv;
struct dma_chan *chan;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* Correct linux dma slave channel request: use dma_request_chan() */
chan = dma_request_chan(&pdev->dev, "tx");
if (IS_ERR(chan)) {
if (PTR_ERR(chan) == -EPROBE_DEFER) {
dev_info(&pdev->dev, "ep_dma_request_demo: DMA controller not ready, deferring probe\n");
return -EPROBE_DEFER;
}
dev_err(&pdev->dev, "ep_dma_request_demo: failed to request tx channel: %ld\n",
PTR_ERR(chan));
return PTR_ERR(chan);
}
priv->tx_chan = chan;
platform_set_drvdata(pdev, priv);
dev_info(&pdev->dev, "ep_dma_request_demo: tx channel %s acquired successfully\n",
dma_chan_name(chan));
return 0;
}
static void ep_dma_request_remove(struct platform_device *pdev)
{
struct ep_dma_request_priv *priv = platform_get_drvdata(pdev);
dma_release_channel(priv->tx_chan);
dev_info(&pdev->dev, "ep_dma_request_demo: tx channel released\n");
}
static const struct of_device_id ep_dma_request_of_match[] = {
{ .compatible = "ep,dma-request-demo", },
{ }
};
MODULE_DEVICE_TABLE(of, ep_dma_request_of_match);
static struct platform_driver ep_dma_request_driver = {
.probe = ep_dma_request_probe,
.remove = ep_dma_request_remove,
.driver = {
.name = "ep_dma_request_demo",
.of_match_table = ep_dma_request_of_match,
},
};
module_platform_driver(ep_dma_request_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Demo driver for correct linux dma slave channel request handling");
The matching Device Tree consumer node reuses the same “tx” naming pattern from our DT bindings lecture:
ep_dma_client: ep-dma-client {
compatible = "ep,dma-request-demo";
dmas = <&dma0 5>;
dma-names = "tx";
};
Building and Loading the Module
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
sudo insmod ep_dma_request_demo.ko
dmesg | tail -n 5
sudo rmmod ep_dma_request_demo
Expected Output
[ 102.441823] ep_dma_request_demo: tx channel dma0chan5 acquired successfully
...
[ 108.902117] ep_dma_request_demo: tx channel released
If the DMA controller module has not been loaded yet, you will instead see the deferred-probe path being exercised:
[ 45.113209] ep_dma_request_demo: DMA controller not ready, deferring probe
[ 46.980341] ep_dma_request_demo: tx channel dma0chan5 acquired successfully
Common Mistakes
- Calling the deprecated dma_request_slave_channel() in new code
- Treating a NULL channel return as “no DMA support” instead of “try again later”
- Forgetting -EPROBE_DEFER propagation from probe()
- Mixing of_dma_request_slave_channel() with ACPI-based platforms where it cannot work
- Not calling dma_release_channel() in the remove() path
Best Practices
- Always use dma_request_chan() for any new linux dma slave channel request
- Always check IS_ERR() and explicitly branch on -EPROBE_DEFER
- Keep the “dma-names” string in the DT node and driver code identical
- Release every requested channel in remove() with dma_release_channel()
- Prefer devm-style cleanup for the surrounding private data structure
Performance Considerations
Channel request itself is a one-time, probe-time cost, so it has no runtime performance impact. The real performance concern is indirect: if your driver silently fails a linux dma slave channel request because of the deprecated NULL-returning wrapper, the kernel falls back to a slower CPU-copy path instead of hardware DMA, and that fallback is often mistaken for a DMA performance problem when it is really a channel-request bug.
Security Considerations
A requested DMA channel is exclusive to the calling driver until it is released, so failing to call dma_release_channel() on every error path can starve other drivers of that channel. Also validate any buffer length or offset coming from userspace before handing it to a DMA transfer built on top of a channel obtained this way, since DMA hardware bypasses normal CPU-side access checks.
Real-World Use Cases
UART, SPI, I2S/audio, and SD/MMC drivers on embedded SoCs all request named slave channels this way at probe time. Historically many of these drivers called the now-deprecated dma_request_slave_channel(), and kernel maintainers have been steadily converting them — the ASoC and DRM subsystems both merged patches switching to dma_request_chan() for exactly the deferred-probing reasons covered in this lecture.
Summary: Key Takeaways from the Complete DMA Engine Chapter
Across this DMA engine chapter (lectures 1-7) you learned:
- Coherent DMA mapping with dma_alloc_coherent() / dmam_alloc_coherent()
- Streaming mapping: dma_map_single() and scatter/gather with dma_map_sg()
- Submitting transactions with dmaengine_submit() and completion callbacks
- Configuring a channel with struct dma_slave_config
- Legacy channel filtering with dma_filter_fn
- Device Tree bindings: dmas, dma-names, #dma-cells
- Making a correct linux dma slave channel request with dma_request_chan()
Conclusion
A linux dma slave channel request looks like a single function call, but the kernel’s history around it hides a real trap: the deprecated dma_request_slave_channel() and the old Device Tree-only of_dma_request_slave_channel() both discard the error information that dma_request_chan() gives you for free. Using dma_request_chan() and correctly handling -EPROBE_DEFER is the difference between a DMA client driver that loads reliably at boot and one that mysteriously fails only when module load order changes. This closes our DMA engine chapter — you now have the complete picture from buffer mapping to channel request.
FAQ
Why is dma_request_slave_channel() deprecated?
Because it discards the error code from dma_request_chan(), always returning NULL on failure, which makes it impossible to detect and handle -EPROBE_DEFER correctly.
Is of_dma_request_slave_channel() still usable in kernel 6.x?
The symbol history shows its Device Tree lookup logic was folded into dma_request_chan(), which is now the single recommended entry point for every lookup mechanism, DT included.
What does dma_request_chan() actually search through?
It tries a Device Tree dmas/dma-names lookup, then an ACPI DMA lookup, then the legacy dma_slave_map table, depending on what your platform provides.
What happens if I ignore -EPROBE_DEFER in probe()?
Your driver will fail permanently if the DMA controller driver has not finished probing yet, instead of being retried automatically by the driver core.
Do I need to release a channel obtained this way?
Yes, call dma_release_channel() in your remove() path so the channel becomes available to other drivers.
Can dma_request_chan() return a channel that does not support what I need?
It returns a channel by name/mapping, not by capability alone, so you should still verify direction and configuration needs via struct dma_slave_config afterward.
Is this lecture’s demo driver hardware-specific?
No, it is written as a generic platform driver pattern; you adapt the compatible string and channel name to your actual SoC’s DMA controller and DT layout.
Where can I read the authoritative kernel documentation for this API?
The DMA Engine API Guide under Documentation/driver-api/dmaengine/client.rst in the kernel source tree, and the docs.kernel.org mirror of the same page.
Continue the Free Linux Kernel Development Course
Explore more lectures in our free Linux device drivers course and free embedded Linux course on EmbeddedPathashala.
