* [PATCH v4 01/10] dmaengine: Move enum dma_slave_buswidth to a new header
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-12 7:57 ` Andy Shevchenko
2026-09-11 17:25 ` [PATCH v4 02/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (8 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Andy Shevchenko
In preparation for the bitmap based bus width capabilities, move
enum dma_slave_buswidth out of linux/dmaengine.h into a new
include/linux/dma/engine/types.h.
linux/dmaengine.h is included nearly everywhere, so growing it with the
new interface would make every one of its users pay for it. Keeping the
basic types in a separate header lets the new interface live next to it
without that cost. linux/dmaengine.h includes the new header, so its
users are unaffected.
While at it, add the missing kernel-doc for the enum members. The block
already opened with /**, so kernel-doc expected every member to be
described and warned about each one of them. Describe the UNDEFINED case
in particular, as its meaning depends on where the value is used.
No functional change intended.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
include/linux/dma/engine/types.h | 41 ++++++++++++++++++++++++++++++++++++++++
include/linux/dmaengine.h | 20 +++-----------------
2 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/include/linux/dma/engine/types.h b/include/linux/dma/engine/types.h
new file mode 100644
index 000000000000..2e8a266e42ef
--- /dev/null
+++ b/include/linux/dma/engine/types.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Basic types shared by the DMA engine interfaces.
+ */
+#ifndef LINUX_DMA_ENGINE_TYPES_H
+#define LINUX_DMA_ENGINE_TYPES_H
+
+#include <linux/types.h>
+
+/**
+ * enum dma_slave_buswidth - defines bus width of the DMA slave
+ * device, source or target buses
+ * @DMA_SLAVE_BUSWIDTH_UNDEFINED: no bus width specified. In a
+ * &struct dma_slave_config it lets the controller pick a width, typically
+ * derived from the transfer itself. In a bus width mask it is a width a
+ * controller genuinely accepts, meaning it imposes no constraint of its
+ * own.
+ * @DMA_SLAVE_BUSWIDTH_1_BYTE: 1 byte wide bus
+ * @DMA_SLAVE_BUSWIDTH_2_BYTES: 2 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_3_BYTES: 3 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_4_BYTES: 4 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_8_BYTES: 8 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_16_BYTES: 16 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_32_BYTES: 32 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_64_BYTES: 64 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_128_BYTES: 128 bytes wide bus
+ */
+enum dma_slave_buswidth {
+ DMA_SLAVE_BUSWIDTH_UNDEFINED = 0,
+ DMA_SLAVE_BUSWIDTH_1_BYTE = 1,
+ DMA_SLAVE_BUSWIDTH_2_BYTES = 2,
+ DMA_SLAVE_BUSWIDTH_3_BYTES = 3,
+ DMA_SLAVE_BUSWIDTH_4_BYTES = 4,
+ DMA_SLAVE_BUSWIDTH_8_BYTES = 8,
+ DMA_SLAVE_BUSWIDTH_16_BYTES = 16,
+ DMA_SLAVE_BUSWIDTH_32_BYTES = 32,
+ DMA_SLAVE_BUSWIDTH_64_BYTES = 64,
+ DMA_SLAVE_BUSWIDTH_128_BYTES = 128,
+};
+
+#endif /* LINUX_DMA_ENGINE_TYPES_H */
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index fe33a20abc61..573e5ea34707 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -12,6 +12,9 @@
#include <linux/scatterlist.h>
#include <linux/bitmap.h>
#include <linux/types.h>
+
+#include <linux/dma/engine/types.h>
+
#include <asm/page.h>
/**
@@ -384,23 +387,6 @@ struct dma_chan_dev {
bool chan_dma_dev;
};
-/**
- * enum dma_slave_buswidth - defines bus width of the DMA slave
- * device, source or target buses
- */
-enum dma_slave_buswidth {
- DMA_SLAVE_BUSWIDTH_UNDEFINED = 0,
- DMA_SLAVE_BUSWIDTH_1_BYTE = 1,
- DMA_SLAVE_BUSWIDTH_2_BYTES = 2,
- DMA_SLAVE_BUSWIDTH_3_BYTES = 3,
- DMA_SLAVE_BUSWIDTH_4_BYTES = 4,
- DMA_SLAVE_BUSWIDTH_8_BYTES = 8,
- DMA_SLAVE_BUSWIDTH_16_BYTES = 16,
- DMA_SLAVE_BUSWIDTH_32_BYTES = 32,
- DMA_SLAVE_BUSWIDTH_64_BYTES = 64,
- DMA_SLAVE_BUSWIDTH_128_BYTES = 128,
-};
-
/**
* struct dma_slave_config - dma slave channel runtime config
* @direction: whether the data shall go in or out on this slave
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v4 01/10] dmaengine: Move enum dma_slave_buswidth to a new header
2026-09-11 17:25 ` [PATCH v4 01/10] dmaengine: Move enum dma_slave_buswidth to a new header Nuno Sá
@ 2026-09-12 7:57 ` Andy Shevchenko
0 siblings, 0 replies; 15+ messages in thread
From: Andy Shevchenko @ 2026-09-12 7:57 UTC (permalink / raw)
To: Nuno Sá
Cc: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi, Vinod Koul,
Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown
On Fri, Sep 11, 2026 at 06:25:36PM +0100, Nuno Sá wrote:
> In preparation for the bitmap based bus width capabilities, move
> enum dma_slave_buswidth out of linux/dmaengine.h into a new
> include/linux/dma/engine/types.h.
>
> linux/dmaengine.h is included nearly everywhere, so growing it with the
> new interface would make every one of its users pay for it. Keeping the
> basic types in a separate header lets the new interface live next to it
> without that cost. linux/dmaengine.h includes the new header, so its
> users are unaffected.
>
> While at it, add the missing kernel-doc for the enum members. The block
> already opened with /**, so kernel-doc expected every member to be
> described and warned about each one of them. Describe the UNDEFINED case
> in particular, as its meaning depends on where the value is used.
>
> No functional change intended.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 02/10] dmaengine: Support bus widths of 32 bytes and above
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
2026-09-11 17:25 ` [PATCH v4 01/10] dmaengine: Move enum dma_slave_buswidth to a new header Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:25 ` [PATCH v4 03/10] dmaengine: dma-axi-dmac: Use bus width capability helpers Nuno Sá
` (7 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown
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, through a new dma_buswidth_mask_t type modeled after
dma_cap_mask_t. To allow DMA controller drivers to be converted
incrementally, the legacy dma_device u32 fields are kept alongside the
new masks and the core folds a legacy-only driver's u32 into the mask
when the device is registered, so consumers only ever have to look at
the mask.
The accessors live in a new include/linux/dma/engine/widthmask.h instead
of in linux/dmaengine.h, so that only their users pay for the
linux/bitmap.h include. They all take a dma_buswidth_mask_t, which means
the interface will not change once the legacy fields are dropped.
The fold is bidirectional while both representations coexist. A driver
that only fills in the legacy u32 gets its mask derived from it, so the
consumers already converted see it. A driver that only fills in the mask
gets its legacy u32 derived from the mask, so the consumers not
converted yet, which read the legacy dma_slave_caps fields, keep working.
On top of that, dma_get_slave_caps() derives the legacy dma_slave_caps
masks from the new ones when a device_caps() callback adjusted them, so
that a converted controller narrowing its per-channel capabilities is
still seen by the consumers not converted yet, while a driver adjusting
the legacy masks directly keeps working.
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
drivers/dma/dmaengine.c | 52 ++++++++++-
include/linux/dma/engine/types.h | 14 +++
include/linux/dma/engine/widthmask.h | 166 +++++++++++++++++++++++++++++++++++
include/linux/dmaengine.h | 38 +++++---
4 files changed, 257 insertions(+), 13 deletions(-)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 6ffd8bd82154..8e68921cf01d 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -33,7 +33,9 @@
#include <linux/acpi.h>
#include <linux/acpi_dma.h>
+#include <linux/bitmap.h>
#include <linux/device.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/hardirq.h>
@@ -592,8 +594,11 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
if (!device->directions)
return -ENXIO;
+ dma_bus_width_copy(caps->src_bus_widths, device->src_bus_widths);
+ dma_bus_width_copy(caps->dst_bus_widths, device->dst_bus_widths);
caps->src_addr_widths = device->src_addr_widths;
caps->dst_addr_widths = device->dst_addr_widths;
+
caps->directions = device->directions;
caps->min_burst = device->min_burst;
caps->max_burst = device->max_burst;
@@ -611,9 +616,31 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
* callback to override the generic capabilities with
* channel-specific ones.
*/
- if (device->device_caps)
+ if (device->device_caps) {
device->device_caps(chan, caps);
+ /*
+ * A driver already converted to the bus width interface
+ * adjusts the masks, so derive the legacy capabilities from
+ * them for the consumers not converted yet. Drivers not
+ * converted adjust the legacy capabilities directly, in which
+ * case there is nothing to do.
+ *
+ * Goes away with the legacy dma_slave_caps fields.
+ */
+ if (!bitmap_equal(caps->src_bus_widths.bits,
+ device->src_bus_widths.bits,
+ DMA_SLAVE_BUSWIDTH_MAX))
+ caps->src_addr_widths = bitmap_read(caps->src_bus_widths.bits,
+ 0, 32);
+
+ if (!bitmap_equal(caps->dst_bus_widths.bits,
+ device->dst_bus_widths.bits,
+ DMA_SLAVE_BUSWIDTH_MAX))
+ caps->dst_addr_widths = bitmap_read(caps->dst_bus_widths.bits,
+ 0, 32);
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(dma_get_slave_caps);
@@ -1170,6 +1197,27 @@ void dma_async_device_channel_unregister(struct dma_device *device,
}
EXPORT_SYMBOL_GPL(dma_async_device_channel_unregister);
+/*
+ * DMA controller drivers not converted to the bus width helpers only fill in
+ * the legacy u32 masks, which cannot hold widths of 32 bytes and above. Fold
+ * them into the mask so that consumers only ever have to look at the mask.
+ *
+ * Goes away with the legacy dma_device fields.
+ */
+static void dma_device_fold_legacy_bus_widths(struct dma_device *device)
+{
+ if (bitmap_empty(device->src_bus_widths.bits, DMA_SLAVE_BUSWIDTH_MAX))
+ bitmap_from_arr32(device->src_bus_widths.bits, &device->src_addr_widths, 32);
+ /* consumers not converted yet still read the legacy caps */
+ else if (!device->src_addr_widths)
+ device->src_addr_widths = bitmap_read(device->src_bus_widths.bits, 0, 32);
+
+ if (bitmap_empty(device->dst_bus_widths.bits, DMA_SLAVE_BUSWIDTH_MAX))
+ bitmap_from_arr32(device->dst_bus_widths.bits, &device->dst_addr_widths, 32);
+ else if (!device->dst_addr_widths)
+ device->dst_addr_widths = bitmap_read(device->dst_bus_widths.bits, 0, 32);
+}
+
/**
* dma_async_device_register - registers DMA devices found
* @device: pointer to &struct dma_device
@@ -1231,6 +1279,8 @@ int dma_async_device_register(struct dma_device *device)
dev_dbg(device->dev,
"WARN: Device release is not defined so it is not safe to unbind this driver while in use\n");
+ dma_device_fold_legacy_bus_widths(device);
+
kref_init(&device->ref);
/* note: this only matters in the
diff --git a/include/linux/dma/engine/types.h b/include/linux/dma/engine/types.h
index 2e8a266e42ef..41c8771f9c0d 100644
--- a/include/linux/dma/engine/types.h
+++ b/include/linux/dma/engine/types.h
@@ -24,6 +24,7 @@
* @DMA_SLAVE_BUSWIDTH_32_BYTES: 32 bytes wide bus
* @DMA_SLAVE_BUSWIDTH_64_BYTES: 64 bytes wide bus
* @DMA_SLAVE_BUSWIDTH_128_BYTES: 128 bytes wide bus
+ * @DMA_SLAVE_BUSWIDTH_MAX: number of bus widths, not a valid width
*/
enum dma_slave_buswidth {
DMA_SLAVE_BUSWIDTH_UNDEFINED = 0,
@@ -36,6 +37,19 @@ 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
};
+/**
+ * typedef dma_buswidth_mask_t - bus width capabilities bitmap modeled after
+ * dma_cap_mask_t.
+ *
+ * Each supported bus width is represented by the bit whose position equals the
+ * corresponding enum dma_slave_buswidth value, e.g. a device supporting a bus
+ * width of 4 bytes has bit 4 set.
+ */
+typedef struct {
+ DECLARE_BITMAP(bits, DMA_SLAVE_BUSWIDTH_MAX);
+} dma_buswidth_mask_t;
+
#endif /* LINUX_DMA_ENGINE_TYPES_H */
diff --git a/include/linux/dma/engine/widthmask.h b/include/linux/dma/engine/widthmask.h
new file mode 100644
index 000000000000..eb50fc2f81cc
--- /dev/null
+++ b/include/linux/dma/engine/widthmask.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Bus width capabilities of DMA engine devices and channels.
+ */
+#ifndef LINUX_DMA_ENGINE_WIDTHMASK_H
+#define LINUX_DMA_ENGINE_WIDTHMASK_H
+
+#include <linux/bitmap.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include <linux/dma/engine/types.h>
+
+/**
+ * dma_bus_width_valid - test if a bus width is a valid one
+ * @width: bus width to validate
+ *
+ * Return: true if @width is a valid &enum dma_slave_buswidth, false otherwise.
+ */
+static inline bool dma_bus_width_valid(enum dma_slave_buswidth width)
+{
+ switch (width) {
+ 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:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline int __dma_bus_width_set_many(dma_buswidth_mask_t *mask,
+ const enum dma_slave_buswidth *widths,
+ unsigned int n_widths)
+{
+ for (unsigned int i = 0; i < n_widths; i++) {
+ if (!dma_bus_width_valid(widths[i]))
+ return -EINVAL;
+
+ __set_bit(widths[i], mask->bits);
+ }
+
+ return 0;
+}
+
+/**
+ * dma_bus_width_set_many - set the supported bus widths
+ * @mask: bus width mask
+ * @widths: array of supported bus widths
+ * @n_widths: number of entries in @widths
+ *
+ * Return: 0 on success, -EINVAL if @widths contains an invalid bus width. Note
+ * that the bus widths validated before the failing one are still set.
+ */
+#define dma_bus_width_set_many(mask, widths, n_widths) \
+ __dma_bus_width_set_many(&(mask), (widths), (n_widths))
+
+/**
+ * dma_bus_width_set - set a single supported bus width
+ * @mask: bus width mask
+ * @width: supported bus width
+ *
+ * Return: 0 on success, -EINVAL if @width is invalid.
+ */
+#define dma_bus_width_set(mask, width) \
+ __dma_bus_width_set_many(&(mask), (const enum dma_slave_buswidth[]){ (width) }, 1)
+
+static inline int __dma_bus_width_clear(dma_buswidth_mask_t *mask,
+ enum dma_slave_buswidth width)
+{
+ if (!dma_bus_width_valid(width))
+ return -EINVAL;
+
+ __clear_bit(width, mask->bits);
+
+ return 0;
+}
+
+/**
+ * dma_bus_width_clear - remove a bus width from a bus width mask
+ * @mask: bus width mask
+ * @width: bus width to clear
+ *
+ * Return: 0 on success, -EINVAL if @width is invalid.
+ */
+#define dma_bus_width_clear(mask, width) __dma_bus_width_clear(&(mask), (width))
+
+static inline bool __dma_bus_width_test(const dma_buswidth_mask_t *mask,
+ enum dma_slave_buswidth width)
+{
+ if (!dma_bus_width_valid(width))
+ return false;
+
+ return test_bit(width, mask->bits);
+}
+
+/**
+ * dma_bus_width_test - test if a bus width is part of a bus width mask
+ * @mask: bus width mask
+ * @width: bus width to test
+ *
+ * Return: true if @width is set in @mask, false otherwise.
+ */
+#define dma_bus_width_test(mask, width) __dma_bus_width_test(&(mask), (width))
+
+static inline enum dma_slave_buswidth
+__dma_bus_width_min(const dma_buswidth_mask_t *mask)
+{
+ enum dma_slave_buswidth width;
+
+ width = find_first_bit(mask->bits, DMA_SLAVE_BUSWIDTH_MAX);
+ if (width == DMA_SLAVE_BUSWIDTH_MAX)
+ return DMA_SLAVE_BUSWIDTH_UNDEFINED;
+
+ return width;
+}
+
+/**
+ * dma_bus_width_min - get the smallest bus width of a bus width mask
+ * @mask: bus width mask
+ *
+ * Return: the smallest bus width set in @mask, or
+ * %DMA_SLAVE_BUSWIDTH_UNDEFINED if @mask is empty.
+ */
+#define dma_bus_width_min(mask) __dma_bus_width_min(&(mask))
+
+static inline void __dma_bus_width_copy(dma_buswidth_mask_t *dst,
+ const dma_buswidth_mask_t *src)
+{
+ bitmap_copy(dst->bits, src->bits, DMA_SLAVE_BUSWIDTH_MAX);
+}
+
+/**
+ * dma_bus_width_copy - copy a bus width mask
+ * @dst: bus width mask to copy to
+ * @src: bus width mask to copy from
+ */
+#define dma_bus_width_copy(dst, src) __dma_bus_width_copy(&(dst), &(src))
+
+static inline bool __dma_bus_width_and(dma_buswidth_mask_t *dst,
+ const dma_buswidth_mask_t *src1,
+ const dma_buswidth_mask_t *src2)
+{
+ return bitmap_and(dst->bits, src1->bits, src2->bits,
+ DMA_SLAVE_BUSWIDTH_MAX);
+}
+
+/**
+ * dma_bus_width_and - intersect two bus width masks
+ * @dst: bus width mask to store the result in
+ * @src1: first bus width mask
+ * @src2: second bus width mask
+ *
+ * Return: true if @dst has at least one bus width set, false otherwise.
+ */
+#define dma_bus_width_and(dst, src1, src2) \
+ __dma_bus_width_and(&(dst), &(src1), &(src2))
+
+#endif /* LINUX_DMA_ENGINE_WIDTHMASK_H */
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 573e5ea34707..8236a1b274fb 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>
@@ -481,10 +482,11 @@ 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.
- * 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
+ * @src_bus_widths: mask of source bus widths the channel supports.
+ * @src_addr_widths: legacy bit mask of source bus widths the channel supports.
+ * @dst_bus_widths: mask 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
@@ -503,8 +505,14 @@ enum dma_residue_granularity {
* resubmitted multiple times
*/
struct dma_slave_caps {
- u32 src_addr_widths;
- u32 dst_addr_widths;
+ struct {
+ dma_buswidth_mask_t src_bus_widths;
+ u32 src_addr_widths;
+ };
+ struct {
+ dma_buswidth_mask_t dst_bus_widths;
+ u32 dst_addr_widths;
+ };
u32 directions;
u32 min_burst;
u32 max_burst;
@@ -797,10 +805,10 @@ 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
- * 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
+ * @src_bus_widths: mask of source bus widths the device supports.
+ * @src_addr_widths: legacy bit mask of source bus widths the device supports.
+ * @dst_bus_widths: mask 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
@@ -882,8 +890,14 @@ struct dma_device {
struct module *owner;
struct ida chan_ida;
- u32 src_addr_widths;
- u32 dst_addr_widths;
+ struct {
+ dma_buswidth_mask_t src_bus_widths;
+ u32 src_addr_widths;
+ };
+ struct {
+ dma_buswidth_mask_t dst_bus_widths;
+ u32 dst_addr_widths;
+ };
u32 directions;
u32 min_burst;
u32 max_burst;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 03/10] dmaengine: dma-axi-dmac: Use bus width capability helpers
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
2026-09-11 17:25 ` [PATCH v4 01/10] dmaengine: Move enum dma_slave_buswidth to a new header Nuno Sá
2026-09-11 17:25 ` [PATCH v4 02/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:39 ` sashiko-bot
2026-09-11 17:25 ` [PATCH v4 04/10] dmaengine: dw-axi-dmac: " Nuno Sá
` (6 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Frank Li
Advertise the source and destination bus widths through the new
dma_bus_width_set() helper 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 | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index d47ff27e1408..dc56178cafe0 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/err.h>
@@ -152,8 +153,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 +1263,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_bus_width_set(dma_dev->src_bus_widths, dmac->chan.src_width);
+ if (ret)
+ return ret;
+
+ ret = dma_bus_width_set(dma_dev->dst_bus_widths, 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] 15+ messages in thread* Re: [PATCH v4 03/10] dmaengine: dma-axi-dmac: Use bus width capability helpers
2026-09-11 17:25 ` [PATCH v4 03/10] dmaengine: dma-axi-dmac: Use bus width capability helpers Nuno Sá
@ 2026-09-11 17:39 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-09-11 17:39 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] Incorrect assignment of byte alignment to log2 alignment shift field (copy_align)
--
commit 0bfee90ef28dc903c00f72e9bd5881ba53dcd68f
Author: Nuno Sá <nuno.sa@analog.com>
dmaengine: dma-axi-dmac: Use bus width capability helpers
This commit updates the dma-axi-dmac driver to use the new
dma_bus_width_set() helper instead of open-coding the legacy BIT() mask for
source and destination bus widths. It also updates the channel width members
to use the proper enum dma_slave_buswidth type, allowing the driver to
express widths of 32 bytes and above.
> diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
> --- a/drivers/dma/dma-axi-dmac.c
> +++ b/drivers/dma/dma-axi-dmac.c
[ ... ]
> @@ -1262,8 +1263,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_bus_width_set(dma_dev->src_bus_widths, dmac->chan.src_width);
> + if (ret)
> + return ret;
> +
> + ret = dma_bus_width_set(dma_dev->dst_bus_widths, 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 */
[Severity: High]
This isn't a bug introduced by this patch, but while evaluating bus width
capabilities in axi_dmac_probe(), is there an existing issue with how
copy_align is assigned further down in the function?
Looking at axi_dmac_probe(), we have this assignment:
dma_dev->copy_align = (dmac->chan.address_align_mask + 1);
The copy_align field requires an enum dmaengine_alignment, which represents
the base-2 logarithm of the byte alignment (e.g. DMAENGINE_ALIGN_8_BYTES = 3).
By assigning it the exact byte count instead of the log2 shift, any
subsystem evaluating 1 << copy_align will compute excessively large
alignment constraints (for example, 1 << 8 = 256 bytes instead of 8).
For a 32-byte bus width, could this lead to undefined behavior in C since
the shift count equals or exceeds the width of the default integer type?
This might cause zero alignment enforcement and subsequent hardware exceptions
when unaligned buffers are passed to the DMA controller.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260911-dmaengine-support-wider-dma-masks-v4-0-72b8fd4cc78e@analog.com?part=3
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 04/10] dmaengine: dw-axi-dmac: Use bus width capability helpers
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (2 preceding siblings ...)
2026-09-11 17:25 ` [PATCH v4 03/10] dmaengine: dma-axi-dmac: Use bus width capability helpers Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:40 ` sashiko-bot
2026-09-11 17:25 ` [PATCH v4 05/10] dmaengine: qcom: gpi: " Nuno Sá
` (5 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Frank Li
Advertise the supported bus widths through dma_bus_width_set_many()
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 | 38 +++++++++++++++-----------
1 file changed, 22 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..ca0ab8dc5f59 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -10,6 +10,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
@@ -33,20 +34,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 +1469,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 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 +1566,13 @@ 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_bus_width_set_many(dw->dma.src_bus_widths, buswidths, ARRAY_SIZE(buswidths));
+ if (ret)
+ return ret;
+
+ ret = dma_bus_width_set_many(dw->dma.dst_bus_widths, buswidths, ARRAY_SIZE(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] 15+ messages in thread* Re: [PATCH v4 04/10] dmaengine: dw-axi-dmac: Use bus width capability helpers
2026-09-11 17:25 ` [PATCH v4 04/10] dmaengine: dw-axi-dmac: " Nuno Sá
@ 2026-09-11 17:40 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-09-11 17:40 UTC (permalink / raw)
To: Nuno Sá; +Cc: vkoul, dmaengine, Frank.Li
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] The interrupt handler is registered with IRQF_SHARED before channel registers are initialized, risking a fatal NULL pointer dereference.
- [High] Out-of-bounds write in axi_req_irqs due to unbounded irq_count from platform metadata.
- [High] Missing check for negative error code from platform_irq_count silently aborts IRQ registration but falsely returns success.
--
commit 547df6badf50a7c40c7c108bf82e51bb78feaed7
Author: Nuno Sá <nuno.sa@analog.com>
dmaengine: dw-axi-dmac: Use bus width capability helpers
Advertise the supported bus widths through dma_bus_width_set_many()
instead of assigning the legacy u32 masks directly. This keeps the
driver using the new bitmap representation while preserving legacy
fields during the transition.
> 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..ca0ab8dc5f596 100644
> --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
[ ... ]
> @@ -1482,6 +1469,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 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)
[Severity: High]
This is a pre-existing issue, but does axi_req_irqs() properly handle a
negative error code from platform_irq_count()?
If platform_irq_count() returns a negative error (like -EPROBE_DEFER):
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:axi_req_irqs() {
...
int irq_count = platform_irq_count(pdev);
for (i = 0; i < irq_count; i++) {
...
}
return 0;
}
The loop will evaluate to false immediately, and the function falsely
returns 0. This silently aborts IRQ registration and causes dw_probe() to
continue without deferring probe or registering interrupts.
[Severity: High]
This is a pre-existing issue, but can the loop in axi_req_irqs() cause an
out-of-bounds write?
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:axi_req_irqs() {
...
int irq_count = platform_irq_count(pdev);
for (i = 0; i < irq_count; i++) {
chip->irq[i] = platform_get_irq(pdev, i);
...
}
}
The chip->irq array has a fixed size of DMAC_MAX_CHANNELS (32). If
platform_irq_count() returns an unbounded value greater than 32 from the
platform metadata, this will write past the end of the array and corrupt
adjacent memory.
[Severity: High]
This is a pre-existing issue, but could there be a NULL pointer dereference
if a shared interrupt fires early during dw_probe()?
In axi_req_irqs(), the interrupt is registered with IRQF_SHARED:
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:axi_req_irqs() {
...
ret = devm_request_irq(chip->dev, chip->irq[i], dw_axi_dma_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip);
...
}
However, the channel registers are initialized after this call returns,
in dw_probe():
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:dw_probe() {
...
ret = axi_req_irqs(pdev, chip);
if (ret)
return ret;
INIT_LIST_HEAD(&dw->dma.channels);
for (i = 0; i < hdata->nr_channels; i++) {
struct axi_dma_chan *chan = &dw->chan[i];
...
chan->chan_regs = chip->regs + COMMON_REG_LEN + i * CHAN_REG_LEN;
...
}
If another device sharing the same IRQ line triggers an interrupt before
the channel registers are initialized, dw_axi_dma_interrupt() will read
from the uninitialized (NULL) chan->chan_regs:
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:dw_axi_dma_interrupt() {
...
for (i = 0; i < dw->hdata->nr_channels; i++) {
chan = &dw->chan[i];
status = axi_chan_irq_read(chan);
...
}
}
Will this cause a panic if the handler tries to access chan->chan_regs?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260911-dmaengine-support-wider-dma-masks-v4-0-72b8fd4cc78e@analog.com?part=4
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 05/10] dmaengine: qcom: gpi: Use bus width capability helpers
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (3 preceding siblings ...)
2026-09-11 17:25 ` [PATCH v4 04/10] dmaengine: dw-axi-dmac: " Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:40 ` sashiko-bot
2026-09-11 17:25 ` [PATCH v4 06/10] dmaengine: stm32-dma3: " Nuno Sá
` (4 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Frank Li
Advertise the single supported source and destination bus width through
the new dma_bus_width_set() helper
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 | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index a5055a6273af..3a35bf4c3397 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -7,6 +7,7 @@
#include <dt-bindings/dma/qcom-gpi.h>
#include <linux/bitfield.h>
#include <linux/dma-mapping.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of_dma.h>
@@ -2265,8 +2266,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_bus_width_set(gpi_dev->dma_device.src_bus_widths,
+ DMA_SLAVE_BUSWIDTH_8_BYTES);
+ if (ret)
+ return ret;
+
+ ret = dma_bus_width_set(gpi_dev->dma_device.dst_bus_widths,
+ 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] 15+ messages in thread* Re: [PATCH v4 05/10] dmaengine: qcom: gpi: Use bus width capability helpers
2026-09-11 17:25 ` [PATCH v4 05/10] dmaengine: qcom: gpi: " Nuno Sá
@ 2026-09-11 17:40 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-09-11 17:40 UTC (permalink / raw)
To: Nuno Sá; +Cc: vkoul, dmaengine, Frank.Li
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing cleanup for DMA controller and async device registration in error paths and missing .remove method lead to UAF.
--
commit bbcb7726e80023f035efafba93cea9b1b9a4a1c3
Author: Nuno Sá <nuno.sa@analog.com>
dmaengine: qcom: gpi: Use bus width capability helpers
This commit uses the new dma_bus_width_set helper to advertise supported
bus widths, replacing legacy assignments.
> diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
> index a5055a6273af6..3a35bf4c33978 100644
> --- a/drivers/dma/qcom/gpi.c
> +++ b/drivers/dma/qcom/gpi.c
[ ... ]
> @@ -2265,8 +2266,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_bus_width_set(gpi_dev->dma_device.src_bus_widths,
> + DMA_SLAVE_BUSWIDTH_8_BYTES);
> + if (ret)
> + return ret;
> +
> + ret = dma_bus_width_set(gpi_dev->dma_device.dst_bus_widths,
> + DMA_SLAVE_BUSWIDTH_8_BYTES);
> + if (ret)
> + return ret;
[Severity: High]
This is a pre-existing issue, but while looking at the changes in
gpi_probe, I noticed a potential memory corruption issue on the error
path and during driver unbind.
If of_dma_controller_register fails later in gpi_probe, it returns an
error without unregistering the previously registered async DMA device:
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;
}
...
}
Additionally, the platform driver gpi_driver completely lacks a remove
callback. If the driver is manually unbound via sysfs, devres will free
the driver's memory while leaving the DMA device and OF controller globally
registered.
Could this lead to a use-after-free if the dangling dma_device pointer is
accessed by other subsystems? Should the error path and driver teardown
clean up these registrations?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260911-dmaengine-support-wider-dma-masks-v4-0-72b8fd4cc78e@analog.com?part=5
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 06/10] dmaengine: stm32-dma3: Use bus width capability helpers
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (4 preceding siblings ...)
2026-09-11 17:25 ` [PATCH v4 05/10] dmaengine: qcom: gpi: " Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:25 ` [PATCH v4 07/10] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors Nuno Sá
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Frank Li
Advertise the controller-wide bus width capabilities through the new
dma_bus_width_set_many() helper and clear the per-channel unsupported
widths through dma_bus_width_clear().
While at it, validate the requested transfer bus widths against the new
capability mask instead of the legacy u32 one, so the driver does not
depend on the legacy field anymore.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
drivers/dma/stm32/stm32-dma3.c | 34 +++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/drivers/dma/stm32/stm32-dma3.c b/drivers/dma/stm32/stm32-dma3.c
index 4724e7fa0008..0689aeb7cff5 100644
--- a/drivers/dma/stm32/stm32-dma3.c
+++ b/drivers/dma/stm32/stm32-dma3.c
@@ -9,6 +9,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/init.h>
@@ -588,7 +589,8 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
dbl_max = chan->dma_config.dst_maxburst ? : 1;
/* Following conditions would raise User Setting Error interrupt */
- if (!(dma_device.src_addr_widths & BIT(sdw)) || !(dma_device.dst_addr_widths & BIT(ddw))) {
+ if (!dma_bus_width_test(dma_device.src_bus_widths, sdw) ||
+ !dma_bus_width_test(dma_device.dst_bus_widths, ddw)) {
dev_err(chan2dev(chan), "Bus width (src=%u, dst=%u) not supported\n", sdw, ddw);
return -EINVAL;
}
@@ -1469,14 +1471,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_bus_width_clear(caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_8_BYTES);
+ dma_bus_width_clear(caps->dst_bus_widths, 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_bus_width_clear(caps->src_bus_widths, DMA_SLAVE_BUSWIDTH_8_BYTES);
+ dma_bus_width_clear(caps->dst_bus_widths, DMA_SLAVE_BUSWIDTH_8_BYTES);
}
}
}
@@ -1734,6 +1736,12 @@ static int stm32_dma3_probe(struct platform_device *pdev)
struct reset_control *reset;
struct stm32_dma3_chan *chan;
struct dma_device *dma_dev;
+ enum dma_slave_buswidth buswidths[] = {
+ DMA_SLAVE_BUSWIDTH_1_BYTE,
+ DMA_SLAVE_BUSWIDTH_2_BYTES,
+ DMA_SLAVE_BUSWIDTH_4_BYTES,
+ DMA_SLAVE_BUSWIDTH_8_BYTES,
+ };
u32 master_ports, chan_reserved, i, verr;
u64 hwcfgr;
int ret;
@@ -1775,14 +1783,14 @@ 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_bus_width_set_many(dma_dev->src_bus_widths, buswidths, ARRAY_SIZE(buswidths));
+ if (ret)
+ goto err_clk_disable;
+
+ ret = dma_bus_width_set_many(dma_dev->dst_bus_widths, buswidths, ARRAY_SIZE(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] 15+ messages in thread* [PATCH v4 07/10] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (5 preceding siblings ...)
2026-09-11 17:25 ` [PATCH v4 06/10] dmaengine: stm32-dma3: " Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:25 ` [PATCH v4 08/10] ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers Nuno Sá
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Frank Li, Jonathan Cameron
Query the minimum supported source and destination bus widths through
the new dma_bus_width_min() helper 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>
Acked-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
drivers/iio/buffer/industrialio-buffer-dmaengine.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index 98acce909854..e1aea691b732 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/cleanup.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
@@ -229,14 +230,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_bus_width_min(caps.src_bus_widths);
+ if (src_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+ src_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dest_width = dma_bus_width_min(caps.dst_bus_widths);
+ 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] 15+ messages in thread* [PATCH v4 08/10] ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (6 preceding siblings ...)
2026-09-11 17:25 ` [PATCH v4 07/10] iio: buffer-dmaengine: Use dma_slave_caps bus width accessors Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:25 ` [PATCH v4 09/10] spi: dw: " Nuno Sá
2026-09-11 17:25 ` [PATCH v4 10/10] dmaengine: Drop legacy bus width fields from dma_slave_caps Nuno Sá
9 siblings, 0 replies; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, 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 | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index 1306b04be171..2dbbdeae6c4c 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dmaengine.h>
#include <linux/slab.h>
#include <sound/pcm.h>
@@ -408,16 +409,24 @@ int snd_dmaengine_pcm_refine_runtime_hwparams(
struct snd_pcm_hardware *hw,
struct dma_chan *chan)
{
+ enum dma_slave_buswidth default_widths[] = {
+ DMA_SLAVE_BUSWIDTH_1_BYTE,
+ DMA_SLAVE_BUSWIDTH_2_BYTES,
+ DMA_SLAVE_BUSWIDTH_4_BYTES,
+ };
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);
+ dma_buswidth_mask_t bus_widths = {};
snd_pcm_format_t i;
int ret = 0;
if (!hw || !chan || !dma_data)
return -EINVAL;
+ ret = dma_bus_width_set_many(bus_widths, default_widths,
+ ARRAY_SIZE(default_widths));
+ if (ret)
+ return ret;
+
ret = dma_get_slave_caps(chan, &dma_caps);
if (ret == 0) {
if (dma_caps.cmd_pause && dma_caps.cmd_resume)
@@ -426,9 +435,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_bus_width_copy(bus_widths, dma_caps.dst_bus_widths);
else
- addr_widths = dma_caps.src_addr_widths;
+ dma_bus_width_copy(bus_widths, dma_caps.src_bus_widths);
}
/*
@@ -460,7 +469,7 @@ int snd_dmaengine_pcm_refine_runtime_hwparams(
case 24:
case 32:
case 64:
- if (addr_widths & (1 << (bits / 8)))
+ if (dma_bus_width_test(bus_widths, bits / 8))
hw->formats |= pcm_format_to_bits(i);
break;
default:
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 09/10] spi: dw: Use dma_slave_caps bus width helpers
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (7 preceding siblings ...)
2026-09-11 17:25 ` [PATCH v4 08/10] ALSA: pcm_dmaengine: Use dma_slave_caps bus width helpers Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
2026-09-11 17:25 ` [PATCH v4 10/10] dmaengine: Drop legacy bus width fields from dma_slave_caps Nuno Sá
9 siblings, 0 replies; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Frank Li, Andy Shevchenko
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>
Acked-by: Mark Brown <broonie@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
drivers/spi/spi-dw-dma.c | 8 +++++---
drivers/spi/spi-dw.h | 3 ++-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index fe726b9b1780..bbd7ee884d0e 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -7,6 +7,7 @@
#include <linux/completion.h>
#include <linux/dma-mapping.h>
+#include <linux/dma/engine/widthmask.h>
#include <linux/dmaengine.h>
#include <linux/irqreturn.h>
#include <linux/jiffies.h>
@@ -100,10 +101,11 @@ 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_bus_width_and(dws->dma_bus_widths, tx.dst_bus_widths,
+ rx.src_bus_widths);
return 0;
}
@@ -253,7 +255,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 dma_bus_width_test(dws->dma_bus_widths, dma_bus_width);
}
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..c27533ecbde9 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -5,6 +5,7 @@
#include <linux/bits.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
+#include <linux/dma/engine/types.h>
#include <linux/irqreturn.h>
#include <linux/io.h>
#include <linux/scatterlist.h>
@@ -190,7 +191,7 @@ struct dw_spi {
struct dma_chan *rxchan;
u32 rxburst;
u32 dma_sg_burst;
- u32 dma_addr_widths;
+ dma_buswidth_mask_t 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] 15+ messages in thread* [PATCH v4 10/10] dmaengine: Drop legacy bus width fields from dma_slave_caps
2026-09-11 17:25 [PATCH v4 00/10] dmaengine: Support bus widths of 32 bytes and above Nuno Sá
` (8 preceding siblings ...)
2026-09-11 17:25 ` [PATCH v4 09/10] spi: dw: " Nuno Sá
@ 2026-09-11 17:25 ` Nuno Sá
9 siblings, 0 replies; 15+ messages in thread
From: Nuno Sá @ 2026-09-11 17:25 UTC (permalink / raw)
To: linux-kernel, dmaengine, linux-arm-msm, linux-stm32,
linux-arm-kernel, linux-iio, linux-sound, linux-spi
Cc: Vinod Koul, Frank Li, Lars-Peter Clausen, Eugeniy Paltsev,
Amélie Delaunay, Maxime Coquelin, Alexandre Torgue,
Jonathan Cameron, David Lechner, Andy Shevchenko, Jaroslav Kysela,
Takashi Iwai, Mark Brown, Frank Li, 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.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
drivers/dma/dmaengine.c | 31 +------------------------------
include/linux/dmaengine.h | 13 ++-----------
2 files changed, 3 insertions(+), 41 deletions(-)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 8e68921cf01d..945079c677b1 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -596,8 +596,6 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
dma_bus_width_copy(caps->src_bus_widths, device->src_bus_widths);
dma_bus_width_copy(caps->dst_bus_widths, device->dst_bus_widths);
- caps->src_addr_widths = device->src_addr_widths;
- caps->dst_addr_widths = device->dst_addr_widths;
caps->directions = device->directions;
caps->min_burst = device->min_burst;
@@ -616,31 +614,9 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
* callback to override the generic capabilities with
* channel-specific ones.
*/
- if (device->device_caps) {
+ if (device->device_caps)
device->device_caps(chan, caps);
- /*
- * A driver already converted to the bus width interface
- * adjusts the masks, so derive the legacy capabilities from
- * them for the consumers not converted yet. Drivers not
- * converted adjust the legacy capabilities directly, in which
- * case there is nothing to do.
- *
- * Goes away with the legacy dma_slave_caps fields.
- */
- if (!bitmap_equal(caps->src_bus_widths.bits,
- device->src_bus_widths.bits,
- DMA_SLAVE_BUSWIDTH_MAX))
- caps->src_addr_widths = bitmap_read(caps->src_bus_widths.bits,
- 0, 32);
-
- if (!bitmap_equal(caps->dst_bus_widths.bits,
- device->dst_bus_widths.bits,
- DMA_SLAVE_BUSWIDTH_MAX))
- caps->dst_addr_widths = bitmap_read(caps->dst_bus_widths.bits,
- 0, 32);
- }
-
return 0;
}
EXPORT_SYMBOL_GPL(dma_get_slave_caps);
@@ -1208,14 +1184,9 @@ static void dma_device_fold_legacy_bus_widths(struct dma_device *device)
{
if (bitmap_empty(device->src_bus_widths.bits, DMA_SLAVE_BUSWIDTH_MAX))
bitmap_from_arr32(device->src_bus_widths.bits, &device->src_addr_widths, 32);
- /* consumers not converted yet still read the legacy caps */
- else if (!device->src_addr_widths)
- device->src_addr_widths = bitmap_read(device->src_bus_widths.bits, 0, 32);
if (bitmap_empty(device->dst_bus_widths.bits, DMA_SLAVE_BUSWIDTH_MAX))
bitmap_from_arr32(device->dst_bus_widths.bits, &device->dst_addr_widths, 32);
- else if (!device->dst_addr_widths)
- device->dst_addr_widths = bitmap_read(device->dst_bus_widths.bits, 0, 32);
}
/**
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 8236a1b274fb..657d3a1ee976 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -483,10 +483,7 @@ enum dma_residue_granularity {
/**
* struct dma_slave_caps - expose capabilities of a slave channel only
* @src_bus_widths: mask of source bus widths the channel supports.
- * @src_addr_widths: legacy bit mask of source bus widths the channel supports.
* @dst_bus_widths: mask 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
@@ -505,14 +502,8 @@ enum dma_residue_granularity {
* resubmitted multiple times
*/
struct dma_slave_caps {
- struct {
- dma_buswidth_mask_t src_bus_widths;
- u32 src_addr_widths;
- };
- struct {
- dma_buswidth_mask_t dst_bus_widths;
- u32 dst_addr_widths;
- };
+ dma_buswidth_mask_t src_bus_widths;
+ dma_buswidth_mask_t dst_bus_widths;
u32 directions;
u32 min_burst;
u32 max_burst;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread