* [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers @ 2026-06-11 15:28 ` Nuno Sá via B4 Relay 0 siblings, 0 replies; 7+ messages in thread From: Nuno Sá @ 2026-06-11 15:28 UTC (permalink / raw) To: linux-iio; +Cc: Jonathan Cameron, David Lechner, Andy Shevchenko Allow buffer blocks flagged as cyclic to be submitted as repeating DMA transfers. For cyclic blocks, use DMA_PREP_REPEAT so the engine keeps replaying the descriptor. Skip installing the completion callback for cyclic blocks. Since the transfer is continuously replayed, the callback would fire on every period, throwing off the block refcount. Because nothing prevents a new cyclic transfer from replacing an already active cyclic one, always set DMA_PREP_LOAD_EOT so the engine correctly terminates the active transfer before loading the new descriptor. Signed-off-by: Nuno Sá <nuno.sa@analog.com> --- There's one subtle choice in here. Given that the termination callback is not set. We will never give the block refcount. That means cyclic blocks are only completely freed when we disable the buffer and iio_dmaengine_buffer_abort() get's called. So no leak, we just defer it as it makes it more simple to handle. I also think this a fair expectation from a cyclic transfer. We set it up and let it run until we disable the buffer. Alternatively, we can give in the refcount as soon as we give the block to the DMA layer with dma_async_issue_pending(). But we also need to make sure that the block is not added to the dmaengine_buffer->active list. As said, I feel that the current approach is just simpler. --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 98acce909854..4a78cd3e7c7d 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -80,6 +80,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, dma_dir = DMA_MEM_TO_DEV; if (block->sg_table) { + unsigned long flags; + sgl = block->sg_table->sgl; nents = sg_nents_for_len(sgl, block->bytes_used); if (nents < 0) @@ -99,9 +101,18 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, sgl = sg_next(sgl); } + if (block->cyclic) + flags = DMA_PREP_REPEAT; + else + flags = DMA_PREP_INTERRUPT; + + /* + * There's nothing preventing a cyclic transfer to replace an active + * cyclic one. So always set the EOT flag. + */ desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, vecs, nents, dma_dir, - DMA_PREP_INTERRUPT); + flags | DMA_PREP_LOAD_EOT); kfree(vecs); } else { max_size = min(block->size, dmaengine_buffer->max_size); @@ -122,8 +133,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, if (!desc) return -ENOMEM; - desc->callback_result = iio_dmaengine_buffer_block_done; - desc->callback_param = block; + if (!block->cyclic) { + desc->callback_result = iio_dmaengine_buffer_block_done; + desc->callback_param = block; + } cookie = dmaengine_submit(desc); if (dma_submit_error(cookie)) --- base-commit: ae696dfa47c30016cd429b9db5e70b259b8f509e change-id: 20260609-iio-dma-cyclic-buffer-support-f18034f8f34c -- Thanks! - Nuno Sá ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers @ 2026-06-11 15:28 ` Nuno Sá via B4 Relay 0 siblings, 0 replies; 7+ messages in thread From: Nuno Sá via B4 Relay @ 2026-06-11 15:28 UTC (permalink / raw) To: linux-iio; +Cc: Jonathan Cameron, David Lechner, Andy Shevchenko From: Nuno Sá <nuno.sa@analog.com> Allow buffer blocks flagged as cyclic to be submitted as repeating DMA transfers. For cyclic blocks, use DMA_PREP_REPEAT so the engine keeps replaying the descriptor. Skip installing the completion callback for cyclic blocks. Since the transfer is continuously replayed, the callback would fire on every period, throwing off the block refcount. Because nothing prevents a new cyclic transfer from replacing an already active cyclic one, always set DMA_PREP_LOAD_EOT so the engine correctly terminates the active transfer before loading the new descriptor. Signed-off-by: Nuno Sá <nuno.sa@analog.com> --- There's one subtle choice in here. Given that the termination callback is not set. We will never give the block refcount. That means cyclic blocks are only completely freed when we disable the buffer and iio_dmaengine_buffer_abort() get's called. So no leak, we just defer it as it makes it more simple to handle. I also think this a fair expectation from a cyclic transfer. We set it up and let it run until we disable the buffer. Alternatively, we can give in the refcount as soon as we give the block to the DMA layer with dma_async_issue_pending(). But we also need to make sure that the block is not added to the dmaengine_buffer->active list. As said, I feel that the current approach is just simpler. --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 98acce909854..4a78cd3e7c7d 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -80,6 +80,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, dma_dir = DMA_MEM_TO_DEV; if (block->sg_table) { + unsigned long flags; + sgl = block->sg_table->sgl; nents = sg_nents_for_len(sgl, block->bytes_used); if (nents < 0) @@ -99,9 +101,18 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, sgl = sg_next(sgl); } + if (block->cyclic) + flags = DMA_PREP_REPEAT; + else + flags = DMA_PREP_INTERRUPT; + + /* + * There's nothing preventing a cyclic transfer to replace an active + * cyclic one. So always set the EOT flag. + */ desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, vecs, nents, dma_dir, - DMA_PREP_INTERRUPT); + flags | DMA_PREP_LOAD_EOT); kfree(vecs); } else { max_size = min(block->size, dmaengine_buffer->max_size); @@ -122,8 +133,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, if (!desc) return -ENOMEM; - desc->callback_result = iio_dmaengine_buffer_block_done; - desc->callback_param = block; + if (!block->cyclic) { + desc->callback_result = iio_dmaengine_buffer_block_done; + desc->callback_param = block; + } cookie = dmaengine_submit(desc); if (dma_submit_error(cookie)) --- base-commit: ae696dfa47c30016cd429b9db5e70b259b8f509e change-id: 20260609-iio-dma-cyclic-buffer-support-f18034f8f34c -- Thanks! - Nuno Sá ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers 2026-06-11 15:28 ` Nuno Sá via B4 Relay (?) @ 2026-06-13 16:33 ` David Lechner 2026-06-15 8:21 ` Nuno Sá -1 siblings, 1 reply; 7+ messages in thread From: David Lechner @ 2026-06-13 16:33 UTC (permalink / raw) To: nuno.sa, linux-iio; +Cc: Jonathan Cameron, Andy Shevchenko On 6/11/26 10:28 AM, Nuno Sá via B4 Relay wrote: > From: Nuno Sá <nuno.sa@analog.com> > > Allow buffer blocks flagged as cyclic to be submitted as repeating DMA > transfers. For cyclic blocks, use DMA_PREP_REPEAT so the engine keeps > replaying the descriptor. Is this for both directions (e.g ADCs and DACs) or only one? > > Skip installing the completion callback for cyclic blocks. Since the > transfer is continuously replayed, the callback would fire on every > period, throwing off the block refcount. > > Because nothing prevents a new cyclic transfer from replacing an > already active cyclic one, always set DMA_PREP_LOAD_EOT so the engine > correctly terminates the active transfer before loading the new > descriptor. Is there more to come after this to actually make use of it? Or is there a way to use this with DMABUF from userspace already? > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > --- > There's one subtle choice in here. Given that the termination callback > is not set. We will never give the block refcount. That means cyclic > blocks are only completely freed when we disable the buffer and > iio_dmaengine_buffer_abort() get's called. So no leak, we just defer it > as it makes it more simple to handle. I also think this a fair > expectation from a cyclic transfer. We set it up and let it run until we > disable the buffer. Makes sense. > > Alternatively, we can give in the refcount as soon as we give the block > to the DMA layer with dma_async_issue_pending(). But we also need to > make sure that the block is not added to the dmaengine_buffer->active list. > As said, I feel that the current approach is just simpler. > --- > drivers/iio/buffer/industrialio-buffer-dmaengine.c | 19 ++++++++++++++++--- > 1 file changed, 16 insertions(+), 3 deletions(-) > > diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > index 98acce909854..4a78cd3e7c7d 100644 > --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c > +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > @@ -80,6 +80,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > dma_dir = DMA_MEM_TO_DEV; > > if (block->sg_table) { > + unsigned long flags; > + > sgl = block->sg_table->sgl; > nents = sg_nents_for_len(sgl, block->bytes_used); > if (nents < 0) > @@ -99,9 +101,18 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > sgl = sg_next(sgl); > } > > + if (block->cyclic) > + flags = DMA_PREP_REPEAT; > + else > + flags = DMA_PREP_INTERRUPT; > + > + /* > + * There's nothing preventing a cyclic transfer to replace an active > + * cyclic one. So always set the EOT flag. What about the non-cyclic case? > + */ > desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, > vecs, nents, dma_dir, > - DMA_PREP_INTERRUPT); > + flags | DMA_PREP_LOAD_EOT); > kfree(vecs); > } else { > max_size = min(block->size, dmaengine_buffer->max_size); > @@ -122,8 +133,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > if (!desc) > return -ENOMEM; > > - desc->callback_result = iio_dmaengine_buffer_block_done; > - desc->callback_param = block; > + if (!block->cyclic) { > + desc->callback_result = iio_dmaengine_buffer_block_done; > + desc->callback_param = block; > + } > > cookie = dmaengine_submit(desc); > if (dma_submit_error(cookie)) > > --- > base-commit: ae696dfa47c30016cd429b9db5e70b259b8f509e > change-id: 20260609-iio-dma-cyclic-buffer-support-f18034f8f34c > -- > > Thanks! > - Nuno Sá > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers 2026-06-13 16:33 ` David Lechner @ 2026-06-15 8:21 ` Nuno Sá 2026-06-22 13:15 ` Nuno Sá 0 siblings, 1 reply; 7+ messages in thread From: Nuno Sá @ 2026-06-15 8:21 UTC (permalink / raw) To: David Lechner; +Cc: nuno.sa, linux-iio, Jonathan Cameron, Andy Shevchenko On Sat, Jun 13, 2026 at 11:33:36AM -0500, David Lechner wrote: > On 6/11/26 10:28 AM, Nuno Sá via B4 Relay wrote: > > From: Nuno Sá <nuno.sa@analog.com> > > > > Allow buffer blocks flagged as cyclic to be submitted as repeating DMA > > transfers. For cyclic blocks, use DMA_PREP_REPEAT so the engine keeps > > replaying the descriptor. > > Is this for both directions (e.g ADCs and DACs) or only one? We just have usecases of TX buffers. IIRC, there should be some validation (some layers above in the call chain) not allowing cyclic RX. > > > > > Skip installing the completion callback for cyclic blocks. Since the > > transfer is continuously replayed, the callback would fire on every > > period, throwing off the block refcount. > > > > Because nothing prevents a new cyclic transfer from replacing an > > already active cyclic one, always set DMA_PREP_LOAD_EOT so the engine > > correctly terminates the active transfer before loading the new > > descriptor. > > Is there more to come after this to actually make use of it? Or is there > a way to use this with DMABUF from userspace already? Yes. One can do TX cyclic DMA transfer today. Some waveforms examples: https://github.com/analogdevicesinc/iio-oscilloscope/tree/main/waveforms For normal non cyclic transfers, libiio also handles DMABUF just fine. Best way to use it is with USB where we support zero copy between IIO and the USB stack. > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > --- > > There's one subtle choice in here. Given that the termination callback > > is not set. We will never give the block refcount. That means cyclic > > blocks are only completely freed when we disable the buffer and > > iio_dmaengine_buffer_abort() get's called. So no leak, we just defer it > > as it makes it more simple to handle. I also think this a fair > > expectation from a cyclic transfer. We set it up and let it run until we > > disable the buffer. > > Makes sense. > > > > > Alternatively, we can give in the refcount as soon as we give the block > > to the DMA layer with dma_async_issue_pending(). But we also need to > > make sure that the block is not added to the dmaengine_buffer->active list. > > As said, I feel that the current approach is just simpler. > > --- > > drivers/iio/buffer/industrialio-buffer-dmaengine.c | 19 ++++++++++++++++--- > > 1 file changed, 16 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > index 98acce909854..4a78cd3e7c7d 100644 > > --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > @@ -80,6 +80,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > dma_dir = DMA_MEM_TO_DEV; > > > > if (block->sg_table) { > > + unsigned long flags; > > + > > sgl = block->sg_table->sgl; > > nents = sg_nents_for_len(sgl, block->bytes_used); > > if (nents < 0) > > @@ -99,9 +101,18 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > sgl = sg_next(sgl); > > } > > > > + if (block->cyclic) > > + flags = DMA_PREP_REPEAT; > > + else > > + flags = DMA_PREP_INTERRUPT; > > + > > + /* > > + * There's nothing preventing a cyclic transfer to replace an active > > + * cyclic one. So always set the EOT flag. > > What about the non-cyclic case? Non cyclic will also have DMA_PREP_LOAD_EOT which should stop an ongoing cyclic transfer. If there's an active, non cyclic, it's business as usual. The transfer get's queued and will fire after the current one ends. IOW, DMA_PREP_LOAD_EOT is only meaningful for active cyclic transfers (it's ignored for non-cyclic) - Nuno Sá > > > + */ > > desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, > > vecs, nents, dma_dir, > > - DMA_PREP_INTERRUPT); > > + flags | DMA_PREP_LOAD_EOT); > > kfree(vecs); > > } else { > > max_size = min(block->size, dmaengine_buffer->max_size); > > @@ -122,8 +133,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > if (!desc) > > return -ENOMEM; > > > > - desc->callback_result = iio_dmaengine_buffer_block_done; > > - desc->callback_param = block; > > + if (!block->cyclic) { > > + desc->callback_result = iio_dmaengine_buffer_block_done; > > + desc->callback_param = block; > > + } > > > > cookie = dmaengine_submit(desc); > > if (dma_submit_error(cookie)) > > > > --- > > base-commit: ae696dfa47c30016cd429b9db5e70b259b8f509e > > change-id: 20260609-iio-dma-cyclic-buffer-support-f18034f8f34c > > -- > > > > Thanks! > > - Nuno Sá > > > > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers 2026-06-15 8:21 ` Nuno Sá @ 2026-06-22 13:15 ` Nuno Sá 2026-06-22 15:15 ` David Lechner 2026-06-22 17:12 ` Jonathan Cameron 0 siblings, 2 replies; 7+ messages in thread From: Nuno Sá @ 2026-06-22 13:15 UTC (permalink / raw) To: David Lechner; +Cc: nuno.sa, linux-iio, Jonathan Cameron, Andy Shevchenko On Mon, Jun 15, 2026 at 09:21:02AM +0100, Nuno Sá wrote: > On Sat, Jun 13, 2026 at 11:33:36AM -0500, David Lechner wrote: > > On 6/11/26 10:28 AM, Nuno Sá via B4 Relay wrote: > > > From: Nuno Sá <nuno.sa@analog.com> > > > > > > Allow buffer blocks flagged as cyclic to be submitted as repeating DMA > > > transfers. For cyclic blocks, use DMA_PREP_REPEAT so the engine keeps > > > replaying the descriptor. > > > > Is this for both directions (e.g ADCs and DACs) or only one? > > We just have usecases of TX buffers. IIRC, there should be some > validation (some layers above in the call chain) not allowing cyclic RX. > > > > > > > > Skip installing the completion callback for cyclic blocks. Since the > > > transfer is continuously replayed, the callback would fire on every > > > period, throwing off the block refcount. > > > > > > Because nothing prevents a new cyclic transfer from replacing an > > > already active cyclic one, always set DMA_PREP_LOAD_EOT so the engine > > > correctly terminates the active transfer before loading the new > > > descriptor. > > > > Is there more to come after this to actually make use of it? Or is there > > a way to use this with DMABUF from userspace already? > > Yes. One can do TX cyclic DMA transfer today. Some waveforms examples: > > https://github.com/analogdevicesinc/iio-oscilloscope/tree/main/waveforms > > For normal non cyclic transfers, libiio also handles DMABUF just fine. > Best way to use it is with USB where we support zero copy between IIO > and the USB stack. Jonathan, It seems there's not much activity on this one. What do you think about the changes? David, from you silence either you forgot about it or I guess you are happy with the reply :) Just trying to move this one forward - Nuno Sá > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > --- > > > There's one subtle choice in here. Given that the termination callback > > > is not set. We will never give the block refcount. That means cyclic > > > blocks are only completely freed when we disable the buffer and > > > iio_dmaengine_buffer_abort() get's called. So no leak, we just defer it > > > as it makes it more simple to handle. I also think this a fair > > > expectation from a cyclic transfer. We set it up and let it run until we > > > disable the buffer. > > > > Makes sense. > > > > > > > > Alternatively, we can give in the refcount as soon as we give the block > > > to the DMA layer with dma_async_issue_pending(). But we also need to > > > make sure that the block is not added to the dmaengine_buffer->active list. > > > As said, I feel that the current approach is just simpler. > > > --- > > > drivers/iio/buffer/industrialio-buffer-dmaengine.c | 19 ++++++++++++++++--- > > > 1 file changed, 16 insertions(+), 3 deletions(-) > > > > > > diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > > index 98acce909854..4a78cd3e7c7d 100644 > > > --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > > +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > > @@ -80,6 +80,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > > dma_dir = DMA_MEM_TO_DEV; > > > > > > if (block->sg_table) { > > > + unsigned long flags; > > > + > > > sgl = block->sg_table->sgl; > > > nents = sg_nents_for_len(sgl, block->bytes_used); > > > if (nents < 0) > > > @@ -99,9 +101,18 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > > sgl = sg_next(sgl); > > > } > > > > > > + if (block->cyclic) > > > + flags = DMA_PREP_REPEAT; > > > + else > > > + flags = DMA_PREP_INTERRUPT; > > > + > > > + /* > > > + * There's nothing preventing a cyclic transfer to replace an active > > > + * cyclic one. So always set the EOT flag. > > > > What about the non-cyclic case? > > Non cyclic will also have DMA_PREP_LOAD_EOT which should stop an ongoing > cyclic transfer. If there's an active, non cyclic, it's business as > usual. The transfer get's queued and will fire after the current one > ends. IOW, DMA_PREP_LOAD_EOT is only meaningful for active cyclic > transfers (it's ignored for non-cyclic) > > - Nuno Sá > > > > > > + */ > > > desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, > > > vecs, nents, dma_dir, > > > - DMA_PREP_INTERRUPT); > > > + flags | DMA_PREP_LOAD_EOT); > > > kfree(vecs); > > > } else { > > > max_size = min(block->size, dmaengine_buffer->max_size); > > > @@ -122,8 +133,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > > if (!desc) > > > return -ENOMEM; > > > > > > - desc->callback_result = iio_dmaengine_buffer_block_done; > > > - desc->callback_param = block; > > > + if (!block->cyclic) { > > > + desc->callback_result = iio_dmaengine_buffer_block_done; > > > + desc->callback_param = block; > > > + } > > > > > > cookie = dmaengine_submit(desc); > > > if (dma_submit_error(cookie)) > > > > > > --- > > > base-commit: ae696dfa47c30016cd429b9db5e70b259b8f509e > > > change-id: 20260609-iio-dma-cyclic-buffer-support-f18034f8f34c > > > -- > > > > > > Thanks! > > > - Nuno Sá > > > > > > > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers 2026-06-22 13:15 ` Nuno Sá @ 2026-06-22 15:15 ` David Lechner 2026-06-22 17:12 ` Jonathan Cameron 1 sibling, 0 replies; 7+ messages in thread From: David Lechner @ 2026-06-22 15:15 UTC (permalink / raw) To: Nuno Sá; +Cc: nuno.sa, linux-iio, Jonathan Cameron, Andy Shevchenko On 6/22/26 8:15 AM, Nuno Sá wrote: > On Mon, Jun 15, 2026 at 09:21:02AM +0100, Nuno Sá wrote: >> On Sat, Jun 13, 2026 at 11:33:36AM -0500, David Lechner wrote: >>> On 6/11/26 10:28 AM, Nuno Sá via B4 Relay wrote: >>>> From: Nuno Sá <nuno.sa@analog.com> >>>> >>>> Allow buffer blocks flagged as cyclic to be submitted as repeating DMA >>>> transfers. For cyclic blocks, use DMA_PREP_REPEAT so the engine keeps >>>> replaying the descriptor. >>> >>> Is this for both directions (e.g ADCs and DACs) or only one? >> >> We just have usecases of TX buffers. IIRC, there should be some >> validation (some layers above in the call chain) not allowing cyclic RX. >>> >>>> >>>> Skip installing the completion callback for cyclic blocks. Since the >>>> transfer is continuously replayed, the callback would fire on every >>>> period, throwing off the block refcount. >>>> >>>> Because nothing prevents a new cyclic transfer from replacing an >>>> already active cyclic one, always set DMA_PREP_LOAD_EOT so the engine >>>> correctly terminates the active transfer before loading the new >>>> descriptor. >>> >>> Is there more to come after this to actually make use of it? Or is there >>> a way to use this with DMABUF from userspace already? >> >> Yes. One can do TX cyclic DMA transfer today. Some waveforms examples: >> >> https://github.com/analogdevicesinc/iio-oscilloscope/tree/main/waveforms >> >> For normal non cyclic transfers, libiio also handles DMABUF just fine. >> Best way to use it is with USB where we support zero copy between IIO >> and the USB stack. > > Jonathan, > > It seems there's not much activity on this one. What do you think about > the changes? > > David, from you silence either you forgot about it or I guess you > are happy with the reply :) I don't have anything more to add. > > Just trying to move this one forward > > - Nuno Sá > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers 2026-06-22 13:15 ` Nuno Sá 2026-06-22 15:15 ` David Lechner @ 2026-06-22 17:12 ` Jonathan Cameron 1 sibling, 0 replies; 7+ messages in thread From: Jonathan Cameron @ 2026-06-22 17:12 UTC (permalink / raw) To: Nuno Sá; +Cc: David Lechner, nuno.sa, linux-iio, Andy Shevchenko On Mon, 22 Jun 2026 14:15:50 +0100 Nuno Sá <noname.nuno@gmail.com> wrote: > On Mon, Jun 15, 2026 at 09:21:02AM +0100, Nuno Sá wrote: > > On Sat, Jun 13, 2026 at 11:33:36AM -0500, David Lechner wrote: > > > On 6/11/26 10:28 AM, Nuno Sá via B4 Relay wrote: > > > > From: Nuno Sá <nuno.sa@analog.com> > > > > > > > > Allow buffer blocks flagged as cyclic to be submitted as repeating DMA > > > > transfers. For cyclic blocks, use DMA_PREP_REPEAT so the engine keeps > > > > replaying the descriptor. > > > > > > Is this for both directions (e.g ADCs and DACs) or only one? > > > > We just have usecases of TX buffers. IIRC, there should be some > > validation (some layers above in the call chain) not allowing cyclic RX. > > > > > > > > > > > Skip installing the completion callback for cyclic blocks. Since the > > > > transfer is continuously replayed, the callback would fire on every > > > > period, throwing off the block refcount. > > > > > > > > Because nothing prevents a new cyclic transfer from replacing an > > > > already active cyclic one, always set DMA_PREP_LOAD_EOT so the engine > > > > correctly terminates the active transfer before loading the new > > > > descriptor. > > > > > > Is there more to come after this to actually make use of it? Or is there > > > a way to use this with DMABUF from userspace already? > > > > Yes. One can do TX cyclic DMA transfer today. Some waveforms examples: > > > > https://github.com/analogdevicesinc/iio-oscilloscope/tree/main/waveforms > > > > For normal non cyclic transfers, libiio also handles DMABUF just fine. > > Best way to use it is with USB where we support zero copy between IIO > > and the USB stack. > > Jonathan, > > It seems there's not much activity on this one. What do you think about > the changes? > > David, from you silence either you forgot about it or I guess you > are happy with the reply :) > > Just trying to move this one forward Fiddly thing so I wanted to leave it till I'm up to date with the easier stuff. 303 emails to go... Also going to be travelling later this week and it's always a bit random if that means I have lots of time to review or none at all. Jonathan > > - Nuno Sá > > > > > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > --- > > > > There's one subtle choice in here. Given that the termination callback > > > > is not set. We will never give the block refcount. That means cyclic > > > > blocks are only completely freed when we disable the buffer and > > > > iio_dmaengine_buffer_abort() get's called. So no leak, we just defer it > > > > as it makes it more simple to handle. I also think this a fair > > > > expectation from a cyclic transfer. We set it up and let it run until we > > > > disable the buffer. > > > > > > Makes sense. > > > > > > > > > > > Alternatively, we can give in the refcount as soon as we give the block > > > > to the DMA layer with dma_async_issue_pending(). But we also need to > > > > make sure that the block is not added to the dmaengine_buffer->active list. > > > > As said, I feel that the current approach is just simpler. > > > > --- > > > > drivers/iio/buffer/industrialio-buffer-dmaengine.c | 19 ++++++++++++++++--- > > > > 1 file changed, 16 insertions(+), 3 deletions(-) > > > > > > > > diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > > > index 98acce909854..4a78cd3e7c7d 100644 > > > > --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > > > +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c > > > > @@ -80,6 +80,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > > > dma_dir = DMA_MEM_TO_DEV; > > > > > > > > if (block->sg_table) { > > > > + unsigned long flags; > > > > + > > > > sgl = block->sg_table->sgl; > > > > nents = sg_nents_for_len(sgl, block->bytes_used); > > > > if (nents < 0) > > > > @@ -99,9 +101,18 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > > > sgl = sg_next(sgl); > > > > } > > > > > > > > + if (block->cyclic) > > > > + flags = DMA_PREP_REPEAT; > > > > + else > > > > + flags = DMA_PREP_INTERRUPT; > > > > + > > > > + /* > > > > + * There's nothing preventing a cyclic transfer to replace an active > > > > + * cyclic one. So always set the EOT flag. > > > > > > What about the non-cyclic case? > > > > Non cyclic will also have DMA_PREP_LOAD_EOT which should stop an ongoing > > cyclic transfer. If there's an active, non cyclic, it's business as > > usual. The transfer get's queued and will fire after the current one > > ends. IOW, DMA_PREP_LOAD_EOT is only meaningful for active cyclic > > transfers (it's ignored for non-cyclic) > > > > - Nuno Sá > > > > > > > > > + */ > > > > desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, > > > > vecs, nents, dma_dir, > > > > - DMA_PREP_INTERRUPT); > > > > + flags | DMA_PREP_LOAD_EOT); > > > > kfree(vecs); > > > > } else { > > > > max_size = min(block->size, dmaengine_buffer->max_size); > > > > @@ -122,8 +133,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, > > > > if (!desc) > > > > return -ENOMEM; > > > > > > > > - desc->callback_result = iio_dmaengine_buffer_block_done; > > > > - desc->callback_param = block; > > > > + if (!block->cyclic) { > > > > + desc->callback_result = iio_dmaengine_buffer_block_done; > > > > + desc->callback_param = block; > > > > + } > > > > > > > > cookie = dmaengine_submit(desc); > > > > if (dma_submit_error(cookie)) > > > > > > > > --- > > > > base-commit: ae696dfa47c30016cd429b9db5e70b259b8f509e > > > > change-id: 20260609-iio-dma-cyclic-buffer-support-f18034f8f34c > > > > -- > > > > > > > > Thanks! > > > > - Nuno Sá > > > > > > > > > > > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-22 17:12 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-11 15:28 [PATCH] iio: buffer-dmaengine: Add support for cyclic DMA transfers Nuno Sá 2026-06-11 15:28 ` Nuno Sá via B4 Relay 2026-06-13 16:33 ` David Lechner 2026-06-15 8:21 ` Nuno Sá 2026-06-22 13:15 ` Nuno Sá 2026-06-22 15:15 ` David Lechner 2026-06-22 17:12 ` Jonathan Cameron
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.