Use iommu-map, when provided, to get the stream ID to be programmed
for each channel. Register each channel separately for allowing it
to use a separate IOMMU domain for the transfer.
Channels will continue to use the same global stream ID if iommu-map
property is not present in the device tree.
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/dma/tegra186-gpc-dma.c | 62 +++++++++++++++++++++++++++-------
1 file changed, 49 insertions(+), 13 deletions(-)
diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index ce3b1dd52bb3..b8ca269fa3ba 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_dma.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/slab.h>
@@ -1403,9 +1404,12 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
static int tegra_dma_probe(struct platform_device *pdev)
{
const struct tegra_dma_chip_data *cdata = NULL;
+ struct tegra_dma_channel *tdc;
+ struct tegra_dma *tdma;
+ struct dma_chan *chan;
+ bool use_iommu_map = false;
unsigned int i;
u32 stream_id;
- struct tegra_dma *tdma;
int ret;
cdata = of_device_get_match_data(&pdev->dev);
@@ -1433,9 +1437,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
tdma->dma_dev.dev = &pdev->dev;
- if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
- dev_err(&pdev->dev, "Missing iommu stream-id\n");
- return -EINVAL;
+ use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map");
+ if (!use_iommu_map) {
+ if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
+ dev_err(&pdev->dev, "Missing iommu stream-id\n");
+ return -EINVAL;
+ }
}
ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
@@ -1449,7 +1456,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&tdma->dma_dev.channels);
for (i = 0; i < cdata->nr_channels; i++) {
- struct tegra_dma_channel *tdc = &tdma->channels[i];
+ tdc = &tdma->channels[i];
/* Check for channel mask */
if (!(tdma->chan_mask & BIT(i)))
@@ -1469,10 +1476,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
vchan_init(&tdc->vc, &tdma->dma_dev);
tdc->vc.desc_free = tegra_dma_desc_free;
-
- /* program stream-id for this channel */
- tegra_dma_program_sid(tdc, stream_id);
- tdc->stream_id = stream_id;
}
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
@@ -1517,20 +1520,53 @@ static int tegra_dma_probe(struct platform_device *pdev)
return ret;
}
+ list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
+ struct device *chdev = &chan->dev->device;
+
+ tdc = to_tegra_dma_chan(chan);
+ if (use_iommu_map) {
+ chdev->coherent_dma_mask = pdev->dev.coherent_dma_mask;
+ chdev->dma_mask = &chdev->coherent_dma_mask;
+ chdev->bus = pdev->dev.bus;
+
+ ret = of_dma_configure_id(chdev, pdev->dev.of_node,
+ true, &tdc->id);
+ if (ret) {
+ dev_err(chdev, "Failed to configure IOMMU for channel %d: %d\n",
+ tdc->id, ret);
+ goto err_unregister;
+ }
+
+ if (!tegra_dev_iommu_get_stream_id(chdev, &stream_id)) {
+ dev_err(chdev, "Failed to get stream ID for channel %d\n",
+ tdc->id);
+ goto err_unregister;
+ }
+
+ chan->dev->chan_dma_dev = true;
+ }
+
+ /* program stream-id for this channel */
+ tegra_dma_program_sid(tdc, stream_id);
+ tdc->stream_id = stream_id;
+ }
+
ret = of_dma_controller_register(pdev->dev.of_node,
tegra_dma_of_xlate, tdma);
if (ret < 0) {
dev_err_probe(&pdev->dev, ret,
"GPC DMA OF registration failed\n");
-
- dma_async_device_unregister(&tdma->dma_dev);
- return ret;
+ goto err_unregister;
}
- dev_info(&pdev->dev, "GPC DMA driver register %lu channels\n",
+ dev_info(&pdev->dev, "GPC DMA driver registered %lu channels\n",
hweight_long(tdma->chan_mask));
return 0;
+
+err_unregister:
+ dma_async_device_unregister(&tdma->dma_dev);
+ return ret;
}
static void tegra_dma_remove(struct platform_device *pdev)
--
2.50.1
Hi Akhil,
kernel test robot noticed the following build warnings:
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Akhil-R/dt-bindings-dma-nvidia-tegra186-gpc-dma-Add-iommu-map-property/20260218-014114
base: https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git next
patch link: https://lore.kernel.org/r/20260217173457.18628-7-akhilrajeev%40nvidia.com
patch subject: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
config: sparc64-randconfig-r072-20260218 (https://download.01.org/0day-ci/archive/20260218/202602181757.Amx49qCP-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 10.5.0
smatch version: v0.5.0-8994-gd50c5a4c
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202602181757.Amx49qCP-lkp@intel.com/
smatch warnings:
drivers/dma/tegra186-gpc-dma.c:1543 tegra_dma_probe() warn: missing error code 'ret'
vim +/ret +1543 drivers/dma/tegra186-gpc-dma.c
ee17028009d49f Akhil R 2022-02-25 1514 tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
ee17028009d49f Akhil R 2022-02-25 1515
ee17028009d49f Akhil R 2022-02-25 1516 ret = dma_async_device_register(&tdma->dma_dev);
ee17028009d49f Akhil R 2022-02-25 1517 if (ret < 0) {
ee17028009d49f Akhil R 2022-02-25 1518 dev_err_probe(&pdev->dev, ret,
ee17028009d49f Akhil R 2022-02-25 1519 "GPC DMA driver registration failed\n");
ee17028009d49f Akhil R 2022-02-25 1520 return ret;
ee17028009d49f Akhil R 2022-02-25 1521 }
ee17028009d49f Akhil R 2022-02-25 1522
43f59d3fa0deca Akhil R 2026-02-17 1523 list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
43f59d3fa0deca Akhil R 2026-02-17 1524 struct device *chdev = &chan->dev->device;
43f59d3fa0deca Akhil R 2026-02-17 1525
43f59d3fa0deca Akhil R 2026-02-17 1526 tdc = to_tegra_dma_chan(chan);
43f59d3fa0deca Akhil R 2026-02-17 1527 if (use_iommu_map) {
43f59d3fa0deca Akhil R 2026-02-17 1528 chdev->coherent_dma_mask = pdev->dev.coherent_dma_mask;
43f59d3fa0deca Akhil R 2026-02-17 1529 chdev->dma_mask = &chdev->coherent_dma_mask;
43f59d3fa0deca Akhil R 2026-02-17 1530 chdev->bus = pdev->dev.bus;
43f59d3fa0deca Akhil R 2026-02-17 1531
43f59d3fa0deca Akhil R 2026-02-17 1532 ret = of_dma_configure_id(chdev, pdev->dev.of_node,
43f59d3fa0deca Akhil R 2026-02-17 1533 true, &tdc->id);
43f59d3fa0deca Akhil R 2026-02-17 1534 if (ret) {
43f59d3fa0deca Akhil R 2026-02-17 1535 dev_err(chdev, "Failed to configure IOMMU for channel %d: %d\n",
43f59d3fa0deca Akhil R 2026-02-17 1536 tdc->id, ret);
43f59d3fa0deca Akhil R 2026-02-17 1537 goto err_unregister;
43f59d3fa0deca Akhil R 2026-02-17 1538 }
43f59d3fa0deca Akhil R 2026-02-17 1539
43f59d3fa0deca Akhil R 2026-02-17 1540 if (!tegra_dev_iommu_get_stream_id(chdev, &stream_id)) {
43f59d3fa0deca Akhil R 2026-02-17 1541 dev_err(chdev, "Failed to get stream ID for channel %d\n",
43f59d3fa0deca Akhil R 2026-02-17 1542 tdc->id);
43f59d3fa0deca Akhil R 2026-02-17 @1543 goto err_unregister;
ret = -EINVAL;
43f59d3fa0deca Akhil R 2026-02-17 1544 }
43f59d3fa0deca Akhil R 2026-02-17 1545
43f59d3fa0deca Akhil R 2026-02-17 1546 chan->dev->chan_dma_dev = true;
43f59d3fa0deca Akhil R 2026-02-17 1547 }
43f59d3fa0deca Akhil R 2026-02-17 1548
43f59d3fa0deca Akhil R 2026-02-17 1549 /* program stream-id for this channel */
43f59d3fa0deca Akhil R 2026-02-17 1550 tegra_dma_program_sid(tdc, stream_id);
43f59d3fa0deca Akhil R 2026-02-17 1551 tdc->stream_id = stream_id;
43f59d3fa0deca Akhil R 2026-02-17 1552 }
43f59d3fa0deca Akhil R 2026-02-17 1553
ee17028009d49f Akhil R 2022-02-25 1554 ret = of_dma_controller_register(pdev->dev.of_node,
ee17028009d49f Akhil R 2022-02-25 1555 tegra_dma_of_xlate, tdma);
ee17028009d49f Akhil R 2022-02-25 1556 if (ret < 0) {
ee17028009d49f Akhil R 2022-02-25 1557 dev_err_probe(&pdev->dev, ret,
ee17028009d49f Akhil R 2022-02-25 1558 "GPC DMA OF registration failed\n");
43f59d3fa0deca Akhil R 2026-02-17 1559 goto err_unregister;
ee17028009d49f Akhil R 2022-02-25 1560 }
ee17028009d49f Akhil R 2022-02-25 1561
43f59d3fa0deca Akhil R 2026-02-17 1562 dev_info(&pdev->dev, "GPC DMA driver registered %lu channels\n",
3a0c95b61385f5 Akhil R 2022-11-10 1563 hweight_long(tdma->chan_mask));
ee17028009d49f Akhil R 2022-02-25 1564
ee17028009d49f Akhil R 2022-02-25 1565 return 0;
43f59d3fa0deca Akhil R 2026-02-17 1566
43f59d3fa0deca Akhil R 2026-02-17 1567 err_unregister:
43f59d3fa0deca Akhil R 2026-02-17 1568 dma_async_device_unregister(&tdma->dma_dev);
43f59d3fa0deca Akhil R 2026-02-17 1569 return ret;
ee17028009d49f Akhil R 2022-02-25 1570 }
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On Tue, Feb 17, 2026 at 11:04:55PM +0530, Akhil R wrote:
> Use iommu-map, when provided, to get the stream ID to be programmed
> for each channel. Register each channel separately for allowing it
> to use a separate IOMMU domain for the transfer.
>
> Channels will continue to use the same global stream ID if iommu-map
> property is not present in the device tree.
>
> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
> ---
> drivers/dma/tegra186-gpc-dma.c | 62 +++++++++++++++++++++++++++-------
> 1 file changed, 49 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
> index ce3b1dd52bb3..b8ca269fa3ba 100644
> --- a/drivers/dma/tegra186-gpc-dma.c
> +++ b/drivers/dma/tegra186-gpc-dma.c
> @@ -15,6 +15,7 @@
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/of_dma.h>
> +#include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/reset.h>
> #include <linux/slab.h>
> @@ -1403,9 +1404,12 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
> static int tegra_dma_probe(struct platform_device *pdev)
> {
> const struct tegra_dma_chip_data *cdata = NULL;
> + struct tegra_dma_channel *tdc;
> + struct tegra_dma *tdma;
> + struct dma_chan *chan;
> + bool use_iommu_map = false;
> unsigned int i;
> u32 stream_id;
> - struct tegra_dma *tdma;
> int ret;
>
> cdata = of_device_get_match_data(&pdev->dev);
> @@ -1433,9 +1437,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
>
> tdma->dma_dev.dev = &pdev->dev;
>
> - if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
> - dev_err(&pdev->dev, "Missing iommu stream-id\n");
> - return -EINVAL;
> + use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map");
> + if (!use_iommu_map) {
> + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
> + dev_err(&pdev->dev, "Missing iommu stream-id\n");
> + return -EINVAL;
> + }
> }
>
> ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
> @@ -1449,7 +1456,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
>
> INIT_LIST_HEAD(&tdma->dma_dev.channels);
> for (i = 0; i < cdata->nr_channels; i++) {
> - struct tegra_dma_channel *tdc = &tdma->channels[i];
> + tdc = &tdma->channels[i];
>
> /* Check for channel mask */
> if (!(tdma->chan_mask & BIT(i)))
> @@ -1469,10 +1476,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
>
> vchan_init(&tdc->vc, &tdma->dma_dev);
> tdc->vc.desc_free = tegra_dma_desc_free;
> -
> - /* program stream-id for this channel */
> - tegra_dma_program_sid(tdc, stream_id);
> - tdc->stream_id = stream_id;
> }
>
> ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
> @@ -1517,20 +1520,53 @@ static int tegra_dma_probe(struct platform_device *pdev)
> return ret;
> }
>
> + list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
> + struct device *chdev = &chan->dev->device;
why no use
for (i = 0; i < cdata->nr_channels; i++) {
struct tegra_dma_channel *tdc = &tdma->channels[i];
> +
> + tdc = to_tegra_dma_chan(chan);
> + if (use_iommu_map) {
> + chdev->coherent_dma_mask = pdev->dev.coherent_dma_mask;
> + chdev->dma_mask = &chdev->coherent_dma_mask;
> + chdev->bus = pdev->dev.bus;
> +
> + ret = of_dma_configure_id(chdev, pdev->dev.of_node,
> + true, &tdc->id);
> + if (ret) {
> + dev_err(chdev, "Failed to configure IOMMU for channel %d: %d\n",
> + tdc->id, ret);
> + goto err_unregister;
> + }
> +
> + if (!tegra_dev_iommu_get_stream_id(chdev, &stream_id)) {
> + dev_err(chdev, "Failed to get stream ID for channel %d\n",
> + tdc->id);
> + goto err_unregister;
> + }
> +
> + chan->dev->chan_dma_dev = true;
> + }
> +
> + /* program stream-id for this channel */
> + tegra_dma_program_sid(tdc, stream_id);
> + tdc->stream_id = stream_id;
> + }
> +
> ret = of_dma_controller_register(pdev->dev.of_node,
> tegra_dma_of_xlate, tdma);
> if (ret < 0) {
> dev_err_probe(&pdev->dev, ret,
> "GPC DMA OF registration failed\n");
> -
> - dma_async_device_unregister(&tdma->dma_dev);
> - return ret;
> + goto err_unregister;
> }
>
> - dev_info(&pdev->dev, "GPC DMA driver register %lu channels\n",
> + dev_info(&pdev->dev, "GPC DMA driver registered %lu channels\n",
> hweight_long(tdma->chan_mask));
>
> return 0;
> +
> +err_unregister:
> + dma_async_device_unregister(&tdma->dma_dev);
Can you use dmaenginem_async_device_register() to simple error path?
Frank
> + return ret;
> }
>
> static void tegra_dma_remove(struct platform_device *pdev)
> --
> 2.50.1
>
On Tue, 17 Feb 2026 14:52:17 -0500, Frank Li wrote:
> On Tue, Feb 17, 2026 at 11:04:55PM +0530, Akhil R wrote:
>> Use iommu-map, when provided, to get the stream ID to be programmed
>> for each channel. Register each channel separately for allowing it
>> to use a separate IOMMU domain for the transfer.
>>
>> Channels will continue to use the same global stream ID if iommu-map
>> property is not present in the device tree.
>>
>> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
>> ---
>> drivers/dma/tegra186-gpc-dma.c | 62 +++++++++++++++++++++++++++-------
>> 1 file changed, 49 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
>> index ce3b1dd52bb3..b8ca269fa3ba 100644
>> --- a/drivers/dma/tegra186-gpc-dma.c
>> +++ b/drivers/dma/tegra186-gpc-dma.c
>> @@ -15,6 +15,7 @@
>> #include <linux/module.h>
>> #include <linux/of.h>
>> #include <linux/of_dma.h>
>> +#include <linux/of_device.h>
>> #include <linux/platform_device.h>
>> #include <linux/reset.h>
>> #include <linux/slab.h>
>> @@ -1403,9 +1404,12 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
>> static int tegra_dma_probe(struct platform_device *pdev)
>> {
>> const struct tegra_dma_chip_data *cdata = NULL;
>> + struct tegra_dma_channel *tdc;
>> + struct tegra_dma *tdma;
>> + struct dma_chan *chan;
>> + bool use_iommu_map = false;
>> unsigned int i;
>> u32 stream_id;
>> - struct tegra_dma *tdma;
>> int ret;
>>
>> cdata = of_device_get_match_data(&pdev->dev);
>> @@ -1433,9 +1437,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>
>> tdma->dma_dev.dev = &pdev->dev;
>>
>> - if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>> - dev_err(&pdev->dev, "Missing iommu stream-id\n");
>> - return -EINVAL;
>> + use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map");
>> + if (!use_iommu_map) {
>> + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>> + dev_err(&pdev->dev, "Missing iommu stream-id\n");
>> + return -EINVAL;
>> + }
>> }
>>
>> ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
>> @@ -1449,7 +1456,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>
>> INIT_LIST_HEAD(&tdma->dma_dev.channels);
>> for (i = 0; i < cdata->nr_channels; i++) {
>> - struct tegra_dma_channel *tdc = &tdma->channels[i];
>> + tdc = &tdma->channels[i];
>>
>> /* Check for channel mask */
>> if (!(tdma->chan_mask & BIT(i)))
>> @@ -1469,10 +1476,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>
>> vchan_init(&tdc->vc, &tdma->dma_dev);
>> tdc->vc.desc_free = tegra_dma_desc_free;
>> -
>> - /* program stream-id for this channel */
>> - tegra_dma_program_sid(tdc, stream_id);
>> - tdc->stream_id = stream_id;
>> }
>>
>> ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
>> @@ -1517,20 +1520,53 @@ static int tegra_dma_probe(struct platform_device *pdev)
>> return ret;
>> }
>>
>> + list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
>> + struct device *chdev = &chan->dev->device;
>>
> why no use
> for (i = 0; i < cdata->nr_channels; i++) {
> struct tegra_dma_channel *tdc = &tdma->channels[i];
I thought this would ensure that we try to configure only the channels
where the chan_dev and vchan are initialized. I understand that it is
not probable in the current implementation that we will have channels
which are uninitialized, but I felt this a better approach.
Do you see any disadvantage in using the channels list?
>> +
>> + tdc = to_tegra_dma_chan(chan);
>> + if (use_iommu_map) {
>> + chdev->coherent_dma_mask = pdev->dev.coherent_dma_mask;
>> + chdev->dma_mask = &chdev->coherent_dma_mask;
>> + chdev->bus = pdev->dev.bus;
>> +
>> + ret = of_dma_configure_id(chdev, pdev->dev.of_node,
>> + true, &tdc->id);
>> + if (ret) {
>> + dev_err(chdev, "Failed to configure IOMMU for channel %d: %d\n",
>> + tdc->id, ret);
>> + goto err_unregister;
>> + }
>> +
>> + if (!tegra_dev_iommu_get_stream_id(chdev, &stream_id)) {
>> + dev_err(chdev, "Failed to get stream ID for channel %d\n",
>> + tdc->id);
>> + goto err_unregister;
>> + }
>> +
>> + chan->dev->chan_dma_dev = true;
>> + }
>> +
>> + /* program stream-id for this channel */
>> + tegra_dma_program_sid(tdc, stream_id);
>> + tdc->stream_id = stream_id;
>> + }
>> +
>> ret = of_dma_controller_register(pdev->dev.of_node,
>> tegra_dma_of_xlate, tdma);
>> if (ret < 0) {
>> dev_err_probe(&pdev->dev, ret,
>> "GPC DMA OF registration failed\n");
>> -
>> - dma_async_device_unregister(&tdma->dma_dev);
>> - return ret;
>> + goto err_unregister;
>> }
>>
>> - dev_info(&pdev->dev, "GPC DMA driver register %lu channels\n",
>> + dev_info(&pdev->dev, "GPC DMA driver registered %lu channels\n",
>> hweight_long(tdma->chan_mask));
>>
>> return 0;
>> +
>> +err_unregister:
>> + dma_async_device_unregister(&tdma->dma_dev);
>
> Can you use dmaenginem_async_device_register() to simple error path?
>
> Frank
Agree. I will update it to use this function instead.
>> + return ret;
>> }
>>
>> static void tegra_dma_remove(struct platform_device *pdev)
>> --
Regards,
Akhil
On Tue, Feb 24, 2026 at 11:55:43AM +0530, Akhil R wrote:
> On Tue, 17 Feb 2026 14:52:17 -0500, Frank Li wrote:
> > On Tue, Feb 17, 2026 at 11:04:55PM +0530, Akhil R wrote:
> >> Use iommu-map, when provided, to get the stream ID to be programmed
> >> for each channel. Register each channel separately for allowing it
> >> to use a separate IOMMU domain for the transfer.
> >>
> >> Channels will continue to use the same global stream ID if iommu-map
> >> property is not present in the device tree.
> >>
> >> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
> >> ---
> >> drivers/dma/tegra186-gpc-dma.c | 62 +++++++++++++++++++++++++++-------
> >> 1 file changed, 49 insertions(+), 13 deletions(-)
> >>
> >> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
> >> index ce3b1dd52bb3..b8ca269fa3ba 100644
> >> --- a/drivers/dma/tegra186-gpc-dma.c
> >> +++ b/drivers/dma/tegra186-gpc-dma.c
> >> @@ -15,6 +15,7 @@
> >> #include <linux/module.h>
> >> #include <linux/of.h>
> >> #include <linux/of_dma.h>
> >> +#include <linux/of_device.h>
> >> #include <linux/platform_device.h>
> >> #include <linux/reset.h>
> >> #include <linux/slab.h>
> >> @@ -1403,9 +1404,12 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
> >> static int tegra_dma_probe(struct platform_device *pdev)
> >> {
> >> const struct tegra_dma_chip_data *cdata = NULL;
> >> + struct tegra_dma_channel *tdc;
> >> + struct tegra_dma *tdma;
> >> + struct dma_chan *chan;
> >> + bool use_iommu_map = false;
> >> unsigned int i;
> >> u32 stream_id;
> >> - struct tegra_dma *tdma;
> >> int ret;
> >>
> >> cdata = of_device_get_match_data(&pdev->dev);
> >> @@ -1433,9 +1437,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
> >>
> >> tdma->dma_dev.dev = &pdev->dev;
> >>
> >> - if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
> >> - dev_err(&pdev->dev, "Missing iommu stream-id\n");
> >> - return -EINVAL;
> >> + use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map");
> >> + if (!use_iommu_map) {
> >> + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
> >> + dev_err(&pdev->dev, "Missing iommu stream-id\n");
> >> + return -EINVAL;
> >> + }
> >> }
> >>
> >> ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
> >> @@ -1449,7 +1456,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
> >>
> >> INIT_LIST_HEAD(&tdma->dma_dev.channels);
> >> for (i = 0; i < cdata->nr_channels; i++) {
> >> - struct tegra_dma_channel *tdc = &tdma->channels[i];
> >> + tdc = &tdma->channels[i];
> >>
> >> /* Check for channel mask */
> >> if (!(tdma->chan_mask & BIT(i)))
> >> @@ -1469,10 +1476,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
> >>
> >> vchan_init(&tdc->vc, &tdma->dma_dev);
> >> tdc->vc.desc_free = tegra_dma_desc_free;
> >> -
> >> - /* program stream-id for this channel */
> >> - tegra_dma_program_sid(tdc, stream_id);
> >> - tdc->stream_id = stream_id;
> >> }
> >>
> >> ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
> >> @@ -1517,20 +1520,53 @@ static int tegra_dma_probe(struct platform_device *pdev)
> >> return ret;
> >> }
> >>
> >> + list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
> >> + struct device *chdev = &chan->dev->device;
> >>
> > why no use
> > for (i = 0; i < cdata->nr_channels; i++) {
> > struct tegra_dma_channel *tdc = &tdma->channels[i];
>
> I thought this would ensure that we try to configure only the channels
> where the chan_dev and vchan are initialized. I understand that it is
> not probable in the current implementation that we will have channels
> which are uninitialized, but I felt this a better approach.
> Do you see any disadvantage in using the channels list?
not big issue, just strange, previous code use
for (i = 0; i < cdata->nr_channels; i++) {
}
why need enumerate it again and use difference method.
Frank
>
> >> +
> >> + tdc = to_tegra_dma_chan(chan);
> >> + if (use_iommu_map) {
> >> + chdev->coherent_dma_mask = pdev->dev.coherent_dma_mask;
> >> + chdev->dma_mask = &chdev->coherent_dma_mask;
> >> + chdev->bus = pdev->dev.bus;
> >> +
> >> + ret = of_dma_configure_id(chdev, pdev->dev.of_node,
> >> + true, &tdc->id);
> >> + if (ret) {
> >> + dev_err(chdev, "Failed to configure IOMMU for channel %d: %d\n",
> >> + tdc->id, ret);
> >> + goto err_unregister;
> >> + }
> >> +
> >> + if (!tegra_dev_iommu_get_stream_id(chdev, &stream_id)) {
> >> + dev_err(chdev, "Failed to get stream ID for channel %d\n",
> >> + tdc->id);
> >> + goto err_unregister;
> >> + }
> >> +
> >> + chan->dev->chan_dma_dev = true;
> >> + }
> >> +
> >> + /* program stream-id for this channel */
> >> + tegra_dma_program_sid(tdc, stream_id);
> >> + tdc->stream_id = stream_id;
> >> + }
> >> +
> >> ret = of_dma_controller_register(pdev->dev.of_node,
> >> tegra_dma_of_xlate, tdma);
> >> if (ret < 0) {
> >> dev_err_probe(&pdev->dev, ret,
> >> "GPC DMA OF registration failed\n");
> >> -
> >> - dma_async_device_unregister(&tdma->dma_dev);
> >> - return ret;
> >> + goto err_unregister;
> >> }
> >>
> >> - dev_info(&pdev->dev, "GPC DMA driver register %lu channels\n",
> >> + dev_info(&pdev->dev, "GPC DMA driver registered %lu channels\n",
> >> hweight_long(tdma->chan_mask));
> >>
> >> return 0;
> >> +
> >> +err_unregister:
> >> + dma_async_device_unregister(&tdma->dma_dev);
> >
> > Can you use dmaenginem_async_device_register() to simple error path?
> >
> > Frank
>
> Agree. I will update it to use this function instead.
>
> >> + return ret;
> >> }
> >>
> >> static void tegra_dma_remove(struct platform_device *pdev)
> >> --
>
> Regards,
> Akhil
On Tue, 24 Feb 2026 16:59:44 -0500 Frank Li wrote:
> On Tue, Feb 24, 2026 at 11:55:43AM +0530, Akhil R wrote:
>> On Tue, 17 Feb 2026 14:52:17 -0500, Frank Li wrote:
>>> On Tue, Feb 17, 2026 at 11:04:55PM +0530, Akhil R wrote:
>>>> Use iommu-map, when provided, to get the stream ID to be programmed
>>>> for each channel. Register each channel separately for allowing it
>>>> to use a separate IOMMU domain for the transfer.
>>>>
>>>> Channels will continue to use the same global stream ID if iommu-map
>>>> property is not present in the device tree.
>>>>
>>>> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
>>>> ---
>>>> drivers/dma/tegra186-gpc-dma.c | 62 +++++++++++++++++++++++++++-------
>>>> 1 file changed, 49 insertions(+), 13 deletions(-)
>>>>
>>>> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
>>>> index ce3b1dd52bb3..b8ca269fa3ba 100644
>>>> --- a/drivers/dma/tegra186-gpc-dma.c
>>>> +++ b/drivers/dma/tegra186-gpc-dma.c
>>>> @@ -15,6 +15,7 @@
>>>> #include <linux/module.h>
>>>> #include <linux/of.h>
>>>> #include <linux/of_dma.h>
>>>> +#include <linux/of_device.h>
>>>> #include <linux/platform_device.h>
>>>> #include <linux/reset.h>
>>>> #include <linux/slab.h>
>>>> @@ -1403,9 +1404,12 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
>>>> static int tegra_dma_probe(struct platform_device *pdev)
>>>> {
>>>> const struct tegra_dma_chip_data *cdata = NULL;
>>>> + struct tegra_dma_channel *tdc;
>>>> + struct tegra_dma *tdma;
>>>> + struct dma_chan *chan;
>>>> + bool use_iommu_map = false;
>>>> unsigned int i;
>>>> u32 stream_id;
>>>> - struct tegra_dma *tdma;
>>>> int ret;
>>>>
>>>> cdata = of_device_get_match_data(&pdev->dev);
>>>> @@ -1433,9 +1437,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>
>>>> tdma->dma_dev.dev = &pdev->dev;
>>>>
>>>> - if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>>>> - dev_err(&pdev->dev, "Missing iommu stream-id\n");
>>>> - return -EINVAL;
>>>> + use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map");
>>>> + if (!use_iommu_map) {
>>>> + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>>>> + dev_err(&pdev->dev, "Missing iommu stream-id\n");
>>>> + return -EINVAL;
>>>> + }
>>>> }
>>>>
>>>> ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
>>>> @@ -1449,7 +1456,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>
>>>> INIT_LIST_HEAD(&tdma->dma_dev.channels);
>>>> for (i = 0; i < cdata->nr_channels; i++) {
>>>> - struct tegra_dma_channel *tdc = &tdma->channels[i];
>>>> + tdc = &tdma->channels[i];
>>>>
>>>> /* Check for channel mask */
>>>> if (!(tdma->chan_mask & BIT(i)))
>>>> @@ -1469,10 +1476,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>
>>>> vchan_init(&tdc->vc, &tdma->dma_dev);
>>>> tdc->vc.desc_free = tegra_dma_desc_free;
>>>> -
>>>> - /* program stream-id for this channel */
>>>> - tegra_dma_program_sid(tdc, stream_id);
>>>> - tdc->stream_id = stream_id;
>>>> }
>>>>
>>>> ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
>>>> @@ -1517,20 +1520,53 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>> return ret;
>>>> }
>>>>
>>>> + list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
>>>> + struct device *chdev = &chan->dev->device;
>>>>
>>> why no use
>>> for (i = 0; i < cdata->nr_channels; i++) {
>>> struct tegra_dma_channel *tdc = &tdma->channels[i];
>>
>> I thought this would ensure that we try to configure only the channels
>> where the chan_dev and vchan are initialized. I understand that it is
>> not probable in the current implementation that we will have channels
>> which are uninitialized, but I felt this a better approach.
>> Do you see any disadvantage in using the channels list?
>
> not big issue, just strange, previous code use
> for (i = 0; i < cdata->nr_channels; i++) {
> }
>
> why need enumerate it again and use difference method.
I think we will not get to use chan->dev->device before
async_device_register() and thats why I added a separate loop to
configure the channels.
I can add a comment on why we need this loop. Do you suggest
changing it to a for-loop itself? Let me know your thoughts.
Regards,
Akhil
On 25/02/2026 10:27, Akhil R wrote:
> On Tue, 24 Feb 2026 16:59:44 -0500 Frank Li wrote:
>> On Tue, Feb 24, 2026 at 11:55:43AM +0530, Akhil R wrote:
>>> On Tue, 17 Feb 2026 14:52:17 -0500, Frank Li wrote:
>>>> On Tue, Feb 17, 2026 at 11:04:55PM +0530, Akhil R wrote:
>>>>> Use iommu-map, when provided, to get the stream ID to be programmed
>>>>> for each channel. Register each channel separately for allowing it
>>>>> to use a separate IOMMU domain for the transfer.
>>>>>
>>>>> Channels will continue to use the same global stream ID if iommu-map
>>>>> property is not present in the device tree.
>>>>>
>>>>> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
>>>>> ---
>>>>> drivers/dma/tegra186-gpc-dma.c | 62 +++++++++++++++++++++++++++-------
>>>>> 1 file changed, 49 insertions(+), 13 deletions(-)
>>>>>
>>>>> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
>>>>> index ce3b1dd52bb3..b8ca269fa3ba 100644
>>>>> --- a/drivers/dma/tegra186-gpc-dma.c
>>>>> +++ b/drivers/dma/tegra186-gpc-dma.c
>>>>> @@ -15,6 +15,7 @@
>>>>> #include <linux/module.h>
>>>>> #include <linux/of.h>
>>>>> #include <linux/of_dma.h>
>>>>> +#include <linux/of_device.h>
>>>>> #include <linux/platform_device.h>
>>>>> #include <linux/reset.h>
>>>>> #include <linux/slab.h>
>>>>> @@ -1403,9 +1404,12 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
>>>>> static int tegra_dma_probe(struct platform_device *pdev)
>>>>> {
>>>>> const struct tegra_dma_chip_data *cdata = NULL;
>>>>> + struct tegra_dma_channel *tdc;
>>>>> + struct tegra_dma *tdma;
>>>>> + struct dma_chan *chan;
>>>>> + bool use_iommu_map = false;
>>>>> unsigned int i;
>>>>> u32 stream_id;
>>>>> - struct tegra_dma *tdma;
>>>>> int ret;
>>>>>
>>>>> cdata = of_device_get_match_data(&pdev->dev);
>>>>> @@ -1433,9 +1437,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>>
>>>>> tdma->dma_dev.dev = &pdev->dev;
>>>>>
>>>>> - if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>>>>> - dev_err(&pdev->dev, "Missing iommu stream-id\n");
>>>>> - return -EINVAL;
>>>>> + use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map");
>>>>> + if (!use_iommu_map) {
>>>>> + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>>>>> + dev_err(&pdev->dev, "Missing iommu stream-id\n");
>>>>> + return -EINVAL;
>>>>> + }
>>>>> }
>>>>>
>>>>> ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
>>>>> @@ -1449,7 +1456,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>>
>>>>> INIT_LIST_HEAD(&tdma->dma_dev.channels);
>>>>> for (i = 0; i < cdata->nr_channels; i++) {
>>>>> - struct tegra_dma_channel *tdc = &tdma->channels[i];
>>>>> + tdc = &tdma->channels[i];
>>>>>
>>>>> /* Check for channel mask */
>>>>> if (!(tdma->chan_mask & BIT(i)))
>>>>> @@ -1469,10 +1476,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>>
>>>>> vchan_init(&tdc->vc, &tdma->dma_dev);
>>>>> tdc->vc.desc_free = tegra_dma_desc_free;
>>>>> -
>>>>> - /* program stream-id for this channel */
>>>>> - tegra_dma_program_sid(tdc, stream_id);
>>>>> - tdc->stream_id = stream_id;
>>>>> }
>>>>>
>>>>> ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
>>>>> @@ -1517,20 +1520,53 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>> return ret;
>>>>> }
>>>>>
>>>>> + list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
>>>>> + struct device *chdev = &chan->dev->device;
>>>>>
>>>> why no use
>>>> for (i = 0; i < cdata->nr_channels; i++) {
>>>> struct tegra_dma_channel *tdc = &tdma->channels[i];
>>>
>>> I thought this would ensure that we try to configure only the channels
>>> where the chan_dev and vchan are initialized. I understand that it is
>>> not probable in the current implementation that we will have channels
>>> which are uninitialized, but I felt this a better approach.
>>> Do you see any disadvantage in using the channels list?
>>
>> not big issue, just strange, previous code use
>> for (i = 0; i < cdata->nr_channels; i++) {
>> }
>>
>> why need enumerate it again and use difference method.
>
> I think we will not get to use chan->dev->device before
> async_device_register() and thats why I added a separate loop to
> configure the channels.
I assume that this needs to be done after the async_device_register()?
If so we should note that in the commit message to explain that we need
a 2nd loop. Unless we can move the 1st loop after the
async_device_register() and just have one loop?
> I can add a comment on why we need this loop. Do you suggest
> changing it to a for-loop itself? Let me know your thoughts.
If using the list avoids the following check, then probably good to keep
as is, but yes explain why we do it this way.
/* Check for channel mask */
if (!(tdma->chan_mask & BIT(i)))
continue;
Jon
--
nvpublic
On Wed, 25 Feb 2026 11:23:08 +0000 Jon Hunter wrote:
> On 25/02/2026 10:27, Akhil R wrote:
>> On Tue, 24 Feb 2026 16:59:44 -0500 Frank Li wrote:
>>> On Tue, Feb 24, 2026 at 11:55:43AM +0530, Akhil R wrote:
>>>> On Tue, 17 Feb 2026 14:52:17 -0500, Frank Li wrote:
>>>>> On Tue, Feb 17, 2026 at 11:04:55PM +0530, Akhil R wrote:
>>>>>> Use iommu-map, when provided, to get the stream ID to be programmed
>>>>>> for each channel. Register each channel separately for allowing it
>>>>>> to use a separate IOMMU domain for the transfer.
>>>>>>
>>>>>> Channels will continue to use the same global stream ID if iommu-map
>>>>>> property is not present in the device tree.
>>>>>>
>>>>>> Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
>>>>>> ---
>>>>>> drivers/dma/tegra186-gpc-dma.c | 62 +++++++++++++++++++++++++++-------
>>>>>> 1 file changed, 49 insertions(+), 13 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
>>>>>> index ce3b1dd52bb3..b8ca269fa3ba 100644
>>>>>> --- a/drivers/dma/tegra186-gpc-dma.c
>>>>>> +++ b/drivers/dma/tegra186-gpc-dma.c
>>>>>> @@ -15,6 +15,7 @@
>>>>>> #include <linux/module.h>
>>>>>> #include <linux/of.h>
>>>>>> #include <linux/of_dma.h>
>>>>>> +#include <linux/of_device.h>
>>>>>> #include <linux/platform_device.h>
>>>>>> #include <linux/reset.h>
>>>>>> #include <linux/slab.h>
>>>>>> @@ -1403,9 +1404,12 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
>>>>>> static int tegra_dma_probe(struct platform_device *pdev)
>>>>>> {
>>>>>> const struct tegra_dma_chip_data *cdata = NULL;
>>>>>> + struct tegra_dma_channel *tdc;
>>>>>> + struct tegra_dma *tdma;
>>>>>> + struct dma_chan *chan;
>>>>>> + bool use_iommu_map = false;
>>>>>> unsigned int i;
>>>>>> u32 stream_id;
>>>>>> - struct tegra_dma *tdma;
>>>>>> int ret;
>>>>>>
>>>>>> cdata = of_device_get_match_data(&pdev->dev);
>>>>>> @@ -1433,9 +1437,12 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>>>
>>>>>> tdma->dma_dev.dev = &pdev->dev;
>>>>>>
>>>>>> - if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>>>>>> - dev_err(&pdev->dev, "Missing iommu stream-id\n");
>>>>>> - return -EINVAL;
>>>>>> + use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map");
>>>>>> + if (!use_iommu_map) {
>>>>>> + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
>>>>>> + dev_err(&pdev->dev, "Missing iommu stream-id\n");
>>>>>> + return -EINVAL;
>>>>>> + }
>>>>>> }
>>>>>>
>>>>>> ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
>>>>>> @@ -1449,7 +1456,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>>>
>>>>>> INIT_LIST_HEAD(&tdma->dma_dev.channels);
>>>>>> for (i = 0; i < cdata->nr_channels; i++) {
>>>>>> - struct tegra_dma_channel *tdc = &tdma->channels[i];
>>>>>> + tdc = &tdma->channels[i];
>>>>>>
>>>>>> /* Check for channel mask */
>>>>>> if (!(tdma->chan_mask & BIT(i)))
>>>>>> @@ -1469,10 +1476,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>>>
>>>>>> vchan_init(&tdc->vc, &tdma->dma_dev);
>>>>>> tdc->vc.desc_free = tegra_dma_desc_free;
>>>>>> -
>>>>>> - /* program stream-id for this channel */
>>>>>> - tegra_dma_program_sid(tdc, stream_id);
>>>>>> - tdc->stream_id = stream_id;
>>>>>> }
>>>>>>
>>>>>> ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits));
>>>>>> @@ -1517,20 +1520,53 @@ static int tegra_dma_probe(struct platform_device *pdev)
>>>>>> return ret;
>>>>>> }
>>>>>>
>>>>>> + list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
>>>>>> + struct device *chdev = &chan->dev->device;
>>>>>>
>>>>> why no use
>>>>> for (i = 0; i < cdata->nr_channels; i++) {
>>>>> struct tegra_dma_channel *tdc = &tdma->channels[i];
>>>>
>>>> I thought this would ensure that we try to configure only the channels
>>>> where the chan_dev and vchan are initialized. I understand that it is
>>>> not probable in the current implementation that we will have channels
>>>> which are uninitialized, but I felt this a better approach.
>>>> Do you see any disadvantage in using the channels list?
>>>
>>> not big issue, just strange, previous code use
>>> for (i = 0; i < cdata->nr_channels; i++) {
>>> }
>>>
>>> why need enumerate it again and use difference method.
>>
>> I think we will not get to use chan->dev->device before
>> async_device_register() and thats why I added a separate loop to
>> configure the channels.
>
> I assume that this needs to be done after the async_device_register()?
> If so we should note that in the commit message to explain that we need
> a 2nd loop. Unless we can move the 1st loop after the
> async_device_register() and just have one loop?
dma_dev.channels is populated by vchan_init(). So, the first loop must
exist before async_device_register(). If we have to restrict to one loop,
we would need to use dma_async_device_channel_register() to register the
channels within this driver directly. I feel having a second loop is
better than trying to restrict it to one.
>
>> I can add a comment on why we need this loop. Do you suggest
>> changing it to a for-loop itself? Let me know your thoughts.
>
> If using the list avoids the following check, then probably good to keep
> as is, but yes explain why we do it this way.
>
> /* Check for channel mask */
> if (!(tdma->chan_mask & BIT(i)))
> continue;
Yes. Using dma_dev.channels avoids the above check. I will describe this
better in the commit message and as comments.
Regards,
Akhil
© 2016 - 2026 Red Hat, Inc.