[PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID

Akhil R posted 8 patches 1 month, 2 weeks ago
There is a newer version of this series
[PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Akhil R 1 month, 2 weeks ago
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
Re: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Dan Carpenter 1 month, 1 week ago
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
Re: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Frank Li 1 month, 2 weeks ago
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
>
Re: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Akhil R 1 month, 1 week ago
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
Re: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Frank Li 1 month, 1 week ago
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
Re: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Akhil R 1 month ago
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
Re: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Jon Hunter 1 month ago

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
Re: [PATCH 6/8] dmaengine: tegra: Use iommu-map for stream ID
Posted by Akhil R 1 month ago
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