* [PATCH v3 01/10] dmaengine: dw-edma: Move control field update of DMA link to the last step
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 02/10] dmaengine: dw-edma: Add xfer_sz field to struct dw_edma_chunk Frank.Li
` (9 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
The control field in a DMA link list entry must be updated as the final
step because it includes the CB bit, which indicates whether the entry is
ready. Add dma_wmb() to ensure the correct memory write ordering.
Currently the driver does not update DMA link entries while the DMA is
running, so no visible failure occurs. However, fixing the ordering now
prepares the driver for supporting link entry updates during DMA operation.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/dw-edma/dw-edma-v0-core.c | 10 ++++++----
drivers/dma/dw-edma/dw-hdma-v0-core.c | 10 ++++++----
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index cfdd6463252e6..ee5c3c317557b 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -284,17 +284,18 @@ static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_edma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;
- lli->control = control;
lli->transfer_size = size;
lli->sar.reg = sar;
lli->dar.reg = dar;
+ dma_wmb();
+ lli->control = control;
} else {
struct dw_edma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;
- writel(control, &lli->control);
writel(size, &lli->transfer_size);
writeq(sar, &lli->sar.reg);
writeq(dar, &lli->dar.reg);
+ writel(control, &lli->control);
}
}
@@ -306,13 +307,14 @@ static void dw_edma_v0_write_ll_link(struct dw_edma_chunk *chunk,
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_edma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;
- llp->control = control;
llp->llp.reg = pointer;
+ dma_wmb();
+ llp->control = control;
} else {
struct dw_edma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;
- writel(control, &llp->control);
writeq(pointer, &llp->llp.reg);
+ writel(control, &llp->control);
}
}
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 632abb8b481cf..1201f1ab5f359 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -160,17 +160,18 @@ static void dw_hdma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_hdma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;
- lli->control = control;
lli->transfer_size = size;
lli->sar.reg = sar;
lli->dar.reg = dar;
+ dma_wmb();
+ lli->control = control;
} else {
struct dw_hdma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;
- writel(control, &lli->control);
writel(size, &lli->transfer_size);
writeq(sar, &lli->sar.reg);
writeq(dar, &lli->dar.reg);
+ writel(control, &lli->control);
}
}
@@ -182,13 +183,14 @@ static void dw_hdma_v0_write_ll_link(struct dw_edma_chunk *chunk,
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_hdma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;
- llp->control = control;
llp->llp.reg = pointer;
+ dma_wmb();
+ llp->control = control;
} else {
struct dw_hdma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;
- writel(control, &llp->control);
writeq(pointer, &llp->llp.reg);
+ writel(control, &llp->control);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 02/10] dmaengine: dw-edma: Add xfer_sz field to struct dw_edma_chunk
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
2026-07-02 21:21 ` [PATCH v3 01/10] dmaengine: dw-edma: Move control field update of DMA link to the last step Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 03/10] dmaengine: dw-edma: Move ll_region from struct dw_edma_chunk to struct dw_edma_chan Frank.Li
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
Reusing ll_region.sz as the transfer size is misleading because
ll_region.sz represents the memory size of the EDMA link list, not the
amount of data to be transferred.
Add a new xfer_sz field to explicitly indicate the total transfer size
of a chunk.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/dw-edma/dw-edma-core.c | 4 ++--
drivers/dma/dw-edma/dw-edma-core.h | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 1fec1b52e3d47..53469c8c8b82e 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -192,7 +192,7 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)
return 0;
dw_edma_core_start(dw, child, !desc->xfer_sz);
- desc->xfer_sz += child->ll_region.sz;
+ desc->xfer_sz += child->xfer_sz;
dw_edma_free_burst(child);
list_del(&child->list);
kfree(child);
@@ -527,7 +527,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
else if (xfer->type == EDMA_XFER_INTERLEAVED)
burst->sz = xfer->xfer.il->sgl[i % fsz].size;
- chunk->ll_region.sz += burst->sz;
+ chunk->xfer_sz += burst->sz;
desc->alloc_sz += burst->sz;
if (dir == DMA_DEV_TO_MEM) {
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 6474cacf71953..db5f45bf048c3 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -57,6 +57,7 @@ struct dw_edma_chunk {
u32 bursts_alloc;
u8 cb;
+ u32 xfer_sz;
struct dw_edma_region ll_region; /* Linked list */
};
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 03/10] dmaengine: dw-edma: Move ll_region from struct dw_edma_chunk to struct dw_edma_chan
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
2026-07-02 21:21 ` [PATCH v3 01/10] dmaengine: dw-edma: Move control field update of DMA link to the last step Frank.Li
2026-07-02 21:21 ` [PATCH v3 02/10] dmaengine: dw-edma: Add xfer_sz field to struct dw_edma_chunk Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 04/10] dmaengine: dw-edma: Pass down dw_edma_chan to reduce one level of indirection Frank.Li
` (7 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
ll_region is identical for all chunks belonging to the same DMA channel,
so there is no need to copy it into each chunk. Move ll_region to
struct dw_edma_chan to avoid redundant copies.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/dw-edma/dw-edma-core.c | 15 ++++-----------
drivers/dma/dw-edma/dw-edma-core.h | 2 +-
drivers/dma/dw-edma/dw-edma-v0-core.c | 18 ++++++++++--------
drivers/dma/dw-edma/dw-hdma-v0-core.c | 18 ++++++++++--------
4 files changed, 25 insertions(+), 28 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 53469c8c8b82e..2652ad8e7a8f6 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -64,7 +64,6 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
{
- struct dw_edma_chip *chip = desc->chan->dw->chip;
struct dw_edma_chan *chan = desc->chan;
struct dw_edma_chunk *chunk;
@@ -81,13 +80,6 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
* - Even chunks originate CB equal to 1
*/
chunk->cb = !(desc->chunks_alloc % 2);
- if (chan->dir == EDMA_DIR_WRITE) {
- chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
- chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
- } else {
- chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
- chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
- }
if (desc->chunk) {
/* Create and add new element into the linked list */
@@ -925,10 +917,11 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
chan->status = EDMA_ST_IDLE;
if (chan->dir == EDMA_DIR_WRITE)
- chan->ll_max = (chip->ll_region_wr[chan->id].sz / EDMA_LL_SZ);
+ chan->ll_region = chip->ll_region_wr[chan->id];
else
- chan->ll_max = (chip->ll_region_rd[chan->id].sz / EDMA_LL_SZ);
- chan->ll_max -= 1;
+ chan->ll_region = chip->ll_region_rd[chan->id];
+
+ chan->ll_max = chan->ll_region.sz / EDMA_LL_SZ - 1;
dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
str_write_read(chan->dir == EDMA_DIR_WRITE),
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index db5f45bf048c3..b96089baf0f9c 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -58,7 +58,6 @@ struct dw_edma_chunk {
u8 cb;
u32 xfer_sz;
- struct dw_edma_region ll_region; /* Linked list */
};
struct dw_edma_desc {
@@ -79,6 +78,7 @@ struct dw_edma_chan {
enum dw_edma_dir dir;
u32 ll_max;
+ struct dw_edma_region ll_region; /* Linked list */
struct msi_msg msi;
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index ee5c3c317557b..51e50f1fdcac4 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -280,9 +280,10 @@ static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
u32 control, u32 size, u64 sar, u64 dar)
{
ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
+ struct dw_edma_chan *chan = chunk->chan;
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
- struct dw_edma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;
+ struct dw_edma_v0_lli *lli = chan->ll_region.vaddr.mem + ofs;
lli->transfer_size = size;
lli->sar.reg = sar;
@@ -290,7 +291,7 @@ static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
dma_wmb();
lli->control = control;
} else {
- struct dw_edma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;
+ struct dw_edma_v0_lli __iomem *lli = chan->ll_region.vaddr.io + ofs;
writel(size, &lli->transfer_size);
writeq(sar, &lli->sar.reg);
@@ -303,15 +304,16 @@ static void dw_edma_v0_write_ll_link(struct dw_edma_chunk *chunk,
int i, u32 control, u64 pointer)
{
ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
+ struct dw_edma_chan *chan = chunk->chan;
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
- struct dw_edma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;
+ struct dw_edma_v0_llp *llp = chan->ll_region.vaddr.mem + ofs;
llp->llp.reg = pointer;
dma_wmb();
llp->control = control;
} else {
- struct dw_edma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;
+ struct dw_edma_v0_llp __iomem *llp = chan->ll_region.vaddr.io + ofs;
writeq(pointer, &llp->llp.reg);
writel(control, &llp->control);
@@ -345,7 +347,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
if (!chunk->cb)
control |= DW_EDMA_V0_CB;
- dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
+ dw_edma_v0_write_ll_link(chunk, i, control, chan->ll_region.paddr);
}
static void dw_edma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
@@ -359,7 +361,7 @@ static void dw_edma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
* last MWr TLP is completed
*/
if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
- readl(chunk->ll_region.vaddr.io);
+ readl(chunk->chan->ll_region.vaddr.io);
}
static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
@@ -430,9 +432,9 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
/* Linked list */
/* llp is not aligned on 64bit -> keep 32bit accesses */
SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
- lower_32_bits(chunk->ll_region.paddr));
+ lower_32_bits(chan->ll_region.paddr));
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
- upper_32_bits(chunk->ll_region.paddr));
+ upper_32_bits(chan->ll_region.paddr));
}
dw_edma_v0_sync_ll_data(chunk);
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 1201f1ab5f359..20089d57f8ab0 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -156,9 +156,10 @@ static void dw_hdma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
u32 control, u32 size, u64 sar, u64 dar)
{
ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli);
+ struct dw_edma_chan *chan = chunk->chan;
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
- struct dw_hdma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;
+ struct dw_hdma_v0_lli *lli = chan->ll_region.vaddr.mem + ofs;
lli->transfer_size = size;
lli->sar.reg = sar;
@@ -166,7 +167,7 @@ static void dw_hdma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
dma_wmb();
lli->control = control;
} else {
- struct dw_hdma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;
+ struct dw_hdma_v0_lli __iomem *lli = chan->ll_region.vaddr.io + ofs;
writel(size, &lli->transfer_size);
writeq(sar, &lli->sar.reg);
@@ -179,15 +180,16 @@ static void dw_hdma_v0_write_ll_link(struct dw_edma_chunk *chunk,
int i, u32 control, u64 pointer)
{
ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli);
+ struct dw_edma_chan *chan = chunk->chan;
if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
- struct dw_hdma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;
+ struct dw_hdma_v0_llp *llp = chan->ll_region.vaddr.mem + ofs;
llp->llp.reg = pointer;
dma_wmb();
llp->control = control;
} else {
- struct dw_hdma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;
+ struct dw_hdma_v0_llp __iomem *llp = chan->ll_region.vaddr.io + ofs;
writeq(pointer, &llp->llp.reg);
writel(control, &llp->control);
@@ -210,7 +212,7 @@ static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
if (!chunk->cb)
control |= DW_HDMA_V0_CB;
- dw_hdma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
+ dw_hdma_v0_write_ll_link(chunk, i, control, chunk->chan->ll_region.paddr);
}
static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
@@ -224,7 +226,7 @@ static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
* last MWr TLP is completed
*/
if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
- readl(chunk->ll_region.vaddr.io);
+ readl(chunk->chan->ll_region.vaddr.io);
}
static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, bool first)
@@ -251,9 +253,9 @@ static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, bool first)
/* Linked list */
/* llp is not aligned on 64bit -> keep 32bit accesses */
SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
- lower_32_bits(chunk->ll_region.paddr));
+ lower_32_bits(chan->ll_region.paddr));
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
- upper_32_bits(chunk->ll_region.paddr));
+ upper_32_bits(chan->ll_region.paddr));
/* Set consumer cycle */
SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 04/10] dmaengine: dw-edma: Pass down dw_edma_chan to reduce one level of indirection
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (2 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 03/10] dmaengine: dw-edma: Move ll_region from struct dw_edma_chunk to struct dw_edma_chan Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 05/10] dmaengine: dw-edma: Add helper dw_(edma|hdma)_v0_core_ch_enable() Frank.Li
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
Some helper functions do not use any information from dw_edma_chunk, so
passing a dw_edma_chan pointer directly avoids an unnecessary level of
pointer dereferencing and simplifies data access.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/dw-edma/dw-edma-v0-core.c | 22 ++++++++++------------
drivers/dma/dw-edma/dw-hdma-v0-core.c | 23 +++++++++++------------
2 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 51e50f1fdcac4..c341aa5343417 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -276,13 +276,12 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
return ret;
}
-static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
+static void dw_edma_v0_write_ll_data(struct dw_edma_chan *chan, int i,
u32 control, u32 size, u64 sar, u64 dar)
{
ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
- struct dw_edma_chan *chan = chunk->chan;
- if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+ if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_edma_v0_lli *lli = chan->ll_region.vaddr.mem + ofs;
lli->transfer_size = size;
@@ -300,13 +299,12 @@ static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
}
}
-static void dw_edma_v0_write_ll_link(struct dw_edma_chunk *chunk,
+static void dw_edma_v0_write_ll_link(struct dw_edma_chan *chan,
int i, u32 control, u64 pointer)
{
ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
- struct dw_edma_chan *chan = chunk->chan;
- if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+ if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_edma_v0_llp *llp = chan->ll_region.vaddr.mem + ofs;
llp->llp.reg = pointer;
@@ -339,7 +337,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
control |= DW_EDMA_V0_RIE;
}
- dw_edma_v0_write_ll_data(chunk, i++, control, child->sz,
+ dw_edma_v0_write_ll_data(chan, i++, control, child->sz,
child->sar, child->dar);
}
@@ -347,10 +345,10 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
if (!chunk->cb)
control |= DW_EDMA_V0_CB;
- dw_edma_v0_write_ll_link(chunk, i, control, chan->ll_region.paddr);
+ dw_edma_v0_write_ll_link(chan, i, control, chan->ll_region.paddr);
}
-static void dw_edma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
+static void dw_edma_v0_sync_ll_data(struct dw_edma_chan *chan)
{
/*
* In case of remote eDMA engine setup, the DW PCIe RP/EP internal
@@ -360,8 +358,8 @@ static void dw_edma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
* LL memory in a hope that the MRd TLP will return only after the
* last MWr TLP is completed
*/
- if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
- readl(chunk->chan->ll_region.vaddr.io);
+ if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+ readl(chan->ll_region.vaddr.io);
}
static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
@@ -437,7 +435,7 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
upper_32_bits(chan->ll_region.paddr));
}
- dw_edma_v0_sync_ll_data(chunk);
+ dw_edma_v0_sync_ll_data(chan);
/* Doorbell */
SET_RW_32(dw, chan->dir, doorbell,
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 20089d57f8ab0..156b1cc225091 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -152,13 +152,12 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
return ret;
}
-static void dw_hdma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
+static void dw_hdma_v0_write_ll_data(struct dw_edma_chan *chan, int i,
u32 control, u32 size, u64 sar, u64 dar)
{
ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli);
- struct dw_edma_chan *chan = chunk->chan;
- if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+ if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_hdma_v0_lli *lli = chan->ll_region.vaddr.mem + ofs;
lli->transfer_size = size;
@@ -176,13 +175,12 @@ static void dw_hdma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
}
}
-static void dw_hdma_v0_write_ll_link(struct dw_edma_chunk *chunk,
+static void dw_hdma_v0_write_ll_link(struct dw_edma_chan *chan,
int i, u32 control, u64 pointer)
{
ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli);
- struct dw_edma_chan *chan = chunk->chan;
- if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+ if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
struct dw_hdma_v0_llp *llp = chan->ll_region.vaddr.mem + ofs;
llp->llp.reg = pointer;
@@ -198,6 +196,7 @@ static void dw_hdma_v0_write_ll_link(struct dw_edma_chunk *chunk,
static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
{
+ struct dw_edma_chan *chan = chunk->chan;
struct dw_edma_burst *child;
u32 control = 0, i = 0;
@@ -205,17 +204,17 @@ static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
control = DW_HDMA_V0_CB;
list_for_each_entry(child, &chunk->burst->list, list)
- dw_hdma_v0_write_ll_data(chunk, i++, control, child->sz,
+ dw_hdma_v0_write_ll_data(chan, i++, control, child->sz,
child->sar, child->dar);
control = DW_HDMA_V0_LLP | DW_HDMA_V0_TCB;
if (!chunk->cb)
control |= DW_HDMA_V0_CB;
- dw_hdma_v0_write_ll_link(chunk, i, control, chunk->chan->ll_region.paddr);
+ dw_hdma_v0_write_ll_link(chan, i, control, chunk->chan->ll_region.paddr);
}
-static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
+static void dw_hdma_v0_sync_ll_data(struct dw_edma_chan *chan)
{
/*
* In case of remote HDMA engine setup, the DW PCIe RP/EP internal
@@ -225,8 +224,8 @@ static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
* LL memory in a hope that the MRd TLP will return only after the
* last MWr TLP is completed
*/
- if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
- readl(chunk->chan->ll_region.vaddr.io);
+ if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+ readl(chan->ll_region.vaddr.io);
}
static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, bool first)
@@ -261,7 +260,7 @@ static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, bool first)
HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
}
- dw_hdma_v0_sync_ll_data(chunk);
+ dw_hdma_v0_sync_ll_data(chan);
/* Doorbell */
SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 05/10] dmaengine: dw-edma: Add helper dw_(edma|hdma)_v0_core_ch_enable()
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (3 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 04/10] dmaengine: dw-edma: Pass down dw_edma_chan to reduce one level of indirection Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 06/10] dmaengine: dw-edma: Add callbacks to fill link list entries Frank.Li
` (5 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
Move the channel-enable logic into a new helper function,
dw_(edma|hdma)_v0_core_ch_enable(), in preparation for supporting dynamic
link entry additions.
No functional changes.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/dw-edma/dw-edma-v0-core.c | 128 +++++++++++++++++-----------------
drivers/dma/dw-edma/dw-hdma-v0-core.c | 54 +++++++-------
2 files changed, 93 insertions(+), 89 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index c341aa5343417..8d38867cd9983 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -318,6 +318,67 @@ static void dw_edma_v0_write_ll_link(struct dw_edma_chan *chan,
}
}
+static void dw_edma_v0_core_ch_enable(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->dw;
+ unsigned long flags;
+ u32 tmp;
+
+ /* Enable engine */
+ SET_RW_32(dw, chan->dir, engine_en, BIT(0));
+ if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
+ switch (chan->id) {
+ case 0:
+ SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en, BIT(0));
+ break;
+ case 1:
+ SET_RW_COMPAT(dw, chan->dir, ch1_pwr_en, BIT(0));
+ break;
+ case 2:
+ SET_RW_COMPAT(dw, chan->dir, ch2_pwr_en, BIT(0));
+ break;
+ case 3:
+ SET_RW_COMPAT(dw, chan->dir, ch3_pwr_en, BIT(0));
+ break;
+ case 4:
+ SET_RW_COMPAT(dw, chan->dir, ch4_pwr_en, BIT(0));
+ break;
+ case 5:
+ SET_RW_COMPAT(dw, chan->dir, ch5_pwr_en, BIT(0));
+ break;
+ case 6:
+ SET_RW_COMPAT(dw, chan->dir, ch6_pwr_en, BIT(0));
+ break;
+ case 7:
+ SET_RW_COMPAT(dw, chan->dir, ch7_pwr_en, BIT(0));
+ break;
+ }
+ }
+ /* Interrupt unmask - done, abort */
+ raw_spin_lock_irqsave(&dw->lock, flags);
+
+ tmp = GET_RW_32(dw, chan->dir, int_mask);
+ tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
+ tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
+ SET_RW_32(dw, chan->dir, int_mask, tmp);
+ /* Linked list error */
+ tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
+ tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
+ SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
+
+ raw_spin_unlock_irqrestore(&dw->lock, flags);
+
+ /* Channel control */
+ SET_CH_32(dw, chan->dir, chan->id, ch_control1,
+ (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
+ /* Linked list */
+ /* llp is not aligned on 64bit -> keep 32bit accesses */
+ SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
+ lower_32_bits(chan->ll_region.paddr));
+ SET_CH_32(dw, chan->dir, chan->id, llp.msb,
+ upper_32_bits(chan->ll_region.paddr));
+}
+
static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
{
struct dw_edma_burst *child;
@@ -366,74 +427,11 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
{
struct dw_edma_chan *chan = chunk->chan;
struct dw_edma *dw = chan->dw;
- unsigned long flags;
- u32 tmp;
dw_edma_v0_core_write_chunk(chunk);
- if (first) {
- /* Enable engine */
- SET_RW_32(dw, chan->dir, engine_en, BIT(0));
- if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
- switch (chan->id) {
- case 0:
- SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
- BIT(0));
- break;
- case 1:
- SET_RW_COMPAT(dw, chan->dir, ch1_pwr_en,
- BIT(0));
- break;
- case 2:
- SET_RW_COMPAT(dw, chan->dir, ch2_pwr_en,
- BIT(0));
- break;
- case 3:
- SET_RW_COMPAT(dw, chan->dir, ch3_pwr_en,
- BIT(0));
- break;
- case 4:
- SET_RW_COMPAT(dw, chan->dir, ch4_pwr_en,
- BIT(0));
- break;
- case 5:
- SET_RW_COMPAT(dw, chan->dir, ch5_pwr_en,
- BIT(0));
- break;
- case 6:
- SET_RW_COMPAT(dw, chan->dir, ch6_pwr_en,
- BIT(0));
- break;
- case 7:
- SET_RW_COMPAT(dw, chan->dir, ch7_pwr_en,
- BIT(0));
- break;
- }
- }
- /* Interrupt unmask - done, abort */
- raw_spin_lock_irqsave(&dw->lock, flags);
-
- tmp = GET_RW_32(dw, chan->dir, int_mask);
- tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
- tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
- SET_RW_32(dw, chan->dir, int_mask, tmp);
- /* Linked list error */
- tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
- tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
- SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
-
- raw_spin_unlock_irqrestore(&dw->lock, flags);
-
- /* Channel control */
- SET_CH_32(dw, chan->dir, chan->id, ch_control1,
- (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
- /* Linked list */
- /* llp is not aligned on 64bit -> keep 32bit accesses */
- SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
- lower_32_bits(chan->ll_region.paddr));
- SET_CH_32(dw, chan->dir, chan->id, llp.msb,
- upper_32_bits(chan->ll_region.paddr));
- }
+ if (first)
+ dw_edma_v0_core_ch_enable(chan);
dw_edma_v0_sync_ll_data(chan);
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 156b1cc225091..31bbdc6a40642 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -194,6 +194,34 @@ static void dw_hdma_v0_write_ll_link(struct dw_edma_chan *chan,
}
}
+static void dw_hdma_v0_core_ch_enable(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->dw;
+ u32 tmp;
+
+ /* Enable engine */
+ SET_CH_32(dw, chan->dir, chan->id, ch_en, BIT(0));
+ /* Interrupt unmask - stop, abort */
+ tmp = GET_CH_32(dw, chan->dir, chan->id, int_setup);
+ tmp &= ~(HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
+ /* Interrupt enable - stop, abort */
+ tmp |= HDMA_V0_LOCAL_STOP_INT_EN | HDMA_V0_LOCAL_ABORT_INT_EN;
+ if (!(dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+ tmp |= HDMA_V0_REMOTE_STOP_INT_EN | HDMA_V0_REMOTE_ABORT_INT_EN;
+ SET_CH_32(dw, chan->dir, chan->id, int_setup, tmp);
+ /* Channel control */
+ SET_CH_32(dw, chan->dir, chan->id, control1, HDMA_V0_LINKLIST_EN);
+ /* Linked list */
+ /* llp is not aligned on 64bit -> keep 32bit accesses */
+ SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
+ lower_32_bits(chan->ll_region.paddr));
+ SET_CH_32(dw, chan->dir, chan->id, llp.msb,
+ upper_32_bits(chan->ll_region.paddr));
+ /* Set consumer cycle */
+ SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
+ HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
+}
+
static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
{
struct dw_edma_chan *chan = chunk->chan;
@@ -232,33 +260,11 @@ static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, bool first)
{
struct dw_edma_chan *chan = chunk->chan;
struct dw_edma *dw = chan->dw;
- u32 tmp;
dw_hdma_v0_core_write_chunk(chunk);
- if (first) {
- /* Enable engine */
- SET_CH_32(dw, chan->dir, chan->id, ch_en, BIT(0));
- /* Interrupt unmask - stop, abort */
- tmp = GET_CH_32(dw, chan->dir, chan->id, int_setup);
- tmp &= ~(HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
- /* Interrupt enable - stop, abort */
- tmp |= HDMA_V0_LOCAL_STOP_INT_EN | HDMA_V0_LOCAL_ABORT_INT_EN;
- if (!(dw->chip->flags & DW_EDMA_CHIP_LOCAL))
- tmp |= HDMA_V0_REMOTE_STOP_INT_EN | HDMA_V0_REMOTE_ABORT_INT_EN;
- SET_CH_32(dw, chan->dir, chan->id, int_setup, tmp);
- /* Channel control */
- SET_CH_32(dw, chan->dir, chan->id, control1, HDMA_V0_LINKLIST_EN);
- /* Linked list */
- /* llp is not aligned on 64bit -> keep 32bit accesses */
- SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
- lower_32_bits(chan->ll_region.paddr));
- SET_CH_32(dw, chan->dir, chan->id, llp.msb,
- upper_32_bits(chan->ll_region.paddr));
- /* Set consumer cycle */
- SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
- HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
- }
+ if (first)
+ dw_hdma_v0_core_ch_enable(chan);
dw_hdma_v0_sync_ll_data(chan);
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 06/10] dmaengine: dw-edma: Add callbacks to fill link list entries
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (4 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 05/10] dmaengine: dw-edma: Add helper dw_(edma|hdma)_v0_core_ch_enable() Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 07/10] dmaengine: dw-edma: Add non_ll_start() callback Frank.Li
` (4 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
Introduce four new callbacks to fill link list entries in preparation for
replacing dw_(edma|hdma)_v0_core_start().
Filling link list entries is expected to become more complex, and without
this abstraction both eDMA and HDMA paths would need to duplicate the same
logic. Add fill-entry callbacks so the code can be shared cleanly between
eDMA and HDMA implementations.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v2
- update commit message
- use eDMA and HDMI
- keep inline to avoid build warnings. dw-edma-v0-core.c also include
dw-edma-core.h
---
drivers/dma/dw-edma/dw-edma-core.h | 29 ++++++++++++++++++++++
drivers/dma/dw-edma/dw-edma-v0-core.c | 46 +++++++++++++++++++++++++++++++++++
drivers/dma/dw-edma/dw-hdma-v0-core.c | 38 +++++++++++++++++++++++++++++
3 files changed, 113 insertions(+)
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index b96089baf0f9c..bab4d49c92feb 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -126,6 +126,12 @@ struct dw_edma_core_ops {
irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
dw_edma_handler_t done, dw_edma_handler_t abort);
void (*start)(struct dw_edma_chunk *chunk, bool first);
+ void (*ll_data)(struct dw_edma_chan *chan, struct dw_edma_burst *burst,
+ u32 idx, bool cb, bool irq);
+ void (*ll_link)(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr);
+ void (*ch_doorbell)(struct dw_edma_chan *chan);
+ void (*ch_enable)(struct dw_edma_chan *chan);
+
void (*ch_config)(struct dw_edma_chan *chan);
void (*debugfs_on)(struct dw_edma *dw);
void (*ack_emulated_irq)(struct dw_edma *dw);
@@ -204,6 +210,29 @@ void dw_edma_core_ch_config(struct dw_edma_chan *chan)
chan->dw->core->ch_config(chan);
}
+static inline void
+dw_edma_core_ll_data(struct dw_edma_chan *chan, struct dw_edma_burst *burst,
+ u32 idx, bool cb, bool irq)
+{
+ chan->dw->core->ll_data(chan, burst, idx, cb, irq);
+}
+
+static inline void
+dw_edma_core_ll_link(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr)
+{
+ chan->dw->core->ll_link(chan, idx, cb, addr);
+}
+
+static inline void dw_edma_core_ch_doorbell(struct dw_edma_chan *chan)
+{
+ chan->dw->core->ch_doorbell(chan);
+}
+
+static inline void dw_edma_core_ch_enable(struct dw_edma_chan *chan)
+{
+ chan->dw->core->ch_enable(chan);
+}
+
static inline
void dw_edma_core_debugfs_on(struct dw_edma *dw)
{
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 8d38867cd9983..10ad63d7e6016 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -509,6 +509,48 @@ static void dw_edma_v0_core_ch_config(struct dw_edma_chan *chan)
}
}
+static void
+dw_edma_v0_core_ll_data(struct dw_edma_chan *chan, struct dw_edma_burst *burst,
+ u32 idx, bool cb, bool irq)
+{
+ u32 control = 0;
+
+ if (cb)
+ control |= DW_EDMA_V0_CB;
+
+ if (irq) {
+ control |= DW_EDMA_V0_LIE;
+
+ if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+ control |= DW_EDMA_V0_RIE;
+ }
+
+ dw_edma_v0_write_ll_data(chan, idx, control, burst->sz, burst->sar,
+ burst->dar);
+}
+
+static void
+dw_edma_v0_core_ll_link(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr)
+{
+ u32 control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
+
+ if (!cb)
+ control |= DW_EDMA_V0_CB;
+
+ dw_edma_v0_write_ll_link(chan, idx, control, chan->ll_region.paddr);
+}
+
+static void dw_edma_v0_core_ch_doorbell(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->dw;
+
+ dw_edma_v0_sync_ll_data(chan);
+
+ /* Doorbell */
+ SET_RW_32(dw, chan->dir, doorbell,
+ FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
+}
+
/* eDMA debugfs callbacks */
static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw)
{
@@ -540,6 +582,10 @@ static const struct dw_edma_core_ops dw_edma_v0_core = {
.ch_status = dw_edma_v0_core_ch_status,
.handle_int = dw_edma_v0_core_handle_int,
.start = dw_edma_v0_core_start,
+ .ll_data = dw_edma_v0_core_ll_data,
+ .ll_link = dw_edma_v0_core_ll_link,
+ .ch_doorbell = dw_edma_v0_core_ch_doorbell,
+ .ch_enable = dw_edma_v0_core_ch_enable,
.ch_config = dw_edma_v0_core_ch_config,
.debugfs_on = dw_edma_v0_core_debugfs_on,
.ack_emulated_irq = dw_edma_v0_core_ack_emulated_irq,
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 31bbdc6a40642..52c6ea09fcab5 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -348,6 +348,40 @@ static void dw_hdma_v0_core_ch_config(struct dw_edma_chan *chan)
SET_CH_32(dw, chan->dir, chan->id, msi_msgdata, chan->msi.data);
}
+static void
+dw_hdma_v0_core_ll_data(struct dw_edma_chan *chan, struct dw_edma_burst *burst,
+ u32 idx, bool cb, bool irq)
+{
+ u32 control = 0;
+
+ if (cb)
+ control |= DW_HDMA_V0_CB;
+
+ dw_hdma_v0_write_ll_data(chan, idx, control, burst->sz, burst->sar,
+ burst->dar);
+}
+
+static void
+dw_hdma_v0_core_ll_link(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr)
+{
+ u32 control = DW_HDMA_V0_LLP | DW_HDMA_V0_TCB;
+
+ if (!cb)
+ control |= DW_HDMA_V0_CB;
+
+ dw_hdma_v0_write_ll_link(chan, idx, control, chan->ll_region.paddr);
+}
+
+static void dw_hdma_v0_core_ch_doorbell(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->dw;
+
+ dw_hdma_v0_sync_ll_data(chan);
+
+ /* Doorbell */
+ SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START);
+}
+
/* HDMA debugfs callbacks */
static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw)
{
@@ -366,6 +400,10 @@ static const struct dw_edma_core_ops dw_hdma_v0_core = {
.ch_status = dw_hdma_v0_core_ch_status,
.handle_int = dw_hdma_v0_core_handle_int,
.start = dw_hdma_v0_core_start,
+ .ll_data = dw_hdma_v0_core_ll_data,
+ .ll_link = dw_hdma_v0_core_ll_link,
+ .ch_doorbell = dw_hdma_v0_core_ch_doorbell,
+ .ch_enable = dw_hdma_v0_core_ch_enable,
.ch_config = dw_hdma_v0_core_ch_config,
.debugfs_on = dw_hdma_v0_core_debugfs_on,
.db_offset = dw_hdma_v0_core_db_offset,
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 07/10] dmaengine: dw-edma: Add non_ll_start() callback
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (5 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 06/10] dmaengine: dw-edma: Add callbacks to fill link list entries Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 08/10] dmaengine: dw-edma: Use common dw_edma_core_start() for both eDMA and HDMA Frank.Li
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
Add a non_ll_start() callback and move the common non-linked-list channel
handling into the EDMA core so it can be shared by both the EDMA and HDMA.
Prepare for the upcoming reorganization of the burst and chunk structures.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/dw-edma/dw-edma-core.h | 12 +++++++++++-
drivers/dma/dw-edma/dw-hdma-v0-core.c | 23 ++++-------------------
2 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index bab4d49c92feb..e18d6e827c2c9 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -126,6 +126,7 @@ struct dw_edma_core_ops {
irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
dw_edma_handler_t done, dw_edma_handler_t abort);
void (*start)(struct dw_edma_chunk *chunk, bool first);
+ void (*non_ll_start)(struct dw_edma_chan *chan, struct dw_edma_burst *child);
void (*ll_data)(struct dw_edma_chan *chan, struct dw_edma_burst *burst,
u32 idx, bool cb, bool irq);
void (*ll_link)(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr);
@@ -201,7 +202,16 @@ dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
static inline
void dw_edma_core_start(struct dw_edma *dw, struct dw_edma_chunk *chunk, bool first)
{
- dw->core->start(chunk, first);
+ if (chunk->chan->non_ll) {
+ struct dw_edma_burst *child;
+
+ child = list_first_entry_or_null(&chunk->burst->list,
+ struct dw_edma_burst, list);
+ if (child)
+ dw->core->non_ll_start(chunk->chan, child);
+ } else {
+ dw->core->start(chunk, first);
+ }
}
static inline
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 52c6ea09fcab5..4cff839022213 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -272,18 +272,12 @@ static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, bool first)
SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START);
}
-static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chunk *chunk)
+static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chan *chan,
+ struct dw_edma_burst *child)
{
- struct dw_edma_chan *chan = chunk->chan;
struct dw_edma *dw = chan->dw;
- struct dw_edma_burst *child;
u32 val;
- child = list_first_entry_or_null(&chunk->burst->list,
- struct dw_edma_burst, list);
- if (!child)
- return;
-
SET_CH_32(dw, chan->dir, chan->id, ch_en, HDMA_V0_CH_EN);
/* Source address */
@@ -324,16 +318,6 @@ static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chunk *chunk)
HDMA_V0_DOORBELL_START);
}
-static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
-{
- struct dw_edma_chan *chan = chunk->chan;
-
- if (chan->non_ll)
- dw_hdma_v0_core_non_ll_start(chunk);
- else
- dw_hdma_v0_core_ll_start(chunk, first);
-}
-
static void dw_hdma_v0_core_ch_config(struct dw_edma_chan *chan)
{
struct dw_edma *dw = chan->dw;
@@ -399,7 +383,8 @@ static const struct dw_edma_core_ops dw_hdma_v0_core = {
.ch_count = dw_hdma_v0_core_ch_count,
.ch_status = dw_hdma_v0_core_ch_status,
.handle_int = dw_hdma_v0_core_handle_int,
- .start = dw_hdma_v0_core_start,
+ .start = dw_hdma_v0_core_ll_start,
+ .non_ll_start = dw_hdma_v0_core_non_ll_start,
.ll_data = dw_hdma_v0_core_ll_data,
.ll_link = dw_hdma_v0_core_ll_link,
.ch_doorbell = dw_hdma_v0_core_ch_doorbell,
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 08/10] dmaengine: dw-edma: Use common dw_edma_core_start() for both eDMA and HDMA
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (6 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 07/10] dmaengine: dw-edma: Add non_ll_start() callback Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 09/10] dmaengine: dw-edma: Use burst array instead of linked list Frank.Li
` (2 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
Use common dw_edma_core_start() for both eDMA and HDMA. Remove .start()
callback functions at eDMA and HDMA.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v2
- use eDMA and HDMA
---
drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++--
drivers/dma/dw-edma/dw-edma-core.h | 16 ------------
drivers/dma/dw-edma/dw-edma-v0-core.c | 48 -----------------------------------
drivers/dma/dw-edma/dw-hdma-v0-core.c | 37 ---------------------------
4 files changed, 30 insertions(+), 103 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 2652ad8e7a8f6..f52d9fd18e573 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -163,9 +163,37 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc)
dw_edma_free_desc(vd2dw_edma_desc(vdesc));
}
+static void dw_edma_core_start(struct dw_edma_chunk *chunk, bool first)
+{
+ struct dw_edma_chan *chan = chunk->chan;
+ struct dw_edma_burst *child;
+ u32 i = 0;
+ int j;
+
+ if (chan->non_ll) {
+ child = list_first_entry_or_null(&chunk->burst->list,
+ struct dw_edma_burst, list);
+ if (child)
+ chan->dw->core->non_ll_start(chunk->chan, child);
+ return;
+ }
+
+ j = chunk->bursts_alloc;
+ list_for_each_entry(child, &chunk->burst->list, list) {
+ j--;
+ dw_edma_core_ll_data(chan, child, i++, chunk->cb, !j);
+ }
+
+ dw_edma_core_ll_link(chan, i, chunk->cb, chan->ll_region.paddr);
+
+ if (first)
+ dw_edma_core_ch_enable(chan);
+
+ dw_edma_core_ch_doorbell(chan);
+}
+
static int dw_edma_start_transfer(struct dw_edma_chan *chan)
{
- struct dw_edma *dw = chan->dw;
struct dw_edma_chunk *child;
struct dw_edma_desc *desc;
struct virt_dma_desc *vd;
@@ -183,7 +211,7 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)
if (!child)
return 0;
- dw_edma_core_start(dw, child, !desc->xfer_sz);
+ dw_edma_core_start(child, !desc->xfer_sz);
desc->xfer_sz += child->xfer_sz;
dw_edma_free_burst(child);
list_del(&child->list);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index e18d6e827c2c9..27415f3a2d04b 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -125,7 +125,6 @@ struct dw_edma_core_ops {
enum dma_status (*ch_status)(struct dw_edma_chan *chan);
irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
dw_edma_handler_t done, dw_edma_handler_t abort);
- void (*start)(struct dw_edma_chunk *chunk, bool first);
void (*non_ll_start)(struct dw_edma_chan *chan, struct dw_edma_burst *child);
void (*ll_data)(struct dw_edma_chan *chan, struct dw_edma_burst *burst,
u32 idx, bool cb, bool irq);
@@ -199,21 +198,6 @@ dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort);
}
-static inline
-void dw_edma_core_start(struct dw_edma *dw, struct dw_edma_chunk *chunk, bool first)
-{
- if (chunk->chan->non_ll) {
- struct dw_edma_burst *child;
-
- child = list_first_entry_or_null(&chunk->burst->list,
- struct dw_edma_burst, list);
- if (child)
- dw->core->non_ll_start(chunk->chan, child);
- } else {
- dw->core->start(chunk, first);
- }
-}
-
static inline
void dw_edma_core_ch_config(struct dw_edma_chan *chan)
{
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 10ad63d7e6016..8ee2db0b3739f 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -379,36 +379,6 @@ static void dw_edma_v0_core_ch_enable(struct dw_edma_chan *chan)
upper_32_bits(chan->ll_region.paddr));
}
-static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
-{
- struct dw_edma_burst *child;
- struct dw_edma_chan *chan = chunk->chan;
- u32 control = 0, i = 0;
- int j;
-
- if (chunk->cb)
- control = DW_EDMA_V0_CB;
-
- j = chunk->bursts_alloc;
- list_for_each_entry(child, &chunk->burst->list, list) {
- j--;
- if (!j) {
- control |= DW_EDMA_V0_LIE;
- if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
- control |= DW_EDMA_V0_RIE;
- }
-
- dw_edma_v0_write_ll_data(chan, i++, control, child->sz,
- child->sar, child->dar);
- }
-
- control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
- if (!chunk->cb)
- control |= DW_EDMA_V0_CB;
-
- dw_edma_v0_write_ll_link(chan, i, control, chan->ll_region.paddr);
-}
-
static void dw_edma_v0_sync_ll_data(struct dw_edma_chan *chan)
{
/*
@@ -423,23 +393,6 @@ static void dw_edma_v0_sync_ll_data(struct dw_edma_chan *chan)
readl(chan->ll_region.vaddr.io);
}
-static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
-{
- struct dw_edma_chan *chan = chunk->chan;
- struct dw_edma *dw = chan->dw;
-
- dw_edma_v0_core_write_chunk(chunk);
-
- if (first)
- dw_edma_v0_core_ch_enable(chan);
-
- dw_edma_v0_sync_ll_data(chan);
-
- /* Doorbell */
- SET_RW_32(dw, chan->dir, doorbell,
- FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
-}
-
static void dw_edma_v0_core_ch_config(struct dw_edma_chan *chan)
{
struct dw_edma *dw = chan->dw;
@@ -581,7 +534,6 @@ static const struct dw_edma_core_ops dw_edma_v0_core = {
.ch_count = dw_edma_v0_core_ch_count,
.ch_status = dw_edma_v0_core_ch_status,
.handle_int = dw_edma_v0_core_handle_int,
- .start = dw_edma_v0_core_start,
.ll_data = dw_edma_v0_core_ll_data,
.ll_link = dw_edma_v0_core_ll_link,
.ch_doorbell = dw_edma_v0_core_ch_doorbell,
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 4cff839022213..ad0ed28c928f8 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -222,26 +222,6 @@ static void dw_hdma_v0_core_ch_enable(struct dw_edma_chan *chan)
HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
}
-static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
-{
- struct dw_edma_chan *chan = chunk->chan;
- struct dw_edma_burst *child;
- u32 control = 0, i = 0;
-
- if (chunk->cb)
- control = DW_HDMA_V0_CB;
-
- list_for_each_entry(child, &chunk->burst->list, list)
- dw_hdma_v0_write_ll_data(chan, i++, control, child->sz,
- child->sar, child->dar);
-
- control = DW_HDMA_V0_LLP | DW_HDMA_V0_TCB;
- if (!chunk->cb)
- control |= DW_HDMA_V0_CB;
-
- dw_hdma_v0_write_ll_link(chan, i, control, chunk->chan->ll_region.paddr);
-}
-
static void dw_hdma_v0_sync_ll_data(struct dw_edma_chan *chan)
{
/*
@@ -256,22 +236,6 @@ static void dw_hdma_v0_sync_ll_data(struct dw_edma_chan *chan)
readl(chan->ll_region.vaddr.io);
}
-static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, bool first)
-{
- struct dw_edma_chan *chan = chunk->chan;
- struct dw_edma *dw = chan->dw;
-
- dw_hdma_v0_core_write_chunk(chunk);
-
- if (first)
- dw_hdma_v0_core_ch_enable(chan);
-
- dw_hdma_v0_sync_ll_data(chan);
-
- /* Doorbell */
- SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START);
-}
-
static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chan *chan,
struct dw_edma_burst *child)
{
@@ -383,7 +347,6 @@ static const struct dw_edma_core_ops dw_hdma_v0_core = {
.ch_count = dw_hdma_v0_core_ch_count,
.ch_status = dw_hdma_v0_core_ch_status,
.handle_int = dw_hdma_v0_core_handle_int,
- .start = dw_hdma_v0_core_ll_start,
.non_ll_start = dw_hdma_v0_core_non_ll_start,
.ll_data = dw_hdma_v0_core_ll_data,
.ll_link = dw_hdma_v0_core_ll_link,
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 09/10] dmaengine: dw-edma: Use burst array instead of linked list
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (7 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 08/10] dmaengine: dw-edma: Use common dw_edma_core_start() for both eDMA and HDMA Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-02 21:21 ` [PATCH v3 10/10] dmaengine: dw-edma: Remove struct dw_edma_chunk Frank.Li
2026-07-06 13:20 ` [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Koichiro Den
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
The current descriptor layout is:
struct dw_edma_desc *desc
└─ chunk list
└─ burst list
Creating a DMA descriptor requires at least three kzalloc() calls because
each burst is allocated as a linked-list node. Since the number of bursts
is already known when the descriptor is created, a linked list is not
necessary.
Allocate a burst array when creating each chunk to simplify the code and
eliminate one kzalloc() call.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/dw-edma/dw-edma-core.c | 120 +++++++------------------------------
drivers/dma/dw-edma/dw-edma-core.h | 9 +--
2 files changed, 26 insertions(+), 103 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index f52d9fd18e573..01bee22fe3b3e 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -40,38 +40,15 @@ u64 dw_edma_get_pci_address(struct dw_edma_chan *chan, phys_addr_t cpu_addr)
return cpu_addr;
}
-static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
-{
- struct dw_edma_burst *burst;
-
- burst = kzalloc_obj(*burst, GFP_NOWAIT);
- if (unlikely(!burst))
- return NULL;
-
- INIT_LIST_HEAD(&burst->list);
- if (chunk->burst) {
- /* Create and add new element into the linked list */
- chunk->bursts_alloc++;
- list_add_tail(&burst->list, &chunk->burst->list);
- } else {
- /* List head */
- chunk->bursts_alloc = 0;
- chunk->burst = burst;
- }
-
- return burst;
-}
-
-static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
+static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc, u32 nburst)
{
struct dw_edma_chan *chan = desc->chan;
struct dw_edma_chunk *chunk;
- chunk = kzalloc_obj(*chunk, GFP_NOWAIT);
+ chunk = kzalloc_flex(*chunk, burst, nburst, GFP_NOWAIT);
if (unlikely(!chunk))
return NULL;
- INIT_LIST_HEAD(&chunk->list);
chunk->chan = chan;
/* Toggling change bit (CB) in each chunk, this is a mechanism to
* inform the eDMA HW block that this is a new linked list ready
@@ -81,20 +58,10 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
*/
chunk->cb = !(desc->chunks_alloc % 2);
- if (desc->chunk) {
- /* Create and add new element into the linked list */
- if (!dw_edma_alloc_burst(chunk)) {
- kfree(chunk);
- return NULL;
- }
- desc->chunks_alloc++;
- list_add_tail(&chunk->list, &desc->chunk->list);
- } else {
- /* List head */
- chunk->burst = NULL;
- desc->chunks_alloc = 0;
- desc->chunk = chunk;
- }
+ chunk->nburst = nburst;
+
+ list_add_tail(&chunk->list, &desc->chunk_list);
+ desc->chunks_alloc++;
return chunk;
}
@@ -108,53 +75,23 @@ static struct dw_edma_desc *dw_edma_alloc_desc(struct dw_edma_chan *chan)
return NULL;
desc->chan = chan;
- if (!dw_edma_alloc_chunk(desc)) {
- kfree(desc);
- return NULL;
- }
- return desc;
-}
+ INIT_LIST_HEAD(&desc->chunk_list);
-static void dw_edma_free_burst(struct dw_edma_chunk *chunk)
-{
- struct dw_edma_burst *child, *_next;
-
- /* Remove all the list elements */
- list_for_each_entry_safe(child, _next, &chunk->burst->list, list) {
- list_del(&child->list);
- kfree(child);
- chunk->bursts_alloc--;
- }
-
- /* Remove the list head */
- kfree(child);
- chunk->burst = NULL;
+ return desc;
}
-static void dw_edma_free_chunk(struct dw_edma_desc *desc)
+static void dw_edma_free_desc(struct dw_edma_desc *desc)
{
struct dw_edma_chunk *child, *_next;
- if (!desc->chunk)
- return;
-
/* Remove all the list elements */
- list_for_each_entry_safe(child, _next, &desc->chunk->list, list) {
- dw_edma_free_burst(child);
+ list_for_each_entry_safe(child, _next, &desc->chunk_list, list) {
list_del(&child->list);
kfree(child);
desc->chunks_alloc--;
}
- /* Remove the list head */
- kfree(child);
- desc->chunk = NULL;
-}
-
-static void dw_edma_free_desc(struct dw_edma_desc *desc)
-{
- dw_edma_free_chunk(desc);
kfree(desc);
}
@@ -166,23 +103,17 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc)
static void dw_edma_core_start(struct dw_edma_chunk *chunk, bool first)
{
struct dw_edma_chan *chan = chunk->chan;
- struct dw_edma_burst *child;
u32 i = 0;
- int j;
if (chan->non_ll) {
- child = list_first_entry_or_null(&chunk->burst->list,
- struct dw_edma_burst, list);
- if (child)
- chan->dw->core->non_ll_start(chunk->chan, child);
+ if (chunk->nburst == 1)
+ chan->dw->core->non_ll_start(chunk->chan, &chunk->burst[0]);
return;
}
- j = chunk->bursts_alloc;
- list_for_each_entry(child, &chunk->burst->list, list) {
- j--;
- dw_edma_core_ll_data(chan, child, i++, chunk->cb, !j);
- }
+ for (i = 0; i < chunk->nburst; i++)
+ dw_edma_core_ll_data(chan, &chunk->burst[i], i, chunk->cb,
+ i == chunk->nburst - 1);
dw_edma_core_ll_link(chan, i, chunk->cb, chan->ll_region.paddr);
@@ -206,14 +137,13 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)
if (!desc)
return 0;
- child = list_first_entry_or_null(&desc->chunk->list,
+ child = list_first_entry_or_null(&desc->chunk_list,
struct dw_edma_chunk, list);
if (!child)
return 0;
dw_edma_core_start(child, !desc->xfer_sz);
desc->xfer_sz += child->xfer_sz;
- dw_edma_free_burst(child);
list_del(&child->list);
kfree(child);
desc->chunks_alloc--;
@@ -425,14 +355,14 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
enum dma_transfer_direction dir = xfer->direction;
struct scatterlist *sg = NULL;
- struct dw_edma_chunk *chunk;
+ struct dw_edma_chunk *chunk = NULL;
struct dw_edma_burst *burst;
struct dw_edma_desc *desc;
u64 src_addr, dst_addr;
size_t fsz = 0;
u32 bursts_max;
u32 cnt = 0;
- int i;
+ u32 i;
if (!chan->configured)
return NULL;
@@ -499,10 +429,6 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
if (unlikely(!desc))
goto err_alloc;
- chunk = dw_edma_alloc_chunk(desc);
- if (unlikely(!chunk))
- goto err_alloc;
-
if (xfer->type == EDMA_XFER_INTERLEAVED) {
src_addr = xfer->xfer.il->src_start;
dst_addr = xfer->xfer.il->dst_start;
@@ -530,15 +456,15 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
if (xfer->type == EDMA_XFER_SCATTER_GATHER && !sg)
break;
- if (chunk->bursts_alloc == bursts_max) {
- chunk = dw_edma_alloc_chunk(desc);
+ if (!(i % chan->ll_max)) {
+ u32 n = min(cnt - i, chan->ll_max);
+
+ chunk = dw_edma_alloc_chunk(desc, n);
if (unlikely(!chunk))
goto err_alloc;
}
- burst = dw_edma_alloc_burst(chunk);
- if (unlikely(!burst))
- goto err_alloc;
+ burst = chunk->burst + (i % chan->ll_max);
if (xfer->type == EDMA_XFER_CYCLIC)
burst->sz = xfer->xfer.cyclic.len;
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 27415f3a2d04b..4950c57fca34f 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -43,7 +43,6 @@ struct dw_edma_chan;
struct dw_edma_chunk;
struct dw_edma_burst {
- struct list_head list;
u64 sar;
u64 dar;
u32 sz;
@@ -52,18 +51,16 @@ struct dw_edma_burst {
struct dw_edma_chunk {
struct list_head list;
struct dw_edma_chan *chan;
- struct dw_edma_burst *burst;
-
- u32 bursts_alloc;
-
u8 cb;
u32 xfer_sz;
+ u32 nburst;
+ struct dw_edma_burst burst[] __counted_by(nburst);
};
struct dw_edma_desc {
struct virt_dma_desc vd;
struct dw_edma_chan *chan;
- struct dw_edma_chunk *chunk;
+ struct list_head chunk_list;
u32 chunks_alloc;
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 10/10] dmaengine: dw-edma: Remove struct dw_edma_chunk
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (8 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 09/10] dmaengine: dw-edma: Use burst array instead of linked list Frank.Li
@ 2026-07-02 21:21 ` Frank.Li
2026-07-06 13:20 ` [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Koichiro Den
10 siblings, 0 replies; 14+ messages in thread
From: Frank.Li @ 2026-07-02 21:21 UTC (permalink / raw)
To: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Manivannan Sadhasivam,
Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Christoph Hellwig, Niklas Cassel
Cc: dmaengine, linux-kernel, linux-hardening, linux-pci, linux-nvme,
Koichiro Den, imx, Verma, Devendra, Frank Li
From: Frank Li <Frank.Li@nxp.com>
The current descriptor layout is:
struct dw_edma_desc *desc
└─ chunk list
└─ burst[]
Creating a DMA descriptor requires at least two kzalloc() calls because
each chunk is allocated as a linked-list node. Since the number of bursts
is already known when the descriptor is created, this linked-list layer is
unnecessary.
Move the burst array directly into struct dw_edma_desc and remove the
struct dw_edma_chunk layer entirely.
Use start_burst and done_burst to track the current bursts, which current
are in the DMA link list.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v2
- remove debug code
- move "residue = desc->alloc_sz;" in if(desc) check
- keep inline to avoid build warning
---
drivers/dma/dw-edma/dw-edma-core.c | 141 ++++++++++++-------------------------
drivers/dma/dw-edma/dw-edma-core.h | 24 ++++---
2 files changed, 59 insertions(+), 106 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 01bee22fe3b3e..eead38897c42d 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -40,82 +40,52 @@ u64 dw_edma_get_pci_address(struct dw_edma_chan *chan, phys_addr_t cpu_addr)
return cpu_addr;
}
-static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc, u32 nburst)
-{
- struct dw_edma_chan *chan = desc->chan;
- struct dw_edma_chunk *chunk;
-
- chunk = kzalloc_flex(*chunk, burst, nburst, GFP_NOWAIT);
- if (unlikely(!chunk))
- return NULL;
-
- chunk->chan = chan;
- /* Toggling change bit (CB) in each chunk, this is a mechanism to
- * inform the eDMA HW block that this is a new linked list ready
- * to be consumed.
- * - Odd chunks originate CB equal to 0
- * - Even chunks originate CB equal to 1
- */
- chunk->cb = !(desc->chunks_alloc % 2);
-
- chunk->nburst = nburst;
-
- list_add_tail(&chunk->list, &desc->chunk_list);
- desc->chunks_alloc++;
-
- return chunk;
-}
-
-static struct dw_edma_desc *dw_edma_alloc_desc(struct dw_edma_chan *chan)
+static struct dw_edma_desc *
+dw_edma_alloc_desc(struct dw_edma_chan *chan, u32 nburst)
{
struct dw_edma_desc *desc;
- desc = kzalloc_obj(*desc, GFP_NOWAIT);
+ desc = kzalloc_flex(*desc, burst, nburst, GFP_NOWAIT);
if (unlikely(!desc))
return NULL;
desc->chan = chan;
-
- INIT_LIST_HEAD(&desc->chunk_list);
+ desc->nburst = nburst;
+ desc->cb = true;
return desc;
}
-static void dw_edma_free_desc(struct dw_edma_desc *desc)
-{
- struct dw_edma_chunk *child, *_next;
-
- /* Remove all the list elements */
- list_for_each_entry_safe(child, _next, &desc->chunk_list, list) {
- list_del(&child->list);
- kfree(child);
- desc->chunks_alloc--;
- }
-
- kfree(desc);
-}
-
static void vchan_free_desc(struct virt_dma_desc *vdesc)
{
- dw_edma_free_desc(vd2dw_edma_desc(vdesc));
+ kfree(vd2dw_edma_desc(vdesc));
}
-static void dw_edma_core_start(struct dw_edma_chunk *chunk, bool first)
+static void dw_edma_core_start(struct dw_edma_desc *desc, bool first)
{
- struct dw_edma_chan *chan = chunk->chan;
+ struct dw_edma_chan *chan = desc->chan;
u32 i = 0;
if (chan->non_ll) {
- if (chunk->nburst == 1)
- chan->dw->core->non_ll_start(chunk->chan, &chunk->burst[0]);
+ chan->dw->core->non_ll_start(chan, &desc->burst[desc->start_burst]);
+ desc->done_burst = desc->start_burst;
+ desc->start_burst += 1;
return;
}
- for (i = 0; i < chunk->nburst; i++)
- dw_edma_core_ll_data(chan, &chunk->burst[i], i, chunk->cb,
- i == chunk->nburst - 1);
+ for (i = 0; i < desc->nburst; i++) {
+ if (i == chan->ll_max - 1)
+ break;
+
+ dw_edma_core_ll_data(chan, &desc->burst[i + desc->start_burst],
+ i, desc->cb,
+ i == desc->nburst - 1 || i == chan->ll_max - 2);
+ }
+
+ desc->done_burst = desc->start_burst;
+ desc->start_burst += i;
- dw_edma_core_ll_link(chan, i, chunk->cb, chan->ll_region.paddr);
+ dw_edma_core_ll_link(chan, i, desc->cb, chan->ll_region.paddr);
if (first)
dw_edma_core_ch_enable(chan);
@@ -125,7 +95,6 @@ static void dw_edma_core_start(struct dw_edma_chunk *chunk, bool first)
static int dw_edma_start_transfer(struct dw_edma_chan *chan)
{
- struct dw_edma_chunk *child;
struct dw_edma_desc *desc;
struct virt_dma_desc *vd;
@@ -137,16 +106,9 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)
if (!desc)
return 0;
- child = list_first_entry_or_null(&desc->chunk_list,
- struct dw_edma_chunk, list);
- if (!child)
- return 0;
+ dw_edma_core_start(desc, !desc->start_burst);
- dw_edma_core_start(child, !desc->xfer_sz);
- desc->xfer_sz += child->xfer_sz;
- list_del(&child->list);
- kfree(child);
- desc->chunks_alloc--;
+ desc->cb = !desc->cb;
return 1;
}
@@ -337,8 +299,10 @@ dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
vd = vchan_find_desc(&chan->vc, cookie);
if (vd) {
desc = vd2dw_edma_desc(vd);
- if (desc)
- residue = desc->alloc_sz - desc->xfer_sz;
+
+ residue = desc->alloc_sz;
+ if (desc && desc->done_burst)
+ residue -= desc->burst[desc->done_burst].xfer_sz;
}
spin_unlock_irqrestore(&chan->vc.lock, flags);
@@ -355,12 +319,10 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
enum dma_transfer_direction dir = xfer->direction;
struct scatterlist *sg = NULL;
- struct dw_edma_chunk *chunk = NULL;
struct dw_edma_burst *burst;
struct dw_edma_desc *desc;
u64 src_addr, dst_addr;
size_t fsz = 0;
- u32 bursts_max;
u32 cnt = 0;
u32 i;
@@ -418,17 +380,6 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
return NULL;
}
- /*
- * For non-LL mode, only a single burst can be handled
- * in a single chunk unlike LL mode where multiple bursts
- * can be configured in a single chunk.
- */
- bursts_max = chan->non_ll ? 1 : chan->ll_max;
-
- desc = dw_edma_alloc_desc(chan);
- if (unlikely(!desc))
- goto err_alloc;
-
if (xfer->type == EDMA_XFER_INTERLEAVED) {
src_addr = xfer->xfer.il->src_start;
dst_addr = xfer->xfer.il->dst_start;
@@ -452,19 +403,15 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
fsz = xfer->xfer.il->frame_size;
}
+ desc = dw_edma_alloc_desc(chan, cnt);
+ if (unlikely(!desc))
+ return NULL;
+
for (i = 0; i < cnt; i++) {
if (xfer->type == EDMA_XFER_SCATTER_GATHER && !sg)
break;
- if (!(i % chan->ll_max)) {
- u32 n = min(cnt - i, chan->ll_max);
-
- chunk = dw_edma_alloc_chunk(desc, n);
- if (unlikely(!chunk))
- goto err_alloc;
- }
-
- burst = chunk->burst + (i % chan->ll_max);
+ burst = desc->burst + i;
if (xfer->type == EDMA_XFER_CYCLIC)
burst->sz = xfer->xfer.cyclic.len;
@@ -473,8 +420,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
else if (xfer->type == EDMA_XFER_INTERLEAVED)
burst->sz = xfer->xfer.il->sgl[i % fsz].size;
- chunk->xfer_sz += burst->sz;
desc->alloc_sz += burst->sz;
+ burst->xfer_sz = desc->alloc_sz;
if (dir == DMA_DEV_TO_MEM) {
burst->sar = src_addr;
@@ -529,12 +476,6 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer,
}
return vchan_tx_prep(&chan->vc, &desc->vd, xfer->flags);
-
-err_alloc:
- if (desc)
- dw_edma_free_desc(desc);
-
- return NULL;
}
static struct dma_async_tx_descriptor *
@@ -605,8 +546,14 @@ static void dw_hdma_set_callback_result(struct virt_dma_desc *vd,
return;
desc = vd2dw_edma_desc(vd);
- if (desc)
- residue = desc->alloc_sz - desc->xfer_sz;
+ if (desc) {
+ residue = desc->alloc_sz;
+
+ if (result == DMA_TRANS_NOERROR)
+ residue -= desc->burst[desc->start_burst - 1].xfer_sz;
+ else if (desc->done_burst)
+ residue -= desc->burst[desc->done_burst - 1].xfer_sz;
+ }
res = &vd->tx_result;
res->result = result;
@@ -625,7 +572,7 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
switch (chan->request) {
case EDMA_REQ_NONE:
desc = vd2dw_edma_desc(vd);
- if (!desc->chunks_alloc) {
+ if (desc->start_burst >= desc->nburst) {
dw_hdma_set_callback_result(vd,
DMA_TRANS_NOERROR);
list_del(&vd->node);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 4950c57fca34f..7f2ec871f5bd5 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -46,15 +46,8 @@ struct dw_edma_burst {
u64 sar;
u64 dar;
u32 sz;
-};
-
-struct dw_edma_chunk {
- struct list_head list;
- struct dw_edma_chan *chan;
- u8 cb;
+ /* precalulate summary of previous burst total size */
u32 xfer_sz;
- u32 nburst;
- struct dw_edma_burst burst[] __counted_by(nburst);
};
struct dw_edma_desc {
@@ -66,6 +59,12 @@ struct dw_edma_desc {
u32 alloc_sz;
u32 xfer_sz;
+
+ u32 done_burst;
+ u32 start_burst;
+ u8 cb;
+ u32 nburst;
+ struct dw_edma_burst burst[] __counted_by(nburst);
};
struct dw_edma_chan {
@@ -128,7 +127,6 @@ struct dw_edma_core_ops {
void (*ll_link)(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr);
void (*ch_doorbell)(struct dw_edma_chan *chan);
void (*ch_enable)(struct dw_edma_chan *chan);
-
void (*ch_config)(struct dw_edma_chan *chan);
void (*debugfs_on)(struct dw_edma *dw);
void (*ack_emulated_irq)(struct dw_edma *dw);
@@ -170,6 +168,14 @@ struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan)
return vc2dw_edma_chan(to_virt_chan(dchan));
}
+static inline u64 dw_edma_core_get_ll_paddr(struct dw_edma_chan *chan)
+{
+ if (chan->dir == EDMA_DIR_WRITE)
+ return chan->dw->chip->ll_region_wr[chan->id].paddr;
+
+ return chan->dw->chip->ll_region_rd[chan->id].paddr;
+}
+
static inline
void dw_edma_core_off(struct dw_edma *dw)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code
2026-07-02 21:21 [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Frank.Li
` (9 preceding siblings ...)
2026-07-02 21:21 ` [PATCH v3 10/10] dmaengine: dw-edma: Remove struct dw_edma_chunk Frank.Li
@ 2026-07-06 13:20 ` Koichiro Den
2026-07-08 14:59 ` Koichiro Den
10 siblings, 1 reply; 14+ messages in thread
From: Koichiro Den @ 2026-07-06 13:20 UTC (permalink / raw)
To: Frank.Li
Cc: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Niklas Cassel, dmaengine, linux-kernel, linux-hardening,
linux-pci, linux-nvme, imx, Verma, Devendra, Frank Li
On Thu, Jul 02, 2026 at 05:21:20PM -0400, Frank.Li@oss.nxp.com wrote:
> Koichiro Den:
> My hardware temperately is unavaible recently. Can you help test
> it.
Sure, I can test it on my side. I'll report back once I have the results.
Best regards,
Koichiro
>
> Rebase and compile test only now.
>
> Verma, Devendra:
> Can you help check if block non-ll mode?
>
> Frank
>
> Basic change
>
> struct dw_edma_desc *desc
> └─ chunk list
> └─ burst list
>
> To
>
> struct dw_edma_desc *desc
> └─ burst[n]
>
> And reduce at least 2 times kzalloc() for each dma descriptor create.
>
> I only test eDMA part, not hardware test hdma part.
>
> The finial goal is dymatic add DMA request when DMA running. So needn't
> wait for irq for fetch next round DMA request.
>
> This work is neccesary to for dymatic DMA request appending.
>
> The post this part first to review and test firstly during working dymatic
> DMA part.
>
> performance is little bit better. Use NVME as EP function
>
> Before
>
> Rnd read, 4KB, QD=1, 1 job : IOPS=6660, BW=26.0MiB/s (27.3MB/s)
> Rnd read, 4KB, QD=32, 1 job : IOPS=28.6k, BW=112MiB/s (117MB/s)
> Rnd read, 4KB, QD=32, 4 jobs: IOPS=33.4k, BW=130MiB/s (137MB/s)
> Rnd read, 128KB, QD=1, 1 job : IOPS=914, BW=114MiB/s (120MB/s)
> Rnd read, 128KB, QD=32, 1 job : IOPS=1204, BW=151MiB/s (158MB/s)
> Rnd read, 128KB, QD=32, 4 jobs: IOPS=1255, BW=157MiB/s (165MB/s)
> Rnd read, 512KB, QD=1, 1 job : IOPS=248, BW=124MiB/s (131MB/s)
> Rnd read, 512KB, QD=32, 1 job : IOPS=353, BW=177MiB/s (185MB/s)
> Rnd read, 512KB, QD=32, 4 jobs: IOPS=388, BW=194MiB/s (204MB/s)
> Rnd write, 4KB, QD=1, 1 job : IOPS=6241, BW=24.4MiB/s (25.6MB/s)
> Rnd write, 4KB, QD=32, 1 job : IOPS=24.7k, BW=96.5MiB/s (101MB/s)
> Rnd write, 4KB, QD=32, 4 jobs: IOPS=26.9k, BW=105MiB/s (110MB/s)
> Rnd write, 128KB, QD=1, 1 job : IOPS=780, BW=97.5MiB/s (102MB/s)
> Rnd write, 128KB, QD=32, 1 job : IOPS=987, BW=123MiB/s (129MB/s)
> Rnd write, 128KB, QD=32, 4 jobs: IOPS=1021, BW=128MiB/s (134MB/s)
> Seq read, 128KB, QD=1, 1 job : IOPS=1190, BW=149MiB/s (156MB/s)
> Seq read, 128KB, QD=32, 1 job : IOPS=1400, BW=175MiB/s (184MB/s)
> Seq read, 512KB, QD=1, 1 job : IOPS=243, BW=122MiB/s (128MB/s)
> Seq read, 512KB, QD=32, 1 job : IOPS=355, BW=178MiB/s (186MB/s)
> Seq read, 1MB, QD=32, 1 job : IOPS=191, BW=192MiB/s (201MB/s)
> Seq write, 128KB, QD=1, 1 job : IOPS=784, BW=98.1MiB/s (103MB/s)
> Seq write, 128KB, QD=32, 1 job : IOPS=1030, BW=129MiB/s (135MB/s)
> Seq write, 512KB, QD=1, 1 job : IOPS=216, BW=108MiB/s (114MB/s)
> Seq write, 512KB, QD=32, 1 job : IOPS=295, BW=148MiB/s (155MB/s)
> Seq write, 1MB, QD=32, 1 job : IOPS=164, BW=165MiB/s (173MB/s)
> Rnd rdwr, 4K..1MB, QD=8, 4 jobs: IOPS=250, BW=126MiB/s (132MB/s)
> IOPS=261, BW=132MiB/s (138MB/s
>
> After
> Rnd read, 4KB, QD=1, 1 job : IOPS=6780, BW=26.5MiB/s (27.8MB/s)
> Rnd read, 4KB, QD=32, 1 job : IOPS=28.6k, BW=112MiB/s (117MB/s)
> Rnd read, 4KB, QD=32, 4 jobs: IOPS=33.4k, BW=130MiB/s (137MB/s)
> Rnd read, 128KB, QD=1, 1 job : IOPS=1188, BW=149MiB/s (156MB/s)
> Rnd read, 128KB, QD=32, 1 job : IOPS=1440, BW=180MiB/s (189MB/s)
> Rnd read, 128KB, QD=32, 4 jobs: IOPS=1282, BW=160MiB/s (168MB/s)
> Rnd read, 512KB, QD=1, 1 job : IOPS=254, BW=127MiB/s (134MB/s)
> Rnd read, 512KB, QD=32, 1 job : IOPS=354, BW=177MiB/s (186MB/s)
> Rnd read, 512KB, QD=32, 4 jobs: IOPS=388, BW=194MiB/s (204MB/s)
> Rnd write, 4KB, QD=1, 1 job : IOPS=6282, BW=24.5MiB/s (25.7MB/s)
> Rnd write, 4KB, QD=32, 1 job : IOPS=24.9k, BW=97.5MiB/s (102MB/s)
> Rnd write, 4KB, QD=32, 4 jobs: IOPS=27.4k, BW=107MiB/s (112MB/s)
> Rnd write, 128KB, QD=1, 1 job : IOPS=1098, BW=137MiB/s (144MB/s)
> Rnd write, 128KB, QD=32, 1 job : IOPS=1195, BW=149MiB/s (157MB/s)
> Rnd write, 128KB, QD=32, 4 jobs: IOPS=1120, BW=140MiB/s (147MB/s)
> Seq read, 128KB, QD=1, 1 job : IOPS=936, BW=117MiB/s (123MB/s)
> Seq read, 128KB, QD=32, 1 job : IOPS=1218, BW=152MiB/s (160MB/s)
> Seq read, 512KB, QD=1, 1 job : IOPS=301, BW=151MiB/s (158MB/s)
> Seq read, 512KB, QD=32, 1 job : IOPS=360, BW=180MiB/s (189MB/s)
> Seq read, 1MB, QD=32, 1 job : IOPS=193, BW=194MiB/s (203MB/s)
> Seq write, 128KB, QD=1, 1 job : IOPS=796, BW=99.5MiB/s (104MB/s)
> Seq write, 128KB, QD=32, 1 job : IOPS=1019, BW=127MiB/s (134MB/s)
> Seq write, 512KB, QD=1, 1 job : IOPS=213, BW=107MiB/s (112MB/s)
> Seq write, 512KB, QD=32, 1 job : IOPS=273, BW=137MiB/s (143MB/s)
> Seq write, 1MB, QD=32, 1 job : IOPS=168, BW=168MiB/s (177MB/s)
> Rnd rdwr, 4K..1MB, QD=8, 4 jobs: IOPS=255, BW=128MiB/s (134MB/s)
> IOPS=266, BW=135MiB/s (141MB/s)
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> Changes in v3:
> - remove patch dmaengine: dw-edma: Remove ll_max = -1 in dw_edma_channel_setup()
> - rebase to vnod's dmaengine topic/config_prep_api
> - Add non-ll-start() callback to handle non-ll mode transfer
> - Link to v2: https://lore.kernel.org/r/20260109-edma_ll-v2-0-5c0b27b2c664@nxp.com
>
> Changes in v2:
> - use 'eDMA' and 'HDMA' at commit message
> - remove debug code.
> - keep 'inline' to avoid build warning
> - Link to v1: https://lore.kernel.org/r/20251212-edma_ll-v1-0-fc863d9f5ca3@nxp.com
>
> ---
> Frank Li (10):
> dmaengine: dw-edma: Move control field update of DMA link to the last step
> dmaengine: dw-edma: Add xfer_sz field to struct dw_edma_chunk
> dmaengine: dw-edma: Move ll_region from struct dw_edma_chunk to struct dw_edma_chan
> dmaengine: dw-edma: Pass down dw_edma_chan to reduce one level of indirection
> dmaengine: dw-edma: Add helper dw_(edma|hdma)_v0_core_ch_enable()
> dmaengine: dw-edma: Add callbacks to fill link list entries
> dmaengine: dw-edma: Add non_ll_start() callback
> dmaengine: dw-edma: Use common dw_edma_core_start() for both eDMA and HDMA
> dmaengine: dw-edma: Use burst array instead of linked list
> dmaengine: dw-edma: Remove struct dw_edma_chunk
>
> drivers/dma/dw-edma/dw-edma-core.c | 216 ++++++++----------------------
> drivers/dma/dw-edma/dw-edma-core.h | 65 ++++++---
> drivers/dma/dw-edma/dw-edma-v0-core.c | 240 +++++++++++++++++-----------------
> drivers/dma/dw-edma/dw-hdma-v0-core.c | 169 ++++++++++++------------
> 4 files changed, 302 insertions(+), 388 deletions(-)
> ---
> base-commit: c9e9927c6d8346cdf6555a8f97da093980172e4b
> change-id: 20251211-edma_ll-0904ba089f01
>
> Best regards,
> --
> Frank Li <Frank.Li@nxp.com>
>
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code
2026-07-06 13:20 ` [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code Koichiro Den
@ 2026-07-08 14:59 ` Koichiro Den
2026-07-08 20:55 ` Frank Li
0 siblings, 1 reply; 14+ messages in thread
From: Koichiro Den @ 2026-07-08 14:59 UTC (permalink / raw)
To: Frank.Li
Cc: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Niklas Cassel, dmaengine, linux-kernel, linux-hardening,
linux-pci, linux-nvme, imx, Verma, Devendra, Frank Li
On Mon, Jul 06, 2026 at 10:20:38PM +0900, Koichiro Den wrote:
> On Thu, Jul 02, 2026 at 05:21:20PM -0400, Frank.Li@oss.nxp.com wrote:
> > Koichiro Den:
> > My hardware temperately is unavaible recently. Can you help test
> > it.
>
> Sure, I can test it on my side. I'll report back once I have the results.
Here are the results. For the series:
Tested-by: Koichiro Den <den@valinux.co.jp>
* I don't see a significant difference between Before and After, but I don't
think that is an issue at all. Most of the differences look like normal
run-to-run variation.
* Each full fio test set was run three times in alternating order (B-A-B-A-B-A),
with runtime=30s and ramp_time=5s.
eDMA:
- Testbed:
* Endpoint: RK3588 (Rock 5B)
controller IP version: v5.60a
ll_max: 170
- Summary by group (BW delta %)
all n=26 mean= -2.3 median= +0.2 min= -28.0 max= +11.7
read n=14 mean= -3.2 median= +0.2 min= -17.3 max= +3.1
write n=11 mean= -1.5 median= -0.2 min= -28.0 max= +11.7
qd32 n=16 mean= +0.5 median= +0.3 min= -3.8 max= +3.1
q1 n= 9 mean= -7.6 median= -6.7 min= -28.0 max= +11.7
small 4K n= 6 mean= -4.0 median= +1.1 min= -28.0 max= +3.1
large >=128K n=20 mean= -1.8 median= +0.1 min= -17.3 max= +11.7
- Before mean -> After mean (MiB/s)
Case Before After Delta
--------------------------- ----------------- ----------------- ------
Rnd read 4KB q1 1j 33.4 (sd 10.1) 32.0 (sd 10.9) -4.0%
Rnd read 4KB q32 1j 196.0 (sd 28.6) 202.0 (sd 29.5) +3.1%
Rnd read 4KB q32 4j 196.7 (sd 29.2) 202.0 (sd 25.1) +2.7%
Rnd read 128KB q1 1j 497.7 (sd 12.2) 420.7 (sd 181.3) -15.5%
Rnd read 128KB q32 1j 2248.0 (sd 6.6) 2277.3 (sd 34.2) +1.3%
Rnd read 128KB q32 4j 2381.3 (sd 2.5) 2386.3 (sd 17.9) +0.2%
Rnd read 512KB q1 1j 627.3 (sd 15.2) 585.3 (sd 78.2) -6.7%
Rnd read 512KB q32 1j 2376.0 (sd 5.2) 2381.3 (sd 21.4) +0.2%
Rnd read 512KB q32 4j 2379.7 (sd 6.7) 2386.7 (sd 17.6) +0.3%
Rnd write 4KB q1 1j 28.1 (sd 4.1) 20.2 (sd 10.1) -28.0%
Rnd write 4KB q32 1j 120.3 (sd 6.1) 122.0 (sd 6.2) +1.4%
Rnd write 4KB q32 4j 124.7 (sd 3.8) 125.7 (sd 4.6) +0.8%
Rnd write 128KB q1 1j 318.7 (sd 44.7) 327.0 (sd 4.4) +2.6%
Rnd write 128KB q32 1j 1080.0 (sd 20.2) 1077.3 (sd 37.6) -0.2%
Rnd write 128KB q32 4j 1069.7 (sd 20.3) 1056.0 (sd 46.2) -1.3%
Seq read 128KB q1 1j 486.3 (sd 138.3) 402.3 (sd 38.0) -17.3%
Seq read 128KB q32 1j 2245.3 (sd 3.5) 2258.7 (sd 26.3) +0.6%
Seq read 512KB q1 1j 662.0 (sd 29.2) 594.3 (sd 13.7) -10.2%
Seq read 512KB q32 1j 2375.7 (sd 7.4) 2382.0 (sd 22.9) +0.3%
Seq read 1MB q32 1j 2380.7 (sd 4.7) 2385.3 (sd 19.3) +0.2%
Seq write 128KB q1 1j 342.0 (sd 58.9) 382.0 (sd 101.1) +11.7%
Seq write 128KB q32 1j 1080.3 (sd 48.8) 1070.7 (sd 37.0) -0.9%
Seq write 512KB q1 1j 509.7 (sd 35.4) 502.7 (sd 39.2) -1.4%
Seq write 512KB q32 1j 1043.3 (sd 56.7) 1074.0 (sd 47.8) +2.9%
Seq write 1MB q32 1j 989.3 (sd 23.0) 952.0 (sd 57.4) -3.8%
Rnd rdwr 4K..1MB q8 4j 841.3 (sd 15.1) 841.7 (sd 12.9) +0.0%
HDMA:
- Testbed:
* Endpoint: SpacemiT K3
controller IP version: v6.30a
ll_max: 170
- Summary by group (BW delta %)
all n=26 mean= +1.1 median= -0.6 min= -4.4 max= +9.5
read n=14 mean= +2.1 median= +0.7 min= -2.5 max= +9.5
write n=11 mean= -0.1 median= -0.8 min= -4.4 max= +4.7
qd32 n=16 mean= +0.6 median= -0.8 min= -2.5 max= +9.5
q1 n= 9 mean= +2.0 median= +4.4 min= -4.4 max= +7.9
small 4K n= 6 mean= +4.8 median= +4.5 min= +0.2 max= +9.5
large >=128K n=20 mean= -0.0 median= -0.9 min= -4.4 max= +7.9
- Before mean -> After mean (MiB/s)
Case Before After Delta
--------------------------- ----------------- ----------------- ------
Rnd read 4KB q1 1j 66.3 (sd 5.8) 69.4 (sd 7.0) +4.6%
Rnd read 4KB q32 1j 300.3 (sd 45.5) 329.0 (sd 21.7) +9.5%
Rnd read 4KB q32 4j 312.0 (sd 51.1) 341.7 (sd 3.1) +9.5%
Rnd read 128KB q1 1j 705.7 (sd 34.8) 736.7 (sd 51.6) +4.4%
Rnd read 128KB q32 1j 1507.7 (sd 25.6) 1486.3 (sd 5.9) -1.4%
Rnd read 128KB q32 4j 1549.7 (sd 7.0) 1534.3 (sd 16.9) -1.0%
Rnd read 512KB q1 1j 848.7 (sd 9.5) 858.0 (sd 15.5) +1.1%
Rnd read 512KB q32 1j 1530.0 (sd 27.0) 1536.0 (sd 14.8) +0.4%
Rnd read 512KB q32 4j 1519.0 (sd 66.7) 1544.3 (sd 15.0) +1.7%
Rnd write 4KB q1 1j 64.0 (sd 6.2) 66.9 (sd 2.2) +4.5%
Rnd write 4KB q32 1j 199.3 (sd 7.1) 199.7 (sd 2.9) +0.2%
Rnd write 4KB q32 4j 199.7 (sd 7.6) 200.3 (sd 3.2) +0.3%
Rnd write 128KB q1 1j 558.3 (sd 18.3) 533.7 (sd 5.0) -4.4%
Rnd write 128KB q32 1j 1248.0 (sd 21.3) 1237.3 (sd 7.5) -0.9%
Rnd write 128KB q32 4j 1248.7 (sd 23.0) 1238.0 (sd 6.1) -0.9%
Seq read 128KB q1 1j 640.7 (sd 60.1) 691.3 (sd 9.0) +7.9%
Seq read 128KB q32 1j 1507.7 (sd 24.2) 1488.3 (sd 5.1) -1.3%
Seq read 512KB q1 1j 866.7 (sd 45.8) 847.0 (sd 32.2) -2.3%
Seq read 512KB q32 1j 1532.3 (sd 31.7) 1516.7 (sd 40.3) -1.0%
Seq read 1MB q32 1j 1550.7 (sd 7.2) 1512.0 (sd 32.9) -2.5%
Seq write 128KB q1 1j 514.0 (sd 34.7) 538.0 (sd 15.1) +4.7%
Seq write 128KB q32 1j 1248.0 (sd 22.1) 1237.0 (sd 7.8) -0.9%
Seq write 512KB q1 1j 755.7 (sd 30.0) 739.3 (sd 2.1) -2.2%
Seq write 512KB q32 1j 1248.7 (sd 22.6) 1238.3 (sd 6.7) -0.8%
Seq write 1MB q32 1j 1248.0 (sd 22.5) 1238.3 (sd 7.6) -0.8%
Rnd rdwr 4K..1MB q8 4j 869.0 (sd 8.9) 865.3 (sd 1.5) -0.4%
Best regards,
Koichiro
>
> Best regards,
> Koichiro
>
> >
> > Rebase and compile test only now.
> >
> > Verma, Devendra:
> > Can you help check if block non-ll mode?
> >
> > Frank
> >
> > Basic change
> >
> > struct dw_edma_desc *desc
> > └─ chunk list
> > └─ burst list
> >
> > To
> >
> > struct dw_edma_desc *desc
> > └─ burst[n]
> >
> > And reduce at least 2 times kzalloc() for each dma descriptor create.
> >
> > I only test eDMA part, not hardware test hdma part.
> >
> > The finial goal is dymatic add DMA request when DMA running. So needn't
> > wait for irq for fetch next round DMA request.
> >
> > This work is neccesary to for dymatic DMA request appending.
> >
> > The post this part first to review and test firstly during working dymatic
> > DMA part.
> >
> > performance is little bit better. Use NVME as EP function
> >
> > Before
> >
> > Rnd read, 4KB, QD=1, 1 job : IOPS=6660, BW=26.0MiB/s (27.3MB/s)
> > Rnd read, 4KB, QD=32, 1 job : IOPS=28.6k, BW=112MiB/s (117MB/s)
> > Rnd read, 4KB, QD=32, 4 jobs: IOPS=33.4k, BW=130MiB/s (137MB/s)
> > Rnd read, 128KB, QD=1, 1 job : IOPS=914, BW=114MiB/s (120MB/s)
> > Rnd read, 128KB, QD=32, 1 job : IOPS=1204, BW=151MiB/s (158MB/s)
> > Rnd read, 128KB, QD=32, 4 jobs: IOPS=1255, BW=157MiB/s (165MB/s)
> > Rnd read, 512KB, QD=1, 1 job : IOPS=248, BW=124MiB/s (131MB/s)
> > Rnd read, 512KB, QD=32, 1 job : IOPS=353, BW=177MiB/s (185MB/s)
> > Rnd read, 512KB, QD=32, 4 jobs: IOPS=388, BW=194MiB/s (204MB/s)
> > Rnd write, 4KB, QD=1, 1 job : IOPS=6241, BW=24.4MiB/s (25.6MB/s)
> > Rnd write, 4KB, QD=32, 1 job : IOPS=24.7k, BW=96.5MiB/s (101MB/s)
> > Rnd write, 4KB, QD=32, 4 jobs: IOPS=26.9k, BW=105MiB/s (110MB/s)
> > Rnd write, 128KB, QD=1, 1 job : IOPS=780, BW=97.5MiB/s (102MB/s)
> > Rnd write, 128KB, QD=32, 1 job : IOPS=987, BW=123MiB/s (129MB/s)
> > Rnd write, 128KB, QD=32, 4 jobs: IOPS=1021, BW=128MiB/s (134MB/s)
> > Seq read, 128KB, QD=1, 1 job : IOPS=1190, BW=149MiB/s (156MB/s)
> > Seq read, 128KB, QD=32, 1 job : IOPS=1400, BW=175MiB/s (184MB/s)
> > Seq read, 512KB, QD=1, 1 job : IOPS=243, BW=122MiB/s (128MB/s)
> > Seq read, 512KB, QD=32, 1 job : IOPS=355, BW=178MiB/s (186MB/s)
> > Seq read, 1MB, QD=32, 1 job : IOPS=191, BW=192MiB/s (201MB/s)
> > Seq write, 128KB, QD=1, 1 job : IOPS=784, BW=98.1MiB/s (103MB/s)
> > Seq write, 128KB, QD=32, 1 job : IOPS=1030, BW=129MiB/s (135MB/s)
> > Seq write, 512KB, QD=1, 1 job : IOPS=216, BW=108MiB/s (114MB/s)
> > Seq write, 512KB, QD=32, 1 job : IOPS=295, BW=148MiB/s (155MB/s)
> > Seq write, 1MB, QD=32, 1 job : IOPS=164, BW=165MiB/s (173MB/s)
> > Rnd rdwr, 4K..1MB, QD=8, 4 jobs: IOPS=250, BW=126MiB/s (132MB/s)
> > IOPS=261, BW=132MiB/s (138MB/s
> >
> > After
> > Rnd read, 4KB, QD=1, 1 job : IOPS=6780, BW=26.5MiB/s (27.8MB/s)
> > Rnd read, 4KB, QD=32, 1 job : IOPS=28.6k, BW=112MiB/s (117MB/s)
> > Rnd read, 4KB, QD=32, 4 jobs: IOPS=33.4k, BW=130MiB/s (137MB/s)
> > Rnd read, 128KB, QD=1, 1 job : IOPS=1188, BW=149MiB/s (156MB/s)
> > Rnd read, 128KB, QD=32, 1 job : IOPS=1440, BW=180MiB/s (189MB/s)
> > Rnd read, 128KB, QD=32, 4 jobs: IOPS=1282, BW=160MiB/s (168MB/s)
> > Rnd read, 512KB, QD=1, 1 job : IOPS=254, BW=127MiB/s (134MB/s)
> > Rnd read, 512KB, QD=32, 1 job : IOPS=354, BW=177MiB/s (186MB/s)
> > Rnd read, 512KB, QD=32, 4 jobs: IOPS=388, BW=194MiB/s (204MB/s)
> > Rnd write, 4KB, QD=1, 1 job : IOPS=6282, BW=24.5MiB/s (25.7MB/s)
> > Rnd write, 4KB, QD=32, 1 job : IOPS=24.9k, BW=97.5MiB/s (102MB/s)
> > Rnd write, 4KB, QD=32, 4 jobs: IOPS=27.4k, BW=107MiB/s (112MB/s)
> > Rnd write, 128KB, QD=1, 1 job : IOPS=1098, BW=137MiB/s (144MB/s)
> > Rnd write, 128KB, QD=32, 1 job : IOPS=1195, BW=149MiB/s (157MB/s)
> > Rnd write, 128KB, QD=32, 4 jobs: IOPS=1120, BW=140MiB/s (147MB/s)
> > Seq read, 128KB, QD=1, 1 job : IOPS=936, BW=117MiB/s (123MB/s)
> > Seq read, 128KB, QD=32, 1 job : IOPS=1218, BW=152MiB/s (160MB/s)
> > Seq read, 512KB, QD=1, 1 job : IOPS=301, BW=151MiB/s (158MB/s)
> > Seq read, 512KB, QD=32, 1 job : IOPS=360, BW=180MiB/s (189MB/s)
> > Seq read, 1MB, QD=32, 1 job : IOPS=193, BW=194MiB/s (203MB/s)
> > Seq write, 128KB, QD=1, 1 job : IOPS=796, BW=99.5MiB/s (104MB/s)
> > Seq write, 128KB, QD=32, 1 job : IOPS=1019, BW=127MiB/s (134MB/s)
> > Seq write, 512KB, QD=1, 1 job : IOPS=213, BW=107MiB/s (112MB/s)
> > Seq write, 512KB, QD=32, 1 job : IOPS=273, BW=137MiB/s (143MB/s)
> > Seq write, 1MB, QD=32, 1 job : IOPS=168, BW=168MiB/s (177MB/s)
> > Rnd rdwr, 4K..1MB, QD=8, 4 jobs: IOPS=255, BW=128MiB/s (134MB/s)
> > IOPS=266, BW=135MiB/s (141MB/s)
> >
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > Changes in v3:
> > - remove patch dmaengine: dw-edma: Remove ll_max = -1 in dw_edma_channel_setup()
> > - rebase to vnod's dmaengine topic/config_prep_api
> > - Add non-ll-start() callback to handle non-ll mode transfer
> > - Link to v2: https://lore.kernel.org/r/20260109-edma_ll-v2-0-5c0b27b2c664@nxp.com
> >
> > Changes in v2:
> > - use 'eDMA' and 'HDMA' at commit message
> > - remove debug code.
> > - keep 'inline' to avoid build warning
> > - Link to v1: https://lore.kernel.org/r/20251212-edma_ll-v1-0-fc863d9f5ca3@nxp.com
> >
> > ---
> > Frank Li (10):
> > dmaengine: dw-edma: Move control field update of DMA link to the last step
> > dmaengine: dw-edma: Add xfer_sz field to struct dw_edma_chunk
> > dmaengine: dw-edma: Move ll_region from struct dw_edma_chunk to struct dw_edma_chan
> > dmaengine: dw-edma: Pass down dw_edma_chan to reduce one level of indirection
> > dmaengine: dw-edma: Add helper dw_(edma|hdma)_v0_core_ch_enable()
> > dmaengine: dw-edma: Add callbacks to fill link list entries
> > dmaengine: dw-edma: Add non_ll_start() callback
> > dmaengine: dw-edma: Use common dw_edma_core_start() for both eDMA and HDMA
> > dmaengine: dw-edma: Use burst array instead of linked list
> > dmaengine: dw-edma: Remove struct dw_edma_chunk
> >
> > drivers/dma/dw-edma/dw-edma-core.c | 216 ++++++++----------------------
> > drivers/dma/dw-edma/dw-edma-core.h | 65 ++++++---
> > drivers/dma/dw-edma/dw-edma-v0-core.c | 240 +++++++++++++++++-----------------
> > drivers/dma/dw-edma/dw-hdma-v0-core.c | 169 ++++++++++++------------
> > 4 files changed, 302 insertions(+), 388 deletions(-)
> > ---
> > base-commit: c9e9927c6d8346cdf6555a8f97da093980172e4b
> > change-id: 20251211-edma_ll-0904ba089f01
> >
> > Best regards,
> > --
> > Frank Li <Frank.Li@nxp.com>
> >
>
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v3 00/10] dmaengine: dw-edma: flatten desc structions and simple code
2026-07-08 14:59 ` Koichiro Den
@ 2026-07-08 20:55 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2026-07-08 20:55 UTC (permalink / raw)
To: Koichiro Den
Cc: Manivannan Sadhasivam, Vinod Koul, Gustavo Pimentel, Kees Cook,
Gustavo A. R. Silva, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Christoph Hellwig,
Niklas Cassel, dmaengine, linux-kernel, linux-hardening,
linux-pci, linux-nvme, imx, Verma, Devendra, Frank Li
On Wed, Jul 08, 2026 at 11:59:21PM +0900, Koichiro Den wrote:
> On Mon, Jul 06, 2026 at 10:20:38PM +0900, Koichiro Den wrote:
> > On Thu, Jul 02, 2026 at 05:21:20PM -0400, Frank.Li@oss.nxp.com wrote:
> > > Koichiro Den:
> > > My hardware temperately is unavaible recently. Can you help test
> > > it.
> >
> > Sure, I can test it on my side. I'll report back once I have the results.
>
> Here are the results. For the series:
>
> Tested-by: Koichiro Den <den@valinux.co.jp>
Thank you for testing it. I just post v4, but still have issues reported
by sashiko.
Frank
>
> * I don't see a significant difference between Before and After, but I don't
> think that is an issue at all. Most of the differences look like normal
> run-to-run variation.
> * Each full fio test set was run three times in alternating order (B-A-B-A-B-A),
> with runtime=30s and ramp_time=5s.
>
> eDMA:
> - Testbed:
> * Endpoint: RK3588 (Rock 5B)
> controller IP version: v5.60a
> ll_max: 170
>
> - Summary by group (BW delta %)
> all n=26 mean= -2.3 median= +0.2 min= -28.0 max= +11.7
> read n=14 mean= -3.2 median= +0.2 min= -17.3 max= +3.1
> write n=11 mean= -1.5 median= -0.2 min= -28.0 max= +11.7
> qd32 n=16 mean= +0.5 median= +0.3 min= -3.8 max= +3.1
> q1 n= 9 mean= -7.6 median= -6.7 min= -28.0 max= +11.7
> small 4K n= 6 mean= -4.0 median= +1.1 min= -28.0 max= +3.1
> large >=128K n=20 mean= -1.8 median= +0.1 min= -17.3 max= +11.7
>
> - Before mean -> After mean (MiB/s)
>
> Case Before After Delta
> --------------------------- ----------------- ----------------- ------
> Rnd read 4KB q1 1j 33.4 (sd 10.1) 32.0 (sd 10.9) -4.0%
> Rnd read 4KB q32 1j 196.0 (sd 28.6) 202.0 (sd 29.5) +3.1%
> Rnd read 4KB q32 4j 196.7 (sd 29.2) 202.0 (sd 25.1) +2.7%
> Rnd read 128KB q1 1j 497.7 (sd 12.2) 420.7 (sd 181.3) -15.5%
> Rnd read 128KB q32 1j 2248.0 (sd 6.6) 2277.3 (sd 34.2) +1.3%
> Rnd read 128KB q32 4j 2381.3 (sd 2.5) 2386.3 (sd 17.9) +0.2%
> Rnd read 512KB q1 1j 627.3 (sd 15.2) 585.3 (sd 78.2) -6.7%
> Rnd read 512KB q32 1j 2376.0 (sd 5.2) 2381.3 (sd 21.4) +0.2%
> Rnd read 512KB q32 4j 2379.7 (sd 6.7) 2386.7 (sd 17.6) +0.3%
> Rnd write 4KB q1 1j 28.1 (sd 4.1) 20.2 (sd 10.1) -28.0%
> Rnd write 4KB q32 1j 120.3 (sd 6.1) 122.0 (sd 6.2) +1.4%
> Rnd write 4KB q32 4j 124.7 (sd 3.8) 125.7 (sd 4.6) +0.8%
> Rnd write 128KB q1 1j 318.7 (sd 44.7) 327.0 (sd 4.4) +2.6%
> Rnd write 128KB q32 1j 1080.0 (sd 20.2) 1077.3 (sd 37.6) -0.2%
> Rnd write 128KB q32 4j 1069.7 (sd 20.3) 1056.0 (sd 46.2) -1.3%
> Seq read 128KB q1 1j 486.3 (sd 138.3) 402.3 (sd 38.0) -17.3%
> Seq read 128KB q32 1j 2245.3 (sd 3.5) 2258.7 (sd 26.3) +0.6%
> Seq read 512KB q1 1j 662.0 (sd 29.2) 594.3 (sd 13.7) -10.2%
> Seq read 512KB q32 1j 2375.7 (sd 7.4) 2382.0 (sd 22.9) +0.3%
> Seq read 1MB q32 1j 2380.7 (sd 4.7) 2385.3 (sd 19.3) +0.2%
> Seq write 128KB q1 1j 342.0 (sd 58.9) 382.0 (sd 101.1) +11.7%
> Seq write 128KB q32 1j 1080.3 (sd 48.8) 1070.7 (sd 37.0) -0.9%
> Seq write 512KB q1 1j 509.7 (sd 35.4) 502.7 (sd 39.2) -1.4%
> Seq write 512KB q32 1j 1043.3 (sd 56.7) 1074.0 (sd 47.8) +2.9%
> Seq write 1MB q32 1j 989.3 (sd 23.0) 952.0 (sd 57.4) -3.8%
> Rnd rdwr 4K..1MB q8 4j 841.3 (sd 15.1) 841.7 (sd 12.9) +0.0%
>
> HDMA:
> - Testbed:
> * Endpoint: SpacemiT K3
> controller IP version: v6.30a
> ll_max: 170
>
> - Summary by group (BW delta %)
>
> all n=26 mean= +1.1 median= -0.6 min= -4.4 max= +9.5
> read n=14 mean= +2.1 median= +0.7 min= -2.5 max= +9.5
> write n=11 mean= -0.1 median= -0.8 min= -4.4 max= +4.7
> qd32 n=16 mean= +0.6 median= -0.8 min= -2.5 max= +9.5
> q1 n= 9 mean= +2.0 median= +4.4 min= -4.4 max= +7.9
> small 4K n= 6 mean= +4.8 median= +4.5 min= +0.2 max= +9.5
> large >=128K n=20 mean= -0.0 median= -0.9 min= -4.4 max= +7.9
>
> - Before mean -> After mean (MiB/s)
>
> Case Before After Delta
> --------------------------- ----------------- ----------------- ------
> Rnd read 4KB q1 1j 66.3 (sd 5.8) 69.4 (sd 7.0) +4.6%
> Rnd read 4KB q32 1j 300.3 (sd 45.5) 329.0 (sd 21.7) +9.5%
> Rnd read 4KB q32 4j 312.0 (sd 51.1) 341.7 (sd 3.1) +9.5%
> Rnd read 128KB q1 1j 705.7 (sd 34.8) 736.7 (sd 51.6) +4.4%
> Rnd read 128KB q32 1j 1507.7 (sd 25.6) 1486.3 (sd 5.9) -1.4%
> Rnd read 128KB q32 4j 1549.7 (sd 7.0) 1534.3 (sd 16.9) -1.0%
> Rnd read 512KB q1 1j 848.7 (sd 9.5) 858.0 (sd 15.5) +1.1%
> Rnd read 512KB q32 1j 1530.0 (sd 27.0) 1536.0 (sd 14.8) +0.4%
> Rnd read 512KB q32 4j 1519.0 (sd 66.7) 1544.3 (sd 15.0) +1.7%
> Rnd write 4KB q1 1j 64.0 (sd 6.2) 66.9 (sd 2.2) +4.5%
> Rnd write 4KB q32 1j 199.3 (sd 7.1) 199.7 (sd 2.9) +0.2%
> Rnd write 4KB q32 4j 199.7 (sd 7.6) 200.3 (sd 3.2) +0.3%
> Rnd write 128KB q1 1j 558.3 (sd 18.3) 533.7 (sd 5.0) -4.4%
> Rnd write 128KB q32 1j 1248.0 (sd 21.3) 1237.3 (sd 7.5) -0.9%
> Rnd write 128KB q32 4j 1248.7 (sd 23.0) 1238.0 (sd 6.1) -0.9%
> Seq read 128KB q1 1j 640.7 (sd 60.1) 691.3 (sd 9.0) +7.9%
> Seq read 128KB q32 1j 1507.7 (sd 24.2) 1488.3 (sd 5.1) -1.3%
> Seq read 512KB q1 1j 866.7 (sd 45.8) 847.0 (sd 32.2) -2.3%
> Seq read 512KB q32 1j 1532.3 (sd 31.7) 1516.7 (sd 40.3) -1.0%
> Seq read 1MB q32 1j 1550.7 (sd 7.2) 1512.0 (sd 32.9) -2.5%
> Seq write 128KB q1 1j 514.0 (sd 34.7) 538.0 (sd 15.1) +4.7%
> Seq write 128KB q32 1j 1248.0 (sd 22.1) 1237.0 (sd 7.8) -0.9%
> Seq write 512KB q1 1j 755.7 (sd 30.0) 739.3 (sd 2.1) -2.2%
> Seq write 512KB q32 1j 1248.7 (sd 22.6) 1238.3 (sd 6.7) -0.8%
> Seq write 1MB q32 1j 1248.0 (sd 22.5) 1238.3 (sd 7.6) -0.8%
> Rnd rdwr 4K..1MB q8 4j 869.0 (sd 8.9) 865.3 (sd 1.5) -0.4%
>
> Best regards,
> Koichiro
>
> >
> > Best regards,
> > Koichiro
> >
> > >
> > > Rebase and compile test only now.
> > >
> > > Verma, Devendra:
> > > Can you help check if block non-ll mode?
> > >
> > > Frank
> > >
> > > Basic change
> > >
> > > struct dw_edma_desc *desc
> > > └─ chunk list
> > > └─ burst list
> > >
> > > To
> > >
> > > struct dw_edma_desc *desc
> > > └─ burst[n]
> > >
> > > And reduce at least 2 times kzalloc() for each dma descriptor create.
> > >
> > > I only test eDMA part, not hardware test hdma part.
> > >
> > > The finial goal is dymatic add DMA request when DMA running. So needn't
> > > wait for irq for fetch next round DMA request.
> > >
> > > This work is neccesary to for dymatic DMA request appending.
> > >
> > > The post this part first to review and test firstly during working dymatic
> > > DMA part.
> > >
> > > performance is little bit better. Use NVME as EP function
> > >
> > > Before
> > >
> > > Rnd read, 4KB, QD=1, 1 job : IOPS=6660, BW=26.0MiB/s (27.3MB/s)
> > > Rnd read, 4KB, QD=32, 1 job : IOPS=28.6k, BW=112MiB/s (117MB/s)
> > > Rnd read, 4KB, QD=32, 4 jobs: IOPS=33.4k, BW=130MiB/s (137MB/s)
> > > Rnd read, 128KB, QD=1, 1 job : IOPS=914, BW=114MiB/s (120MB/s)
> > > Rnd read, 128KB, QD=32, 1 job : IOPS=1204, BW=151MiB/s (158MB/s)
> > > Rnd read, 128KB, QD=32, 4 jobs: IOPS=1255, BW=157MiB/s (165MB/s)
> > > Rnd read, 512KB, QD=1, 1 job : IOPS=248, BW=124MiB/s (131MB/s)
> > > Rnd read, 512KB, QD=32, 1 job : IOPS=353, BW=177MiB/s (185MB/s)
> > > Rnd read, 512KB, QD=32, 4 jobs: IOPS=388, BW=194MiB/s (204MB/s)
> > > Rnd write, 4KB, QD=1, 1 job : IOPS=6241, BW=24.4MiB/s (25.6MB/s)
> > > Rnd write, 4KB, QD=32, 1 job : IOPS=24.7k, BW=96.5MiB/s (101MB/s)
> > > Rnd write, 4KB, QD=32, 4 jobs: IOPS=26.9k, BW=105MiB/s (110MB/s)
> > > Rnd write, 128KB, QD=1, 1 job : IOPS=780, BW=97.5MiB/s (102MB/s)
> > > Rnd write, 128KB, QD=32, 1 job : IOPS=987, BW=123MiB/s (129MB/s)
> > > Rnd write, 128KB, QD=32, 4 jobs: IOPS=1021, BW=128MiB/s (134MB/s)
> > > Seq read, 128KB, QD=1, 1 job : IOPS=1190, BW=149MiB/s (156MB/s)
> > > Seq read, 128KB, QD=32, 1 job : IOPS=1400, BW=175MiB/s (184MB/s)
> > > Seq read, 512KB, QD=1, 1 job : IOPS=243, BW=122MiB/s (128MB/s)
> > > Seq read, 512KB, QD=32, 1 job : IOPS=355, BW=178MiB/s (186MB/s)
> > > Seq read, 1MB, QD=32, 1 job : IOPS=191, BW=192MiB/s (201MB/s)
> > > Seq write, 128KB, QD=1, 1 job : IOPS=784, BW=98.1MiB/s (103MB/s)
> > > Seq write, 128KB, QD=32, 1 job : IOPS=1030, BW=129MiB/s (135MB/s)
> > > Seq write, 512KB, QD=1, 1 job : IOPS=216, BW=108MiB/s (114MB/s)
> > > Seq write, 512KB, QD=32, 1 job : IOPS=295, BW=148MiB/s (155MB/s)
> > > Seq write, 1MB, QD=32, 1 job : IOPS=164, BW=165MiB/s (173MB/s)
> > > Rnd rdwr, 4K..1MB, QD=8, 4 jobs: IOPS=250, BW=126MiB/s (132MB/s)
> > > IOPS=261, BW=132MiB/s (138MB/s
> > >
> > > After
> > > Rnd read, 4KB, QD=1, 1 job : IOPS=6780, BW=26.5MiB/s (27.8MB/s)
> > > Rnd read, 4KB, QD=32, 1 job : IOPS=28.6k, BW=112MiB/s (117MB/s)
> > > Rnd read, 4KB, QD=32, 4 jobs: IOPS=33.4k, BW=130MiB/s (137MB/s)
> > > Rnd read, 128KB, QD=1, 1 job : IOPS=1188, BW=149MiB/s (156MB/s)
> > > Rnd read, 128KB, QD=32, 1 job : IOPS=1440, BW=180MiB/s (189MB/s)
> > > Rnd read, 128KB, QD=32, 4 jobs: IOPS=1282, BW=160MiB/s (168MB/s)
> > > Rnd read, 512KB, QD=1, 1 job : IOPS=254, BW=127MiB/s (134MB/s)
> > > Rnd read, 512KB, QD=32, 1 job : IOPS=354, BW=177MiB/s (186MB/s)
> > > Rnd read, 512KB, QD=32, 4 jobs: IOPS=388, BW=194MiB/s (204MB/s)
> > > Rnd write, 4KB, QD=1, 1 job : IOPS=6282, BW=24.5MiB/s (25.7MB/s)
> > > Rnd write, 4KB, QD=32, 1 job : IOPS=24.9k, BW=97.5MiB/s (102MB/s)
> > > Rnd write, 4KB, QD=32, 4 jobs: IOPS=27.4k, BW=107MiB/s (112MB/s)
> > > Rnd write, 128KB, QD=1, 1 job : IOPS=1098, BW=137MiB/s (144MB/s)
> > > Rnd write, 128KB, QD=32, 1 job : IOPS=1195, BW=149MiB/s (157MB/s)
> > > Rnd write, 128KB, QD=32, 4 jobs: IOPS=1120, BW=140MiB/s (147MB/s)
> > > Seq read, 128KB, QD=1, 1 job : IOPS=936, BW=117MiB/s (123MB/s)
> > > Seq read, 128KB, QD=32, 1 job : IOPS=1218, BW=152MiB/s (160MB/s)
> > > Seq read, 512KB, QD=1, 1 job : IOPS=301, BW=151MiB/s (158MB/s)
> > > Seq read, 512KB, QD=32, 1 job : IOPS=360, BW=180MiB/s (189MB/s)
> > > Seq read, 1MB, QD=32, 1 job : IOPS=193, BW=194MiB/s (203MB/s)
> > > Seq write, 128KB, QD=1, 1 job : IOPS=796, BW=99.5MiB/s (104MB/s)
> > > Seq write, 128KB, QD=32, 1 job : IOPS=1019, BW=127MiB/s (134MB/s)
> > > Seq write, 512KB, QD=1, 1 job : IOPS=213, BW=107MiB/s (112MB/s)
> > > Seq write, 512KB, QD=32, 1 job : IOPS=273, BW=137MiB/s (143MB/s)
> > > Seq write, 1MB, QD=32, 1 job : IOPS=168, BW=168MiB/s (177MB/s)
> > > Rnd rdwr, 4K..1MB, QD=8, 4 jobs: IOPS=255, BW=128MiB/s (134MB/s)
> > > IOPS=266, BW=135MiB/s (141MB/s)
> > >
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > Changes in v3:
> > > - remove patch dmaengine: dw-edma: Remove ll_max = -1 in dw_edma_channel_setup()
> > > - rebase to vnod's dmaengine topic/config_prep_api
> > > - Add non-ll-start() callback to handle non-ll mode transfer
> > > - Link to v2: https://lore.kernel.org/r/20260109-edma_ll-v2-0-5c0b27b2c664@nxp.com
> > >
> > > Changes in v2:
> > > - use 'eDMA' and 'HDMA' at commit message
> > > - remove debug code.
> > > - keep 'inline' to avoid build warning
> > > - Link to v1: https://lore.kernel.org/r/20251212-edma_ll-v1-0-fc863d9f5ca3@nxp.com
> > >
> > > ---
> > > Frank Li (10):
> > > dmaengine: dw-edma: Move control field update of DMA link to the last step
> > > dmaengine: dw-edma: Add xfer_sz field to struct dw_edma_chunk
> > > dmaengine: dw-edma: Move ll_region from struct dw_edma_chunk to struct dw_edma_chan
> > > dmaengine: dw-edma: Pass down dw_edma_chan to reduce one level of indirection
> > > dmaengine: dw-edma: Add helper dw_(edma|hdma)_v0_core_ch_enable()
> > > dmaengine: dw-edma: Add callbacks to fill link list entries
> > > dmaengine: dw-edma: Add non_ll_start() callback
> > > dmaengine: dw-edma: Use common dw_edma_core_start() for both eDMA and HDMA
> > > dmaengine: dw-edma: Use burst array instead of linked list
> > > dmaengine: dw-edma: Remove struct dw_edma_chunk
> > >
> > > drivers/dma/dw-edma/dw-edma-core.c | 216 ++++++++----------------------
> > > drivers/dma/dw-edma/dw-edma-core.h | 65 ++++++---
> > > drivers/dma/dw-edma/dw-edma-v0-core.c | 240 +++++++++++++++++-----------------
> > > drivers/dma/dw-edma/dw-hdma-v0-core.c | 169 ++++++++++++------------
> > > 4 files changed, 302 insertions(+), 388 deletions(-)
> > > ---
> > > base-commit: c9e9927c6d8346cdf6555a8f97da093980172e4b
> > > change-id: 20251211-edma_ll-0904ba089f01
> > >
> > > Best regards,
> > > --
> > > Frank Li <Frank.Li@nxp.com>
> > >
> >
^ permalink raw reply [flat|nested] 14+ messages in thread