* [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining
2026-09-11 13:11 [PATCH v10 0/2] dmaengine: fsl-edma: Scatter/gather improvements Benoît Monin
@ 2026-09-11 13:11 ` Benoît Monin
2026-09-11 13:23 ` sashiko-bot
2026-09-11 14:14 ` Frank Li
0 siblings, 2 replies; 5+ messages in thread
From: Benoît Monin @ 2026-09-11 13:11 UTC (permalink / raw)
To: Frank Li, Vinod Koul
Cc: Thomas Petazzoni, Frank Li, imx, dmaengine, linux-kernel,
Benoît Monin
Implement dynamic linking of scatter/gather transfers to enable
chaining multiple DMA descriptors without stopping the channel.
This avoids waiting for the channel to go idle if there is another
transaction already issued.
Add fsl_edma_link_sg() to dynamically link the last TCD of a previously
issued descriptor to the first TCD of a new descriptor by setting the
scatter/gather address and the E_SG flag, and keeping the channel active
by clearing the DREQ bit.
Also in fsl_edma_link_sg(), assign a non-zero identifier to the new
descriptor that is stored in the EDMA_TCD_CSR_LINKCH field of the CSR
of each TCD, after checking that the descriptors are not using channel
linking. The use of this field (MAJORLINKCH in the datasheet) as an
identifier for dynamic scatter/gather is suggested in the i.MX93 datasheet.
When the last issued descriptor is the one currently active on the
channel and has a single TCD, the scatter/gather address and CSR are
also written directly to the hardware registers to ensure the link
takes effect immediately, unless the DMA controller requires the DONE
bit to be cleared for the CSR change to take effect. Clearing the DONE
bit would disrupt the interrupt handler.
Linking is done in fsl_edma_issue_pending(), which iterates over the
submitted descriptors, links each one to the previously issued
descriptor via fsl_edma_link_sg(), and then moves it to the issued
list. This ensures that transactions are linked in the order they were
issued. Linking of a descriptor is limited to 31 outstanding descriptors
on the issued list so the identifier fits in the LINKCH field of the CSR
register. The value of zero is left to identify non-linked descriptors.
Update fsl_edma_xfer_desc() to avoid re-initializing the hardware when a
transfer is already in progress, allowing seamless chaining of descriptors.
Modify the transfer completion handler to check the DONE flag in the
channel CSR before marking the transfer complete. Since this flag is only
available on SoC with the split registers layout, only link transactions
for DMA controllers flagged with newly added FSL_EDMA_DRV_CSR_LINKCH. This
flag is set for eDMA3 and EDMA4 controllers which are able to perform
dynamic scatter/gather linking.
The completion handler also reaps issued descriptors whose link channel ID
(EDMA_TCD_CSR_LINKCH) has already been passed by the hardware, marking
them as completed even if their corresponding interrupt has been missed.
Add trace event for scatter/gather linking operations.
Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
drivers/dma/fsl-edma-common.c | 138 ++++++++++++++++++++++++++++++++++++++++--
drivers/dma/fsl-edma-common.h | 11 +++-
drivers/dma/fsl-edma-trace.h | 5 ++
3 files changed, 146 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index c5f5951c988b..76fbd2bc5154 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -55,10 +55,36 @@ void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan)
}
if (!fsl_chan->edesc->iscyclic) {
- list_del(&fsl_chan->edesc->vdesc.node);
- vchan_cookie_complete(&fsl_chan->edesc->vdesc);
+ u16 csr = edma_read_tcdreg(fsl_chan, csr);
+ u8 link_sg_id = FIELD_GET(EDMA_TCD_CSR_LINKCH, csr);
+ struct virt_dma_desc *vdesc, *tmp;
+
+ /* Channel is DONE when a TCD with D_REQ set completes */
+ if (!(fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_SPLIT_REG) ||
+ (edma_readl_chreg(fsl_chan, ch_csr) & EDMA_V3_CH_CSR_DONE)) {
+ fsl_chan->status = DMA_COMPLETE;
+ }
+
+ list_for_each_entry_safe(vdesc, tmp, &fsl_chan->vchan.desc_issued, node) {
+ struct fsl_edma_desc *fsl_desc = to_fsl_edma_desc(vdesc);
+ bool id_match = (link_sg_id == fsl_desc->link_sg_id);
+
+ /*
+ * If the transfer is still running,
+ * don't mark as complete the current descriptor
+ */
+ if (id_match && fsl_chan->status != DMA_COMPLETE)
+ break;
+
+ list_del(&vdesc->node);
+ vchan_cookie_complete(vdesc);
+
+ if (id_match)
+ break;
+ }
+
fsl_chan->edesc = NULL;
- fsl_chan->status = DMA_COMPLETE;
+
} else {
vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
}
@@ -931,14 +957,99 @@ void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
if (!vdesc)
return;
fsl_chan->edesc = to_fsl_edma_desc(vdesc);
- fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
- fsl_edma_enable_request(fsl_chan);
- fsl_chan->status = DMA_IN_PROGRESS;
+
+ if (fsl_chan->status != DMA_IN_PROGRESS) {
+ fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
+ fsl_edma_enable_request(fsl_chan);
+ fsl_chan->status = DMA_IN_PROGRESS;
+ }
+}
+
+static void fsl_edma_link_sg(struct fsl_edma_chan *fsl_chan, struct fsl_edma_desc *fsl_desc)
+{
+ u32 flags = fsl_edma_drvflags(fsl_chan);
+ struct fsl_edma_hw_tcd *last_tcd;
+ struct fsl_edma_desc *prev_desc;
+ struct virt_dma_desc *vdesc;
+ u16 last_csr;
+
+ lockdep_assert_held(&fsl_chan->vchan.lock);
+
+ if (!(flags & FSL_EDMA_DRV_CSR_LINKCH) || fsl_desc->iscyclic)
+ return;
+
+ vdesc = list_last_entry_or_null(&fsl_chan->vchan.desc_issued,
+ struct virt_dma_desc, node);
+ if (!vdesc)
+ return;
+
+ prev_desc = to_fsl_edma_desc(vdesc);
+ if (prev_desc->iscyclic)
+ return;
+
+ last_tcd = prev_desc->tcd[prev_desc->n_tcds - 1].vtcd;
+ last_csr = fsl_edma_get_tcd_to_cpu(fsl_chan, last_tcd, csr);
+
+ for (unsigned int i = 0; i < fsl_desc->n_tcds; i++) {
+ struct fsl_edma_hw_tcd *tcd = fsl_desc->tcd[i].vtcd;
+
+ if (fsl_edma_get_tcd_to_cpu(fsl_chan, tcd, csr) & EDMA_TCD_CSR_E_LINK)
+ return;
+ }
+
+ if (!(last_csr & EDMA_TCD_CSR_D_REQ) ||
+ last_csr & EDMA_TCD_CSR_E_LINK)
+ return;
+
+ /* Set a non-zero linked SG identifier to all TCD of the new descriptor */
+ fsl_chan->link_sg_id++;
+ if (fsl_chan->link_sg_id > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
+ fsl_chan->link_sg_id = 1;
+
+ fsl_desc->link_sg_id = fsl_chan->link_sg_id;
+
+ for (unsigned int i = 0; i < fsl_desc->n_tcds; i++) {
+ struct fsl_edma_hw_tcd *tcd = fsl_desc->tcd[i].vtcd;
+ u16 csr = fsl_edma_get_tcd_to_cpu(fsl_chan, tcd, csr);
+
+ csr |= FIELD_PREP(EDMA_TCD_CSR_LINKCH, fsl_chan->link_sg_id);
+ fsl_edma_set_tcd_to_le(fsl_chan, tcd, csr, csr);
+ }
+
+ /*
+ * Set DLAST_SGA before enabling E_SG in CSR: if the DMA engine
+ * only picks up the former, it updates DADDR at end of transfer,
+ * which is not reused.
+ */
+ fsl_edma_set_tcd_to_le(fsl_chan, last_tcd, fsl_desc->tcd[0].ptcd, dlast_sga);
+
+ dma_wmb();
+
+ last_csr &= ~EDMA_TCD_CSR_D_REQ;
+ last_csr |= EDMA_TCD_CSR_E_SG;
+ fsl_edma_set_tcd_to_le(fsl_chan, last_tcd, last_csr, csr);
+
+ /*
+ * Update the registers if the engine already loaded the TCD,
+ * unless doing so requires clearing the DONE bit, as that could
+ * lead to lost completion.
+ */
+ if (prev_desc == fsl_chan->edesc &&
+ prev_desc->n_tcds == 1 &&
+ !(flags & FSL_EDMA_DRV_CLEAR_DONE_E_SG)) {
+ edma_cp_tcd_to_reg(fsl_chan, last_tcd, dlast_sga);
+ edma_cp_tcd_to_reg(fsl_chan, last_tcd, csr);
+ }
+
+ trace_edma_link_sg(fsl_chan, last_tcd);
}
void fsl_edma_issue_pending(struct dma_chan *chan)
{
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ struct virt_dma_desc *vdesc, *tmp;
+ size_t issued_count = 0;
+ struct list_head *pos;
unsigned long flags;
spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
@@ -949,6 +1060,21 @@ void fsl_edma_issue_pending(struct dma_chan *chan)
return;
}
+ /* Count the issued desc up to the maximum number of linked SG id */
+ list_for_each(pos, &fsl_chan->vchan.desc_issued) {
+ if (++issued_count > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
+ break;
+ }
+
+ /* Link the SG descriptors with the available identifiers */
+ list_for_each_entry_safe(vdesc, tmp, &fsl_chan->vchan.desc_submitted, node) {
+ if (++issued_count > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
+ break;
+ fsl_edma_link_sg(fsl_chan, to_fsl_edma_desc(vdesc));
+ list_move_tail(&vdesc->node, &fsl_chan->vchan.desc_issued);
+ }
+
+ /* Issue the rest of the descriptors unlinked */
if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
fsl_edma_xfer_desc(fsl_chan);
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
index 0d028048701d..cbb077e98f55 100644
--- a/drivers/dma/fsl-edma-common.h
+++ b/drivers/dma/fsl-edma-common.h
@@ -42,6 +42,7 @@
#define EDMA_TCD_CSR_E_LINK BIT(5)
#define EDMA_TCD_CSR_ACTIVE BIT(6)
#define EDMA_TCD_CSR_DONE BIT(7)
+#define EDMA_TCD_CSR_LINKCH GENMASK(12, 8)
#define EDMA_V3_TCD_NBYTES_MLOFF_NBYTES(x) ((x) & GENMASK(9, 0))
#define EDMA_V3_TCD_NBYTES_MLOFF(x) (x << 10)
@@ -169,6 +170,7 @@ struct fsl_edma_chan {
struct dma_slave_config cfg;
u32 attr;
bool is_sw;
+ u8 link_sg_id;
struct dma_pool *tcd_pool;
dma_addr_t dma_dev_addr;
u32 dma_dev_size;
@@ -199,6 +201,7 @@ struct fsl_edma_desc {
struct virt_dma_desc vdesc;
struct fsl_edma_chan *echan;
bool iscyclic;
+ u8 link_sg_id;
enum dma_transfer_direction dirn;
unsigned int n_tcds;
struct fsl_edma_sw_tcd tcd[];
@@ -225,6 +228,8 @@ struct fsl_edma_desc {
#define FSL_EDMA_DRV_TCD64 BIT(15)
/* All channel ERR IRQ share one IRQ line */
#define FSL_EDMA_DRV_ERRIRQ_SHARE BIT(16)
+/* Major link channel in CSR used for linking SG descriptors */
+#define FSL_EDMA_DRV_CSR_LINKCH BIT(17)
#define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \
@@ -232,13 +237,15 @@ struct fsl_edma_desc {
FSL_EDMA_DRV_DEV_TO_DEV | \
FSL_EDMA_DRV_ALIGN_64BYTE | \
FSL_EDMA_DRV_CLEAR_DONE_E_SG | \
- FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
+ FSL_EDMA_DRV_CLEAR_DONE_E_LINK | \
+ FSL_EDMA_DRV_CSR_LINKCH)
#define FSL_EDMA_DRV_EDMA4 (FSL_EDMA_DRV_SPLIT_REG | \
FSL_EDMA_DRV_BUS_8BYTE | \
FSL_EDMA_DRV_DEV_TO_DEV | \
FSL_EDMA_DRV_ALIGN_64BYTE | \
- FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
+ FSL_EDMA_DRV_CLEAR_DONE_E_LINK | \
+ FSL_EDMA_DRV_CSR_LINKCH)
struct fsl_edma_drvdata {
u32 dmamuxs; /* only used before v3 */
diff --git a/drivers/dma/fsl-edma-trace.h b/drivers/dma/fsl-edma-trace.h
index 45d964a3726d..f4b0021d2bd0 100644
--- a/drivers/dma/fsl-edma-trace.h
+++ b/drivers/dma/fsl-edma-trace.h
@@ -121,6 +121,11 @@ DEFINE_EVENT(edma_log_tcd, edma_fill_tcd,
TP_ARGS(chan, tcd)
);
+DEFINE_EVENT(edma_log_tcd, edma_link_sg,
+ TP_PROTO(struct fsl_edma_chan *chan, void *tcd),
+ TP_ARGS(chan, tcd)
+);
+
#endif
/* this part must be outside header guard */
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining
2026-09-11 13:11 ` [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining Benoît Monin
@ 2026-09-11 13:23 ` sashiko-bot
2026-09-11 14:14 ` Frank Li
1 sibling, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-11 13:23 UTC (permalink / raw)
To: Benoît Monin; +Cc: Frank.Li, dmaengine, imx, vkoul
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The completion handler erroneously completes and drops pending descriptors if hardware channel linking (E_LINK) is used.
--
commit 1703b2e67fb35f2931ebc1bf4444955c605a74fd
Author: Benoît Monin <benoit.monin@bootlin.com>
dmaengine: fsl-edma: Support dynamic scatter/gather chaining
This commit implements dynamic linking of scatter/gather transfers to allow
chaining multiple DMA descriptors without stopping the channel. It adds
fsl_edma_link_sg() to link descriptors and updates the transfer completion
handler to reap issued descriptors using the EDMA_TCD_CSR_LINKCH field.
> diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> index c5f5951c988be..76fbd2bc5154f 100644
> --- a/drivers/dma/fsl-edma-common.c
> +++ b/drivers/dma/fsl-edma-common.c
> @@ -55,10 +55,36 @@ void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan)
[ ... ]
> if (!fsl_chan->edesc->iscyclic) {
> - list_del(&fsl_chan->edesc->vdesc.node);
> - vchan_cookie_complete(&fsl_chan->edesc->vdesc);
> + u16 csr = edma_read_tcdreg(fsl_chan, csr);
> + u8 link_sg_id = FIELD_GET(EDMA_TCD_CSR_LINKCH, csr);
[Severity: High]
When hardware channel linking is used (the E_LINK bit is set in the CSR),
doesn't the EDMA_TCD_CSR_LINKCH field represent the MAJORLINKCH target
channel rather than a software scatter/gather ID?
If fsl_edma_link_sg() explicitly skips assigning dynamic SG IDs to
descriptors with E_LINK set, their software fsl_desc->link_sg_id will
remain 0. If this interrupt handler extracts a target channel number
(e.g., 15) into link_sg_id here, it will fail to match the software ID of 0.
> + struct virt_dma_desc *vdesc, *tmp;
> +
> + /* Channel is DONE when a TCD with D_REQ set completes */
> + if (!(fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_SPLIT_REG) ||
> + (edma_readl_chreg(fsl_chan, ch_csr) & EDMA_V3_CH_CSR_DONE)) {
> + fsl_chan->status = DMA_COMPLETE;
> + }
> +
> + list_for_each_entry_safe(vdesc, tmp, &fsl_chan->vchan.desc_issued, node) {
> + struct fsl_edma_desc *fsl_desc = to_fsl_edma_desc(vdesc);
> + bool id_match = (link_sg_id == fsl_desc->link_sg_id);
> +
> + /*
> + * If the transfer is still running,
> + * don't mark as complete the current descriptor
> + */
> + if (id_match && fsl_chan->status != DMA_COMPLETE)
> + break;
> +
> + list_del(&vdesc->node);
> + vchan_cookie_complete(vdesc);
> +
> + if (id_match)
> + break;
> + }
[Severity: High]
Following from the E_LINK mismatch above, if id_match evaluates to false
for a descriptor using hardware channel linking, will this loop erroneously
continue deleting and completing all subsequent pending descriptors in the
desc_issued list?
Since their software IDs will also fail to match the extracted hardware
channel number, it looks like these pending descriptors will be silently
dropped and completed without ever being submitted to the hardware.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260911-fsl-edma-dyn-sg-v10-0-700eb72def57@bootlin.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining
2026-09-11 13:11 ` [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining Benoît Monin
2026-09-11 13:23 ` sashiko-bot
@ 2026-09-11 14:14 ` Frank Li
1 sibling, 0 replies; 5+ messages in thread
From: Frank Li @ 2026-09-11 14:14 UTC (permalink / raw)
To: Benoît Monin
Cc: Frank Li, Vinod Koul, Thomas Petazzoni, Frank Li, imx, dmaengine,
linux-kernel
On Fri, Sep 11, 2026 at 03:11:37PM +0200, Benoît Monin wrote:
> Implement dynamic linking of scatter/gather transfers to enable
> chaining multiple DMA descriptors without stopping the channel.
> This avoids waiting for the channel to go idle if there is another
> transaction already issued.
>
> Add fsl_edma_link_sg() to dynamically link the last TCD of a previously
> issued descriptor to the first TCD of a new descriptor by setting the
> scatter/gather address and the E_SG flag, and keeping the channel active
> by clearing the DREQ bit.
>
> Also in fsl_edma_link_sg(), assign a non-zero identifier to the new
> descriptor that is stored in the EDMA_TCD_CSR_LINKCH field of the CSR
> of each TCD, after checking that the descriptors are not using channel
> linking. The use of this field (MAJORLINKCH in the datasheet) as an
> identifier for dynamic scatter/gather is suggested in the i.MX93 datasheet.
>
> When the last issued descriptor is the one currently active on the
> channel and has a single TCD, the scatter/gather address and CSR are
> also written directly to the hardware registers to ensure the link
> takes effect immediately, unless the DMA controller requires the DONE
> bit to be cleared for the CSR change to take effect. Clearing the DONE
> bit would disrupt the interrupt handler.
>
> Linking is done in fsl_edma_issue_pending(), which iterates over the
> submitted descriptors, links each one to the previously issued
> descriptor via fsl_edma_link_sg(), and then moves it to the issued
> list. This ensures that transactions are linked in the order they were
> issued. Linking of a descriptor is limited to 31 outstanding descriptors
> on the issued list so the identifier fits in the LINKCH field of the CSR
> register. The value of zero is left to identify non-linked descriptors.
>
> Update fsl_edma_xfer_desc() to avoid re-initializing the hardware when a
> transfer is already in progress, allowing seamless chaining of descriptors.
>
> Modify the transfer completion handler to check the DONE flag in the
> channel CSR before marking the transfer complete. Since this flag is only
> available on SoC with the split registers layout, only link transactions
> for DMA controllers flagged with newly added FSL_EDMA_DRV_CSR_LINKCH. This
> flag is set for eDMA3 and EDMA4 controllers which are able to perform
> dynamic scatter/gather linking.
>
> The completion handler also reaps issued descriptors whose link channel ID
> (EDMA_TCD_CSR_LINKCH) has already been passed by the hardware, marking
> them as completed even if their corresponding interrupt has been missed.
>
> Add trace event for scatter/gather linking operations.
>
> Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/dma/fsl-edma-common.c | 138 ++++++++++++++++++++++++++++++++++++++++--
> drivers/dma/fsl-edma-common.h | 11 +++-
> drivers/dma/fsl-edma-trace.h | 5 ++
> 3 files changed, 146 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> index c5f5951c988b..76fbd2bc5154 100644
> --- a/drivers/dma/fsl-edma-common.c
> +++ b/drivers/dma/fsl-edma-common.c
> @@ -55,10 +55,36 @@ void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan)
> }
>
> if (!fsl_chan->edesc->iscyclic) {
> - list_del(&fsl_chan->edesc->vdesc.node);
> - vchan_cookie_complete(&fsl_chan->edesc->vdesc);
> + u16 csr = edma_read_tcdreg(fsl_chan, csr);
> + u8 link_sg_id = FIELD_GET(EDMA_TCD_CSR_LINKCH, csr);
> + struct virt_dma_desc *vdesc, *tmp;
> +
> + /* Channel is DONE when a TCD with D_REQ set completes */
> + if (!(fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_SPLIT_REG) ||
> + (edma_readl_chreg(fsl_chan, ch_csr) & EDMA_V3_CH_CSR_DONE)) {
> + fsl_chan->status = DMA_COMPLETE;
> + }
> +
> + list_for_each_entry_safe(vdesc, tmp, &fsl_chan->vchan.desc_issued, node) {
> + struct fsl_edma_desc *fsl_desc = to_fsl_edma_desc(vdesc);
> + bool id_match = (link_sg_id == fsl_desc->link_sg_id);
> +
> + /*
> + * If the transfer is still running,
> + * don't mark as complete the current descriptor
> + */
> + if (id_match && fsl_chan->status != DMA_COMPLETE)
> + break;
> +
> + list_del(&vdesc->node);
> + vchan_cookie_complete(vdesc);
> +
> + if (id_match)
> + break;
> + }
> +
> fsl_chan->edesc = NULL;
> - fsl_chan->status = DMA_COMPLETE;
> +
> } else {
> vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
> }
> @@ -931,14 +957,99 @@ void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
> if (!vdesc)
> return;
> fsl_chan->edesc = to_fsl_edma_desc(vdesc);
> - fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
> - fsl_edma_enable_request(fsl_chan);
> - fsl_chan->status = DMA_IN_PROGRESS;
> +
> + if (fsl_chan->status != DMA_IN_PROGRESS) {
> + fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
> + fsl_edma_enable_request(fsl_chan);
> + fsl_chan->status = DMA_IN_PROGRESS;
> + }
> +}
> +
> +static void fsl_edma_link_sg(struct fsl_edma_chan *fsl_chan, struct fsl_edma_desc *fsl_desc)
> +{
> + u32 flags = fsl_edma_drvflags(fsl_chan);
> + struct fsl_edma_hw_tcd *last_tcd;
> + struct fsl_edma_desc *prev_desc;
> + struct virt_dma_desc *vdesc;
> + u16 last_csr;
> +
> + lockdep_assert_held(&fsl_chan->vchan.lock);
> +
> + if (!(flags & FSL_EDMA_DRV_CSR_LINKCH) || fsl_desc->iscyclic)
> + return;
> +
> + vdesc = list_last_entry_or_null(&fsl_chan->vchan.desc_issued,
> + struct virt_dma_desc, node);
> + if (!vdesc)
> + return;
> +
> + prev_desc = to_fsl_edma_desc(vdesc);
> + if (prev_desc->iscyclic)
> + return;
> +
> + last_tcd = prev_desc->tcd[prev_desc->n_tcds - 1].vtcd;
> + last_csr = fsl_edma_get_tcd_to_cpu(fsl_chan, last_tcd, csr);
> +
> + for (unsigned int i = 0; i < fsl_desc->n_tcds; i++) {
> + struct fsl_edma_hw_tcd *tcd = fsl_desc->tcd[i].vtcd;
> +
> + if (fsl_edma_get_tcd_to_cpu(fsl_chan, tcd, csr) & EDMA_TCD_CSR_E_LINK)
> + return;
> + }
> +
> + if (!(last_csr & EDMA_TCD_CSR_D_REQ) ||
> + last_csr & EDMA_TCD_CSR_E_LINK)
> + return;
> +
> + /* Set a non-zero linked SG identifier to all TCD of the new descriptor */
> + fsl_chan->link_sg_id++;
> + if (fsl_chan->link_sg_id > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
> + fsl_chan->link_sg_id = 1;
> +
> + fsl_desc->link_sg_id = fsl_chan->link_sg_id;
> +
> + for (unsigned int i = 0; i < fsl_desc->n_tcds; i++) {
> + struct fsl_edma_hw_tcd *tcd = fsl_desc->tcd[i].vtcd;
> + u16 csr = fsl_edma_get_tcd_to_cpu(fsl_chan, tcd, csr);
> +
> + csr |= FIELD_PREP(EDMA_TCD_CSR_LINKCH, fsl_chan->link_sg_id);
> + fsl_edma_set_tcd_to_le(fsl_chan, tcd, csr, csr);
> + }
> +
> + /*
> + * Set DLAST_SGA before enabling E_SG in CSR: if the DMA engine
> + * only picks up the former, it updates DADDR at end of transfer,
> + * which is not reused.
> + */
> + fsl_edma_set_tcd_to_le(fsl_chan, last_tcd, fsl_desc->tcd[0].ptcd, dlast_sga);
> +
> + dma_wmb();
> +
> + last_csr &= ~EDMA_TCD_CSR_D_REQ;
> + last_csr |= EDMA_TCD_CSR_E_SG;
> + fsl_edma_set_tcd_to_le(fsl_chan, last_tcd, last_csr, csr);
> +
> + /*
> + * Update the registers if the engine already loaded the TCD,
> + * unless doing so requires clearing the DONE bit, as that could
> + * lead to lost completion.
> + */
> + if (prev_desc == fsl_chan->edesc &&
> + prev_desc->n_tcds == 1 &&
> + !(flags & FSL_EDMA_DRV_CLEAR_DONE_E_SG)) {
> + edma_cp_tcd_to_reg(fsl_chan, last_tcd, dlast_sga);
> + edma_cp_tcd_to_reg(fsl_chan, last_tcd, csr);
> + }
> +
> + trace_edma_link_sg(fsl_chan, last_tcd);
> }
>
> void fsl_edma_issue_pending(struct dma_chan *chan)
> {
> struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> + struct virt_dma_desc *vdesc, *tmp;
> + size_t issued_count = 0;
> + struct list_head *pos;
> unsigned long flags;
>
> spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> @@ -949,6 +1060,21 @@ void fsl_edma_issue_pending(struct dma_chan *chan)
> return;
> }
>
> + /* Count the issued desc up to the maximum number of linked SG id */
> + list_for_each(pos, &fsl_chan->vchan.desc_issued) {
> + if (++issued_count > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
> + break;
> + }
> +
> + /* Link the SG descriptors with the available identifiers */
> + list_for_each_entry_safe(vdesc, tmp, &fsl_chan->vchan.desc_submitted, node) {
> + if (++issued_count > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
> + break;
> + fsl_edma_link_sg(fsl_chan, to_fsl_edma_desc(vdesc));
> + list_move_tail(&vdesc->node, &fsl_chan->vchan.desc_issued);
> + }
> +
> + /* Issue the rest of the descriptors unlinked */
> if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
> fsl_edma_xfer_desc(fsl_chan);
>
> diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
> index 0d028048701d..cbb077e98f55 100644
> --- a/drivers/dma/fsl-edma-common.h
> +++ b/drivers/dma/fsl-edma-common.h
> @@ -42,6 +42,7 @@
> #define EDMA_TCD_CSR_E_LINK BIT(5)
> #define EDMA_TCD_CSR_ACTIVE BIT(6)
> #define EDMA_TCD_CSR_DONE BIT(7)
> +#define EDMA_TCD_CSR_LINKCH GENMASK(12, 8)
>
> #define EDMA_V3_TCD_NBYTES_MLOFF_NBYTES(x) ((x) & GENMASK(9, 0))
> #define EDMA_V3_TCD_NBYTES_MLOFF(x) (x << 10)
> @@ -169,6 +170,7 @@ struct fsl_edma_chan {
> struct dma_slave_config cfg;
> u32 attr;
> bool is_sw;
> + u8 link_sg_id;
> struct dma_pool *tcd_pool;
> dma_addr_t dma_dev_addr;
> u32 dma_dev_size;
> @@ -199,6 +201,7 @@ struct fsl_edma_desc {
> struct virt_dma_desc vdesc;
> struct fsl_edma_chan *echan;
> bool iscyclic;
> + u8 link_sg_id;
> enum dma_transfer_direction dirn;
> unsigned int n_tcds;
> struct fsl_edma_sw_tcd tcd[];
> @@ -225,6 +228,8 @@ struct fsl_edma_desc {
> #define FSL_EDMA_DRV_TCD64 BIT(15)
> /* All channel ERR IRQ share one IRQ line */
> #define FSL_EDMA_DRV_ERRIRQ_SHARE BIT(16)
> +/* Major link channel in CSR used for linking SG descriptors */
> +#define FSL_EDMA_DRV_CSR_LINKCH BIT(17)
>
>
> #define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \
> @@ -232,13 +237,15 @@ struct fsl_edma_desc {
> FSL_EDMA_DRV_DEV_TO_DEV | \
> FSL_EDMA_DRV_ALIGN_64BYTE | \
> FSL_EDMA_DRV_CLEAR_DONE_E_SG | \
> - FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
> + FSL_EDMA_DRV_CLEAR_DONE_E_LINK | \
> + FSL_EDMA_DRV_CSR_LINKCH)
>
> #define FSL_EDMA_DRV_EDMA4 (FSL_EDMA_DRV_SPLIT_REG | \
> FSL_EDMA_DRV_BUS_8BYTE | \
> FSL_EDMA_DRV_DEV_TO_DEV | \
> FSL_EDMA_DRV_ALIGN_64BYTE | \
> - FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
> + FSL_EDMA_DRV_CLEAR_DONE_E_LINK | \
> + FSL_EDMA_DRV_CSR_LINKCH)
>
> struct fsl_edma_drvdata {
> u32 dmamuxs; /* only used before v3 */
> diff --git a/drivers/dma/fsl-edma-trace.h b/drivers/dma/fsl-edma-trace.h
> index 45d964a3726d..f4b0021d2bd0 100644
> --- a/drivers/dma/fsl-edma-trace.h
> +++ b/drivers/dma/fsl-edma-trace.h
> @@ -121,6 +121,11 @@ DEFINE_EVENT(edma_log_tcd, edma_fill_tcd,
> TP_ARGS(chan, tcd)
> );
>
> +DEFINE_EVENT(edma_log_tcd, edma_link_sg,
> + TP_PROTO(struct fsl_edma_chan *chan, void *tcd),
> + TP_ARGS(chan, tcd)
> +);
> +
> #endif
>
> /* this part must be outside header guard */
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining
@ 2026-09-23 13:16 kernel test robot
0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-09-23 13:16 UTC (permalink / raw)
To: oe-kbuild; +Cc: lkp
::::::
:::::: Manual check reason: "linux-review patch is more than 7 days old, verify it wasn't already superseded"
::::::
BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20260911-fsl-edma-dyn-sg-v10-2-700eb72def57@bootlin.com>
References: <20260911-fsl-edma-dyn-sg-v10-2-700eb72def57@bootlin.com>
TO: "Benoît Monin" <benoit.monin@bootlin.com>
TO: Frank Li <Frank.Li@nxp.com>
TO: Vinod Koul <vkoul@kernel.org>
CC: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
CC: imx@lists.linux.dev
CC: dmaengine@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: "Benoît Monin" <benoit.monin@bootlin.com>
Hi Benoît,
kernel test robot noticed the following build errors:
[auto build test ERROR on cee9395acd8043be0644b25c34bfa86623f2b935]
url: https://github.com/intel-lab-lkp/linux/commits/Beno-t-Monin/dmaengine-fsl-edma-Implement-device_prep_peripheral_dma_vec/20260911-151136
base: cee9395acd8043be0644b25c34bfa86623f2b935
patch link: https://lore.kernel.org/r/20260911-fsl-edma-dyn-sg-v10-2-700eb72def57%40bootlin.com
patch subject: [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining
:::::: branch date: 12 days ago
:::::: commit date: 12 days ago
config: sparc-randconfig-r2201-20260923 (https://download.01.org/0day-ci/archive/20260923/202609231550.rY6WcsbN-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 11.5.0
smatch: v0.5.0-9187-g5189e3fb
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260923/202609231550.rY6WcsbN-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/r/202609231550.rY6WcsbN-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/dma/fsl-edma-common.c: In function 'fsl_edma_prep_peripheral_dma_vec':
>> drivers/dma/fsl-edma-common.c:758:55: error: implicit declaration of function 'FIELD_MAX' [-Werror=implicit-function-declaration]
758 | if (!nbytes || vecs[i].len / nbytes > FIELD_MAX(EDMA_TCD_ITER_MASK))
| ^~~~~~~~~
cc1: some warnings being treated as errors
vim +/FIELD_MAX +758 drivers/dma/fsl-edma-common.c
9d831528a6567d Angelo Dureghello 2018-08-19 675
526bb30b847c23 Benoît Monin 2026-09-11 676 struct dma_async_tx_descriptor *
526bb30b847c23 Benoît Monin 2026-09-11 677 fsl_edma_prep_peripheral_dma_vec(struct dma_chan *chan, const struct dma_vec *vecs,
526bb30b847c23 Benoît Monin 2026-09-11 678 size_t nb, enum dma_transfer_direction direction,
526bb30b847c23 Benoît Monin 2026-09-11 679 unsigned long flags)
526bb30b847c23 Benoît Monin 2026-09-11 680 {
526bb30b847c23 Benoît Monin 2026-09-11 681 struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
526bb30b847c23 Benoît Monin 2026-09-11 682 dma_addr_t src_addr, dst_addr, last_sg;
526bb30b847c23 Benoît Monin 2026-09-11 683 struct fsl_edma_desc *fsl_desc;
526bb30b847c23 Benoît Monin 2026-09-11 684 u16 soff, doff, iter;
526bb30b847c23 Benoît Monin 2026-09-11 685 u32 nbytes;
526bb30b847c23 Benoît Monin 2026-09-11 686 int i;
526bb30b847c23 Benoît Monin 2026-09-11 687
526bb30b847c23 Benoît Monin 2026-09-11 688 if (!is_slave_direction(direction))
526bb30b847c23 Benoît Monin 2026-09-11 689 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 690
526bb30b847c23 Benoît Monin 2026-09-11 691 if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
526bb30b847c23 Benoît Monin 2026-09-11 692 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 693
526bb30b847c23 Benoît Monin 2026-09-11 694 fsl_desc = fsl_edma_alloc_desc(fsl_chan, nb);
526bb30b847c23 Benoît Monin 2026-09-11 695 if (!fsl_desc)
526bb30b847c23 Benoît Monin 2026-09-11 696 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 697 fsl_desc->iscyclic = flags & DMA_PREP_REPEAT;
526bb30b847c23 Benoît Monin 2026-09-11 698 fsl_desc->dirn = direction;
526bb30b847c23 Benoît Monin 2026-09-11 699
526bb30b847c23 Benoît Monin 2026-09-11 700 if (direction == DMA_MEM_TO_DEV) {
526bb30b847c23 Benoît Monin 2026-09-11 701 if (!fsl_chan->cfg.src_addr_width)
526bb30b847c23 Benoît Monin 2026-09-11 702 fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 703 fsl_chan->attr =
526bb30b847c23 Benoît Monin 2026-09-11 704 fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
526bb30b847c23 Benoît Monin 2026-09-11 705 fsl_chan->cfg.dst_addr_width);
526bb30b847c23 Benoît Monin 2026-09-11 706 nbytes = fsl_chan->cfg.dst_addr_width * fsl_chan->cfg.dst_maxburst;
526bb30b847c23 Benoît Monin 2026-09-11 707 } else {
526bb30b847c23 Benoît Monin 2026-09-11 708 if (!fsl_chan->cfg.dst_addr_width)
526bb30b847c23 Benoît Monin 2026-09-11 709 fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 710 fsl_chan->attr =
526bb30b847c23 Benoît Monin 2026-09-11 711 fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
526bb30b847c23 Benoît Monin 2026-09-11 712 fsl_chan->cfg.dst_addr_width);
526bb30b847c23 Benoît Monin 2026-09-11 713 nbytes = fsl_chan->cfg.src_addr_width * fsl_chan->cfg.src_maxburst;
526bb30b847c23 Benoît Monin 2026-09-11 714 }
526bb30b847c23 Benoît Monin 2026-09-11 715
526bb30b847c23 Benoît Monin 2026-09-11 716 for (i = 0; i < nb; i++) {
526bb30b847c23 Benoît Monin 2026-09-11 717 if (direction == DMA_MEM_TO_DEV) {
526bb30b847c23 Benoît Monin 2026-09-11 718 src_addr = vecs[i].addr;
526bb30b847c23 Benoît Monin 2026-09-11 719 dst_addr = fsl_chan->dma_dev_addr;
526bb30b847c23 Benoît Monin 2026-09-11 720 soff = fsl_chan->cfg.dst_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 721 doff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 722 } else if (direction == DMA_DEV_TO_MEM) {
526bb30b847c23 Benoît Monin 2026-09-11 723 src_addr = fsl_chan->dma_dev_addr;
526bb30b847c23 Benoît Monin 2026-09-11 724 dst_addr = vecs[i].addr;
526bb30b847c23 Benoît Monin 2026-09-11 725 soff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 726 doff = fsl_chan->cfg.src_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 727 } else {
526bb30b847c23 Benoît Monin 2026-09-11 728 /* DMA_DEV_TO_DEV */
526bb30b847c23 Benoît Monin 2026-09-11 729 src_addr = fsl_chan->cfg.src_addr;
526bb30b847c23 Benoît Monin 2026-09-11 730 dst_addr = fsl_chan->cfg.dst_addr;
526bb30b847c23 Benoît Monin 2026-09-11 731 soff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 732 doff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 733 }
526bb30b847c23 Benoît Monin 2026-09-11 734
526bb30b847c23 Benoît Monin 2026-09-11 735 /*
526bb30b847c23 Benoît Monin 2026-09-11 736 * Choose the suitable burst length if dma_vec length is not
526bb30b847c23 Benoît Monin 2026-09-11 737 * multiple of burst length so that the whole transfer length is
526bb30b847c23 Benoît Monin 2026-09-11 738 * multiple of minor loop(burst length).
526bb30b847c23 Benoît Monin 2026-09-11 739 */
526bb30b847c23 Benoît Monin 2026-09-11 740 if (nbytes && vecs[i].len % nbytes) {
526bb30b847c23 Benoît Monin 2026-09-11 741 u32 width = (direction == DMA_DEV_TO_MEM) ? doff : soff;
526bb30b847c23 Benoît Monin 2026-09-11 742 u32 burst = (direction == DMA_DEV_TO_MEM) ?
526bb30b847c23 Benoît Monin 2026-09-11 743 fsl_chan->cfg.src_maxburst :
526bb30b847c23 Benoît Monin 2026-09-11 744 fsl_chan->cfg.dst_maxburst;
526bb30b847c23 Benoît Monin 2026-09-11 745 int j;
526bb30b847c23 Benoît Monin 2026-09-11 746
526bb30b847c23 Benoît Monin 2026-09-11 747 for (j = burst; j > 1; j--) {
526bb30b847c23 Benoît Monin 2026-09-11 748 if (!(vecs[i].len % (j * width))) {
526bb30b847c23 Benoît Monin 2026-09-11 749 nbytes = j * width;
526bb30b847c23 Benoît Monin 2026-09-11 750 break;
526bb30b847c23 Benoît Monin 2026-09-11 751 }
526bb30b847c23 Benoît Monin 2026-09-11 752 }
526bb30b847c23 Benoît Monin 2026-09-11 753 /* Set burst size as 1 if there's no suitable one */
526bb30b847c23 Benoît Monin 2026-09-11 754 if (j == 1)
526bb30b847c23 Benoît Monin 2026-09-11 755 nbytes = width;
526bb30b847c23 Benoît Monin 2026-09-11 756 }
526bb30b847c23 Benoît Monin 2026-09-11 757
526bb30b847c23 Benoît Monin 2026-09-11 @758 if (!nbytes || vecs[i].len / nbytes > FIELD_MAX(EDMA_TCD_ITER_MASK))
526bb30b847c23 Benoît Monin 2026-09-11 759 goto err_free_desc;
526bb30b847c23 Benoît Monin 2026-09-11 760
526bb30b847c23 Benoît Monin 2026-09-11 761 iter = vecs[i].len / nbytes;
526bb30b847c23 Benoît Monin 2026-09-11 762 if (i < nb - 1) {
526bb30b847c23 Benoît Monin 2026-09-11 763 last_sg = fsl_desc->tcd[(i + 1)].ptcd;
526bb30b847c23 Benoît Monin 2026-09-11 764 fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
526bb30b847c23 Benoît Monin 2026-09-11 765 dst_addr, fsl_chan->attr, soff,
526bb30b847c23 Benoît Monin 2026-09-11 766 nbytes, 0, iter, iter, doff, last_sg,
526bb30b847c23 Benoît Monin 2026-09-11 767 false, false, true);
526bb30b847c23 Benoît Monin 2026-09-11 768 } else {
526bb30b847c23 Benoît Monin 2026-09-11 769 if (fsl_desc->iscyclic) {
526bb30b847c23 Benoît Monin 2026-09-11 770 last_sg = fsl_desc->tcd[0].ptcd;
526bb30b847c23 Benoît Monin 2026-09-11 771 fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
526bb30b847c23 Benoît Monin 2026-09-11 772 dst_addr, fsl_chan->attr, soff,
526bb30b847c23 Benoît Monin 2026-09-11 773 nbytes, 0, iter, iter, doff, last_sg,
526bb30b847c23 Benoît Monin 2026-09-11 774 true, false, true);
526bb30b847c23 Benoît Monin 2026-09-11 775 } else {
526bb30b847c23 Benoît Monin 2026-09-11 776 last_sg = 0;
526bb30b847c23 Benoît Monin 2026-09-11 777 fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
526bb30b847c23 Benoît Monin 2026-09-11 778 dst_addr, fsl_chan->attr, soff,
526bb30b847c23 Benoît Monin 2026-09-11 779 nbytes, 0, iter, iter, doff, last_sg,
526bb30b847c23 Benoît Monin 2026-09-11 780 true, true, false);
526bb30b847c23 Benoît Monin 2026-09-11 781 }
526bb30b847c23 Benoît Monin 2026-09-11 782 }
526bb30b847c23 Benoît Monin 2026-09-11 783 }
526bb30b847c23 Benoît Monin 2026-09-11 784
526bb30b847c23 Benoît Monin 2026-09-11 785 return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
526bb30b847c23 Benoît Monin 2026-09-11 786
526bb30b847c23 Benoît Monin 2026-09-11 787 err_free_desc:
526bb30b847c23 Benoît Monin 2026-09-11 788 fsl_edma_free_desc(&fsl_desc->vdesc);
526bb30b847c23 Benoît Monin 2026-09-11 789 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 790 }
526bb30b847c23 Benoît Monin 2026-09-11 791
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining
@ 2026-09-24 3:39 kernel test robot
0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-09-24 3:39 UTC (permalink / raw)
To: oe-kbuild; +Cc: lkp
::::::
:::::: Manual check reason: "linux-review patch is more than 7 days old, verify it wasn't already superseded"
::::::
BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20260911-fsl-edma-dyn-sg-v10-2-700eb72def57@bootlin.com>
References: <20260911-fsl-edma-dyn-sg-v10-2-700eb72def57@bootlin.com>
TO: "Benoît Monin" <benoit.monin@bootlin.com>
TO: Frank Li <Frank.Li@nxp.com>
TO: Vinod Koul <vkoul@kernel.org>
CC: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
CC: imx@lists.linux.dev
CC: dmaengine@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: "Benoît Monin" <benoit.monin@bootlin.com>
Hi Benoît,
kernel test robot noticed the following build errors:
[auto build test ERROR on cee9395acd8043be0644b25c34bfa86623f2b935]
url: https://github.com/intel-lab-lkp/linux/commits/Beno-t-Monin/dmaengine-fsl-edma-Implement-device_prep_peripheral_dma_vec/20260911-151136
base: cee9395acd8043be0644b25c34bfa86623f2b935
patch link: https://lore.kernel.org/r/20260911-fsl-edma-dyn-sg-v10-2-700eb72def57%40bootlin.com
patch subject: [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining
:::::: branch date: 13 days ago
:::::: commit date: 13 days ago
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20260924/202609240552.xlFOcW61-lkp@intel.com/config)
compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260924/202609240552.xlFOcW61-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/r/202609240552.xlFOcW61-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/dma/fsl-edma-common.c:758:41: error: call to undeclared function 'FIELD_MAX'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
758 | if (!nbytes || vecs[i].len / nbytes > FIELD_MAX(EDMA_TCD_ITER_MASK))
| ^
1 error generated.
vim +/FIELD_MAX +758 drivers/dma/fsl-edma-common.c
9d831528a6567d Angelo Dureghello 2018-08-19 675
526bb30b847c23 Benoît Monin 2026-09-11 676 struct dma_async_tx_descriptor *
526bb30b847c23 Benoît Monin 2026-09-11 677 fsl_edma_prep_peripheral_dma_vec(struct dma_chan *chan, const struct dma_vec *vecs,
526bb30b847c23 Benoît Monin 2026-09-11 678 size_t nb, enum dma_transfer_direction direction,
526bb30b847c23 Benoît Monin 2026-09-11 679 unsigned long flags)
526bb30b847c23 Benoît Monin 2026-09-11 680 {
526bb30b847c23 Benoît Monin 2026-09-11 681 struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
526bb30b847c23 Benoît Monin 2026-09-11 682 dma_addr_t src_addr, dst_addr, last_sg;
526bb30b847c23 Benoît Monin 2026-09-11 683 struct fsl_edma_desc *fsl_desc;
526bb30b847c23 Benoît Monin 2026-09-11 684 u16 soff, doff, iter;
526bb30b847c23 Benoît Monin 2026-09-11 685 u32 nbytes;
526bb30b847c23 Benoît Monin 2026-09-11 686 int i;
526bb30b847c23 Benoît Monin 2026-09-11 687
526bb30b847c23 Benoît Monin 2026-09-11 688 if (!is_slave_direction(direction))
526bb30b847c23 Benoît Monin 2026-09-11 689 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 690
526bb30b847c23 Benoît Monin 2026-09-11 691 if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
526bb30b847c23 Benoît Monin 2026-09-11 692 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 693
526bb30b847c23 Benoît Monin 2026-09-11 694 fsl_desc = fsl_edma_alloc_desc(fsl_chan, nb);
526bb30b847c23 Benoît Monin 2026-09-11 695 if (!fsl_desc)
526bb30b847c23 Benoît Monin 2026-09-11 696 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 697 fsl_desc->iscyclic = flags & DMA_PREP_REPEAT;
526bb30b847c23 Benoît Monin 2026-09-11 698 fsl_desc->dirn = direction;
526bb30b847c23 Benoît Monin 2026-09-11 699
526bb30b847c23 Benoît Monin 2026-09-11 700 if (direction == DMA_MEM_TO_DEV) {
526bb30b847c23 Benoît Monin 2026-09-11 701 if (!fsl_chan->cfg.src_addr_width)
526bb30b847c23 Benoît Monin 2026-09-11 702 fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 703 fsl_chan->attr =
526bb30b847c23 Benoît Monin 2026-09-11 704 fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
526bb30b847c23 Benoît Monin 2026-09-11 705 fsl_chan->cfg.dst_addr_width);
526bb30b847c23 Benoît Monin 2026-09-11 706 nbytes = fsl_chan->cfg.dst_addr_width * fsl_chan->cfg.dst_maxburst;
526bb30b847c23 Benoît Monin 2026-09-11 707 } else {
526bb30b847c23 Benoît Monin 2026-09-11 708 if (!fsl_chan->cfg.dst_addr_width)
526bb30b847c23 Benoît Monin 2026-09-11 709 fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 710 fsl_chan->attr =
526bb30b847c23 Benoît Monin 2026-09-11 711 fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
526bb30b847c23 Benoît Monin 2026-09-11 712 fsl_chan->cfg.dst_addr_width);
526bb30b847c23 Benoît Monin 2026-09-11 713 nbytes = fsl_chan->cfg.src_addr_width * fsl_chan->cfg.src_maxburst;
526bb30b847c23 Benoît Monin 2026-09-11 714 }
526bb30b847c23 Benoît Monin 2026-09-11 715
526bb30b847c23 Benoît Monin 2026-09-11 716 for (i = 0; i < nb; i++) {
526bb30b847c23 Benoît Monin 2026-09-11 717 if (direction == DMA_MEM_TO_DEV) {
526bb30b847c23 Benoît Monin 2026-09-11 718 src_addr = vecs[i].addr;
526bb30b847c23 Benoît Monin 2026-09-11 719 dst_addr = fsl_chan->dma_dev_addr;
526bb30b847c23 Benoît Monin 2026-09-11 720 soff = fsl_chan->cfg.dst_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 721 doff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 722 } else if (direction == DMA_DEV_TO_MEM) {
526bb30b847c23 Benoît Monin 2026-09-11 723 src_addr = fsl_chan->dma_dev_addr;
526bb30b847c23 Benoît Monin 2026-09-11 724 dst_addr = vecs[i].addr;
526bb30b847c23 Benoît Monin 2026-09-11 725 soff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 726 doff = fsl_chan->cfg.src_addr_width;
526bb30b847c23 Benoît Monin 2026-09-11 727 } else {
526bb30b847c23 Benoît Monin 2026-09-11 728 /* DMA_DEV_TO_DEV */
526bb30b847c23 Benoît Monin 2026-09-11 729 src_addr = fsl_chan->cfg.src_addr;
526bb30b847c23 Benoît Monin 2026-09-11 730 dst_addr = fsl_chan->cfg.dst_addr;
526bb30b847c23 Benoît Monin 2026-09-11 731 soff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 732 doff = 0;
526bb30b847c23 Benoît Monin 2026-09-11 733 }
526bb30b847c23 Benoît Monin 2026-09-11 734
526bb30b847c23 Benoît Monin 2026-09-11 735 /*
526bb30b847c23 Benoît Monin 2026-09-11 736 * Choose the suitable burst length if dma_vec length is not
526bb30b847c23 Benoît Monin 2026-09-11 737 * multiple of burst length so that the whole transfer length is
526bb30b847c23 Benoît Monin 2026-09-11 738 * multiple of minor loop(burst length).
526bb30b847c23 Benoît Monin 2026-09-11 739 */
526bb30b847c23 Benoît Monin 2026-09-11 740 if (nbytes && vecs[i].len % nbytes) {
526bb30b847c23 Benoît Monin 2026-09-11 741 u32 width = (direction == DMA_DEV_TO_MEM) ? doff : soff;
526bb30b847c23 Benoît Monin 2026-09-11 742 u32 burst = (direction == DMA_DEV_TO_MEM) ?
526bb30b847c23 Benoît Monin 2026-09-11 743 fsl_chan->cfg.src_maxburst :
526bb30b847c23 Benoît Monin 2026-09-11 744 fsl_chan->cfg.dst_maxburst;
526bb30b847c23 Benoît Monin 2026-09-11 745 int j;
526bb30b847c23 Benoît Monin 2026-09-11 746
526bb30b847c23 Benoît Monin 2026-09-11 747 for (j = burst; j > 1; j--) {
526bb30b847c23 Benoît Monin 2026-09-11 748 if (!(vecs[i].len % (j * width))) {
526bb30b847c23 Benoît Monin 2026-09-11 749 nbytes = j * width;
526bb30b847c23 Benoît Monin 2026-09-11 750 break;
526bb30b847c23 Benoît Monin 2026-09-11 751 }
526bb30b847c23 Benoît Monin 2026-09-11 752 }
526bb30b847c23 Benoît Monin 2026-09-11 753 /* Set burst size as 1 if there's no suitable one */
526bb30b847c23 Benoît Monin 2026-09-11 754 if (j == 1)
526bb30b847c23 Benoît Monin 2026-09-11 755 nbytes = width;
526bb30b847c23 Benoît Monin 2026-09-11 756 }
526bb30b847c23 Benoît Monin 2026-09-11 757
526bb30b847c23 Benoît Monin 2026-09-11 @758 if (!nbytes || vecs[i].len / nbytes > FIELD_MAX(EDMA_TCD_ITER_MASK))
526bb30b847c23 Benoît Monin 2026-09-11 759 goto err_free_desc;
526bb30b847c23 Benoît Monin 2026-09-11 760
526bb30b847c23 Benoît Monin 2026-09-11 761 iter = vecs[i].len / nbytes;
526bb30b847c23 Benoît Monin 2026-09-11 762 if (i < nb - 1) {
526bb30b847c23 Benoît Monin 2026-09-11 763 last_sg = fsl_desc->tcd[(i + 1)].ptcd;
526bb30b847c23 Benoît Monin 2026-09-11 764 fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
526bb30b847c23 Benoît Monin 2026-09-11 765 dst_addr, fsl_chan->attr, soff,
526bb30b847c23 Benoît Monin 2026-09-11 766 nbytes, 0, iter, iter, doff, last_sg,
526bb30b847c23 Benoît Monin 2026-09-11 767 false, false, true);
526bb30b847c23 Benoît Monin 2026-09-11 768 } else {
526bb30b847c23 Benoît Monin 2026-09-11 769 if (fsl_desc->iscyclic) {
526bb30b847c23 Benoît Monin 2026-09-11 770 last_sg = fsl_desc->tcd[0].ptcd;
526bb30b847c23 Benoît Monin 2026-09-11 771 fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
526bb30b847c23 Benoît Monin 2026-09-11 772 dst_addr, fsl_chan->attr, soff,
526bb30b847c23 Benoît Monin 2026-09-11 773 nbytes, 0, iter, iter, doff, last_sg,
526bb30b847c23 Benoît Monin 2026-09-11 774 true, false, true);
526bb30b847c23 Benoît Monin 2026-09-11 775 } else {
526bb30b847c23 Benoît Monin 2026-09-11 776 last_sg = 0;
526bb30b847c23 Benoît Monin 2026-09-11 777 fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
526bb30b847c23 Benoît Monin 2026-09-11 778 dst_addr, fsl_chan->attr, soff,
526bb30b847c23 Benoît Monin 2026-09-11 779 nbytes, 0, iter, iter, doff, last_sg,
526bb30b847c23 Benoît Monin 2026-09-11 780 true, true, false);
526bb30b847c23 Benoît Monin 2026-09-11 781 }
526bb30b847c23 Benoît Monin 2026-09-11 782 }
526bb30b847c23 Benoît Monin 2026-09-11 783 }
526bb30b847c23 Benoît Monin 2026-09-11 784
526bb30b847c23 Benoît Monin 2026-09-11 785 return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
526bb30b847c23 Benoît Monin 2026-09-11 786
526bb30b847c23 Benoît Monin 2026-09-11 787 err_free_desc:
526bb30b847c23 Benoît Monin 2026-09-11 788 fsl_edma_free_desc(&fsl_desc->vdesc);
526bb30b847c23 Benoît Monin 2026-09-11 789 return NULL;
526bb30b847c23 Benoît Monin 2026-09-11 790 }
526bb30b847c23 Benoît Monin 2026-09-11 791
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-24 3:40 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-24 3:39 [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining kernel test robot
-- strict thread matches above, loose matches on Subject: below --
2026-09-23 13:16 kernel test robot
2026-09-11 13:11 [PATCH v10 0/2] dmaengine: fsl-edma: Scatter/gather improvements Benoît Monin
2026-09-11 13:11 ` [PATCH v10 2/2] dmaengine: fsl-edma: Support dynamic scatter/gather chaining Benoît Monin
2026-09-11 13:23 ` sashiko-bot
2026-09-11 14:14 ` Frank Li
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.