[PATCH v2 1/3] dmaengine: Allow drivers to assign static channel IDs
From: Koichiro Den
Date: Fri Aug 28 2026 - 12:36:38 EST
The dmaengine core assigns channel IDs in registration order. If a driver
skips a hardware channel, chan_id can differ from the hardware numbering
and a client cannot reliably correlate a requested channel with hardware
resources.
Let a driver request an exact channel ID before device registration.
Reserve static IDs through the existing IDA so they remain unique, while
retaining automatic IDA allocation as the default.
For example, idma32 uses chan_id to select DMA_CTL_CH() and
DMA_XBAR_SEL(), so it relies on ascending registration order to match
chan_id with the hardware channel number.
Use direction-flattened IDs for dw-edma channels. Unlike the
direction-local hardware channel number, these IDs are unique within the
DMA device.
Suggested-by: Frank Li <Frank.Li@xxxxxxx>
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Changes in v2:
- Carry over PCI DMA EPF v7 patch 1.
https://lore.kernel.org/r/20260813063757.3131865-2-den@xxxxxxxxxxxxx/
- Add the idma32 example requested during v7 review. (Frank)
https://lore.kernel.org/r/an4TXwT37vWYEzCn@SMW015318/
drivers/dma/dmaengine.c | 13 ++++++++-----
drivers/dma/dw-edma/dw-edma-core.c | 1 +
include/linux/dmaengine.h | 20 ++++++++++++++++++++
3 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 6ffd8bd82154..cc64a4679e6f 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1078,6 +1078,7 @@ static int __dma_async_device_channel_register(struct dma_device *device,
struct dma_chan *chan,
const char *name)
{
+ unsigned int id;
int rc;
chan->local = alloc_percpu(typeof(*chan->local));
@@ -1089,11 +1090,13 @@ static int __dma_async_device_channel_register(struct dma_device *device,
goto err_free_local;
}
- /*
- * When the chan_id is a negative value, we are dynamically adding
- * the channel. Otherwise we are static enumerating.
- */
- chan->chan_id = ida_alloc(&device->chan_ida, GFP_KERNEL);
+ if (chan->chan_id & DMA_CHAN_ID_STATIC) {
+ id = chan->chan_id & ~DMA_CHAN_ID_STATIC;
+ chan->chan_id = ida_alloc_range(&device->chan_ida, id, id,
+ GFP_KERNEL);
+ } else {
+ chan->chan_id = ida_alloc(&device->chan_ida, GFP_KERNEL);
+ }
if (chan->chan_id < 0) {
pr_err("%s: unable to alloc ida for chan: %d\n",
__func__, chan->chan_id);
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 03b2c2188351..a678c70a78fe 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -988,6 +988,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
&dw->chip->dt_region_rd[chan->id];
vchan_init(&chan->vc, dma);
+ dmaengine_set_static_chan_id(&chan->vc.chan, i);
dw_edma_core_ch_config(chan);
}
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index fe33a20abc61..f669b79d7731 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -369,6 +369,26 @@ struct dma_chan {
void *private;
};
+#define DMA_CHAN_ID_STATIC BIT(30)
+
+/**
+ * dmaengine_set_static_chan_id - request an exact DMA engine channel ID
+ * @chan: DMA channel
+ * @id: channel ID, unique within the DMA device
+ *
+ * Drivers may call this after initializing @chan and before registering its
+ * DMA device. The dmaengine core reserves @id from the device IDA instead of
+ * assigning the next available ID.
+ */
+static inline void dmaengine_set_static_chan_id(struct dma_chan *chan,
+ unsigned int id)
+{
+ if (WARN_ON_ONCE(id >= DMA_CHAN_ID_STATIC))
+ return;
+
+ chan->chan_id = DMA_CHAN_ID_STATIC | id;
+}
+
/**
* struct dma_chan_dev - relate sysfs device node to backing channel device
* @chan: driver channel device
--
2.51.0