DMA Engine development
 help / color / mirror / Atom feed
* [PATCH] dmaengine: axi-dmac: fix incorrect segment size calculation
@ 2026-11-05 13:15 Sergey Matsievskiy
  2026-11-05 13:26 ` sashiko-bot
  2026-11-05 17:16 ` Frank Li
  0 siblings, 2 replies; 4+ messages in thread
From: Sergey Matsievskiy @ 2026-11-05 13:15 UTC (permalink / raw)
  To: dmaengine; +Cc: lars, vkoul, Frank.Li, linux-kernel, Sergey Matsievskiy

When chan->max_length has a value of 0xffffffff (which is a possible IP
configuration), DIV_ROUND_UP returns 0, resulting in incorrect number of
segments calculation. Fix this by using DIV_ROUND_UP_ULL division
function.

Signed-off-by: Sergey Matsievskiy <matsievskiysv@gmail.com>
---
 drivers/dma/dma-axi-dmac.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index 02acde918117..0a308630e542 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -707,7 +707,7 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
 	unsigned int len;
 
 	/* Split into multiple equally sized segments if necessary */
-	num_segments = DIV_ROUND_UP(period_len, chan->max_length);
+	num_segments = DIV_ROUND_UP_ULL(period_len, chan->max_length);
 	segment_size = DIV_ROUND_UP(period_len, num_segments);
 	/* Take care of alignment */
 	segment_size = ((segment_size - 1) | chan->length_align_mask) + 1;
@@ -753,7 +753,7 @@ axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs,
 		return NULL;
 
 	for (i = 0; i < nb; i++)
-		num_sgs += DIV_ROUND_UP(vecs[i].len, chan->max_length);
+		num_sgs += DIV_ROUND_UP_ULL(vecs[i].len, chan->max_length);
 
 	desc = axi_dmac_alloc_desc(chan, num_sgs);
 	if (!desc)
@@ -840,7 +840,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
 		return NULL;
 
 	num_periods = buf_len / period_len;
-	num_segments = DIV_ROUND_UP(period_len, chan->max_length);
+	num_segments = DIV_ROUND_UP_ULL(period_len, chan->max_length);
 	num_sgs = num_periods * num_segments;
 
 	desc = axi_dmac_alloc_desc(chan, num_sgs);
-- 
2.47.3


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

* Re: [PATCH] dmaengine: axi-dmac: fix incorrect segment size calculation
  2026-11-05 13:15 [PATCH] dmaengine: axi-dmac: fix incorrect segment size calculation Sergey Matsievskiy
@ 2026-11-05 13:26 ` sashiko-bot
  2026-11-05 13:55   ` Sergey Matsievskiy
  2026-11-05 17:16 ` Frank Li
  1 sibling, 1 reply; 4+ messages in thread
From: sashiko-bot @ 2026-11-05 13:26 UTC (permalink / raw)
  To: Sergey Matsievskiy, dmaengine; +Cc: vkoul, Frank.Li

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] dmaengine: axi-dmac: 32-bit overflow in axi_dmac_prep_slave_sg()
--

commit 6fad587f5aff185e8ba37fde1bcd2a484b6fa19d
Author: Sergey Matsievskiy <matsievskiysv@gmail.com>

dmaengine: axi-dmac: fix incorrect segment size calculation

This commit switches segment count calculations in axi-dmac from DIV_ROUND_UP
to DIV_ROUND_UP_ULL to avoid 32-bit unsigned integer overflow when
chan->max_length is 0xffffffff.

> diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
> index d47ff27e1408f..bfa83ccfd7dc0 100644
> --- a/drivers/dma/dma-axi-dmac.c
> +++ b/drivers/dma/dma-axi-dmac.c
> @@ -706,7 +706,7 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
>  	unsigned int len;
>  
>  	/* Split into multiple equally sized segments if necessary */
> -	num_segments = DIV_ROUND_UP(period_len, chan->max_length);
> +	num_segments = DIV_ROUND_UP_ULL(period_len, chan->max_length);

[Severity: High]
Can axi_dmac_prep_slave_sg() under-allocate desc->sg[] and write out of
bounds on 32-bit architectures when chan->max_length is 0xffffffff?

While axi_dmac_fill_linear_sg(), axi_dmac_prep_peripheral_dma_vec(), and
axi_dmac_prep_dma_cyclic() now use DIV_ROUND_UP_ULL(), axi_dmac_prep_slave_sg()
still calculates num_sgs via sg_nents_for_dma() before calling
axi_dmac_alloc_desc() and axi_dmac_fill_linear_sg():

drivers/dma/dma-axi-dmac.c:axi_dmac_prep_slave_sg() {
	...
	num_sgs = sg_nents_for_dma(sgl, sg_len, chan->max_length);
	desc = axi_dmac_alloc_desc(chan, num_sgs);
	if (!desc)
		return NULL;

	dsg = desc->sg;

	for_each_sg(sgl, sg, sg_len, i) {
		...
		dsg = axi_dmac_fill_linear_sg(chan, direction, sg_dma_address(sg), 1,
			sg_dma_len(sg), dsg);
	}
	...
}

In lib/scatterlist.c, sg_nents_for_dma() uses DIV_ROUND_UP() with unsigned
int sg_dma_len(sg) and size_t len:

lib/scatterlist.c:sg_nents_for_dma() {
	...
	for_each_sg(sgl, sg, sglen, i)
		nents += DIV_ROUND_UP(sg_dma_len(sg), len);
	return nents;
}

On 32-bit architectures where size_t is 32 bits wide, passing len = 0xffffffff
causes DIV_ROUND_UP(sg_dma_len(sg), len) to overflow 32-bit arithmetic and
evaluate to 0 for any scatterlist entry with length >= 2.

When that happens, axi_dmac_alloc_desc(chan, num_sgs) either dereferences
desc->sg[num_sgs - 1].hw out of bounds when num_sgs is 0:

drivers/dma/dma-axi-dmac.c:axi_dmac_alloc_desc() {
	...
	/* The last hardware descriptor will trigger an interrupt */
	desc->sg[num_sgs - 1].hw->flags = AXI_DMAC_HW_FLAG_LAST | AXI_DMAC_HW_FLAG_IRQ;
	...
}

or allocates fewer sg entries than needed while the updated
axi_dmac_fill_linear_sg() computes num_segments = 1 via DIV_ROUND_UP_ULL()
and advances dsg past the end of desc->sg[].

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261105131547.305510-1-matsievskiysv@gmail.com?part=1

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

* Re: [PATCH] dmaengine: axi-dmac: fix incorrect segment size calculation
  2026-11-05 13:26 ` sashiko-bot
@ 2026-11-05 13:55   ` Sergey Matsievskiy
  0 siblings, 0 replies; 4+ messages in thread
From: Sergey Matsievskiy @ 2026-11-05 13:55 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: dmaengine, vkoul, Frank.Li

On Thu, Nov 05, 2026 at 01:26:06PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] dmaengine: axi-dmac: 32-bit overflow in axi_dmac_prep_slave_sg()

I don't think that this warning is applicable. Both arguments are 32 bit
integers and the result of the division should also fit into 32
bits. Intermediate promotion to 64 bit integers should not have negative side
effects.

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

* Re: [PATCH] dmaengine: axi-dmac: fix incorrect segment size calculation
  2026-11-05 13:15 [PATCH] dmaengine: axi-dmac: fix incorrect segment size calculation Sergey Matsievskiy
  2026-11-05 13:26 ` sashiko-bot
@ 2026-11-05 17:16 ` Frank Li
  1 sibling, 0 replies; 4+ messages in thread
From: Frank Li @ 2026-11-05 17:16 UTC (permalink / raw)
  To: Sergey Matsievskiy; +Cc: dmaengine, lars, vkoul, Frank.Li, linux-kernel

On Thu, Nov 05, 2026 at 04:15:47PM +0300, Sergey Matsievskiy wrote:
> [You don't often get email from matsievskiysv@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> When chan->max_length has a value of 0xffffffff (which is a possible IP
> configuration), DIV_ROUND_UP returns 0, resulting in incorrect number of
> segments calculation. Fix this by using DIV_ROUND_UP_ULL division
> function.
>
> Signed-off-by: Sergey Matsievskiy <matsievskiysv@gmail.com>
> ---

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

>  drivers/dma/dma-axi-dmac.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
> index 02acde918117..0a308630e542 100644
> --- a/drivers/dma/dma-axi-dmac.c
> +++ b/drivers/dma/dma-axi-dmac.c
> @@ -707,7 +707,7 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
>         unsigned int len;
>
>         /* Split into multiple equally sized segments if necessary */
> -       num_segments = DIV_ROUND_UP(period_len, chan->max_length);
> +       num_segments = DIV_ROUND_UP_ULL(period_len, chan->max_length);
>         segment_size = DIV_ROUND_UP(period_len, num_segments);
>         /* Take care of alignment */
>         segment_size = ((segment_size - 1) | chan->length_align_mask) + 1;
> @@ -753,7 +753,7 @@ axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs,
>                 return NULL;
>
>         for (i = 0; i < nb; i++)
> -               num_sgs += DIV_ROUND_UP(vecs[i].len, chan->max_length);
> +               num_sgs += DIV_ROUND_UP_ULL(vecs[i].len, chan->max_length);
>
>         desc = axi_dmac_alloc_desc(chan, num_sgs);
>         if (!desc)
> @@ -840,7 +840,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
>                 return NULL;
>
>         num_periods = buf_len / period_len;
> -       num_segments = DIV_ROUND_UP(period_len, chan->max_length);
> +       num_segments = DIV_ROUND_UP_ULL(period_len, chan->max_length);
>         num_sgs = num_periods * num_segments;
>
>         desc = axi_dmac_alloc_desc(chan, num_sgs);
> --
> 2.47.3
>

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

end of thread, other threads:[~2026-11-05 17:16 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 13:15 [PATCH] dmaengine: axi-dmac: fix incorrect segment size calculation Sergey Matsievskiy
2026-11-05 13:26 ` sashiko-bot
2026-11-05 13:55   ` Sergey Matsievskiy
2026-11-05 17:16 ` Frank Li

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