public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts
@ 2026-01-14 17:12 Frank Li
  2026-01-14 17:12 ` [PATCH 1/6] dmaengine: Move struct dma_chan after struct dma_slave_config Frank Li
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Frank Li @ 2026-01-14 17:12 UTC (permalink / raw)
  To: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: dmaengine, linux-kernel, imx, linux-arm-kernel, Frank Li

Many DMA engine drivers store a dma_slave_config per channel. Propagate
this configuration into struct dma_chan to avoid duplicating the same
code in each driver.

Much of dma_slave_config is identical for source and destination. Split
the configuration into src and dst groups and use a union to preserve
backward compatibility. This reduces the need for drivers to repeatedly
check the DMA transfer direction.

This change introduces the general approach. If this method is accepted,
more drivers can be updated incrementally.

Looking ahead, this also enables improvements to the vchan
implementation. Most DMA engines follow one of two descriptor models:

  - Cyclic hardware buffers (e.g. dw-edma)
  - Linked-list descriptors (e.g. fsl-edma)

 *
 *       ┌──────┐    ┌──────┐    ┌──────┐
 *       │      │ ┌─►│      │ ┌─►│      │
 *       │      │ │  │      │ │  │      │
 *       ├──────┤ │  ├──────┤ │  ├──────┤
 *       │ Next ├─┘  │ Next ├─┘  │ Next │
 *       └──────┘    └──────┘    └──────┘

A large portion of the software logic is shared between these models.
Recent work already shares circular buffer handling between eDMA and
HDMA [1], and this can be extended to support more hardware.

Ultimately, a DMA engine should only need to implement logic to fill a
single list item.

[1] https://lore.kernel.org/dmaengine/aWTyGpGN6WqtVCfN@ryzen/T/#t

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Frank Li (6):
      dmaengine: Move struct dma_chan after struct dma_slave_config
      dmaengine: Add common slave configuration to dma_chan
      dmaengine: fsl-edma: use dma_chan common config
      dmaengine: imx-sdma: use common config at dma_chan
      dmaengine: Add union and dma_slave_get_config() helper for dma_slave_config
      dmaengine: fsl-edma: use common dma_slave_get_cfg()

 drivers/dma/fsl-edma-common.c | 141 +++++++++++++++++------------------
 drivers/dma/fsl-edma-common.h |   1 -
 drivers/dma/imx-sdma.c        |   8 +-
 include/linux/dmaengine.h     | 166 +++++++++++++++++++++++++-----------------
 4 files changed, 166 insertions(+), 150 deletions(-)
---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20260112-dma_common_config-cb87b461296f

Best regards,
--
Frank Li <Frank.Li@nxp.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/6] dmaengine: Move struct dma_chan after struct dma_slave_config
  2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
@ 2026-01-14 17:12 ` Frank Li
  2026-01-14 17:12 ` [PATCH 2/6] dmaengine: Add common slave configuration to dma_chan Frank Li
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-01-14 17:12 UTC (permalink / raw)
  To: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: dmaengine, linux-kernel, imx, linux-arm-kernel, Frank Li

Move struct dma_chan below struct dma_slave_config to prepare for adding
common dma_slave_config field.

No functional change.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 include/linux/dmaengine.h | 120 +++++++++++++++++++++++-----------------------
 1 file changed, 60 insertions(+), 60 deletions(-)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 99efe2b9b4ea9844ca6161208362ef18ef111d96..01d3e44e3cb426d9ad085eda1bc562ca7d266cb0 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -316,66 +316,6 @@ struct dma_router {
 	void (*route_free)(struct device *dev, void *route_data);
 };
 
-/**
- * struct dma_chan - devices supply DMA channels, clients use them
- * @device: ptr to the dma device who supplies this channel, always !%NULL
- * @slave: ptr to the device using this channel
- * @cookie: last cookie value returned to client
- * @completed_cookie: last completed cookie for this channel
- * @chan_id: channel ID for sysfs
- * @dev: class device for sysfs
- * @name: backlink name for sysfs
- * @dbg_client_name: slave name for debugfs in format:
- *	dev_name(requester's dev):channel name, for example: "2b00000.mcasp:tx"
- * @device_node: used to add this to the device chan list
- * @local: per-cpu pointer to a struct dma_chan_percpu
- * @client_count: how many clients are using this channel
- * @table_count: number of appearances in the mem-to-mem allocation table
- * @router: pointer to the DMA router structure
- * @route_data: channel specific data for the router
- * @private: private data for certain client-channel associations
- */
-struct dma_chan {
-	struct dma_device *device;
-	struct device *slave;
-	dma_cookie_t cookie;
-	dma_cookie_t completed_cookie;
-
-	/* sysfs */
-	int chan_id;
-	struct dma_chan_dev *dev;
-	const char *name;
-#ifdef CONFIG_DEBUG_FS
-	char *dbg_client_name;
-#endif
-
-	struct list_head device_node;
-	struct dma_chan_percpu __percpu *local;
-	int client_count;
-	int table_count;
-
-	/* DMA router */
-	struct dma_router *router;
-	void *route_data;
-
-	void *private;
-};
-
-/**
- * struct dma_chan_dev - relate sysfs device node to backing channel device
- * @chan: driver channel device
- * @device: sysfs device
- * @dev_id: parent dma_device dev_id
- * @chan_dma_dev: The channel is using custom/different dma-mapping
- * compared to the parent dma_device
- */
-struct dma_chan_dev {
-	struct dma_chan *chan;
-	struct device device;
-	int dev_id;
-	bool chan_dma_dev;
-};
-
 /**
  * enum dma_slave_buswidth - defines bus width of the DMA slave
  * device, source or target buses
@@ -459,6 +399,66 @@ struct dma_slave_config {
 	size_t peripheral_size;
 };
 
+/**
+ * struct dma_chan - devices supply DMA channels, clients use them
+ * @device: ptr to the dma device who supplies this channel, always !%NULL
+ * @slave: ptr to the device using this channel
+ * @cookie: last cookie value returned to client
+ * @completed_cookie: last completed cookie for this channel
+ * @chan_id: channel ID for sysfs
+ * @dev: class device for sysfs
+ * @name: backlink name for sysfs
+ * @dbg_client_name: slave name for debugfs in format:
+ *      dev_name(requester's dev):channel name, for example: "2b00000.mcasp:tx"
+ * @device_node: used to add this to the device chan list
+ * @local: per-cpu pointer to a struct dma_chan_percpu
+ * @client_count: how many clients are using this channel
+ * @table_count: number of appearances in the mem-to-mem allocation table
+ * @router: pointer to the DMA router structure
+ * @route_data: channel specific data for the router
+ * @private: private data for certain client-channel associations
+ */
+struct dma_chan {
+	struct dma_device *device;
+	struct device *slave;
+	dma_cookie_t cookie;
+	dma_cookie_t completed_cookie;
+
+	/* sysfs */
+	int chan_id;
+	struct dma_chan_dev *dev;
+	const char *name;
+#ifdef CONFIG_DEBUG_FS
+	char *dbg_client_name;
+#endif
+
+	struct list_head device_node;
+	struct dma_chan_percpu __percpu *local;
+	int client_count;
+	int table_count;
+
+	/* DMA router */
+	struct dma_router *router;
+	void *route_data;
+
+	void *private;
+};
+
+/**
+ * struct dma_chan_dev - relate sysfs device node to backing channel device
+ * @chan: driver channel device
+ * @device: sysfs device
+ * @dev_id: parent dma_device dev_id
+ * @chan_dma_dev: The channel is using custom/different dma-mapping
+ * compared to the parent dma_device
+ */
+struct dma_chan_dev {
+	struct dma_chan *chan;
+	struct device device;
+	int dev_id;
+	bool chan_dma_dev;
+};
+
 /**
  * enum dma_residue_granularity - Granularity of the reported transfer residue
  * @DMA_RESIDUE_GRANULARITY_DESCRIPTOR: Residue reporting is not support. The

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/6] dmaengine: Add common slave configuration to dma_chan
  2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
  2026-01-14 17:12 ` [PATCH 1/6] dmaengine: Move struct dma_chan after struct dma_slave_config Frank Li
@ 2026-01-14 17:12 ` Frank Li
  2026-01-14 17:12 ` [PATCH 3/6] dmaengine: fsl-edma: use dma_chan common config Frank Li
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-01-14 17:12 UTC (permalink / raw)
  To: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: dmaengine, linux-kernel, imx, linux-arm-kernel, Frank Li

Add a common slave configuration 'config' to struct dma_chan to avoid
duplicating configuration data in each driver. Store the configuration when
dmaengine_slave_config() is called.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 include/linux/dmaengine.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 01d3e44e3cb426d9ad085eda1bc562ca7d266cb0..362a43c3e36e232b5a65ff78ba0b692c0401e50c 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -432,6 +432,8 @@ struct dma_chan {
 	char *dbg_client_name;
 #endif
 
+	struct dma_slave_config config;
+
 	struct list_head device_node;
 	struct dma_chan_percpu __percpu *local;
 	int client_count;
@@ -962,6 +964,8 @@ struct dma_device {
 static inline int dmaengine_slave_config(struct dma_chan *chan,
 					  struct dma_slave_config *config)
 {
+	chan->config = *config;
+
 	if (chan->device->device_config)
 		return chan->device->device_config(chan, config);
 

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/6] dmaengine: fsl-edma: use dma_chan common config
  2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
  2026-01-14 17:12 ` [PATCH 1/6] dmaengine: Move struct dma_chan after struct dma_slave_config Frank Li
  2026-01-14 17:12 ` [PATCH 2/6] dmaengine: Add common slave configuration to dma_chan Frank Li
@ 2026-01-14 17:12 ` Frank Li
  2026-01-14 17:12 ` [PATCH 4/6] dmaengine: imx-sdma: use common config at dma_chan Frank Li
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-01-14 17:12 UTC (permalink / raw)
  To: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: dmaengine, linux-kernel, imx, linux-arm-kernel, Frank Li

Use common config in dma_chan.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 drivers/dma/fsl-edma-common.c | 88 +++++++++++++++++++++----------------------
 drivers/dma/fsl-edma-common.h |  1 -
 2 files changed, 44 insertions(+), 45 deletions(-)

diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index a592127580299681304b222d8cb383535dbcc10f..33fc4fa8d1302d899ce550b0ce5d4325fa2e3916 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -294,6 +294,7 @@ static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan)
 static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan,
 				    enum dma_transfer_direction dir)
 {
+	struct dma_slave_config *cfg = &fsl_chan->vchan.chan.config;
 	struct device *dev = fsl_chan->vchan.chan.device->dev;
 	enum dma_data_direction dma_dir;
 	phys_addr_t addr = 0;
@@ -302,13 +303,13 @@ static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan,
 	switch (dir) {
 	case DMA_MEM_TO_DEV:
 		dma_dir = DMA_FROM_DEVICE;
-		addr = fsl_chan->cfg.dst_addr;
-		size = fsl_chan->cfg.dst_maxburst;
+		addr = cfg->dst_addr;
+		size = cfg->dst_maxburst;
 		break;
 	case DMA_DEV_TO_MEM:
 		dma_dir = DMA_TO_DEVICE;
-		addr = fsl_chan->cfg.src_addr;
-		size = fsl_chan->cfg.src_maxburst;
+		addr = cfg->src_addr;
+		size = cfg->src_maxburst;
 		break;
 	default:
 		dma_dir = DMA_NONE;
@@ -335,7 +336,6 @@ int fsl_edma_slave_config(struct dma_chan *chan,
 {
 	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
 
-	memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg));
 	fsl_edma_unprep_slave_dma(fsl_chan);
 
 	return 0;
@@ -483,7 +483,7 @@ void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
 		       u16 biter, u16 doff, dma_addr_t dlast_sga, bool major_int,
 		       bool disable_req, bool enable_sg)
 {
-	struct dma_slave_config *cfg = &fsl_chan->cfg;
+	struct dma_slave_config *cfg = &fsl_chan->vchan.chan.config;
 	u32 burst = 0;
 	u16 csr = 0;
 
@@ -593,6 +593,7 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
 		unsigned long flags)
 {
 	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	struct dma_slave_config *cfg = &chan->config;
 	struct fsl_edma_desc *fsl_desc;
 	dma_addr_t dma_buf_next;
 	bool major_int = true;
@@ -616,21 +617,19 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
 
 	dma_buf_next = dma_addr;
 	if (direction == DMA_MEM_TO_DEV) {
-		if (!fsl_chan->cfg.src_addr_width)
-			fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width;
+		if (!cfg->src_addr_width)
+			cfg->src_addr_width = cfg->dst_addr_width;
 		fsl_chan->attr =
-			fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
-					      fsl_chan->cfg.dst_addr_width);
-		nbytes = fsl_chan->cfg.dst_addr_width *
-			fsl_chan->cfg.dst_maxburst;
+			fsl_edma_get_tcd_attr(cfg->src_addr_width,
+					      cfg->dst_addr_width);
+		nbytes = cfg->dst_addr_width * cfg->dst_maxburst;
 	} else {
-		if (!fsl_chan->cfg.dst_addr_width)
-			fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width;
+		if (!cfg->dst_addr_width)
+			cfg->dst_addr_width = cfg->src_addr_width;
 		fsl_chan->attr =
-			fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
-					      fsl_chan->cfg.dst_addr_width);
-		nbytes = fsl_chan->cfg.src_addr_width *
-			fsl_chan->cfg.src_maxburst;
+			fsl_edma_get_tcd_attr(cfg->src_addr_width,
+					      cfg->dst_addr_width);
+		nbytes = cfg->src_addr_width * cfg->src_maxburst;
 	}
 
 	iter = period_len / nbytes;
@@ -645,21 +644,21 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
 		if (direction == DMA_MEM_TO_DEV) {
 			src_addr = dma_buf_next;
 			dst_addr = fsl_chan->dma_dev_addr;
-			soff = fsl_chan->cfg.dst_addr_width;
+			soff = cfg->dst_addr_width;
 			doff = fsl_chan->is_multi_fifo ? 4 : 0;
-			if (fsl_chan->cfg.dst_port_window_size)
-				doff = fsl_chan->cfg.dst_addr_width;
+			if (cfg->dst_port_window_size)
+				doff = cfg->dst_addr_width;
 		} else if (direction == DMA_DEV_TO_MEM) {
 			src_addr = fsl_chan->dma_dev_addr;
 			dst_addr = dma_buf_next;
 			soff = fsl_chan->is_multi_fifo ? 4 : 0;
-			doff = fsl_chan->cfg.src_addr_width;
-			if (fsl_chan->cfg.src_port_window_size)
-				soff = fsl_chan->cfg.src_addr_width;
+			doff = cfg->src_addr_width;
+			if (cfg->src_port_window_size)
+				soff = cfg->src_addr_width;
 		} else {
 			/* DMA_DEV_TO_DEV */
-			src_addr = fsl_chan->cfg.src_addr;
-			dst_addr = fsl_chan->cfg.dst_addr;
+			src_addr = cfg->src_addr;
+			dst_addr = cfg->dst_addr;
 			soff = doff = 0;
 			major_int = false;
 		}
@@ -679,6 +678,7 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
 		unsigned long flags, void *context)
 {
 	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+	struct dma_slave_config *cfg = &chan->config;
 	struct fsl_edma_desc *fsl_desc;
 	struct scatterlist *sg;
 	dma_addr_t src_addr, dst_addr, last_sg;
@@ -699,38 +699,38 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
 	fsl_desc->dirn = direction;
 
 	if (direction == DMA_MEM_TO_DEV) {
-		if (!fsl_chan->cfg.src_addr_width)
-			fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width;
+		if (!cfg->src_addr_width)
+			cfg->src_addr_width = cfg->dst_addr_width;
 		fsl_chan->attr =
-			fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
-					      fsl_chan->cfg.dst_addr_width);
-		nbytes = fsl_chan->cfg.dst_addr_width *
-			fsl_chan->cfg.dst_maxburst;
+			fsl_edma_get_tcd_attr(cfg->src_addr_width,
+					      cfg->dst_addr_width);
+		nbytes = cfg->dst_addr_width *
+			cfg->dst_maxburst;
 	} else {
-		if (!fsl_chan->cfg.dst_addr_width)
-			fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width;
+		if (!cfg->dst_addr_width)
+			cfg->dst_addr_width = cfg->src_addr_width;
 		fsl_chan->attr =
-			fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
-					      fsl_chan->cfg.dst_addr_width);
-		nbytes = fsl_chan->cfg.src_addr_width *
-			fsl_chan->cfg.src_maxburst;
+			fsl_edma_get_tcd_attr(cfg->src_addr_width,
+					      cfg->dst_addr_width);
+		nbytes = cfg->src_addr_width *
+			cfg->src_maxburst;
 	}
 
 	for_each_sg(sgl, sg, sg_len, i) {
 		if (direction == DMA_MEM_TO_DEV) {
 			src_addr = sg_dma_address(sg);
 			dst_addr = fsl_chan->dma_dev_addr;
-			soff = fsl_chan->cfg.dst_addr_width;
+			soff = cfg->dst_addr_width;
 			doff = 0;
 		} else if (direction == DMA_DEV_TO_MEM) {
 			src_addr = fsl_chan->dma_dev_addr;
 			dst_addr = sg_dma_address(sg);
 			soff = 0;
-			doff = fsl_chan->cfg.src_addr_width;
+			doff = cfg->src_addr_width;
 		} else {
 			/* DMA_DEV_TO_DEV */
-			src_addr = fsl_chan->cfg.src_addr;
-			dst_addr = fsl_chan->cfg.dst_addr;
+			src_addr = cfg->src_addr;
+			dst_addr = cfg->dst_addr;
 			soff = 0;
 			doff = 0;
 		}
@@ -743,8 +743,8 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
 		if (sg_dma_len(sg) % nbytes) {
 			u32 width = (direction == DMA_DEV_TO_MEM) ? doff : soff;
 			u32 burst = (direction == DMA_DEV_TO_MEM) ?
-						fsl_chan->cfg.src_maxburst :
-						fsl_chan->cfg.dst_maxburst;
+						cfg->src_maxburst :
+						cfg->dst_maxburst;
 			int j;
 
 			for (j = burst; j > 1; j--) {
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
index 205a96489094805aa728b72a51ae101cd88fa003..8e45770a0d3960ee34361fe5884a169de64e14a7 100644
--- a/drivers/dma/fsl-edma-common.h
+++ b/drivers/dma/fsl-edma-common.h
@@ -166,7 +166,6 @@ struct fsl_edma_chan {
 	enum fsl_edma_pm_state		pm_state;
 	struct fsl_edma_engine		*edma;
 	struct fsl_edma_desc		*edesc;
-	struct dma_slave_config		cfg;
 	u32				attr;
 	bool                            is_sw;
 	struct dma_pool			*tcd_pool;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/6] dmaengine: imx-sdma: use common config at dma_chan
  2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
                   ` (2 preceding siblings ...)
  2026-01-14 17:12 ` [PATCH 3/6] dmaengine: fsl-edma: use dma_chan common config Frank Li
@ 2026-01-14 17:12 ` Frank Li
  2026-01-14 17:12 ` [PATCH 5/6] dmaengine: Add union and dma_slave_get_config() helper for dma_slave_config Frank Li
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-01-14 17:12 UTC (permalink / raw)
  To: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: dmaengine, linux-kernel, imx, linux-arm-kernel, Frank Li

Use common config at dma_chan. No functional change.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 drivers/dma/imx-sdma.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index ed9e56de5a9b9484c6598d438f66a836504818be..13a9522eb914bd7808a079fd661d99e8fcff6a0b 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -413,7 +413,6 @@ struct sdma_desc {
  * @sdma:		pointer to the SDMA engine for this channel
  * @channel:		the channel number, matches dmaengine chan_id + 1
  * @direction:		transfer type. Needed for setting SDMA script
- * @slave_config:	Slave configuration
  * @peripheral_type:	Peripheral type. Needed for setting SDMA script
  * @event_id0:		aka dma request line
  * @event_id1:		for channels that use 2 events
@@ -449,7 +448,6 @@ struct sdma_channel {
 	struct sdma_engine		*sdma;
 	unsigned int			channel;
 	enum dma_transfer_direction		direction;
-	struct dma_slave_config		slave_config;
 	enum sdma_peripheral_type	peripheral_type;
 	unsigned int			event_id0;
 	unsigned int			event_id1;
@@ -1647,7 +1645,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 	struct scatterlist *sg;
 	struct sdma_desc *desc;
 
-	sdma_config_write(chan, &sdmac->slave_config, direction);
+	sdma_config_write(chan, &chan->config, direction);
 
 	desc = sdma_transfer_init(sdmac, direction, sg_len);
 	if (!desc)
@@ -1739,7 +1737,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 	if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
 		num_periods = buf_len / period_len;
 
-	sdma_config_write(chan, &sdmac->slave_config, direction);
+	sdma_config_write(chan, &chan->config, direction);
 
 	desc = sdma_transfer_init(sdmac, direction, num_periods);
 	if (!desc)
@@ -1838,8 +1836,6 @@ static int sdma_config(struct dma_chan *chan,
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 	struct sdma_engine *sdma = sdmac->sdma;
 
-	memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
-
 	if (dmaengine_cfg->peripheral_config) {
 		struct sdma_peripheral_config *sdmacfg = dmaengine_cfg->peripheral_config;
 		if (dmaengine_cfg->peripheral_size != sizeof(struct sdma_peripheral_config)) {

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/6] dmaengine: Add union and dma_slave_get_config() helper for dma_slave_config
  2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
                   ` (3 preceding siblings ...)
  2026-01-14 17:12 ` [PATCH 4/6] dmaengine: imx-sdma: use common config at dma_chan Frank Li
@ 2026-01-14 17:12 ` Frank Li
  2026-01-14 17:12 ` [PATCH 6/6] dmaengine: fsl-edma: use common dma_slave_get_cfg() Frank Li
  2026-03-09 11:24 ` [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Vinod Koul
  6 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-01-14 17:12 UTC (permalink / raw)
  To: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: dmaengine, linux-kernel, imx, linux-arm-kernel, Frank Li

Previously, src_ and dst_ prefixes were used to distinguish address,
addr_width, maxburst, and port_window_size fields. This required drivers
to add conditional logic based on transfer direction.

Introduce struct dma_slave_cfg to group these fields and add the
dma_slave_get_config() helper to retrieve the source or destination
configuration based on the DMA transfer direction. This reduces
direction-based branching in drivers and improves readability.

Use a union to preserve the old field naming and maintain compatibility.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 include/linux/dmaengine.h | 42 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 8 deletions(-)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 362a43c3e36e232b5a65ff78ba0b692c0401e50c..03632bccc7ccb3c0c4a9c78f15865f35a375836a 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -384,21 +384,47 @@ enum dma_slave_buswidth {
  * If not: if it is fixed so that it be sent in static from the platform
  * data, then prefer to do that.
  */
+struct dma_slave_cfg { /* order must be align below dma_slave_config union */
+	phys_addr_t addr;
+	enum dma_slave_buswidth addr_width;
+	u32 maxburst;
+	u32 port_window_size;
+};
+
 struct dma_slave_config {
 	enum dma_transfer_direction direction;
-	phys_addr_t src_addr;
-	phys_addr_t dst_addr;
-	enum dma_slave_buswidth src_addr_width;
-	enum dma_slave_buswidth dst_addr_width;
-	u32 src_maxburst;
-	u32 dst_maxburst;
-	u32 src_port_window_size;
-	u32 dst_port_window_size;
+	union {
+		struct {
+			phys_addr_t src_addr;
+			enum dma_slave_buswidth src_addr_width;
+			u32 src_maxburst;
+			u32 src_port_window_size;
+			phys_addr_t dst_addr;
+			enum dma_slave_buswidth dst_addr_width;
+			u32 dst_maxburst;
+			u32 dst_port_window_size;
+		};
+
+		struct {
+			struct dma_slave_cfg src;
+			struct dma_slave_cfg dst;
+		};
+	};
 	bool device_fc;
 	void *peripheral_config;
 	size_t peripheral_size;
 };
 
+static inline struct dma_slave_cfg *
+dma_slave_get_cfg(struct dma_slave_config *config,
+		  enum dma_transfer_direction dir)
+{
+	if (dir == DMA_MEM_TO_DEV)
+		return &config->dst;
+
+	return &config->src;
+}
+
 /**
  * struct dma_chan - devices supply DMA channels, clients use them
  * @device: ptr to the dma device who supplies this channel, always !%NULL

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/6] dmaengine: fsl-edma: use common dma_slave_get_cfg()
  2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
                   ` (4 preceding siblings ...)
  2026-01-14 17:12 ` [PATCH 5/6] dmaengine: Add union and dma_slave_get_config() helper for dma_slave_config Frank Li
@ 2026-01-14 17:12 ` Frank Li
  2026-03-09 11:24 ` [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Vinod Koul
  6 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-01-14 17:12 UTC (permalink / raw)
  To: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam
  Cc: dmaengine, linux-kernel, imx, linux-arm-kernel, Frank Li

Use common dma_slave_get_cfg() to simple code. No functional change.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
 drivers/dma/fsl-edma-common.c | 61 ++++++++++++++++++-------------------------
 1 file changed, 26 insertions(+), 35 deletions(-)

diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index 33fc4fa8d1302d899ce550b0ce5d4325fa2e3916..c4ac63d9612ce9f1f5826a2186938a785ed529d1 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -291,30 +291,32 @@ static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan)
 	fsl_chan->dma_dir = DMA_NONE;
 }
 
+static enum dma_data_direction
+fsl_dma_dir_trans_to_data(enum dma_transfer_direction dir)
+{
+	if (dir == DMA_MEM_TO_DEV)
+		return DMA_FROM_DEVICE;
+
+	if (dir ==  DMA_DEV_TO_MEM)
+		return DMA_TO_DEVICE;
+
+	return DMA_NONE;
+}
+
 static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan,
 				    enum dma_transfer_direction dir)
 {
 	struct dma_slave_config *cfg = &fsl_chan->vchan.chan.config;
+	struct dma_slave_cfg *c = dma_slave_get_cfg(cfg, dir);
 	struct device *dev = fsl_chan->vchan.chan.device->dev;
 	enum dma_data_direction dma_dir;
 	phys_addr_t addr = 0;
 	u32 size = 0;
 
-	switch (dir) {
-	case DMA_MEM_TO_DEV:
-		dma_dir = DMA_FROM_DEVICE;
-		addr = cfg->dst_addr;
-		size = cfg->dst_maxburst;
-		break;
-	case DMA_DEV_TO_MEM:
-		dma_dir = DMA_TO_DEVICE;
-		addr = cfg->src_addr;
-		size = cfg->src_maxburst;
-		break;
-	default:
-		dma_dir = DMA_NONE;
-		break;
-	}
+	dma_dir = fsl_dma_dir_trans_to_data(dir);
+
+	addr = c->addr;
+	size = c->maxburst;
 
 	/* Already mapped for this config? */
 	if (fsl_chan->dma_dir == dma_dir)
@@ -484,6 +486,7 @@ void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
 		       bool disable_req, bool enable_sg)
 {
 	struct dma_slave_config *cfg = &fsl_chan->vchan.chan.config;
+	struct dma_slave_cfg *c = dma_slave_get_cfg(cfg, cfg->direction);
 	u32 burst = 0;
 	u16 csr = 0;
 
@@ -507,26 +510,14 @@ void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
 	 * If we don't have either of those, will use a major loop reading from addr
 	 * nbytes (29bits).
 	 */
-	if (cfg->direction == DMA_MEM_TO_DEV) {
-		if (fsl_chan->is_multi_fifo)
-			burst = cfg->dst_maxburst * 4;
-		if (cfg->dst_port_window_size)
-			burst = cfg->dst_port_window_size * cfg->dst_addr_width;
-		if (burst) {
-			nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-burst);
-			nbytes |= EDMA_V3_TCD_NBYTES_DMLOE;
-			nbytes &= ~EDMA_V3_TCD_NBYTES_SMLOE;
-		}
-	} else {
-		if (fsl_chan->is_multi_fifo)
-			burst = cfg->src_maxburst * 4;
-		if (cfg->src_port_window_size)
-			burst = cfg->src_port_window_size * cfg->src_addr_width;
-		if (burst) {
-			nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-burst);
-			nbytes |= EDMA_V3_TCD_NBYTES_SMLOE;
-			nbytes &= ~EDMA_V3_TCD_NBYTES_DMLOE;
-		}
+	if (fsl_chan->is_multi_fifo)
+		burst = c->maxburst * 4;
+	if (c->port_window_size)
+		burst = c->port_window_size * c->addr_width;
+	if (burst) {
+		nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-burst);
+		nbytes |= EDMA_V3_TCD_NBYTES_DMLOE;
+		nbytes &= ~EDMA_V3_TCD_NBYTES_SMLOE;
 	}
 
 	fsl_edma_set_tcd_to_le(fsl_chan, tcd, nbytes, nbytes);

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts
  2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
                   ` (5 preceding siblings ...)
  2026-01-14 17:12 ` [PATCH 6/6] dmaengine: fsl-edma: use common dma_slave_get_cfg() Frank Li
@ 2026-03-09 11:24 ` Vinod Koul
  2026-03-09 14:27   ` Frank Li
  6 siblings, 1 reply; 11+ messages in thread
From: Vinod Koul @ 2026-03-09 11:24 UTC (permalink / raw)
  To: Frank Li
  Cc: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	dmaengine, linux-kernel, imx, linux-arm-kernel

On 14-01-26, 12:12, Frank Li wrote:
> Many DMA engine drivers store a dma_slave_config per channel. Propagate
> this configuration into struct dma_chan to avoid duplicating the same
> code in each driver.
> 
> Much of dma_slave_config is identical for source and destination. Split
> the configuration into src and dst groups and use a union to preserve
> backward compatibility. This reduces the need for drivers to repeatedly
> check the DMA transfer direction.

The reason why we had both the src/dstn sides was intended method to
allow upport ofr device to device dma. Some interest was shown for that
at that time.
I dont think we have such a user even now...


-- 
~Vinod

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts
  2026-03-09 11:24 ` [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Vinod Koul
@ 2026-03-09 14:27   ` Frank Li
  2026-03-17 10:26     ` Vinod Koul
  0 siblings, 1 reply; 11+ messages in thread
From: Frank Li @ 2026-03-09 14:27 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	dmaengine, linux-kernel, imx, linux-arm-kernel

On Mon, Mar 09, 2026 at 12:24:33PM +0100, Vinod Koul wrote:
> On 14-01-26, 12:12, Frank Li wrote:
> > Many DMA engine drivers store a dma_slave_config per channel. Propagate
> > this configuration into struct dma_chan to avoid duplicating the same
> > code in each driver.
> >
> > Much of dma_slave_config is identical for source and destination. Split
> > the configuration into src and dst groups and use a union to preserve
> > backward compatibility. This reduces the need for drivers to repeatedly
> > check the DMA transfer direction.
>
> The reason why we had both the src/dstn sides was intended method to
> allow upport ofr device to device dma. Some interest was shown for that
> at that time.
> I dont think we have such a user even now...

My means is the field name is identical, not value identical although most
case is the identical. but it is possible, especial FIFO space windows,

sound/soc/fsl/fsl_asrc_dma.c use DEV_TO_DEV, at least src and addr use
differece address.

Frank

>
>
> --
> ~Vinod

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts
  2026-03-09 14:27   ` Frank Li
@ 2026-03-17 10:26     ` Vinod Koul
  2026-03-17 13:56       ` Frank Li
  0 siblings, 1 reply; 11+ messages in thread
From: Vinod Koul @ 2026-03-17 10:26 UTC (permalink / raw)
  To: Frank Li
  Cc: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	dmaengine, linux-kernel, imx, linux-arm-kernel

On 09-03-26, 10:27, Frank Li wrote:
> On Mon, Mar 09, 2026 at 12:24:33PM +0100, Vinod Koul wrote:
> > On 14-01-26, 12:12, Frank Li wrote:
> > > Many DMA engine drivers store a dma_slave_config per channel. Propagate
> > > this configuration into struct dma_chan to avoid duplicating the same
> > > code in each driver.
> > >
> > > Much of dma_slave_config is identical for source and destination. Split
> > > the configuration into src and dst groups and use a union to preserve
> > > backward compatibility. This reduces the need for drivers to repeatedly
> > > check the DMA transfer direction.
> >
> > The reason why we had both the src/dstn sides was intended method to
> > allow upport ofr device to device dma. Some interest was shown for that
> > at that time.
> > I dont think we have such a user even now...
> 
> My means is the field name is identical, not value identical although most
> case is the identical. but it is possible, especial FIFO space windows,
> 
> sound/soc/fsl/fsl_asrc_dma.c use DEV_TO_DEV, at least src and addr use
> differece address.

Yeah so this would break if we go ahead. Thanks for looking this up

-- 
~Vinod

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts
  2026-03-17 10:26     ` Vinod Koul
@ 2026-03-17 13:56       ` Frank Li
  0 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-03-17 13:56 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	dmaengine, linux-kernel, imx, linux-arm-kernel

On Tue, Mar 17, 2026 at 03:56:40PM +0530, Vinod Koul wrote:
> On 09-03-26, 10:27, Frank Li wrote:
> > On Mon, Mar 09, 2026 at 12:24:33PM +0100, Vinod Koul wrote:
> > > On 14-01-26, 12:12, Frank Li wrote:
> > > > Many DMA engine drivers store a dma_slave_config per channel. Propagate
> > > > this configuration into struct dma_chan to avoid duplicating the same
> > > > code in each driver.
> > > >
> > > > Much of dma_slave_config is identical for source and destination. Split
> > > > the configuration into src and dst groups and use a union to preserve
> > > > backward compatibility. This reduces the need for drivers to repeatedly
> > > > check the DMA transfer direction.
> > >
> > > The reason why we had both the src/dstn sides was intended method to
> > > allow upport ofr device to device dma. Some interest was shown for that
> > > at that time.
> > > I dont think we have such a user even now...
> >
> > My means is the field name is identical, not value identical although most
> > case is the identical. but it is possible, especial FIFO space windows,
> >
> > sound/soc/fsl/fsl_asrc_dma.c use DEV_TO_DEV, at least src and addr use
> > differece address.
>
> Yeah so this would break if we go ahead. Thanks for looking this up

Sorry, what break? This patch just group these informations.

Frank

>
> --
> ~Vinod

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-03-17 13:56 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-14 17:12 [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Frank Li
2026-01-14 17:12 ` [PATCH 1/6] dmaengine: Move struct dma_chan after struct dma_slave_config Frank Li
2026-01-14 17:12 ` [PATCH 2/6] dmaengine: Add common slave configuration to dma_chan Frank Li
2026-01-14 17:12 ` [PATCH 3/6] dmaengine: fsl-edma: use dma_chan common config Frank Li
2026-01-14 17:12 ` [PATCH 4/6] dmaengine: imx-sdma: use common config at dma_chan Frank Li
2026-01-14 17:12 ` [PATCH 5/6] dmaengine: Add union and dma_slave_get_config() helper for dma_slave_config Frank Li
2026-01-14 17:12 ` [PATCH 6/6] dmaengine: fsl-edma: use common dma_slave_get_cfg() Frank Li
2026-03-09 11:24 ` [PATCH 0/6] dmaengine: Add common dma_slave_config and split it into src and dst parts Vinod Koul
2026-03-09 14:27   ` Frank Li
2026-03-17 10:26     ` Vinod Koul
2026-03-17 13:56       ` Frank Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox