DMA Engine development
 help / color / mirror / Atom feed
* [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above
@ 2026-08-10 15:06 Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 1/9] " Nuno Sá
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

The DMA engine slave capabilities advertise the supported source and
destination bus widths through src_addr_widths / dst_addr_widths. These
are plain u32 bitmasks where a set bit's position equals the
corresponding enum dma_slave_buswidth value, e.g.
DMA_SLAVE_BUSWIDTH_4_BYTES sets bit 4.

The consequence is that widths of 32 bytes and above cannot be
represented at all: DMA_SLAVE_BUSWIDTH_32/64/128_BYTES would need bits
32, 64 and 128, which do not fit in a u32. Hardware with wider data
paths is becoming common, so add a representation that can express these
widths while still using enum dma_slave_buswidth.

This series switches consumers and a small set of producers to bitmap
based bus width capabilities. The legacy dma_device u32 fields are kept
for now so the remaining DMA controller drivers can be converted
incrementally. dma_get_slave_caps() folds legacy producer masks into the
new bitmap representation returned to consumers.

Once the remaining producers are converted, the legacy dma_device
src/dst_addr_widths fields can be removed as a final cleanup.

This issue was discussed before here:

https://lore.kernel.org/dmaengine/abkoXXbaxaiqbBuX@vaman/

---
Changes in v2:
- Patch 5:
  - Goto the error label instead of directly returning so the clock is
    disabled if setting the bus width capabilities fails.
- Patch 9:
  - Improve the commit message to make it explicit that only the
    struct dma_slave_caps legacy fields are removed and that the
    struct dma_device ones are kept until all the DMA controller drivers
    are converted.
- Link to v1: https://patch.msgid.link/20260730-dmaengine-support-wider-dma-masks-v1-0-3732f1f9d9ca@analog.com

---
Nuno Sá (9):
      dmaengine: Support bus widths of 32 bytes and above
      dmaengine: dma-axi-dmac: Use bus width capability helpers
      dmaengine: dw-axi-dmac: Use bus width capability helpers
      dmaengine: qcom: gpi: Use bus width capability helpers
      dmaengine: stm32-dma3: Use bus width capability helpers
      iio: buffer-dmaengine: Use dma_slave_caps bus width accessors
      ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers
      spi: dw: Use dma_slave_caps bus width helpers
      dmaengine: Drop legacy bus width fields from dma_slave_caps

 drivers/dma/dma-axi-dmac.c                         |  13 +-
 drivers/dma/dmaengine.c                            |  20 +-
 drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c     |  39 ++--
 drivers/dma/qcom/gpi.c                             |  11 +-
 drivers/dma/stm32/stm32-dma3.c                     |  32 +--
 drivers/iio/buffer/industrialio-buffer-dmaengine.c |  15 +-
 drivers/spi/spi-dw-dma.c                           |   6 +-
 drivers/spi/spi-dw.h                               |   3 +-
 include/linux/dmaengine.h                          | 234 ++++++++++++++++++++-
 sound/core/pcm_dmaengine.c                         |  14 +-
 10 files changed, 323 insertions(+), 64 deletions(-)
---
base-commit: 0613e7934ee233d726af8d8c89f251a1c4df738d
change-id: 20260615-dmaengine-support-wider-dma-masks-5aac12497e27
--

Thanks!
- Nuno Sá


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

* [PATCH v2 1/9] dmaengine: Support bus widths of 32 bytes and above
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:17   ` sashiko-bot
  2026-08-10 17:15   ` Andy Shevchenko
  2026-08-10 15:06 ` [PATCH v2 2/9] dmaengine: dma-axi-dmac: Use bus width capability helpers Nuno Sá
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

The src_addr_widths and dst_addr_widths capability masks encode each
supported width as a bit whose position equals the corresponding
enum dma_slave_buswidth value (e.g. DMA_SLAVE_BUSWIDTH_4_BYTES sets bit
4). As these masks are plain u32, widths of 32 bytes and above
(DMA_SLAVE_BUSWIDTH_32/64/128_BYTES map to bits 32, 64 and 128) cannot
be represented at all.

Introduce bitmap-based bus width capabilities that span the full enum
range. To allow DMA controller producers to be converted incrementally,
keep the legacy dma_device u32 fields alongside the new bitmaps:
producers using the new helpers populate the bitmap and mirror the low
32 bits back into the legacy field, while dma_get_slave_caps() folds a
legacy-only producer's u32 into the returned bitmap.

Add helpers for producers and consumers so users do not need to depend
on the bitmap layout directly. Once the remaining producers are
converted, the legacy dma_device u32 fields can be dropped.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/dma/dmaengine.c   |  18 ++++
 include/linux/dmaengine.h | 246 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 254 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 6ffd8bd82154..a80a84cf87eb 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -593,7 +593,25 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
 		return -ENXIO;
 
 	caps->src_addr_widths = device->src_addr_widths;
+	if (bitmap_empty(device->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
+		bitmap_zero(caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
+		bitmap_from_arr32(caps->src_bus_widths,
+				  &device->src_addr_widths, 32);
+	} else {
+		bitmap_copy(caps->src_bus_widths, device->src_bus_widths,
+			    DMA_SLAVE_BUSWIDTH_MAX);
+	}
+
 	caps->dst_addr_widths = device->dst_addr_widths;
+	if (bitmap_empty(device->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
+		bitmap_zero(caps->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
+		bitmap_from_arr32(caps->dst_bus_widths,
+				  &device->dst_addr_widths, 32);
+	} else {
+		bitmap_copy(caps->dst_bus_widths, device->dst_bus_widths,
+			    DMA_SLAVE_BUSWIDTH_MAX);
+	}
+
 	caps->directions = device->directions;
 	caps->min_burst = device->min_burst;
 	caps->max_burst = device->max_burst;
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index fe33a20abc61..8697583e2ed3 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -5,6 +5,7 @@
 #ifndef LINUX_DMAENGINE_H
 #define LINUX_DMAENGINE_H
 
+#include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/uio.h>
@@ -399,8 +400,12 @@ enum dma_slave_buswidth {
 	DMA_SLAVE_BUSWIDTH_32_BYTES = 32,
 	DMA_SLAVE_BUSWIDTH_64_BYTES = 64,
 	DMA_SLAVE_BUSWIDTH_128_BYTES = 128,
+	DMA_SLAVE_BUSWIDTH_MAX
 };
 
+#define DECLARE_DMA_BUS_WIDTHS(name) \
+	DECLARE_BITMAP(name, DMA_SLAVE_BUSWIDTH_MAX)
+
 /**
  * struct dma_slave_config - dma slave channel runtime config
  * @direction: whether the data shall go in or out on this slave
@@ -495,10 +500,12 @@ enum dma_residue_granularity {
 
 /**
  * struct dma_slave_caps - expose capabilities of a slave channel only
- * @src_addr_widths: bit mask of src addr widths the channel supports.
+ * @src_bus_widths: bitmap of source bus widths the channel supports.
  *	Width is specified in bytes, e.g. for a channel supporting
- *	a width of 4 the mask should have BIT(4) set.
- * @dst_addr_widths: bit mask of dst addr widths the channel supports
+ *	a width of 4 the bitmap should have bit 4 set.
+ * @src_addr_widths: legacy bit mask of source bus widths the channel supports.
+ * @dst_bus_widths: bitmap of destination bus widths the channel supports.
+ * @dst_addr_widths: legacy bit mask of destination bus widths the channel supports.
  * @directions: bit mask of slave directions the channel supports.
  *	Since the enum dma_transfer_direction is not defined as bit flag for
  *	each type, the dma controller should set BIT(<TYPE>) and same
@@ -517,8 +524,14 @@ enum dma_residue_granularity {
  * resubmitted multiple times
  */
 struct dma_slave_caps {
-	u32 src_addr_widths;
-	u32 dst_addr_widths;
+	struct {
+		DECLARE_DMA_BUS_WIDTHS(src_bus_widths);
+		u32 src_addr_widths;
+	};
+	struct {
+		DECLARE_DMA_BUS_WIDTHS(dst_bus_widths);
+		u32 dst_addr_widths;
+	};
 	u32 directions;
 	u32 min_burst;
 	u32 max_burst;
@@ -811,10 +824,12 @@ struct dma_filter {
  * @dev: struct device reference for dma mapping api
  * @owner: owner module (automatically set based on the provided dev)
  * @chan_ida: unique channel ID
- * @src_addr_widths: bit mask of src addr widths the device supports
+ * @src_bus_widths: bitmap of source bus widths the device supports.
  *	Width is specified in bytes, e.g. for a device supporting
- *	a width of 4 the mask should have BIT(4) set.
- * @dst_addr_widths: bit mask of dst addr widths the device supports
+ *	a width of 4 the bitmap should have bit 4 set.
+ * @src_addr_widths: legacy bit mask of source bus widths the device supports.
+ * @dst_bus_widths: bitmap of destination bus widths the device supports.
+ * @dst_addr_widths: legacy bit mask of destination bus widths the device supports.
  * @directions: bit mask of slave directions the device supports.
  *	Since the enum dma_transfer_direction is not defined as bit flag for
  *	each type, the dma controller should set BIT(<TYPE>) and same
@@ -896,8 +911,14 @@ struct dma_device {
 	struct module *owner;
 	struct ida chan_ida;
 
-	u32 src_addr_widths;
-	u32 dst_addr_widths;
+	struct {
+		DECLARE_DMA_BUS_WIDTHS(src_bus_widths);
+		u32 src_addr_widths;
+	};
+	struct {
+		DECLARE_DMA_BUS_WIDTHS(dst_bus_widths);
+		u32 dst_addr_widths;
+	};
 	u32 directions;
 	u32 min_burst;
 	u32 max_burst;
@@ -1811,4 +1832,209 @@ static inline struct device *dmaengine_get_dma_device(struct dma_chan *chan)
 	return chan->device->dev;
 }
 
+static inline enum dma_slave_buswidth
+__dma_slave_caps_get_width_min(const unsigned long *bus_widths)
+{
+	enum dma_slave_buswidth width = find_first_bit(bus_widths,
+						       DMA_SLAVE_BUSWIDTH_MAX);
+
+	if (width == DMA_SLAVE_BUSWIDTH_MAX)
+		return DMA_SLAVE_BUSWIDTH_UNDEFINED;
+
+	return width;
+}
+
+/**
+ * dma_slave_caps_get_src_width_min - get the minimum source bus width
+ * @caps: DMA slave capabilities
+ *
+ * Return: the minimum supported source bus width, or
+ * %DMA_SLAVE_BUSWIDTH_UNDEFINED if no source bus width is advertised.
+ */
+static inline enum dma_slave_buswidth
+dma_slave_caps_get_src_width_min(const struct dma_slave_caps *caps)
+{
+	return __dma_slave_caps_get_width_min(caps->src_bus_widths);
+}
+
+/**
+ * dma_slave_caps_get_dst_width_min - get the minimum destination bus width
+ * @caps: DMA slave capabilities
+ *
+ * Return: the minimum supported destination bus width, or
+ * %DMA_SLAVE_BUSWIDTH_UNDEFINED if no destination bus width is advertised.
+ */
+static inline enum dma_slave_buswidth
+dma_slave_caps_get_dst_width_min(const struct dma_slave_caps *caps)
+{
+	return __dma_slave_caps_get_width_min(caps->dst_bus_widths);
+}
+
+/**
+ * dma_slave_caps_copy_src_widths - copy source bus width capabilities
+ * @caps: DMA slave capabilities
+ * @bus_widths: destination bitmap declared with DECLARE_DMA_BUS_WIDTHS()
+ */
+static inline void
+dma_slave_caps_copy_src_widths(const struct dma_slave_caps *caps,
+			       unsigned long *bus_widths)
+{
+	bitmap_copy(bus_widths, caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
+}
+
+/**
+ * dma_slave_caps_copy_dst_widths - copy destination bus width capabilities
+ * @caps: DMA slave capabilities
+ * @bus_widths: destination bitmap declared with DECLARE_DMA_BUS_WIDTHS()
+ */
+static inline void
+dma_slave_caps_copy_dst_widths(const struct dma_slave_caps *caps,
+			       unsigned long *bus_widths)
+{
+	bitmap_copy(bus_widths, caps->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
+}
+
+/**
+ * dma_slave_caps_intersect_widths - intersect destination and source widths
+ * @dst_caps: DMA slave capabilities providing destination bus widths
+ * @src_caps: DMA slave capabilities providing source bus widths
+ * @bus_widths: destination bitmap declared with DECLARE_DMA_BUS_WIDTHS()
+ *
+ * Return: true if the resulting bitmap contains at least one common bus width,
+ * false otherwise.
+ */
+static inline bool
+dma_slave_caps_intersect_widths(const struct dma_slave_caps *dst_caps,
+				const struct dma_slave_caps *src_caps,
+				unsigned long *bus_widths)
+{
+	return bitmap_and(bus_widths, dst_caps->dst_bus_widths,
+			  src_caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
+}
+
+/**
+ * dma_slave_caps_clear_src_width - clear a source bus width capability
+ * @caps: DMA slave capabilities
+ * @width: source bus width to clear
+ */
+static inline void
+dma_slave_caps_clear_src_width(struct dma_slave_caps *caps,
+			       enum dma_slave_buswidth width)
+{
+	__clear_bit(width, caps->src_bus_widths);
+	if (width < DMA_SLAVE_BUSWIDTH_32_BYTES)
+		caps->src_addr_widths &= ~BIT(width);
+}
+
+/**
+ * dma_slave_caps_clear_dst_width - clear a destination bus width capability
+ * @caps: DMA slave capabilities
+ * @width: destination bus width to clear
+ */
+static inline void
+dma_slave_caps_clear_dst_width(struct dma_slave_caps *caps,
+			       enum dma_slave_buswidth width)
+{
+	__clear_bit(width, caps->dst_bus_widths);
+	if (width < DMA_SLAVE_BUSWIDTH_32_BYTES)
+		caps->dst_addr_widths &= ~BIT(width);
+}
+
+static inline int __dma_set_bus_widths(unsigned long *bus_widths,
+				       const enum dma_slave_buswidth *widths,
+				       unsigned int n_widths)
+{
+	for (unsigned int i = 0; i < n_widths; i++) {
+		switch (widths[i]) {
+		case DMA_SLAVE_BUSWIDTH_UNDEFINED:
+		case DMA_SLAVE_BUSWIDTH_1_BYTE:
+		case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		case DMA_SLAVE_BUSWIDTH_3_BYTES:
+		case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		case DMA_SLAVE_BUSWIDTH_8_BYTES:
+		case DMA_SLAVE_BUSWIDTH_16_BYTES:
+		case DMA_SLAVE_BUSWIDTH_32_BYTES:
+		case DMA_SLAVE_BUSWIDTH_64_BYTES:
+		case DMA_SLAVE_BUSWIDTH_128_BYTES:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		__set_bit(widths[i], bus_widths);
+	}
+
+	return 0;
+}
+
+/**
+ * dma_set_src_bus_widths - set supported source bus widths for a DMA device
+ * @device: DMA device
+ * @widths: array of supported source bus widths
+ * @n_widths: number of entries in @widths
+ *
+ * Return: 0 on success, -EINVAL if @widths contains an invalid bus width.
+ */
+static inline int dma_set_src_bus_widths(struct dma_device *device,
+					 const enum dma_slave_buswidth *widths,
+					 unsigned int n_widths)
+{
+	int ret;
+
+	ret = __dma_set_bus_widths(device->src_bus_widths, widths, n_widths);
+	if (ret)
+		return ret;
+
+	device->src_addr_widths = bitmap_read(device->src_bus_widths, 0, 32);
+	return 0;
+}
+
+/**
+ * dma_set_dst_bus_widths - set supported destination bus widths for a DMA device
+ * @device: DMA device
+ * @widths: array of supported destination bus widths
+ * @n_widths: number of entries in @widths
+ *
+ * Return: 0 on success, -EINVAL if @widths contains an invalid bus width.
+ */
+static inline int dma_set_dst_bus_widths(struct dma_device *device,
+					 const enum dma_slave_buswidth *widths,
+					 unsigned int n_widths)
+{
+	int ret;
+
+	ret = __dma_set_bus_widths(device->dst_bus_widths, widths, n_widths);
+	if (ret)
+		return ret;
+
+	device->dst_addr_widths = bitmap_read(device->dst_bus_widths, 0, 32);
+	return 0;
+}
+
+/**
+ * dma_set_src_bus_width - set a single supported source bus width
+ * @device: DMA device
+ * @width: supported source bus width
+ *
+ * Return: 0 on success, -EINVAL if @width is invalid.
+ */
+static inline int dma_set_src_bus_width(struct dma_device *device,
+					enum dma_slave_buswidth width)
+{
+	return dma_set_src_bus_widths(device, &width, 1);
+}
+
+/**
+ * dma_set_dst_bus_width - set a single supported destination bus width
+ * @device: DMA device
+ * @width: supported destination bus width
+ *
+ * Return: 0 on success, -EINVAL if @width is invalid.
+ */
+static inline int dma_set_dst_bus_width(struct dma_device *device,
+					enum dma_slave_buswidth width)
+{
+	return dma_set_dst_bus_widths(device, &width, 1);
+}
+
 #endif /* DMAENGINE_H */

-- 
2.55.0


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

* [PATCH v2 2/9] dmaengine: dma-axi-dmac: Use bus width capability helpers
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 1/9] " Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 3/9] dmaengine: dw-axi-dmac: " Nuno Sá
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

Advertise the source and destination bus widths through the new
dma_set_{src,dst}_bus_width() helpers instead of open-coding the legacy
BIT() mask. This moves the driver onto the representation that can
express widths of 32 bytes and above while keeping the legacy u32 fields
populated during the transition.

While at it, give the channel width members their proper
enum dma_slave_buswidth type.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/dma/dma-axi-dmac.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index d47ff27e1408..26912330e3c8 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -152,8 +152,8 @@ struct axi_dmac_chan {
 	struct list_head active_descs;
 	enum dma_transfer_direction direction;
 
-	unsigned int src_width;
-	unsigned int dest_width;
+	enum dma_slave_buswidth src_width;
+	enum dma_slave_buswidth dest_width;
 	unsigned int src_type;
 	unsigned int dest_type;
 
@@ -1262,8 +1262,13 @@ static int axi_dmac_probe(struct platform_device *pdev)
 	dma_dev->device_terminate_all = axi_dmac_terminate_all;
 	dma_dev->device_synchronize = axi_dmac_synchronize;
 	dma_dev->dev = &pdev->dev;
-	dma_dev->src_addr_widths = BIT(dmac->chan.src_width);
-	dma_dev->dst_addr_widths = BIT(dmac->chan.dest_width);
+	ret = dma_set_src_bus_width(dma_dev, dmac->chan.src_width);
+	if (ret)
+		return ret;
+
+	ret = dma_set_dst_bus_width(dma_dev, dmac->chan.dest_width);
+	if (ret)
+		return ret;
 	dma_dev->directions = BIT(dmac->chan.direction);
 	dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
 	dma_dev->max_sg_burst = 31; /* 31 SGs maximum in one burst */

-- 
2.55.0


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

* [PATCH v2 3/9] dmaengine: dw-axi-dmac: Use bus width capability helpers
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 1/9] " Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 2/9] dmaengine: dma-axi-dmac: Use bus width capability helpers Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:18   ` sashiko-bot
  2026-08-10 15:06 ` [PATCH v2 4/9] dmaengine: qcom: gpi: " Nuno Sá
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

Advertise the supported bus widths through dma_set_src_bus_widths()
and dma_set_dst_bus_widths() instead of assigning the legacy u32 masks
directly. This keeps the driver using the new bitmap representation
while preserving legacy fields during the transition.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 39 +++++++++++++++-----------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index eebed2474210..0fc4aa537346 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -33,20 +33,6 @@
 #include "../dmaengine.h"
 #include "../virt-dma.h"
 
-/*
- * The set of bus widths supported by the DMA controller. DW AXI DMAC supports
- * master data bus width up to 512 bits (for both AXI master interfaces), but
- * it depends on IP block configuration.
- */
-#define AXI_DMA_BUSWIDTHS		  \
-	(DMA_SLAVE_BUSWIDTH_1_BYTE	| \
-	DMA_SLAVE_BUSWIDTH_2_BYTES	| \
-	DMA_SLAVE_BUSWIDTH_4_BYTES	| \
-	DMA_SLAVE_BUSWIDTH_8_BYTES	| \
-	DMA_SLAVE_BUSWIDTH_16_BYTES	| \
-	DMA_SLAVE_BUSWIDTH_32_BYTES	| \
-	DMA_SLAVE_BUSWIDTH_64_BYTES)
-
 #define AXI_DMA_FLAG_HAS_APB_REGS	BIT(0)
 #define AXI_DMA_FLAG_HAS_RESETS		BIT(1)
 #define AXI_DMA_FLAG_USE_CFG2		BIT(2)
@@ -1482,6 +1468,20 @@ static int dw_probe(struct platform_device *pdev)
 	unsigned int flags;
 	u32 i;
 	int ret;
+	/*
+	 * The set of bus widths supported by the DMA controller. DW AXI DMAC
+	 * supports master data bus width up to 512 bits (for both AXI master
+	 * interfaces), but it depends on IP block configuration.
+	 */
+	enum dma_slave_buswidth axi_dma_buswidths[] = {
+		DMA_SLAVE_BUSWIDTH_1_BYTE,
+		DMA_SLAVE_BUSWIDTH_2_BYTES,
+		DMA_SLAVE_BUSWIDTH_4_BYTES,
+		DMA_SLAVE_BUSWIDTH_8_BYTES,
+		DMA_SLAVE_BUSWIDTH_16_BYTES,
+		DMA_SLAVE_BUSWIDTH_32_BYTES,
+		DMA_SLAVE_BUSWIDTH_64_BYTES,
+	};
 
 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
@@ -1565,8 +1565,15 @@ static int dw_probe(struct platform_device *pdev)
 
 	/* DMA capabilities */
 	dw->dma.max_burst = hdata->axi_rw_burst_len;
-	dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS;
-	dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS;
+	ret = dma_set_src_bus_widths(&dw->dma, axi_dma_buswidths,
+				     ARRAY_SIZE(axi_dma_buswidths));
+	if (ret)
+		return ret;
+
+	ret = dma_set_dst_bus_widths(&dw->dma, axi_dma_buswidths,
+				     ARRAY_SIZE(axi_dma_buswidths));
+	if (ret)
+		return ret;
 	dw->dma.directions = BIT(DMA_MEM_TO_MEM);
 	dw->dma.directions |= BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
 	dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;

-- 
2.55.0


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

* [PATCH v2 4/9] dmaengine: qcom: gpi: Use bus width capability helpers
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
                   ` (2 preceding siblings ...)
  2026-08-10 15:06 ` [PATCH v2 3/9] dmaengine: dw-axi-dmac: " Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:15   ` sashiko-bot
  2026-08-10 15:06 ` [PATCH v2 5/9] dmaengine: stm32-dma3: " Nuno Sá
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

Advertise the single supported source and destination bus width through
the new dma_set_src_bus_width() and dma_set_dst_bus_width() helpers
instead of assigning the legacy u32 fields directly.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/dma/qcom/gpi.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index a5055a6273af..fd45cadce91f 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -2265,8 +2265,15 @@ static int gpi_probe(struct platform_device *pdev)
 	/* configure dmaengine apis */
 	gpi_dev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
 	gpi_dev->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
-	gpi_dev->dma_device.src_addr_widths = DMA_SLAVE_BUSWIDTH_8_BYTES;
-	gpi_dev->dma_device.dst_addr_widths = DMA_SLAVE_BUSWIDTH_8_BYTES;
+	ret = dma_set_src_bus_width(&gpi_dev->dma_device,
+				    DMA_SLAVE_BUSWIDTH_8_BYTES);
+	if (ret)
+		return ret;
+
+	ret = dma_set_dst_bus_width(&gpi_dev->dma_device,
+				    DMA_SLAVE_BUSWIDTH_8_BYTES);
+	if (ret)
+		return ret;
 	gpi_dev->dma_device.device_alloc_chan_resources = gpi_alloc_chan_resources;
 	gpi_dev->dma_device.device_free_chan_resources = gpi_free_chan_resources;
 	gpi_dev->dma_device.device_tx_status = dma_cookie_status;

-- 
2.55.0


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

* [PATCH v2 5/9] dmaengine: stm32-dma3: Use bus width capability helpers
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
                   ` (3 preceding siblings ...)
  2026-08-10 15:06 ` [PATCH v2 4/9] dmaengine: qcom: gpi: " Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 6/9] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors Nuno Sá
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

Advertise the controller-wide bus width capabilities through the new
dma_set_src_bus_widths() and dma_set_dst_bus_widths() helpers.

Also update the per-channel capability callback to clear unsupported
widths through the dma_slave_caps helpers so the bitmap and
transitional legacy fields stay in sync.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/dma/stm32/stm32-dma3.c | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/stm32/stm32-dma3.c b/drivers/dma/stm32/stm32-dma3.c
index 4724e7fa0008..f0781fb1b66f 100644
--- a/drivers/dma/stm32/stm32-dma3.c
+++ b/drivers/dma/stm32/stm32-dma3.c
@@ -1469,14 +1469,14 @@ static void stm32_dma3_caps(struct dma_chan *c, struct dma_slave_caps *caps)
 
 	if (!chan->fifo_size) {
 		caps->max_burst = 0;
-		caps->src_addr_widths &= ~BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
-		caps->dst_addr_widths &= ~BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
+		dma_slave_caps_clear_src_width(caps, DMA_SLAVE_BUSWIDTH_8_BYTES);
+		dma_slave_caps_clear_dst_width(caps, DMA_SLAVE_BUSWIDTH_8_BYTES);
 	} else {
 		/* Burst transfer should not exceed half of the fifo size */
 		caps->max_burst = chan->max_burst;
 		if (caps->max_burst < DMA_SLAVE_BUSWIDTH_8_BYTES) {
-			caps->src_addr_widths &= ~BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
-			caps->dst_addr_widths &= ~BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
+			dma_slave_caps_clear_src_width(caps, DMA_SLAVE_BUSWIDTH_8_BYTES);
+			dma_slave_caps_clear_dst_width(caps, DMA_SLAVE_BUSWIDTH_8_BYTES);
 		}
 	}
 }
@@ -1737,6 +1737,12 @@ static int stm32_dma3_probe(struct platform_device *pdev)
 	u32 master_ports, chan_reserved, i, verr;
 	u64 hwcfgr;
 	int ret;
+	enum dma_slave_buswidth stm32_dma3_buswidths[] = {
+		DMA_SLAVE_BUSWIDTH_1_BYTE,
+		DMA_SLAVE_BUSWIDTH_2_BYTES,
+		DMA_SLAVE_BUSWIDTH_4_BYTES,
+		DMA_SLAVE_BUSWIDTH_8_BYTES,
+	};
 
 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 	if (!ddata)
@@ -1775,14 +1781,16 @@ static int stm32_dma3_probe(struct platform_device *pdev)
 	 * channel, and can only access address at even boundaries, multiple of the buswidth.
 	 */
 	dma_dev->copy_align = DMAENGINE_ALIGN_8_BYTES;
-	dma_dev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
-				   BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
-				   BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
-				   BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
-	dma_dev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
-				   BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
-				   BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
-				   BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
+	ret = dma_set_src_bus_widths(dma_dev, stm32_dma3_buswidths,
+				     ARRAY_SIZE(stm32_dma3_buswidths));
+	if (ret)
+		goto err_clk_disable;
+
+	ret = dma_set_dst_bus_widths(dma_dev, stm32_dma3_buswidths,
+				     ARRAY_SIZE(stm32_dma3_buswidths));
+	if (ret)
+		goto err_clk_disable;
+
 	dma_dev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM);
 
 	dma_dev->descriptor_reuse = true;

-- 
2.55.0


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

* [PATCH v2 6/9] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
                   ` (4 preceding siblings ...)
  2026-08-10 15:06 ` [PATCH v2 5/9] dmaengine: stm32-dma3: " Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:32   ` sashiko-bot
  2026-08-10 15:06 ` [PATCH v2 7/9] ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers Nuno Sá
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

Query the minimum supported source and destination bus widths through
the new dma_slave_caps_get_{src,dst}_width_min() helpers rather than
decoding the raw legacy u32 width masks. This keeps the buffer working
with DMA controllers that advertise bus widths via the new bitmap
representation.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/buffer/industrialio-buffer-dmaengine.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index 98acce909854..855e3662cd3d 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -229,14 +229,13 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct dma_chan *chan)
 		return ERR_PTR(-ENOMEM);
 
 	/* Needs to be aligned to the maximum of the minimums */
-	if (caps.src_addr_widths)
-		src_width = __ffs(caps.src_addr_widths);
-	else
-		src_width = 1;
-	if (caps.dst_addr_widths)
-		dest_width = __ffs(caps.dst_addr_widths);
-	else
-		dest_width = 1;
+	src_width = dma_slave_caps_get_src_width_min(&caps);
+	if (src_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+		src_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dest_width = dma_slave_caps_get_dst_width_min(&caps);
+	if (dest_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+		dest_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+
 	width = max(src_width, dest_width);
 
 	INIT_LIST_HEAD(&dmaengine_buffer->active);

-- 
2.55.0


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

* [PATCH v2 7/9] ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
                   ` (5 preceding siblings ...)
  2026-08-10 15:06 ` [PATCH v2 6/9] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 8/9] spi: dw: " Nuno Sá
  2026-08-10 15:06 ` [PATCH v2 9/9] dmaengine: Drop legacy bus width fields from dma_slave_caps Nuno Sá
  8 siblings, 0 replies; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

Use the dma_slave_caps bus width helpers instead of reading the legacy
src_addr_widths and dst_addr_widths masks directly.

Keep the existing default assumption of 1, 2 and 4 byte widths when the
DMA channel does not report slave capabilities.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 sound/core/pcm_dmaengine.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index 1306b04be171..37468f4643bc 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -409,15 +409,17 @@ int snd_dmaengine_pcm_refine_runtime_hwparams(
 	struct dma_chan *chan)
 {
 	struct dma_slave_caps dma_caps;
-	u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
-			  BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
-			  BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+	DECLARE_DMA_BUS_WIDTHS(bus_widths) = {};
 	snd_pcm_format_t i;
 	int ret = 0;
 
 	if (!hw || !chan || !dma_data)
 		return -EINVAL;
 
+	__set_bit(DMA_SLAVE_BUSWIDTH_1_BYTE, bus_widths);
+	__set_bit(DMA_SLAVE_BUSWIDTH_2_BYTES, bus_widths);
+	__set_bit(DMA_SLAVE_BUSWIDTH_4_BYTES, bus_widths);
+
 	ret = dma_get_slave_caps(chan, &dma_caps);
 	if (ret == 0) {
 		if (dma_caps.cmd_pause && dma_caps.cmd_resume)
@@ -426,9 +428,9 @@ int snd_dmaengine_pcm_refine_runtime_hwparams(
 			hw->info |= SNDRV_PCM_INFO_BATCH;
 
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			addr_widths = dma_caps.dst_addr_widths;
+			dma_slave_caps_copy_dst_widths(&dma_caps, bus_widths);
 		else
-			addr_widths = dma_caps.src_addr_widths;
+			dma_slave_caps_copy_src_widths(&dma_caps, bus_widths);
 	}
 
 	/*
@@ -460,7 +462,7 @@ int snd_dmaengine_pcm_refine_runtime_hwparams(
 			case 24:
 			case 32:
 			case 64:
-				if (addr_widths & (1 << (bits / 8)))
+				if (test_bit(bits / 8, bus_widths))
 					hw->formats |= pcm_format_to_bits(i);
 				break;
 			default:

-- 
2.55.0


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

* [PATCH v2 8/9] spi: dw: Use dma_slave_caps bus width helpers
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
                   ` (6 preceding siblings ...)
  2026-08-10 15:06 ` [PATCH v2 7/9] ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 15:28   ` sashiko-bot
  2026-08-10 15:06 ` [PATCH v2 9/9] dmaengine: Drop legacy bus width fields from dma_slave_caps Nuno Sá
  8 siblings, 1 reply; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Frank Li

Store the common TX destination and RX source bus widths in a
driver-owned DMA bus width bitmap and populate it through the
dma_slave_caps helper.

This avoids depending on the legacy src_addr_widths and dst_addr_widths
masks returned by dma_get_slave_caps().

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/spi/spi-dw-dma.c | 6 +++---
 drivers/spi/spi-dw.h     | 3 ++-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index fe726b9b1780..2e23ead4a94f 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -100,10 +100,10 @@ static int dw_spi_dma_caps_init(struct dw_spi *dws)
 
 	/*
 	 * Assuming both channels belong to the same DMA controller hence the
-	 * peripheral side address width capabilities most likely would be
+	 * peripheral side bus width capabilities most likely would be
 	 * the same.
 	 */
-	dws->dma_addr_widths = tx.dst_addr_widths & rx.src_addr_widths;
+	dma_slave_caps_intersect_widths(&tx, &rx, dws->dma_bus_widths);
 
 	return 0;
 }
@@ -253,7 +253,7 @@ static bool dw_spi_can_dma(struct spi_controller *ctlr,
 
 	dma_bus_width = dw_spi_dma_convert_width(dws->n_bytes);
 
-	return dws->dma_addr_widths & BIT(dma_bus_width);
+	return test_bit(dma_bus_width, dws->dma_bus_widths);
 }
 
 static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 2f2debc64e73..2c3aac4360b5 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -10,6 +10,7 @@
 #include <linux/scatterlist.h>
 #include <linux/spi/spi-mem.h>
 #include <linux/bitfield.h>
+#include <linux/dmaengine.h>
 
 /* Synopsys DW SSI IP-core virtual IDs */
 #define DW_PSSI_ID			0
@@ -190,7 +191,7 @@ struct dw_spi {
 	struct dma_chan		*rxchan;
 	u32			rxburst;
 	u32			dma_sg_burst;
-	u32			dma_addr_widths;
+	DECLARE_DMA_BUS_WIDTHS(dma_bus_widths);
 	unsigned long		dma_chan_busy;
 	dma_addr_t		dma_addr; /* phy address of the Data register */
 	const struct dw_spi_dma_ops *dma_ops;

-- 
2.55.0


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

* [PATCH v2 9/9] dmaengine: Drop legacy bus width fields from dma_slave_caps
  2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
                   ` (7 preceding siblings ...)
  2026-08-10 15:06 ` [PATCH v2 8/9] spi: dw: " Nuno Sá
@ 2026-08-10 15:06 ` Nuno Sá
  2026-08-10 16:56   ` Frank Li
  8 siblings, 1 reply; 17+ messages in thread
From: Nuno Sá @ 2026-08-10 15:06 UTC (permalink / raw)
  To: dmaengine, linux-iio
  Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Jonathan Cameron,
	David Lechner, Andy Shevchenko

All users of dma_get_slave_caps() that inspect bus width capabilities now
use the bitmap helpers.

Hence, remove the legacy u32 src_addr_widths and dst_addr_widths fields
from struct dma_slave_caps and stop copying the dma_device masks into
them.

Note the legacy u32 src_addr_widths and dst_addr_widths fields in struct
dma_device are kept for now as every DMA controller driver setting them
still has to be converted to the new helpers. dma_get_slave_caps() keeps
folding those masks into the bitmaps it returns so unconverted producers
continue to work during the transition.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/dma/dmaengine.c   |  2 --
 include/linux/dmaengine.h | 16 ++--------------
 2 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index a80a84cf87eb..36e9b6ddd88d 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -592,7 +592,6 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
 	if (!device->directions)
 		return -ENXIO;
 
-	caps->src_addr_widths = device->src_addr_widths;
 	if (bitmap_empty(device->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
 		bitmap_zero(caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
 		bitmap_from_arr32(caps->src_bus_widths,
@@ -602,7 +601,6 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
 			    DMA_SLAVE_BUSWIDTH_MAX);
 	}
 
-	caps->dst_addr_widths = device->dst_addr_widths;
 	if (bitmap_empty(device->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
 		bitmap_zero(caps->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
 		bitmap_from_arr32(caps->dst_bus_widths,
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 8697583e2ed3..4efaa27e9f7e 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -503,9 +503,7 @@ enum dma_residue_granularity {
  * @src_bus_widths: bitmap of source bus widths the channel supports.
  *	Width is specified in bytes, e.g. for a channel supporting
  *	a width of 4 the bitmap should have bit 4 set.
- * @src_addr_widths: legacy bit mask of source bus widths the channel supports.
  * @dst_bus_widths: bitmap of destination bus widths the channel supports.
- * @dst_addr_widths: legacy bit mask of destination bus widths the channel supports.
  * @directions: bit mask of slave directions the channel supports.
  *	Since the enum dma_transfer_direction is not defined as bit flag for
  *	each type, the dma controller should set BIT(<TYPE>) and same
@@ -524,14 +522,8 @@ enum dma_residue_granularity {
  * resubmitted multiple times
  */
 struct dma_slave_caps {
-	struct {
-		DECLARE_DMA_BUS_WIDTHS(src_bus_widths);
-		u32 src_addr_widths;
-	};
-	struct {
-		DECLARE_DMA_BUS_WIDTHS(dst_bus_widths);
-		u32 dst_addr_widths;
-	};
+	DECLARE_DMA_BUS_WIDTHS(src_bus_widths);
+	DECLARE_DMA_BUS_WIDTHS(dst_bus_widths);
 	u32 directions;
 	u32 min_burst;
 	u32 max_burst;
@@ -1922,8 +1914,6 @@ dma_slave_caps_clear_src_width(struct dma_slave_caps *caps,
 			       enum dma_slave_buswidth width)
 {
 	__clear_bit(width, caps->src_bus_widths);
-	if (width < DMA_SLAVE_BUSWIDTH_32_BYTES)
-		caps->src_addr_widths &= ~BIT(width);
 }
 
 /**
@@ -1936,8 +1926,6 @@ dma_slave_caps_clear_dst_width(struct dma_slave_caps *caps,
 			       enum dma_slave_buswidth width)
 {
 	__clear_bit(width, caps->dst_bus_widths);
-	if (width < DMA_SLAVE_BUSWIDTH_32_BYTES)
-		caps->dst_addr_widths &= ~BIT(width);
 }
 
 static inline int __dma_set_bus_widths(unsigned long *bus_widths,

-- 
2.55.0


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

* Re: [PATCH v2 4/9] dmaengine: qcom: gpi: Use bus width capability helpers
  2026-08-10 15:06 ` [PATCH v2 4/9] dmaengine: qcom: gpi: " Nuno Sá
@ 2026-08-10 15:15   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-10 15:15 UTC (permalink / raw)
  To: Nuno Sá; +Cc: Frank.Li, vkoul, dmaengine

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing unregistration of the DMA device on probe error and driver unbind leads to Use-After-Free.
--

--- Patch [4]: [PATCH v2 4/9] dmaengine: qcom: gpi: Use bus width capability helpers ---
commit 7a53f944daa4cc2b2af28a305b5fb4e022bb0d4d
Author: Nuno Sá <nuno.sa@analog.com>

dmaengine: qcom: gpi: Use bus width capability helpers

Advertise the single supported source and destination bus width through
the new dma_set_src_bus_width() and dma_set_dst_bus_width() helpers
instead of assigning the legacy u32 fields directly.

> diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
> --- a/drivers/dma/qcom/gpi.c
> +++ b/drivers/dma/qcom/gpi.c
> @@ -2265,8 +2265,15 @@ static int gpi_probe(struct platform_device *pdev)
>  	/* configure dmaengine apis */
>  	gpi_dev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
>  	gpi_dev->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
> -	gpi_dev->dma_device.src_addr_widths = DMA_SLAVE_BUSWIDTH_8_BYTES;
> -	gpi_dev->dma_device.dst_addr_widths = DMA_SLAVE_BUSWIDTH_8_BYTES;
> +	ret = dma_set_src_bus_width(&gpi_dev->dma_device,
> +				    DMA_SLAVE_BUSWIDTH_8_BYTES);
> +	if (ret)
> +		return ret;
> +
> +	ret = dma_set_dst_bus_width(&gpi_dev->dma_device,
> +				    DMA_SLAVE_BUSWIDTH_8_BYTES);
> +	if (ret)
> +		return ret;

[Severity: High]
This is a pre-existing issue, but since we are modifying gpi_probe(), is it
possible that the DMA device is left registered if probe fails later?

Looking at the end of gpi_probe():

	ret = dma_async_device_register(&gpi_dev->dma_device);
	if (ret) {
		dev_err(gpi_dev->dev, "async_device_register failed ret:%d", ret);
		return ret;
	}

	ret = of_dma_controller_register(gpi_dev->dev->of_node,
					 gpi_of_dma_xlate, gpi_dev);
	if (ret) {
		dev_err(gpi_dev->dev, "of_dma_controller_reg failed ret:%d", ret);
		return ret;
	}

If of_dma_controller_register() fails, the function returns without calling
dma_async_device_unregister(). Since gpi_dev is allocated with devm_kzalloc,
it will be freed automatically by devres, leaving dangling pointers in the core
DMA subsystem's device list.

Additionally, the gpi_driver platform driver definition lacks a .remove
callback entirely:

static struct platform_driver gpi_driver = {
	.probe = gpi_probe,
	.driver = {
		.name = KBUILD_MODNAME,
		.of_match_table = gpi_of_match,
	},
};

Does this mean a manual driver unbind via sysfs or device removal will also
cause a use-after-free for the same reason?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260810-dmaengine-support-wider-dma-masks-v2-0-1f7b798d035f@analog.com?part=4

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

* Re: [PATCH v2 1/9] dmaengine: Support bus widths of 32 bytes and above
  2026-08-10 15:06 ` [PATCH v2 1/9] " Nuno Sá
@ 2026-08-10 15:17   ` sashiko-bot
  2026-08-10 17:15   ` Andy Shevchenko
  1 sibling, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-10 15:17 UTC (permalink / raw)
  To: Nuno Sá; +Cc: vkoul, Frank.Li, dmaengine

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Inconsistent state between legacy `u32` capabilities and new bus width bitmaps due to legacy `device_caps()` modifications.
--

--- Patch [1]: [PATCH v2 1/9] dmaengine: Support bus widths of 32 bytes and above ---
commit cae7966e8491d2d3566b285f48d250a84ed67596
Author: Nuno Sá <nuno.sa@analog.com>

dmaengine: Support bus widths of 32 bytes and above

This commit introduces bitmap-based bus width capabilities to support
bus widths of 32 bytes and above, which exceed the capacity of the
legacy u32 masks. Legacy u32 fields are kept alongside the new bitmaps
to allow incremental conversion of drivers.

> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -593,7 +593,25 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
>  		return -ENXIO;
>  
>  	caps->src_addr_widths = device->src_addr_widths;
> +	if (bitmap_empty(device->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
> +		bitmap_zero(caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
> +		bitmap_from_arr32(caps->src_bus_widths,
> +				  &device->src_addr_widths, 32);
> +	} else {
> +		bitmap_copy(caps->src_bus_widths, device->src_bus_widths,
> +			    DMA_SLAVE_BUSWIDTH_MAX);
> +	}
> +
>  	caps->dst_addr_widths = device->dst_addr_widths;
> +	if (bitmap_empty(device->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
> +		bitmap_zero(caps->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
> +		bitmap_from_arr32(caps->dst_bus_widths,
> +				  &device->dst_addr_widths, 32);
> +	} else {
> +		bitmap_copy(caps->dst_bus_widths, device->dst_bus_widths,
> +			    DMA_SLAVE_BUSWIDTH_MAX);
> +	}
> +

[Severity: Medium]
Does this sequence leave the new bitmaps out of sync if a legacy driver
modifies the capabilities dynamically?

Later in dma_get_slave_caps(), the device_caps callback is invoked:

    if (device->device_caps)
        device->device_caps(chan, caps);

Some legacy drivers restrict bus widths dynamically in this callback by
modifying the legacy u32 fields directly. For example, in stm32-dma3.c:

stm32_dma3_caps() {
    ...
    caps->src_addr_widths &= ~BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
}

Because the new bitmaps are populated from the static device capabilities
before the callback is executed, won't these dynamic restrictions be missed
in the new bitmap fields?

When consumers migrate to the new API, could they see unsupported bus widths
as available, potentially leading to invalid configurations?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260810-dmaengine-support-wider-dma-masks-v2-0-1f7b798d035f@analog.com?part=1

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

* Re: [PATCH v2 3/9] dmaengine: dw-axi-dmac: Use bus width capability helpers
  2026-08-10 15:06 ` [PATCH v2 3/9] dmaengine: dw-axi-dmac: " Nuno Sá
@ 2026-08-10 15:18   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-10 15:18 UTC (permalink / raw)
  To: Nuno Sá; +Cc: dmaengine, Frank.Li, vkoul

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] The driver requests a shared IRQ before fully initializing the channel structures and enabling device clocks, risking a system crash and NULL pointer dereference if an interrupt fires early.
--

--- Patch [3]: [PATCH v2 3/9] dmaengine: dw-axi-dmac: Use bus width capability helpers ---
commit 716fd3c99096094837bfe18d429e50e20434ac33
Author: Nuno Sá <nuno.sa@analog.com>
Subject: dmaengine: dw-axi-dmac: Use bus width capability helpers

This commit updates the driver to advertise supported bus widths through
the dma_set_src_bus_widths and dma_set_dst_bus_widths helpers. It moves
away from assigning legacy u32 masks directly.

> diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> index eebed2474210d..0fc4aa537346d 100644
> --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c

[ ... ]

> @@ -1565,8 +1565,15 @@ static int dw_probe(struct platform_device *pdev)
>  
>  	/* DMA capabilities */
>  	dw->dma.max_burst = hdata->axi_rw_burst_len;

[Severity: High]
This is a pre-existing issue in dw_probe(), but does the current
initialization sequence risk a bus fault or NULL pointer dereference?

Earlier in dw_probe(), the driver requests a shared IRQ before fully
initializing the channel structures and enabling device clocks:

dw_probe() {
    ...
    ret = axi_req_irqs(pdev, chip);
    ...
    for (i = 0; i < hdata->nr_channels; i++) {
        struct axi_dma_chan *chan = &dw->chan[i];
        chan->chan_regs = chip->regs + ...
        ...
    }
    ...
    ret = axi_dma_resume(chip);
}

If the IRQ is shared and fires immediately after the request,
dw_axi_dma_interrupt() is invoked while the hardware clocks are still
disabled. It accesses hardware registers via axi_dma_irq_disable() which
might cause a synchronous external abort.

If the system survives the unclocked access, dw_axi_dma_interrupt()
iterates over the channels and calls axi_chan_irq_read(), dereferencing
the uninitialized chan->chan_regs pointer:

dw_axi_dma_interrupt() {
    ...
    axi_dma_irq_disable(chip);
    for (i = 0; i < dw->hdata->nr_channels; i++) {
        chan = &dw->chan[i];
        status = axi_chan_irq_read(chan);
        ...
}

Would it be safer to request the IRQ only after the channel structures
are fully initialized and the clocks are enabled?

> -	dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS;
> -	dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS;
> +	ret = dma_set_src_bus_widths(&dw->dma, axi_dma_buswidths,
> +				     ARRAY_SIZE(axi_dma_buswidths));
> +	if (ret)
> +		return ret;
> +
> +	ret = dma_set_dst_bus_widths(&dw->dma, axi_dma_buswidths,
> +				     ARRAY_SIZE(axi_dma_buswidths));
> +	if (ret)
> +		return ret;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260810-dmaengine-support-wider-dma-masks-v2-0-1f7b798d035f@analog.com?part=3

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

* Re: [PATCH v2 8/9] spi: dw: Use dma_slave_caps bus width helpers
  2026-08-10 15:06 ` [PATCH v2 8/9] spi: dw: " Nuno Sá
@ 2026-08-10 15:28   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-10 15:28 UTC (permalink / raw)
  To: Nuno Sá; +Cc: Frank.Li, dmaengine, vkoul

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] `dw_spi_can_dma()` evaluates DMA capabilities using a stale or uninitialized `dws->n_bytes` value, which can incorrectly accept or reject DMA mapping.
--

--- Patch [8]: [PATCH v2 8/9] spi: dw: Use dma_slave_caps bus width helpers ---
commit 4458885866ffec3718df2694d83959e2e55d8975
Author: Nuno Sá <nuno.sa@analog.com>

spi: dw: Use dma_slave_caps bus width helpers
    
Store the common TX destination and RX source bus widths in a driver-owned
DMA bus width bitmap and populate it through the dma_slave_caps helper.

> diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
> index fe726b9b1780d..2e23ead4a94f9 100644
> --- a/drivers/spi/spi-dw-dma.c
> +++ b/drivers/spi/spi-dw-dma.c
[ ... ]
> @@ -253,7 +253,7 @@ static bool dw_spi_can_dma(struct spi_controller *ctlr,
>  
>  	dma_bus_width = dw_spi_dma_convert_width(dws->n_bytes);
>  
> -	return dws->dma_addr_widths & BIT(dma_bus_width);
> +	return test_bit(dma_bus_width, dws->dma_bus_widths);
>  }

[Severity: High]
This is a pre-existing issue, but does evaluating the DMA capabilities here
rely on a stale or uninitialized value for dws->n_bytes?

The SPI core calls spi_map_msg(), which invokes the can_dma callback for
each transfer before any transfer_one callbacks are executed. However, it
looks like dws->n_bytes is not updated based on the current transfer's
bits_per_word until later:

drivers/spi/spi-dw-core.c:dw_spi_transfer_one() {
    ...
    dws->n_bytes = spi_bpw_to_bytes(transfer->bits_per_word);
    ...
}

Because of this sequence, dw_spi_can_dma() appears to use the n_bytes value
left over from the last transfer of the previous message (or 0 for the first
message).

If the previous message used a supported bus width (e.g., 1 byte) but the
current message uses an unsupported one (e.g., 4 bytes), will
dw_spi_can_dma() incorrectly return true? This seems like it could force an
unsupported DMA setup and fail the transfer entirely, rather than gracefully
falling back to PIO mode.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260810-dmaengine-support-wider-dma-masks-v2-0-1f7b798d035f@analog.com?part=8

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

* Re: [PATCH v2 6/9] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors
  2026-08-10 15:06 ` [PATCH v2 6/9] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors Nuno Sá
@ 2026-08-10 15:32   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-10 15:32 UTC (permalink / raw)
  To: Nuno Sá; +Cc: vkoul, Frank.Li, dmaengine

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] DMA buffer alignment calculation uses `round_down()` with non-power-of-2 alignments, causing broken truncation
--

--- Patch [6]: [PATCH v2 6/9] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors ---
commit 5f03b0a586d9a871f77efec877e70d9047e60575
Author: Nuno Sá <nuno.sa@analog.com>

iio: buffer-dmaengine: Use dma_slave_caps bus width accessors

This commit updates the IIO DMA buffer to use the new dma_slave_caps
bus width helpers instead of decoding raw legacy width masks. This ensures
compatibility with DMA controllers using the new bitmap representation.

> diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
> index 98acce9098547..855e3662cd3dc 100644
> --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
> +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
> @@ -229,14 +229,13 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct dma_chan *chan)
>  		return ERR_PTR(-ENOMEM);
>  
>  	/* Needs to be aligned to the maximum of the minimums */
> -	if (caps.src_addr_widths)
> -		src_width = __ffs(caps.src_addr_widths);
> -	else
> -		src_width = 1;
> -	if (caps.dst_addr_widths)
> -		dest_width = __ffs(caps.dst_addr_widths);
> -	else
> -		dest_width = 1;
> +	src_width = dma_slave_caps_get_src_width_min(&caps);
> +	if (src_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
> +		src_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +	dest_width = dma_slave_caps_get_dst_width_min(&caps);
> +	if (dest_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
> +		dest_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +
>  	width = max(src_width, dest_width);

[Severity: High]
This is a pre-existing issue, but does this alignment calculation
cause broken truncation when used with 3-byte bus widths?

If a DMA controller advertises a 3-byte minimum bus width
(e.g., using 24-bit transfers), width and subsequently
dmaengine_buffer->align will be set to 3.

In iio_dmaengine_buffer_submit_block(), this alignment is used:

    max_size = round_down(max_size, dmaengine_buffer->align);

The round_down(x, y) macro requires y to be a power of 2 because it
evaluates to (x & ~(y - 1)). When align is 3, round_down(max_size, 3) 
yields (max_size & ~2) instead of properly rounding to a multiple of 3.

For example, round_down(30, 3) evaluates to 28 instead of 27. 

This incorrectly aligned length is then assigned to block->bytes_used 
and passed to the DMA controller, which could result in unaligned 
transfer configurations and DMA controller faults.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260810-dmaengine-support-wider-dma-masks-v2-0-1f7b798d035f@analog.com?part=6

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

* Re: [PATCH v2 9/9] dmaengine: Drop legacy bus width fields from dma_slave_caps
  2026-08-10 15:06 ` [PATCH v2 9/9] dmaengine: Drop legacy bus width fields from dma_slave_caps Nuno Sá
@ 2026-08-10 16:56   ` Frank Li
  0 siblings, 0 replies; 17+ messages in thread
From: Frank Li @ 2026-08-10 16:56 UTC (permalink / raw)
  To: Nuno Sá
  Cc: dmaengine, linux-iio, Vinod Koul, Frank Li, Lars-Peter Clausen,
	Jonathan Cameron, David Lechner, Andy Shevchenko

On Mon, Aug 10, 2026 at 04:06:50PM +0100, Nuno Sá wrote:
> All users of dma_get_slave_caps() that inspect bus width capabilities now
> use the bitmap helpers.
>
> Hence, remove the legacy u32 src_addr_widths and dst_addr_widths fields
> from struct dma_slave_caps and stop copying the dma_device masks into
> them.
>
> Note the legacy u32 src_addr_widths and dst_addr_widths fields in struct
> dma_device are kept for now as every DMA controller driver setting them
> still has to be converted to the new helpers. dma_get_slave_caps() keeps
> folding those masks into the bitmaps it returns so unconverted producers
> continue to work during the transition.
>
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/dma/dmaengine.c   |  2 --
>  include/linux/dmaengine.h | 16 ++--------------
>  2 files changed, 2 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> index a80a84cf87eb..36e9b6ddd88d 100644
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -592,7 +592,6 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
>  	if (!device->directions)
>  		return -ENXIO;
>
> -	caps->src_addr_widths = device->src_addr_widths;
>  	if (bitmap_empty(device->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
>  		bitmap_zero(caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
>  		bitmap_from_arr32(caps->src_bus_widths,
> @@ -602,7 +601,6 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
>  			    DMA_SLAVE_BUSWIDTH_MAX);
>  	}
>
> -	caps->dst_addr_widths = device->dst_addr_widths;
>  	if (bitmap_empty(device->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX)) {
>  		bitmap_zero(caps->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
>  		bitmap_from_arr32(caps->dst_bus_widths,
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 8697583e2ed3..4efaa27e9f7e 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -503,9 +503,7 @@ enum dma_residue_granularity {
>   * @src_bus_widths: bitmap of source bus widths the channel supports.
>   *	Width is specified in bytes, e.g. for a channel supporting
>   *	a width of 4 the bitmap should have bit 4 set.
> - * @src_addr_widths: legacy bit mask of source bus widths the channel supports.
>   * @dst_bus_widths: bitmap of destination bus widths the channel supports.
> - * @dst_addr_widths: legacy bit mask of destination bus widths the channel supports.
>   * @directions: bit mask of slave directions the channel supports.
>   *	Since the enum dma_transfer_direction is not defined as bit flag for
>   *	each type, the dma controller should set BIT(<TYPE>) and same
> @@ -524,14 +522,8 @@ enum dma_residue_granularity {
>   * resubmitted multiple times
>   */
>  struct dma_slave_caps {
> -	struct {
> -		DECLARE_DMA_BUS_WIDTHS(src_bus_widths);
> -		u32 src_addr_widths;
> -	};
> -	struct {
> -		DECLARE_DMA_BUS_WIDTHS(dst_bus_widths);
> -		u32 dst_addr_widths;
> -	};
> +	DECLARE_DMA_BUS_WIDTHS(src_bus_widths);
> +	DECLARE_DMA_BUS_WIDTHS(dst_bus_widths);
>  	u32 directions;
>  	u32 min_burst;
>  	u32 max_burst;
> @@ -1922,8 +1914,6 @@ dma_slave_caps_clear_src_width(struct dma_slave_caps *caps,
>  			       enum dma_slave_buswidth width)
>  {
>  	__clear_bit(width, caps->src_bus_widths);
> -	if (width < DMA_SLAVE_BUSWIDTH_32_BYTES)
> -		caps->src_addr_widths &= ~BIT(width);
>  }
>
>  /**
> @@ -1936,8 +1926,6 @@ dma_slave_caps_clear_dst_width(struct dma_slave_caps *caps,
>  			       enum dma_slave_buswidth width)
>  {
>  	__clear_bit(width, caps->dst_bus_widths);
> -	if (width < DMA_SLAVE_BUSWIDTH_32_BYTES)
> -		caps->dst_addr_widths &= ~BIT(width);
>  }
>
>  static inline int __dma_set_bus_widths(unsigned long *bus_widths,
>
> --
> 2.55.0
>

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

* Re: [PATCH v2 1/9] dmaengine: Support bus widths of 32 bytes and above
  2026-08-10 15:06 ` [PATCH v2 1/9] " Nuno Sá
  2026-08-10 15:17   ` sashiko-bot
@ 2026-08-10 17:15   ` Andy Shevchenko
  1 sibling, 0 replies; 17+ messages in thread
From: Andy Shevchenko @ 2026-08-10 17:15 UTC (permalink / raw)
  To: Nuno Sá
  Cc: dmaengine, linux-iio, Vinod Koul, Frank Li, Lars-Peter Clausen,
	Jonathan Cameron, David Lechner, Andy Shevchenko, Frank Li

On Mon, Aug 10, 2026 at 04:06:42PM +0100, Nuno Sá wrote:
> The src_addr_widths and dst_addr_widths capability masks encode each
> supported width as a bit whose position equals the corresponding
> enum dma_slave_buswidth value (e.g. DMA_SLAVE_BUSWIDTH_4_BYTES sets bit
> 4). As these masks are plain u32, widths of 32 bytes and above
> (DMA_SLAVE_BUSWIDTH_32/64/128_BYTES map to bits 32, 64 and 128) cannot
> be represented at all.
> 
> Introduce bitmap-based bus width capabilities that span the full enum
> range. To allow DMA controller producers to be converted incrementally,
> keep the legacy dma_device u32 fields alongside the new bitmaps:
> producers using the new helpers populate the bitmap and mirror the low
> 32 bits back into the legacy field, while dma_get_slave_caps() folds a
> legacy-only producer's u32 into the returned bitmap.
> 
> Add helpers for producers and consumers so users do not need to depend
> on the bitmap layout directly. Once the remaining producers are
> converted, the legacy dma_device u32 fields can be dropped.

...

> +++ b/include/linux/dmaengine.h

>  #ifndef LINUX_DMAENGINE_H
>  #define LINUX_DMAENGINE_H
>  
> +#include <linux/bitops.h>

Ah, this is unfortunate, this is a wrong header, the correct one is bitmap.h
and I think we may not include it here (see below on why).

>  #include <linux/device.h>
>  #include <linux/err.h>
>  #include <linux/uio.h>

...

> +static inline enum dma_slave_buswidth
> +__dma_slave_caps_get_width_min(const unsigned long *bus_widths)
> +{
> +	enum dma_slave_buswidth width = find_first_bit(bus_widths,
> +						       DMA_SLAVE_BUSWIDTH_MAX);

This is from find.h which is internals of bitmap.h.

> +	if (width == DMA_SLAVE_BUSWIDTH_MAX)
> +		return DMA_SLAVE_BUSWIDTH_UNDEFINED;
> +
> +	return width;
> +}

The (big) problem is quite a header dependencies hell we have. All my cleanup
work of kernel.h I started on the simplest thing I wanted, id est to make
bitmap_zalloc() and similar to be static inlines. But it's impossible to achieve
(and I think that no one, except may be Ingo, see his 2000+ patch series a few
 years back, is capable of fix that at once). That's why having bitmap.h in the
kernel wide public _header_ is bad, bad idea (at least at the current state of
affairs). So, make it exported function instead and keep bitmap.h in dmaengine.c.

...

> +/**
> + * dma_slave_caps_copy_src_widths - copy source bus width capabilities
> + * @caps: DMA slave capabilities
> + * @bus_widths: destination bitmap declared with DECLARE_DMA_BUS_WIDTHS()
> + */
> +static inline void
> +dma_slave_caps_copy_src_widths(const struct dma_slave_caps *caps,
> +			       unsigned long *bus_widths)
> +{
> +	bitmap_copy(bus_widths, caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
> +}

> +/**
> + * dma_slave_caps_copy_dst_widths - copy destination bus width capabilities
> + * @caps: DMA slave capabilities
> + * @bus_widths: destination bitmap declared with DECLARE_DMA_BUS_WIDTHS()
> + */
> +static inline void
> +dma_slave_caps_copy_dst_widths(const struct dma_slave_caps *caps,
> +			       unsigned long *bus_widths)
> +{
> +	bitmap_copy(bus_widths, caps->dst_bus_widths, DMA_SLAVE_BUSWIDTH_MAX);
> +}

As per above.

...

Another (compromise approach) is to split the header that includes bitmap.h to
something like dmaengine-width.h, but I don't know how spread this use is. Do
we have all the users of the current dmaengine.h to use these APIs? If not,
split, if yes, then comment on this in the cover letter and perhaps that will
justify including bitmap.h in the dmaengine.h (but personally I am fully
against that).

-- 
With Best Regards,
Andy Shevchenko



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

end of thread, other threads:[~2026-08-10 17:15 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10 15:06 [PATCH v2 0/9] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
2026-08-10 15:06 ` [PATCH v2 1/9] " Nuno Sá
2026-08-10 15:17   ` sashiko-bot
2026-08-10 17:15   ` Andy Shevchenko
2026-08-10 15:06 ` [PATCH v2 2/9] dmaengine: dma-axi-dmac: Use bus width capability helpers Nuno Sá
2026-08-10 15:06 ` [PATCH v2 3/9] dmaengine: dw-axi-dmac: " Nuno Sá
2026-08-10 15:18   ` sashiko-bot
2026-08-10 15:06 ` [PATCH v2 4/9] dmaengine: qcom: gpi: " Nuno Sá
2026-08-10 15:15   ` sashiko-bot
2026-08-10 15:06 ` [PATCH v2 5/9] dmaengine: stm32-dma3: " Nuno Sá
2026-08-10 15:06 ` [PATCH v2 6/9] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors Nuno Sá
2026-08-10 15:32   ` sashiko-bot
2026-08-10 15:06 ` [PATCH v2 7/9] ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers Nuno Sá
2026-08-10 15:06 ` [PATCH v2 8/9] spi: dw: " Nuno Sá
2026-08-10 15:28   ` sashiko-bot
2026-08-10 15:06 ` [PATCH v2 9/9] dmaengine: Drop legacy bus width fields from dma_slave_caps Nuno Sá
2026-08-10 16: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