Linux IIO development
 help / color / mirror / Atom feed
* [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems
@ 2025-10-02 15:06 Nuno Sá via B4 Relay
  2025-10-02 15:06 ` [PATCH 1/3] iio: buffer: support getting dma channel from the buffer Nuno Sá via B4 Relay
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Nuno Sá via B4 Relay @ 2025-10-02 15:06 UTC (permalink / raw)
  To: linux-iio; +Cc: Jonathan Cameron, David Lechner, Andy Shevchenko

This series fixes an issue with DMABUF support in the IIO subsystem where
the wrong DMA device could be used for buffer mapping operations. This
becomes critical on systems like Xilinx/AMD ZynqMP Ultrascale where memory
can be mapped above the 32-bit address range.

Problem:
--------
The current IIO DMABUF implementation assumes it can use the parent device
of the IIO device for DMA operations. However, this device may not have
the appropriate DMA mask configuration for accessing high memory addresses.
On systems where memory is mapped above 32-bits, this leads to the use of
bounce buffers through swiotlb, significantly impacting performance.

Solution:
---------
This series introduces a new .get_dma_dev() callback in the buffer access
functions that allows buffer implementations to specify the correct DMA
device that should be used for DMABUF operations. The DMA buffer
infrastructure implements this callback to return the device that actually
owns the DMA channel, ensuring proper memory mapping without bounce buffers.

Changes:
--------
1. Add .get_dma_dev() callback to iio_buffer_access_funcs and update core
   DMABUF code to use it when available
2. Implement the callback in the DMA buffer infrastructure
3. Wire up the callback in the dmaengine buffer implementation

This ensures that DMABUF operations use the device with the correct DMA
configuration, eliminating unnecessary bounce buffer usage and improving
performance on high-memory systems.

(AI generated cover. I would not be this formal but I guess is not
that bad :))

---
Nuno Sá (3):
      iio: buffer: support getting dma channel from the buffer
      iio: buffer-dma: support getting the DMA channel
      iio: buffer-dmaengine: enable .get_dma_dev()

 drivers/iio/buffer/industrialio-buffer-dma.c       |  6 +++++
 drivers/iio/buffer/industrialio-buffer-dmaengine.c |  2 ++
 drivers/iio/industrialio-buffer.c                  | 28 +++++++++++++++++-----
 include/linux/iio/buffer-dma.h                     |  1 +
 include/linux/iio/buffer_impl.h                    |  2 ++
 5 files changed, 33 insertions(+), 6 deletions(-)
---
base-commit: b9700f87939f0f477e5c00db817f54ab8a97702b
change-id: 20250930-fix-iio-dmabuf-get-dma-device-339ac70543db
--

Thanks!
- Nuno Sá



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

* [PATCH 1/3] iio: buffer: support getting dma channel from the buffer
  2025-10-02 15:06 [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Nuno Sá via B4 Relay
@ 2025-10-02 15:06 ` Nuno Sá via B4 Relay
  2025-10-02 16:14   ` David Lechner
  2025-10-02 15:06 ` [PATCH 2/3] iio: buffer-dma: support getting the DMA channel Nuno Sá via B4 Relay
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Nuno Sá via B4 Relay @ 2025-10-02 15:06 UTC (permalink / raw)
  To: linux-iio; +Cc: Jonathan Cameron, David Lechner, Andy Shevchenko

From: Nuno Sá <nuno.sa@analog.com>

Add a new buffer accessor .get_dma_dev() in order to get the
struct device responsible for actually providing the dma channel. We
cannot assume that we can use the parent of the IIO device for mapping
the DMA buffer. This becomes important on systems (like the Xilinx/AMD
zynqMP Ultrascale) where memory (or part of it) is mapped above the
32 bit range. On such systems and given that a device by default has
a dma mask of 32 bits we would then need to rely on bounce buffers (to
swiotlb) for mapping memory above the dma mask limit.

Fixes: 3e26d9f08fbe ("iio: core: Add new DMABUF interface infrastructure")
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/industrialio-buffer.c | 28 ++++++++++++++++++++++------
 include/linux/iio/buffer_impl.h   |  2 ++
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index f1448ae1b843fc577599fc1b9cf6d859bba226f1..279c7d716bf5d467d40b5c290789fcbd1f949660 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -1627,15 +1627,20 @@ static struct dma_buf_attachment *
 iio_buffer_find_attachment(struct iio_dev_buffer_pair *ib,
 			   struct dma_buf *dmabuf, bool nonblock)
 {
-	struct device *dev = ib->indio_dev->dev.parent;
+	struct device *dma_dev;
 	struct iio_buffer *buffer = ib->buffer;
 	struct dma_buf_attachment *attach = NULL;
 	struct iio_dmabuf_priv *priv;
 
+	if (buffer->access->get_dma_dev)
+		dma_dev = buffer->access->get_dma_dev(buffer);
+	else
+		dma_dev = ib->indio_dev->dev.parent;
+
 	guard(mutex)(&buffer->dmabufs_mutex);
 
 	list_for_each_entry(priv, &buffer->dmabufs, entry) {
-		if (priv->attach->dev == dev
+		if (priv->attach->dev == dma_dev
 		    && priv->attach->dmabuf == dmabuf) {
 			attach = priv->attach;
 			break;
@@ -1655,6 +1660,7 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
 	struct iio_buffer *buffer = ib->buffer;
 	struct dma_buf_attachment *attach;
 	struct iio_dmabuf_priv *priv, *each;
+	struct device *dma_dev;
 	struct dma_buf *dmabuf;
 	int err, fd;
 
@@ -1679,7 +1685,12 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
 		goto err_free_priv;
 	}
 
-	attach = dma_buf_attach(dmabuf, indio_dev->dev.parent);
+	if (buffer->access->get_dma_dev)
+		dma_dev = buffer->access->get_dma_dev(buffer);
+	else
+		dma_dev = indio_dev->dev.parent;
+
+	attach = dma_buf_attach(dmabuf, dma_dev);
 	if (IS_ERR(attach)) {
 		err = PTR_ERR(attach);
 		goto err_dmabuf_put;
@@ -1719,7 +1730,7 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
 	 * combo. If we do, refuse to attach.
 	 */
 	list_for_each_entry(each, &buffer->dmabufs, entry) {
-		if (each->attach->dev == indio_dev->dev.parent
+		if (each->attach->dev == dma_dev
 		    && each->attach->dmabuf == dmabuf) {
 			/*
 			 * We unlocked the reservation object, so going through
@@ -1759,6 +1770,7 @@ static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib,
 	struct iio_buffer *buffer = ib->buffer;
 	struct iio_dev *indio_dev = ib->indio_dev;
 	struct iio_dmabuf_priv *priv;
+	struct device *dma_dev;
 	struct dma_buf *dmabuf;
 	int dmabuf_fd, ret = -EPERM;
 
@@ -1769,11 +1781,15 @@ static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib,
 	if (IS_ERR(dmabuf))
 		return PTR_ERR(dmabuf);
 
+	if (buffer->access->get_dma_dev)
+		dma_dev = buffer->access->get_dma_dev(buffer);
+	else
+		dma_dev = indio_dev->dev.parent;
+
 	guard(mutex)(&buffer->dmabufs_mutex);
 
 	list_for_each_entry(priv, &buffer->dmabufs, entry) {
-		if (priv->attach->dev == indio_dev->dev.parent
-		    && priv->attach->dmabuf == dmabuf) {
+		if (priv->attach->dev == dma_dev && priv->attach->dmabuf == dmabuf) {
 			list_del(&priv->entry);
 
 			/* Unref the reference from iio_buffer_attach_dmabuf() */
diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
index 0daff9ff20ce49de67fa0f2ac6191882de2f4a67..c0b0e0992a85b2813a126c1a61f13f1ed0b498dd 100644
--- a/include/linux/iio/buffer_impl.h
+++ b/include/linux/iio/buffer_impl.h
@@ -51,6 +51,7 @@ struct sg_table;
  * @enqueue_dmabuf:	called from userspace via ioctl to queue this DMABUF
  *			object to this buffer. Requires a valid DMABUF fd, that
  *			was previouly attached to this buffer.
+ * @get_dma_dev:	called to get the DMA channel associated with this buffer.
  * @lock_queue:		called when the core needs to lock the buffer queue;
  *                      it is used when enqueueing DMABUF objects.
  * @unlock_queue:       used to unlock a previously locked buffer queue
@@ -91,6 +92,7 @@ struct iio_buffer_access_funcs {
 			      struct iio_dma_buffer_block *block,
 			      struct dma_fence *fence, struct sg_table *sgt,
 			      size_t size, bool cyclic);
+	struct device * (*get_dma_dev)(struct iio_buffer *buffer);
 	void (*lock_queue)(struct iio_buffer *buffer);
 	void (*unlock_queue)(struct iio_buffer *buffer);
 

-- 
2.51.0



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

* [PATCH 2/3] iio: buffer-dma: support getting the DMA channel
  2025-10-02 15:06 [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Nuno Sá via B4 Relay
  2025-10-02 15:06 ` [PATCH 1/3] iio: buffer: support getting dma channel from the buffer Nuno Sá via B4 Relay
@ 2025-10-02 15:06 ` Nuno Sá via B4 Relay
  2025-10-02 15:06 ` [PATCH 3/3] iio: buffer-dmaengine: enable .get_dma_dev() Nuno Sá via B4 Relay
  2025-10-04 13:21 ` [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Jonathan Cameron
  3 siblings, 0 replies; 7+ messages in thread
From: Nuno Sá via B4 Relay @ 2025-10-02 15:06 UTC (permalink / raw)
  To: linux-iio; +Cc: Jonathan Cameron, David Lechner, Andy Shevchenko

From: Nuno Sá <nuno.sa@analog.com>

Implement the .get_dma_dev() callback for DMA buffers by returning the
device that owns the DMA channel. This allows the core DMABUF
infrastructure to properly map DMA buffers using the correct device,
avoiding the need for bounce buffers on systems where memory is mapped
above the 32-bit range.

The function returns the DMA queue's device, which is the actual device
responsible for DMA operations in buffer-dma implementations.

Fixes: d85318900c1c ("iio: buffer-dma: Enable support for DMABUFs")
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/buffer/industrialio-buffer-dma.c | 6 ++++++
 include/linux/iio/buffer-dma.h               | 1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c
index ee294a775e8aa050aca85e422de4c267adee1a33..7a7a9d37339bc1c2ffec58687a42dde16b1412bb 100644
--- a/drivers/iio/buffer/industrialio-buffer-dma.c
+++ b/drivers/iio/buffer/industrialio-buffer-dma.c
@@ -786,6 +786,12 @@ int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer,
 }
 EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_enqueue_dmabuf, "IIO_DMA_BUFFER");
 
+struct device *iio_dma_buffer_get_dma_dev(struct iio_buffer *buffer)
+{
+	return iio_buffer_to_queue(buffer)->dev;
+}
+EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_get_dma_dev, "IIO_DMA_BUFFER");
+
 void iio_dma_buffer_lock_queue(struct iio_buffer *buffer)
 {
 	struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h
index 5eb66a3990021afb1821297e540656a65916daa7..4f33e6a39797d3ecfddc69c11d6d3985b9212920 100644
--- a/include/linux/iio/buffer-dma.h
+++ b/include/linux/iio/buffer-dma.h
@@ -174,5 +174,6 @@ int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer,
 				  size_t size, bool cyclic);
 void iio_dma_buffer_lock_queue(struct iio_buffer *buffer);
 void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer);
+struct device *iio_dma_buffer_get_dma_dev(struct iio_buffer *buffer);
 
 #endif

-- 
2.51.0



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

* [PATCH 3/3] iio: buffer-dmaengine: enable .get_dma_dev()
  2025-10-02 15:06 [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Nuno Sá via B4 Relay
  2025-10-02 15:06 ` [PATCH 1/3] iio: buffer: support getting dma channel from the buffer Nuno Sá via B4 Relay
  2025-10-02 15:06 ` [PATCH 2/3] iio: buffer-dma: support getting the DMA channel Nuno Sá via B4 Relay
@ 2025-10-02 15:06 ` Nuno Sá via B4 Relay
  2025-10-04 13:21 ` [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Jonathan Cameron
  3 siblings, 0 replies; 7+ messages in thread
From: Nuno Sá via B4 Relay @ 2025-10-02 15:06 UTC (permalink / raw)
  To: linux-iio; +Cc: Jonathan Cameron, David Lechner, Andy Shevchenko

From: Nuno Sá <nuno.sa@analog.com>

Wire up the .get_dma_dev() callback to use the DMA buffer infrastructure's
implementation. This ensures that DMABUF operations use the correct DMA
device for mapping, which is essential for proper operation on systems
where memory is mapped above the 32-bit range.

Without this callback, the core would fall back to using the IIO device's
parent, which may not have the appropriate DMA mask configuration for
high memory access.

Fixes: 7a86d469983a ("iio: buffer-dmaengine: Support new DMABUF based userspace API")
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/buffer/industrialio-buffer-dmaengine.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index e9d9a7d39fe191c2b6e8c196a08cdd26cd3a8d4b..27dd56334345135742d077fab157e2f091d07488 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -177,6 +177,8 @@ static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
 	.lock_queue = iio_dma_buffer_lock_queue,
 	.unlock_queue = iio_dma_buffer_unlock_queue,
 
+	.get_dma_dev = iio_dma_buffer_get_dma_dev,
+
 	.modes = INDIO_BUFFER_HARDWARE,
 	.flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK,
 };

-- 
2.51.0



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

* Re: [PATCH 1/3] iio: buffer: support getting dma channel from the buffer
  2025-10-02 15:06 ` [PATCH 1/3] iio: buffer: support getting dma channel from the buffer Nuno Sá via B4 Relay
@ 2025-10-02 16:14   ` David Lechner
  2025-10-03  6:12     ` Nuno Sá
  0 siblings, 1 reply; 7+ messages in thread
From: David Lechner @ 2025-10-02 16:14 UTC (permalink / raw)
  To: nuno.sa; +Cc: linux-iio, Jonathan Cameron, Andy Shevchenko

On Thu, Oct 2, 2025 at 5:06 PM Nuno Sá via B4 Relay
<devnull+nuno.sa.analog.com@kernel.org> wrote:
>
> From: Nuno Sá <nuno.sa@analog.com>
>
> Add a new buffer accessor .get_dma_dev() in order to get the
> struct device responsible for actually providing the dma channel. We
> cannot assume that we can use the parent of the IIO device for mapping
> the DMA buffer. This becomes important on systems (like the Xilinx/AMD
> zynqMP Ultrascale) where memory (or part of it) is mapped above the
> 32 bit range. On such systems and given that a device by default has
> a dma mask of 32 bits we would then need to rely on bounce buffers (to
> swiotlb) for mapping memory above the dma mask limit.
>
> Fixes: 3e26d9f08fbe ("iio: core: Add new DMABUF interface infrastructure")

Does this actually fix it or is it just a prerequisite for a later
fix? (In that case, this would just be Cc: stable@vger.kernel.org)

> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> ---
>  drivers/iio/industrialio-buffer.c | 28 ++++++++++++++++++++++------
>  include/linux/iio/buffer_impl.h   |  2 ++
>  2 files changed, 24 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index f1448ae1b843fc577599fc1b9cf6d859bba226f1..279c7d716bf5d467d40b5c290789fcbd1f949660 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -1627,15 +1627,20 @@ static struct dma_buf_attachment *
>  iio_buffer_find_attachment(struct iio_dev_buffer_pair *ib,
>                            struct dma_buf *dmabuf, bool nonblock)
>  {
> -       struct device *dev = ib->indio_dev->dev.parent;
> +       struct device *dma_dev;
>         struct iio_buffer *buffer = ib->buffer;
>         struct dma_buf_attachment *attach = NULL;
>         struct iio_dmabuf_priv *priv;
>
> +       if (buffer->access->get_dma_dev)
> +               dma_dev = buffer->access->get_dma_dev(buffer);
> +       else
> +               dma_dev = ib->indio_dev->dev.parent;
> +

This gets repeated 3 times, so maybe worth adding a helper function?

>         guard(mutex)(&buffer->dmabufs_mutex);
>
>         list_for_each_entry(priv, &buffer->dmabufs, entry) {
> -               if (priv->attach->dev == dev
> +               if (priv->attach->dev == dma_dev
>                     && priv->attach->dmabuf == dmabuf) {
>                         attach = priv->attach;
>                         break;
> @@ -1655,6 +1660,7 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
>         struct iio_buffer *buffer = ib->buffer;
>         struct dma_buf_attachment *attach;
>         struct iio_dmabuf_priv *priv, *each;
> +       struct device *dma_dev;
>         struct dma_buf *dmabuf;
>         int err, fd;
>
> @@ -1679,7 +1685,12 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
>                 goto err_free_priv;
>         }
>
> -       attach = dma_buf_attach(dmabuf, indio_dev->dev.parent);
> +       if (buffer->access->get_dma_dev)
> +               dma_dev = buffer->access->get_dma_dev(buffer);
> +       else
> +               dma_dev = indio_dev->dev.parent;
> +
> +       attach = dma_buf_attach(dmabuf, dma_dev);
>         if (IS_ERR(attach)) {
>                 err = PTR_ERR(attach);
>                 goto err_dmabuf_put;
> @@ -1719,7 +1730,7 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
>          * combo. If we do, refuse to attach.
>          */
>         list_for_each_entry(each, &buffer->dmabufs, entry) {
> -               if (each->attach->dev == indio_dev->dev.parent
> +               if (each->attach->dev == dma_dev
>                     && each->attach->dmabuf == dmabuf) {
>                         /*
>                          * We unlocked the reservation object, so going through
> @@ -1759,6 +1770,7 @@ static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib,
>         struct iio_buffer *buffer = ib->buffer;
>         struct iio_dev *indio_dev = ib->indio_dev;
>         struct iio_dmabuf_priv *priv;
> +       struct device *dma_dev;
>         struct dma_buf *dmabuf;
>         int dmabuf_fd, ret = -EPERM;
>
> @@ -1769,11 +1781,15 @@ static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib,
>         if (IS_ERR(dmabuf))
>                 return PTR_ERR(dmabuf);
>
> +       if (buffer->access->get_dma_dev)
> +               dma_dev = buffer->access->get_dma_dev(buffer);
> +       else
> +               dma_dev = indio_dev->dev.parent;
> +
>         guard(mutex)(&buffer->dmabufs_mutex);
>
>         list_for_each_entry(priv, &buffer->dmabufs, entry) {
> -               if (priv->attach->dev == indio_dev->dev.parent
> -                   && priv->attach->dmabuf == dmabuf) {
> +               if (priv->attach->dev == dma_dev && priv->attach->dmabuf == dmabuf) {
>                         list_del(&priv->entry);
>
>                         /* Unref the reference from iio_buffer_attach_dmabuf() */
> diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
> index 0daff9ff20ce49de67fa0f2ac6191882de2f4a67..c0b0e0992a85b2813a126c1a61f13f1ed0b498dd 100644
> --- a/include/linux/iio/buffer_impl.h
> +++ b/include/linux/iio/buffer_impl.h
> @@ -51,6 +51,7 @@ struct sg_table;
>   * @enqueue_dmabuf:    called from userspace via ioctl to queue this DMABUF
>   *                     object to this buffer. Requires a valid DMABUF fd, that
>   *                     was previouly attached to this buffer.
> + * @get_dma_dev:       called to get the DMA channel associated with this buffer.

Could probably clarify that this is required for DMA buffers but
should not be provided for other buffers.

>   * @lock_queue:                called when the core needs to lock the buffer queue;
>   *                      it is used when enqueueing DMABUF objects.
>   * @unlock_queue:       used to unlock a previously locked buffer queue
> @@ -91,6 +92,7 @@ struct iio_buffer_access_funcs {
>                               struct iio_dma_buffer_block *block,
>                               struct dma_fence *fence, struct sg_table *sgt,
>                               size_t size, bool cyclic);
> +       struct device * (*get_dma_dev)(struct iio_buffer *buffer);
>         void (*lock_queue)(struct iio_buffer *buffer);
>         void (*unlock_queue)(struct iio_buffer *buffer);
>
>
> --
> 2.51.0
>
>

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

* Re: [PATCH 1/3] iio: buffer: support getting dma channel from the buffer
  2025-10-02 16:14   ` David Lechner
@ 2025-10-03  6:12     ` Nuno Sá
  0 siblings, 0 replies; 7+ messages in thread
From: Nuno Sá @ 2025-10-03  6:12 UTC (permalink / raw)
  To: David Lechner, nuno.sa; +Cc: linux-iio, Jonathan Cameron, Andy Shevchenko

On Thu, 2025-10-02 at 18:14 +0200, David Lechner wrote:
> On Thu, Oct 2, 2025 at 5:06 PM Nuno Sá via B4 Relay
> <devnull+nuno.sa.analog.com@kernel.org> wrote:
> > 
> > From: Nuno Sá <nuno.sa@analog.com>
> > 
> > Add a new buffer accessor .get_dma_dev() in order to get the
> > struct device responsible for actually providing the dma channel. We
> > cannot assume that we can use the parent of the IIO device for mapping
> > the DMA buffer. This becomes important on systems (like the Xilinx/AMD
> > zynqMP Ultrascale) where memory (or part of it) is mapped above the
> > 32 bit range. On such systems and given that a device by default has
> > a dma mask of 32 bits we would then need to rely on bounce buffers (to
> > swiotlb) for mapping memory above the dma mask limit.
> > 
> > Fixes: 3e26d9f08fbe ("iio: core: Add new DMABUF interface infrastructure")
> 
> Does this actually fix it or is it just a prerequisite for a later
> fix? (In that case, this would just be Cc: stable@vger.kernel.org)

Yeah, that came to mind and I ended up doing with a fixes on all three patches. But
naturally the "real" fix is the combination of the three patches otherwise we still
get the parent device. So I did thought about CCing stable with dependencies to the
other patches. Or maybe doing that the last patch with dependencies the first two?

- Nuno Sá

> 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> > ---
> >  drivers/iio/industrialio-buffer.c | 28 ++++++++++++++++++++++------
> >  include/linux/iio/buffer_impl.h   |  2 ++
> >  2 files changed, 24 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-
> > buffer.c
> > index
> > f1448ae1b843fc577599fc1b9cf6d859bba226f1..279c7d716bf5d467d40b5c290789fcbd1f94966
> > 0 100644
> > --- a/drivers/iio/industrialio-buffer.c
> > +++ b/drivers/iio/industrialio-buffer.c
> > @@ -1627,15 +1627,20 @@ static struct dma_buf_attachment *
> >  iio_buffer_find_attachment(struct iio_dev_buffer_pair *ib,
> >                            struct dma_buf *dmabuf, bool nonblock)
> >  {
> > -       struct device *dev = ib->indio_dev->dev.parent;
> > +       struct device *dma_dev;
> >         struct iio_buffer *buffer = ib->buffer;
> >         struct dma_buf_attachment *attach = NULL;
> >         struct iio_dmabuf_priv *priv;
> > 
> > +       if (buffer->access->get_dma_dev)
> > +               dma_dev = buffer->access->get_dma_dev(buffer);
> > +       else
> > +               dma_dev = ib->indio_dev->dev.parent;
> > +
> 
> This gets repeated 3 times, so maybe worth adding a helper function?
> 
> >         guard(mutex)(&buffer->dmabufs_mutex);
> > 
> >         list_for_each_entry(priv, &buffer->dmabufs, entry) {
> > -               if (priv->attach->dev == dev
> > +               if (priv->attach->dev == dma_dev
> >                     && priv->attach->dmabuf == dmabuf) {
> >                         attach = priv->attach;
> >                         break;
> > @@ -1655,6 +1660,7 @@ static int iio_buffer_attach_dmabuf(struct
> > iio_dev_buffer_pair *ib,
> >         struct iio_buffer *buffer = ib->buffer;
> >         struct dma_buf_attachment *attach;
> >         struct iio_dmabuf_priv *priv, *each;
> > +       struct device *dma_dev;
> >         struct dma_buf *dmabuf;
> >         int err, fd;
> > 
> > @@ -1679,7 +1685,12 @@ static int iio_buffer_attach_dmabuf(struct
> > iio_dev_buffer_pair *ib,
> >                 goto err_free_priv;
> >         }
> > 
> > -       attach = dma_buf_attach(dmabuf, indio_dev->dev.parent);
> > +       if (buffer->access->get_dma_dev)
> > +               dma_dev = buffer->access->get_dma_dev(buffer);
> > +       else
> > +               dma_dev = indio_dev->dev.parent;
> > +
> > +       attach = dma_buf_attach(dmabuf, dma_dev);
> >         if (IS_ERR(attach)) {
> >                 err = PTR_ERR(attach);
> >                 goto err_dmabuf_put;
> > @@ -1719,7 +1730,7 @@ static int iio_buffer_attach_dmabuf(struct
> > iio_dev_buffer_pair *ib,
> >          * combo. If we do, refuse to attach.
> >          */
> >         list_for_each_entry(each, &buffer->dmabufs, entry) {
> > -               if (each->attach->dev == indio_dev->dev.parent
> > +               if (each->attach->dev == dma_dev
> >                     && each->attach->dmabuf == dmabuf) {
> >                         /*
> >                          * We unlocked the reservation object, so going through
> > @@ -1759,6 +1770,7 @@ static int iio_buffer_detach_dmabuf(struct
> > iio_dev_buffer_pair *ib,
> >         struct iio_buffer *buffer = ib->buffer;
> >         struct iio_dev *indio_dev = ib->indio_dev;
> >         struct iio_dmabuf_priv *priv;
> > +       struct device *dma_dev;
> >         struct dma_buf *dmabuf;
> >         int dmabuf_fd, ret = -EPERM;
> > 
> > @@ -1769,11 +1781,15 @@ static int iio_buffer_detach_dmabuf(struct
> > iio_dev_buffer_pair *ib,
> >         if (IS_ERR(dmabuf))
> >                 return PTR_ERR(dmabuf);
> > 
> > +       if (buffer->access->get_dma_dev)
> > +               dma_dev = buffer->access->get_dma_dev(buffer);
> > +       else
> > +               dma_dev = indio_dev->dev.parent;
> > +
> >         guard(mutex)(&buffer->dmabufs_mutex);
> > 
> >         list_for_each_entry(priv, &buffer->dmabufs, entry) {
> > -               if (priv->attach->dev == indio_dev->dev.parent
> > -                   && priv->attach->dmabuf == dmabuf) {
> > +               if (priv->attach->dev == dma_dev && priv->attach->dmabuf ==
> > dmabuf) {
> >                         list_del(&priv->entry);
> > 
> >                         /* Unref the reference from iio_buffer_attach_dmabuf() */
> > diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
> > index
> > 0daff9ff20ce49de67fa0f2ac6191882de2f4a67..c0b0e0992a85b2813a126c1a61f13f1ed0b498d
> > d 100644
> > --- a/include/linux/iio/buffer_impl.h
> > +++ b/include/linux/iio/buffer_impl.h
> > @@ -51,6 +51,7 @@ struct sg_table;
> >   * @enqueue_dmabuf:    called from userspace via ioctl to queue this DMABUF
> >   *                     object to this buffer. Requires a valid DMABUF fd, that
> >   *                     was previouly attached to this buffer.
> > + * @get_dma_dev:       called to get the DMA channel associated with this
> > buffer.
> 
> Could probably clarify that this is required for DMA buffers but
> should not be provided for other buffers.
> 
> >   * @lock_queue:                called when the core needs to lock the buffer
> > queue;
> >   *                      it is used when enqueueing DMABUF objects.
> >   * @unlock_queue:       used to unlock a previously locked buffer queue
> > @@ -91,6 +92,7 @@ struct iio_buffer_access_funcs {
> >                               struct iio_dma_buffer_block *block,
> >                               struct dma_fence *fence, struct sg_table *sgt,
> >                               size_t size, bool cyclic);
> > +       struct device * (*get_dma_dev)(struct iio_buffer *buffer);
> >         void (*lock_queue)(struct iio_buffer *buffer);
> >         void (*unlock_queue)(struct iio_buffer *buffer);
> > 
> > 
> > --
> > 2.51.0
> > 
> > 

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

* Re: [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems
  2025-10-02 15:06 [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Nuno Sá via B4 Relay
                   ` (2 preceding siblings ...)
  2025-10-02 15:06 ` [PATCH 3/3] iio: buffer-dmaengine: enable .get_dma_dev() Nuno Sá via B4 Relay
@ 2025-10-04 13:21 ` Jonathan Cameron
  3 siblings, 0 replies; 7+ messages in thread
From: Jonathan Cameron @ 2025-10-04 13:21 UTC (permalink / raw)
  To: Nuno Sá via B4 Relay
  Cc: nuno.sa, linux-iio, David Lechner, Andy Shevchenko

On Thu, 02 Oct 2025 16:06:27 +0100
Nuno Sá via B4 Relay <devnull+nuno.sa.analog.com@kernel.org> wrote:

> This series fixes an issue with DMABUF support in the IIO subsystem where
> the wrong DMA device could be used for buffer mapping operations. This
> becomes critical on systems like Xilinx/AMD ZynqMP Ultrascale where memory
> can be mapped above the 32-bit address range.
> 
> Problem:
> --------
> The current IIO DMABUF implementation assumes it can use the parent device
> of the IIO device for DMA operations. However, this device may not have
> the appropriate DMA mask configuration for accessing high memory addresses.
> On systems where memory is mapped above 32-bits, this leads to the use of
> bounce buffers through swiotlb, significantly impacting performance.
> 
> Solution:
> ---------
> This series introduces a new .get_dma_dev() callback in the buffer access
> functions that allows buffer implementations to specify the correct DMA
> device that should be used for DMABUF operations. The DMA buffer
> infrastructure implements this callback to return the device that actually
> owns the DMA channel, ensuring proper memory mapping without bounce buffers.
> 
> Changes:
> --------
> 1. Add .get_dma_dev() callback to iio_buffer_access_funcs and update core
>    DMABUF code to use it when available
> 2. Implement the callback in the DMA buffer infrastructure
> 3. Wire up the callback in the dmaengine buffer implementation
> 
> This ensures that DMABUF operations use the device with the correct DMA
> configuration, eliminating unnecessary bounce buffer usage and improving
> performance on high-memory systems.
> 
> (AI generated cover. I would not be this formal but I guess is not
> that bad :))

Not too bad indeed.

Series looks fine to me in general. Just those suggestions from David
to enact in v2.

Thanks,

Jonathan

> 
> ---
> Nuno Sá (3):
>       iio: buffer: support getting dma channel from the buffer
>       iio: buffer-dma: support getting the DMA channel
>       iio: buffer-dmaengine: enable .get_dma_dev()
> 
>  drivers/iio/buffer/industrialio-buffer-dma.c       |  6 +++++
>  drivers/iio/buffer/industrialio-buffer-dmaengine.c |  2 ++
>  drivers/iio/industrialio-buffer.c                  | 28 +++++++++++++++++-----
>  include/linux/iio/buffer-dma.h                     |  1 +
>  include/linux/iio/buffer_impl.h                    |  2 ++
>  5 files changed, 33 insertions(+), 6 deletions(-)
> ---
> base-commit: b9700f87939f0f477e5c00db817f54ab8a97702b
> change-id: 20250930-fix-iio-dmabuf-get-dma-device-339ac70543db
> --
> 
> Thanks!
> - Nuno Sá
> 
> 


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

end of thread, other threads:[~2025-10-04 13:21 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-02 15:06 [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Nuno Sá via B4 Relay
2025-10-02 15:06 ` [PATCH 1/3] iio: buffer: support getting dma channel from the buffer Nuno Sá via B4 Relay
2025-10-02 16:14   ` David Lechner
2025-10-03  6:12     ` Nuno Sá
2025-10-02 15:06 ` [PATCH 2/3] iio: buffer-dma: support getting the DMA channel Nuno Sá via B4 Relay
2025-10-02 15:06 ` [PATCH 3/3] iio: buffer-dmaengine: enable .get_dma_dev() Nuno Sá via B4 Relay
2025-10-04 13:21 ` [PATCH 0/3] iio: buffer: Fix DMABUF mapping in some systems Jonathan Cameron

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