From: Rosen Penev <rosenp@gmail.com>
To: dmaengine@vger.kernel.org
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
Vinod Koul <vkoul@kernel.org>, Frank Li <Frank.Li@kernel.org>,
Kees Cook <kees@kernel.org>,
"Gustavo A. R. Silva" <gustavoars@kernel.org>,
linux-kernel@vger.kernel.org (open list),
linux-hardening@vger.kernel.org (open list:KERNEL HARDENING (not
covered by other areas):Keyword:\b__counted_by(_le|_be|_ptr)?\b)
Subject: [PATCHv2 2/2] dmaengine: idma64: use sg_nents_for_dma to respect hardware descriptor length limit
Date: Sun, 12 Jul 2026 15:00:39 -0700 [thread overview]
Message-ID: <20260712220039.924958-3-rosenp@gmail.com> (raw)
In-Reply-To: <20260712220039.924958-1-rosenp@gmail.com>
The iDMA 64-bit hardware has a 17-bit block transfer size field in the
CTL_HI register (IDMA64C_CTLH_BLOCK_TS_MASK = 0x1ffff). When a
scatterlist entry exceeds this limit, the driver would silently
truncate the length, transferring fewer bytes than intended.
Use sg_nents_for_dma() to compute the number of hardware descriptors
needed after splitting large SG entries into chunks that fit within
the hardware limit. Split the loop to iterate over each chunk.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/idma64.c | 44 ++++++++++++++++++++++++++++++--------------
drivers/dma/idma64.h | 3 ++-
2 files changed, 32 insertions(+), 15 deletions(-)
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index d914f50ec309..6954ec2cdeae 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -287,27 +287,43 @@ static struct dma_async_tx_descriptor *idma64_prep_slave_sg(
struct idma64_chan *idma64c = to_idma64_chan(chan);
struct idma64_desc *desc;
struct scatterlist *sg;
- unsigned int i;
+ unsigned int i, nents;
+ int ndesc;
- desc = kzalloc_flex(*desc, hw, sg_len, GFP_NOWAIT);
+ ndesc = sg_nents_for_dma(sgl, sg_len, IDMA64C_CTLH_BLOCK_TS_MASK);
+ if (ndesc <= 0)
+ return NULL;
+
+ desc = kzalloc_flex(*desc, hw, ndesc, GFP_NOWAIT);
if (!desc)
return NULL;
- desc->ndesc = sg_len;
+ desc->ndesc = ndesc;
+ nents = 0;
for_each_sg(sgl, sg, sg_len, i) {
- struct idma64_hw_desc *hw = &desc->hw[i];
-
- /* Allocate DMA capable memory for hardware descriptor */
- hw->lli = dma_pool_alloc(idma64c->pool, GFP_NOWAIT, &hw->llp);
- if (!hw->lli) {
- desc->ndesc = i;
- idma64_desc_free(idma64c, desc);
- return NULL;
+ dma_addr_t addr = sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
+
+ while (len) {
+ struct idma64_hw_desc *hwdesc = &desc->hw[nents++];
+ unsigned int chunk = min(len, IDMA64C_CTLH_BLOCK_TS_MASK);
+
+ hwdesc->lli = dma_pool_alloc(idma64c->pool, GFP_NOWAIT,
+ &hwdesc->llp);
+ if (!hwdesc->lli) {
+ /* nents was already incremented by ++ above */
+ desc->ndesc = nents - 1;
+ idma64_desc_free(idma64c, desc);
+ return NULL;
+ }
+
+ hwdesc->phys = addr;
+ hwdesc->len = chunk;
+
+ addr += chunk;
+ len -= chunk;
}
-
- hw->phys = sg_dma_address(sg);
- hw->len = sg_dma_len(sg);
}
desc->direction = direction;
diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h
index 1a67dbb24db5..297a91594b31 100644
--- a/drivers/dma/idma64.h
+++ b/drivers/dma/idma64.h
@@ -8,6 +8,7 @@
#ifndef __DMA_IDMA64_H__
#define __DMA_IDMA64_H__
+#include <linux/bits.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/spinlock.h>
@@ -51,7 +52,7 @@
#define IDMA64C_CTLL_LLP_S_EN (1 << 28) /* src block chain */
/* Bitfields in CTL_HI */
-#define IDMA64C_CTLH_BLOCK_TS_MASK ((1 << 17) - 1)
+#define IDMA64C_CTLH_BLOCK_TS_MASK GENMASK_U32(16, 0)
#define IDMA64C_CTLH_BLOCK_TS(x) ((x) & IDMA64C_CTLH_BLOCK_TS_MASK)
#define IDMA64C_CTLH_DONE (1 << 17)
--
2.55.0
next prev parent reply other threads:[~2026-07-12 22:00 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-12 22:00 [PATCHv2 0/2] dmaengine: idma64: descriptor allocation and length limit fixes Rosen Penev
2026-07-12 22:00 ` [PATCHv2 1/2] dmaengine: idma64: use kzalloc_flex Rosen Penev
2026-07-12 22:11 ` sashiko-bot
2026-07-12 22:15 ` Rosen Penev
2026-07-13 11:57 ` Andy Shevchenko
2026-07-12 22:00 ` Rosen Penev [this message]
2026-07-13 12:13 ` [PATCHv2 2/2] dmaengine: idma64: use sg_nents_for_dma to respect hardware descriptor length limit Andy Shevchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260712220039.924958-3-rosenp@gmail.com \
--to=rosenp@gmail.com \
--cc=Frank.Li@kernel.org \
--cc=andriy.shevchenko@linux.intel.com \
--cc=dmaengine@vger.kernel.org \
--cc=gustavoars@kernel.org \
--cc=kees@kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox