* [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W Channels
@ 2026-06-03 14:41 Devendra K Verma
2026-06-04 19:58 ` Frank Li
0 siblings, 1 reply; 5+ messages in thread
From: Devendra K Verma @ 2026-06-03 14:41 UTC (permalink / raw)
To: bhelgaas, mani, vkoul, Frank.Li
Cc: dmaengine, linux-kernel, michal.simek, devendra.verma
As per 'Designware Cores PCI Express Controller Databook',
Section 7.1 - Overview, HDMA supports 64 Read and 64 Write
channels. Current controller driver supports up to 8 read and
write channels only. In order to utilize all the channels the
controller driver need to have the channel related structs
and variables as per the number of channels supported by IP.
Following changes are made to enable 64 Read / 64 Write
channel support:
o Defined HDMA specific macros to reflect the channel count.
o The count of ll_regions and dt_regions in dw_edma_chip and
dw_edma_pcie_data shall be in accordance to number of read
and write channels.
o In dw_edma_probe() configure the channels as per the channels
of the IP used.
o Changed mask types to u64 for higher channel counts.
Signed-off-by: Devendra K Verma <devendra.verma@amd.com>
---
Changes in v2:
o Fixed the pre-existing bug related to GET_CH_32
interchanging the channel direction and id.
This bug was not caused by any version of this patch.
o Fixed the issue when using for_each_set_bit() for mask
of u64 type.
Changes in v1:
o On review recommendation of sashiko bot, in the function
dw_hdma_v0_core_off(), the loop iterates over registers
as per the number of channels enabled and not on total
number of channels supported.
o Changed mask types to u64 for higher channel counts.
---
drivers/dma/dw-edma/dw-edma-core.c | 19 ++++++++++-----
drivers/dma/dw-edma/dw-edma-core.h | 4 +--
drivers/dma/dw-edma/dw-edma-pcie.c | 8 +++---
drivers/dma/dw-edma/dw-hdma-v0-core.c | 35 ++++++++++++++++++++-------
drivers/dma/dw-edma/dw-hdma-v0-regs.h | 2 +-
include/linux/dma/edma.h | 10 +++++---
6 files changed, 52 insertions(+), 26 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index c2feb3adc79f..adf1b3939f96 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -925,9 +925,9 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
irq = &dw->irq[pos];
if (chan->dir == EDMA_DIR_WRITE)
- irq->wr_mask |= BIT(chan->id);
+ irq->wr_mask |= BIT_ULL(chan->id);
else
- irq->rd_mask |= BIT(chan->id);
+ irq->rd_mask |= BIT_ULL(chan->id);
irq->dw = dw;
memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));
@@ -1079,6 +1079,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
struct dw_edma *dw;
u32 wr_alloc = 0;
u32 rd_alloc = 0;
+ u16 max_wr_cnt;
+ u16 max_rd_cnt;
int i, err;
if (!chip)
@@ -1094,20 +1096,25 @@ int dw_edma_probe(struct dw_edma_chip *chip)
dw->chip = chip;
- if (dw->chip->mf == EDMA_MF_HDMA_NATIVE)
+ if (dw->chip->mf == EDMA_MF_HDMA_NATIVE) {
dw_hdma_v0_core_register(dw);
- else
+ max_wr_cnt = HDMA_MAX_WR_CH;
+ max_rd_cnt = HDMA_MAX_RD_CH;
+ } else {
dw_edma_v0_core_register(dw);
+ max_wr_cnt = EDMA_MAX_WR_CH;
+ max_rd_cnt = EDMA_MAX_RD_CH;
+ }
raw_spin_lock_init(&dw->lock);
dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
dw_edma_core_ch_count(dw, EDMA_DIR_WRITE));
- dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
+ dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, max_wr_cnt);
dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
dw_edma_core_ch_count(dw, EDMA_DIR_READ));
- dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
+ dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, max_rd_cnt);
if (!dw->wr_ch_cnt && !dw->rd_ch_cnt)
return -EINVAL;
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 902574b1ba86..d12fefbf3952 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -91,8 +91,8 @@ struct dw_edma_chan {
struct dw_edma_irq {
struct msi_msg msi;
- u32 wr_mask;
- u32 rd_mask;
+ u64 wr_mask;
+ u64 rd_mask;
struct dw_edma *dw;
};
diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 0b30ce138503..79f653da8e0f 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -61,11 +61,11 @@ struct dw_edma_pcie_data {
/* eDMA registers location */
struct dw_edma_block rg;
/* eDMA memory linked list location */
- struct dw_edma_block ll_wr[EDMA_MAX_WR_CH];
- struct dw_edma_block ll_rd[EDMA_MAX_RD_CH];
+ struct dw_edma_block ll_wr[HDMA_MAX_WR_CH];
+ struct dw_edma_block ll_rd[HDMA_MAX_RD_CH];
/* eDMA memory data location */
- struct dw_edma_block dt_wr[EDMA_MAX_WR_CH];
- struct dw_edma_block dt_rd[EDMA_MAX_RD_CH];
+ struct dw_edma_block dt_wr[HDMA_MAX_WR_CH];
+ struct dw_edma_block dt_rd[HDMA_MAX_RD_CH];
/* Other */
enum dw_edma_map_format mf;
u8 irqs;
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 632abb8b481c..d4cfb2d456ab 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -53,13 +53,24 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
static void dw_hdma_v0_core_off(struct dw_edma *dw)
{
int id;
+ enum dw_edma_dir dir;
+
+ dir = EDMA_DIR_WRITE;
+ for (id = 0; id < dw->wr_ch_cnt; id++) {
+ SET_CH_32(dw, dir, id, int_setup,
+ HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
+ SET_CH_32(dw, dir, id, int_clear,
+ HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
+ SET_CH_32(dw, dir, id, ch_en, 0);
+ }
- for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) {
- SET_BOTH_CH_32(dw, id, int_setup,
- HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
- SET_BOTH_CH_32(dw, id, int_clear,
- HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
- SET_BOTH_CH_32(dw, id, ch_en, 0);
+ dir = EDMA_DIR_READ;
+ for (id = 0; id < dw->rd_ch_cnt; id++) {
+ SET_CH_32(dw, dir, id, int_setup,
+ HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
+ SET_CH_32(dw, dir, id, int_clear,
+ HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
+ SET_CH_32(dw, dir, id, ch_en, 0);
}
}
@@ -79,7 +90,7 @@ static enum dma_status dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan)
u32 tmp;
tmp = FIELD_GET(HDMA_V0_CH_STATUS_MASK,
- GET_CH_32(dw, chan->id, chan->dir, ch_stat));
+ GET_CH_32(dw, chan->dir, chan->id, ch_stat));
if (tmp == 1)
return DMA_IN_PROGRESS;
@@ -118,7 +129,8 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
unsigned long total, pos, val;
irqreturn_t ret = IRQ_NONE;
struct dw_edma_chan *chan;
- unsigned long off, mask;
+ unsigned long off;
+ u64 mask;
if (dir == EDMA_DIR_WRITE) {
total = dw->wr_ch_cnt;
@@ -130,7 +142,11 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
mask = dw_irq->rd_mask;
}
- for_each_set_bit(pos, &mask, total) {
+ while (mask) {
+ pos = __ffs64(mask);
+ if (pos >= total)
+ break;
+
chan = &dw->chan[pos + off];
val = dw_hdma_v0_core_status_int(chan);
@@ -147,6 +163,7 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
ret = IRQ_HANDLED;
}
+ mask &= mask - 1;
}
return ret;
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-regs.h b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index 7759ba9b4850..48e40efceb2e 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
+++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
@@ -11,7 +11,7 @@
#include <linux/dmaengine.h>
-#define HDMA_V0_MAX_NR_CH 8
+#define HDMA_V0_MAX_NR_CH 64
#define HDMA_V0_CH_EN BIT(0)
#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)
#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 1fafd5b0e315..da7a5cc93ad4 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -14,6 +14,8 @@
#define EDMA_MAX_WR_CH 8
#define EDMA_MAX_RD_CH 8
+#define HDMA_MAX_WR_CH 64
+#define HDMA_MAX_RD_CH 64
struct dw_edma;
@@ -89,12 +91,12 @@ struct dw_edma_chip {
u16 ll_wr_cnt;
u16 ll_rd_cnt;
/* link list address */
- struct dw_edma_region ll_region_wr[EDMA_MAX_WR_CH];
- struct dw_edma_region ll_region_rd[EDMA_MAX_RD_CH];
+ struct dw_edma_region ll_region_wr[HDMA_MAX_WR_CH];
+ struct dw_edma_region ll_region_rd[HDMA_MAX_RD_CH];
/* data region */
- struct dw_edma_region dt_region_wr[EDMA_MAX_WR_CH];
- struct dw_edma_region dt_region_rd[EDMA_MAX_RD_CH];
+ struct dw_edma_region dt_region_wr[HDMA_MAX_WR_CH];
+ struct dw_edma_region dt_region_rd[HDMA_MAX_RD_CH];
/* interrupt emulation */
int db_irq;
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W Channels
2026-06-03 14:41 [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W Channels Devendra K Verma
@ 2026-06-04 19:58 ` Frank Li
2026-06-05 11:48 ` Verma, Devendra
0 siblings, 1 reply; 5+ messages in thread
From: Frank Li @ 2026-06-04 19:58 UTC (permalink / raw)
To: Devendra K Verma
Cc: bhelgaas, mani, vkoul, Frank.Li, dmaengine, linux-kernel,
michal.simek
On Wed, Jun 03, 2026 at 08:11:47PM +0530, Devendra K Verma wrote:
> As per 'Designware Cores PCI Express Controller Databook',
> Section 7.1 - Overview, HDMA supports 64 Read and 64 Write
> channels. Current controller driver supports up to 8 read and
> write channels only. In order to utilize all the channels the
> controller driver need to have the channel related structs
> and variables as per the number of channels supported by IP.
> Following changes are made to enable 64 Read / 64 Write
> channel support:
>
> o Defined HDMA specific macros to reflect the channel count.
> o The count of ll_regions and dt_regions in dw_edma_chip and
> dw_edma_pcie_data shall be in accordance to number of read
> and write channels.
> o In dw_edma_probe() configure the channels as per the channels
> of the IP used.
> o Changed mask types to u64 for higher channel counts.
>
> Signed-off-by: Devendra K Verma <devendra.verma@amd.com>
> ---
> Changes in v2:
> o Fixed the pre-existing bug related to GET_CH_32
> interchanging the channel direction and id.
> This bug was not caused by any version of this patch.
> o Fixed the issue when using for_each_set_bit() for mask
> of u64 type.
>
> Changes in v1:
> o On review recommendation of sashiko bot, in the function
> dw_hdma_v0_core_off(), the loop iterates over registers
> as per the number of channels enabled and not on total
> number of channels supported.
> o Changed mask types to u64 for higher channel counts.
> ---
...
> +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> @@ -53,13 +53,24 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> static void dw_hdma_v0_core_off(struct dw_edma *dw)
> {
> int id;
> + enum dw_edma_dir dir;
> +
> + dir = EDMA_DIR_WRITE;
> + for (id = 0; id < dw->wr_ch_cnt; id++) {
> + SET_CH_32(dw, dir, id, int_setup,
> + HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
> + SET_CH_32(dw, dir, id, int_clear,
> + HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
> + SET_CH_32(dw, dir, id, ch_en, 0);
> + }
>
> - for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) {
> - SET_BOTH_CH_32(dw, id, int_setup,
> - HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
> - SET_BOTH_CH_32(dw, id, int_clear,
> - HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
> - SET_BOTH_CH_32(dw, id, ch_en, 0);
> + dir = EDMA_DIR_READ;
> + for (id = 0; id < dw->rd_ch_cnt; id++) {
> + SET_CH_32(dw, dir, id, int_setup,
> + HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
> + SET_CH_32(dw, dir, id, int_clear,
> + HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK);
> + SET_CH_32(dw, dir, id, ch_en, 0);
why SET_BOTH_CH_32 not work for 64 channel?
> }
> }
>
> @@ -79,7 +90,7 @@ static enum dma_status dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan)
> u32 tmp;
>
> tmp = FIELD_GET(HDMA_V0_CH_STATUS_MASK,
> - GET_CH_32(dw, chan->id, chan->dir, ch_stat));
> + GET_CH_32(dw, chan->dir, chan->id, ch_stat));
why need swtich id and dir here ?
Frank
>
> if (tmp == 1)
> return DMA_IN_PROGRESS;
> @@ -118,7 +129,8 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
> unsigned long total, pos, val;
> irqreturn_t ret = IRQ_NONE;
> struct dw_edma_chan *chan;
> - unsigned long off, mask;
> + unsigned long off;
> + u64 mask;
>
> if (dir == EDMA_DIR_WRITE) {
> total = dw->wr_ch_cnt;
> @@ -130,7 +142,11 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
> mask = dw_irq->rd_mask;
> }
>
> - for_each_set_bit(pos, &mask, total) {
> + while (mask) {
> + pos = __ffs64(mask);
> + if (pos >= total)
> + break;
> +
> chan = &dw->chan[pos + off];
>
> val = dw_hdma_v0_core_status_int(chan);
> @@ -147,6 +163,7 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
>
> ret = IRQ_HANDLED;
> }
> + mask &= mask - 1;
> }
>
> return ret;
> diff --git a/drivers/dma/dw-edma/dw-hdma-v0-regs.h b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> index 7759ba9b4850..48e40efceb2e 100644
> --- a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> +++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> @@ -11,7 +11,7 @@
>
> #include <linux/dmaengine.h>
>
> -#define HDMA_V0_MAX_NR_CH 8
> +#define HDMA_V0_MAX_NR_CH 64
> #define HDMA_V0_CH_EN BIT(0)
> #define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)
> #define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 1fafd5b0e315..da7a5cc93ad4 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -14,6 +14,8 @@
>
> #define EDMA_MAX_WR_CH 8
> #define EDMA_MAX_RD_CH 8
> +#define HDMA_MAX_WR_CH 64
> +#define HDMA_MAX_RD_CH 64
>
> struct dw_edma;
>
> @@ -89,12 +91,12 @@ struct dw_edma_chip {
> u16 ll_wr_cnt;
> u16 ll_rd_cnt;
> /* link list address */
> - struct dw_edma_region ll_region_wr[EDMA_MAX_WR_CH];
> - struct dw_edma_region ll_region_rd[EDMA_MAX_RD_CH];
> + struct dw_edma_region ll_region_wr[HDMA_MAX_WR_CH];
> + struct dw_edma_region ll_region_rd[HDMA_MAX_RD_CH];
>
> /* data region */
> - struct dw_edma_region dt_region_wr[EDMA_MAX_WR_CH];
> - struct dw_edma_region dt_region_rd[EDMA_MAX_RD_CH];
> + struct dw_edma_region dt_region_wr[HDMA_MAX_WR_CH];
> + struct dw_edma_region dt_region_rd[HDMA_MAX_RD_CH];
>
> /* interrupt emulation */
> int db_irq;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W Channels
2026-06-04 19:58 ` Frank Li
@ 2026-06-05 11:48 ` Verma, Devendra
2026-06-05 18:15 ` Frank Li
0 siblings, 1 reply; 5+ messages in thread
From: Verma, Devendra @ 2026-06-05 11:48 UTC (permalink / raw)
To: Frank Li
Cc: bhelgaas@google.com, mani@kernel.org, vkoul@kernel.org,
Frank.Li@kernel.org, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org, Simek, Michal
Public
> -----Original Message-----
> From: Frank Li <Frank.li@nxp.com>
> Sent: Friday, June 5, 2026 01:28
> To: Verma, Devendra <Devendra.Verma@amd.com>
> Cc: bhelgaas@google.com; mani@kernel.org; vkoul@kernel.org;
> Frank.Li@kernel.org; dmaengine@vger.kernel.org; linux-
> kernel@vger.kernel.org; Simek, Michal <michal.simek@amd.com>
> Subject: Re: [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W
> Channels
>
> On Wed, Jun 03, 2026 at 08:11:47PM +0530, Devendra K Verma wrote:
> > As per 'Designware Cores PCI Express Controller Databook', Section 7.1
> > - Overview, HDMA supports 64 Read and 64 Write channels. Current
> > controller driver supports up to 8 read and write channels only. In
> > order to utilize all the channels the controller driver need to have
> > the channel related structs and variables as per the number of
> > channels supported by IP.
> > Following changes are made to enable 64 Read / 64 Write channel
> > support:
> >
> > o Defined HDMA specific macros to reflect the channel count.
> > o The count of ll_regions and dt_regions in dw_edma_chip and
> > dw_edma_pcie_data shall be in accordance to number of read
> > and write channels.
> > o In dw_edma_probe() configure the channels as per the channels
> > of the IP used.
> > o Changed mask types to u64 for higher channel counts.
> >
> > Signed-off-by: Devendra K Verma <devendra.verma@amd.com>
> > ---
> > Changes in v2:
> > o Fixed the pre-existing bug related to GET_CH_32
> > interchanging the channel direction and id.
> > This bug was not caused by any version of this patch.
> > o Fixed the issue when using for_each_set_bit() for mask
> > of u64 type.
> >
> > Changes in v1:
> > o On review recommendation of sashiko bot, in the function
> > dw_hdma_v0_core_off(), the loop iterates over registers
> > as per the number of channels enabled and not on total
> > number of channels supported.
> > o Changed mask types to u64 for higher channel counts.
> > ---
> ...
> > +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> > @@ -53,13 +53,24 @@ __dw_ch_regs(struct dw_edma *dw, enum
> dw_edma_dir
> > dir, u16 ch) static void dw_hdma_v0_core_off(struct dw_edma *dw) {
> > int id;
> > + enum dw_edma_dir dir;
> > +
> > + dir = EDMA_DIR_WRITE;
> > + for (id = 0; id < dw->wr_ch_cnt; id++) {
> > + SET_CH_32(dw, dir, id, int_setup,
> > + HDMA_V0_STOP_INT_MASK |
> HDMA_V0_ABORT_INT_MASK);
> > + SET_CH_32(dw, dir, id, int_clear,
> > + HDMA_V0_STOP_INT_MASK |
> HDMA_V0_ABORT_INT_MASK);
> > + SET_CH_32(dw, dir, id, ch_en, 0);
> > + }
> >
> > - for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) {
> > - SET_BOTH_CH_32(dw, id, int_setup,
> > - HDMA_V0_STOP_INT_MASK |
> HDMA_V0_ABORT_INT_MASK);
> > - SET_BOTH_CH_32(dw, id, int_clear,
> > - HDMA_V0_STOP_INT_MASK |
> HDMA_V0_ABORT_INT_MASK);
> > - SET_BOTH_CH_32(dw, id, ch_en, 0);
> > + dir = EDMA_DIR_READ;
> > + for (id = 0; id < dw->rd_ch_cnt; id++) {
> > + SET_CH_32(dw, dir, id, int_setup,
> > + HDMA_V0_STOP_INT_MASK |
> HDMA_V0_ABORT_INT_MASK);
> > + SET_CH_32(dw, dir, id, int_clear,
> > + HDMA_V0_STOP_INT_MASK |
> HDMA_V0_ABORT_INT_MASK);
> > + SET_CH_32(dw, dir, id, ch_en, 0);
>
> why SET_BOTH_CH_32 not work for 64 channel?
>
SET_BOTH_CH_32 works, but this needs to be done on the channels enabled for the IP.
HDMA supports maximum of 64 channels. So if some IP enables 8 or fewer read / write channels only then the number of channels come from dw->wr_ch_cnt and dw->rd_ch_cnt. Now the logic is derived by individual read & write enabled channel count. Earlier, it was assumed that user will enable max of 8 channels which would have worked well using SET_BOTH_CH_32() but as the channels grow, the assumption that equal number of read / write channels and that they are set to max count are enabled might not hold true.
- Devendra
> > }
> > }
> >
> > @@ -79,7 +90,7 @@ static enum dma_status
> dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan)
> > u32 tmp;
> >
> > tmp = FIELD_GET(HDMA_V0_CH_STATUS_MASK,
> > - GET_CH_32(dw, chan->id, chan->dir, ch_stat));
> > + GET_CH_32(dw, chan->dir, chan->id, ch_stat));
>
> why need swtich id and dir here ?
>
> Frank
This is the correct order of arguments to the GET_CH_32. The second & third arguments shall be direction and channel_id respectively. It is a pre-existing issue reported by AI bot.
> >
> > if (tmp == 1)
> > return DMA_IN_PROGRESS;
> > @@ -118,7 +129,8 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq
> *dw_irq, enum dw_edma_dir dir,
> > unsigned long total, pos, val;
> > irqreturn_t ret = IRQ_NONE;
> > struct dw_edma_chan *chan;
> > - unsigned long off, mask;
> > + unsigned long off;
> > + u64 mask;
> >
> > if (dir == EDMA_DIR_WRITE) {
> > total = dw->wr_ch_cnt;
> > @@ -130,7 +142,11 @@ dw_hdma_v0_core_handle_int(struct
> dw_edma_irq *dw_irq, enum dw_edma_dir dir,
> > mask = dw_irq->rd_mask;
> > }
> >
> > - for_each_set_bit(pos, &mask, total) {
> > + while (mask) {
> > + pos = __ffs64(mask);
> > + if (pos >= total)
> > + break;
> > +
> > chan = &dw->chan[pos + off];
> >
> > val = dw_hdma_v0_core_status_int(chan); @@ -147,6 +163,7
> @@
> > dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum
> > dw_edma_dir dir,
> >
> > ret = IRQ_HANDLED;
> > }
> > + mask &= mask - 1;
> > }
> >
> > return ret;
> > diff --git a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > index 7759ba9b4850..48e40efceb2e 100644
> > --- a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > +++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > @@ -11,7 +11,7 @@
> >
> > #include <linux/dmaengine.h>
> >
> > -#define HDMA_V0_MAX_NR_CH 8
> > +#define HDMA_V0_MAX_NR_CH 64
> > #define HDMA_V0_CH_EN BIT(0)
> > #define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)
> > #define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)
> > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h index
> > 1fafd5b0e315..da7a5cc93ad4 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -14,6 +14,8 @@
> >
> > #define EDMA_MAX_WR_CH 8
> > #define EDMA_MAX_RD_CH 8
> > +#define HDMA_MAX_WR_CH 64
> > +#define HDMA_MAX_RD_CH 64
> >
> > struct dw_edma;
> >
> > @@ -89,12 +91,12 @@ struct dw_edma_chip {
> > u16 ll_wr_cnt;
> > u16 ll_rd_cnt;
> > /* link list address */
> > - struct dw_edma_region ll_region_wr[EDMA_MAX_WR_CH];
> > - struct dw_edma_region ll_region_rd[EDMA_MAX_RD_CH];
> > + struct dw_edma_region ll_region_wr[HDMA_MAX_WR_CH];
> > + struct dw_edma_region ll_region_rd[HDMA_MAX_RD_CH];
> >
> > /* data region */
> > - struct dw_edma_region dt_region_wr[EDMA_MAX_WR_CH];
> > - struct dw_edma_region dt_region_rd[EDMA_MAX_RD_CH];
> > + struct dw_edma_region dt_region_wr[HDMA_MAX_WR_CH];
> > + struct dw_edma_region dt_region_rd[HDMA_MAX_RD_CH];
> >
> > /* interrupt emulation */
> > int db_irq;
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W Channels
2026-06-05 11:48 ` Verma, Devendra
@ 2026-06-05 18:15 ` Frank Li
2026-06-08 11:18 ` Verma, Devendra
0 siblings, 1 reply; 5+ messages in thread
From: Frank Li @ 2026-06-05 18:15 UTC (permalink / raw)
To: Verma, Devendra
Cc: bhelgaas@google.com, mani@kernel.org, vkoul@kernel.org,
Frank.Li@kernel.org, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org, Simek, Michal
On Fri, Jun 05, 2026 at 11:48:05AM +0000, Verma, Devendra wrote:
> Public
>
> > -----Original Message-----
> > From: Frank Li <Frank.li@nxp.com>
> > Sent: Friday, June 5, 2026 01:28
> > To: Verma, Devendra <Devendra.Verma@amd.com>
> > Cc: bhelgaas@google.com; mani@kernel.org; vkoul@kernel.org;
> > Frank.Li@kernel.org; dmaengine@vger.kernel.org; linux-
> > kernel@vger.kernel.org; Simek, Michal <michal.simek@amd.com>
> > Subject: Re: [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W
> > Channels
> >
> > On Wed, Jun 03, 2026 at 08:11:47PM +0530, Devendra K Verma wrote:
> > > As per 'Designware Cores PCI Express Controller Databook', Section 7.1
> > > - Overview, HDMA supports 64 Read and 64 Write channels. Current
> > > controller driver supports up to 8 read and write channels only. In
> > > order to utilize all the channels the controller driver need to have
> > > the channel related structs and variables as per the number of
> > > channels supported by IP.
> > > Following changes are made to enable 64 Read / 64 Write channel
> > > support:
> > >
> > > o Defined HDMA specific macros to reflect the channel count.
> > > o The count of ll_regions and dt_regions in dw_edma_chip and
> > > dw_edma_pcie_data shall be in accordance to number of read
> > > and write channels.
> > > o In dw_edma_probe() configure the channels as per the channels
> > > of the IP used.
> > > o Changed mask types to u64 for higher channel counts.
> > >
> > > Signed-off-by: Devendra K Verma <devendra.verma@amd.com>
> > > ---
> > > Changes in v2:
> > > o Fixed the pre-existing bug related to GET_CH_32
> > > interchanging the channel direction and id.
> > > This bug was not caused by any version of this patch.
> > > o Fixed the issue when using for_each_set_bit() for mask
> > > of u64 type.
> > >
> > > Changes in v1:
> > > o On review recommendation of sashiko bot, in the function
> > > dw_hdma_v0_core_off(), the loop iterates over registers
> > > as per the number of channels enabled and not on total
> > > number of channels supported.
> > > o Changed mask types to u64 for higher channel counts.
> > > ---
> > ...
> > > +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> > > @@ -53,13 +53,24 @@ __dw_ch_regs(struct dw_edma *dw, enum
> > dw_edma_dir
> > > dir, u16 ch) static void dw_hdma_v0_core_off(struct dw_edma *dw) {
> > > int id;
> > > + enum dw_edma_dir dir;
> > > +
> > > + dir = EDMA_DIR_WRITE;
> > > + for (id = 0; id < dw->wr_ch_cnt; id++) {
> > > + SET_CH_32(dw, dir, id, int_setup,
> > > + HDMA_V0_STOP_INT_MASK |
> > HDMA_V0_ABORT_INT_MASK);
> > > + SET_CH_32(dw, dir, id, int_clear,
> > > + HDMA_V0_STOP_INT_MASK |
> > HDMA_V0_ABORT_INT_MASK);
> > > + SET_CH_32(dw, dir, id, ch_en, 0);
> > > + }
> > >
> > > - for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) {
> > > - SET_BOTH_CH_32(dw, id, int_setup,
> > > - HDMA_V0_STOP_INT_MASK |
> > HDMA_V0_ABORT_INT_MASK);
> > > - SET_BOTH_CH_32(dw, id, int_clear,
> > > - HDMA_V0_STOP_INT_MASK |
> > HDMA_V0_ABORT_INT_MASK);
> > > - SET_BOTH_CH_32(dw, id, ch_en, 0);
> > > + dir = EDMA_DIR_READ;
> > > + for (id = 0; id < dw->rd_ch_cnt; id++) {
> > > + SET_CH_32(dw, dir, id, int_setup,
> > > + HDMA_V0_STOP_INT_MASK |
> > HDMA_V0_ABORT_INT_MASK);
> > > + SET_CH_32(dw, dir, id, int_clear,
> > > + HDMA_V0_STOP_INT_MASK |
> > HDMA_V0_ABORT_INT_MASK);
> > > + SET_CH_32(dw, dir, id, ch_en, 0);
> >
> > why SET_BOTH_CH_32 not work for 64 channel?
> >
>
> SET_BOTH_CH_32 works, but this needs to be done on the channels enabled for the IP.
> HDMA supports maximum of 64 channels. So if some IP enables 8 or fewer read / write channels only then the number of channels come from dw->wr_ch_cnt and dw->rd_ch_cnt. Now the logic is derived by individual read & write enabled channel count. Earlier, it was assumed that user will enable max of 8 channels which would have worked well using SET_BOTH_CH_32() but as the channels grow, the assumption that equal number of read / write channels and that they are set to max count are enabled might not hold true.
Make sense, please wrap your reply, it is hard to read
>
> - Devendra
>
> > > }
> > > }
> > >
> > > @@ -79,7 +90,7 @@ static enum dma_status
> > dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan)
> > > u32 tmp;
> > >
> > > tmp = FIELD_GET(HDMA_V0_CH_STATUS_MASK,
> > > - GET_CH_32(dw, chan->id, chan->dir, ch_stat));
> > > + GET_CH_32(dw, chan->dir, chan->id, ch_stat));
> >
> > why need swtich id and dir here ?
> >
> > Frank
>
> This is the correct order of arguments to the GET_CH_32. The second & third arguments shall be direction and channel_id respectively. It is a pre-existing issue reported by AI bot.
AI found existing problem, need seperate patch to fix it.
Frank
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W Channels
2026-06-05 18:15 ` Frank Li
@ 2026-06-08 11:18 ` Verma, Devendra
0 siblings, 0 replies; 5+ messages in thread
From: Verma, Devendra @ 2026-06-08 11:18 UTC (permalink / raw)
To: Frank Li
Cc: bhelgaas@google.com, mani@kernel.org, vkoul@kernel.org,
Frank.Li@kernel.org, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org, Simek, Michal, Verma, Devendra
On 05-Jun-26 23:45, Frank Li wrote:
> On Fri, Jun 05, 2026 at 11:48:05AM +0000, Verma, Devendra wrote:
>> Public
>>
>>> -----Original Message-----
>>> From: Frank Li <Frank.li@nxp.com>
>>> Sent: Friday, June 5, 2026 01:28
>>> To: Verma, Devendra <Devendra.Verma@amd.com>
>>> Cc: bhelgaas@google.com; mani@kernel.org; vkoul@kernel.org;
>>> Frank.Li@kernel.org; dmaengine@vger.kernel.org; linux-
>>> kernel@vger.kernel.org; Simek, Michal <michal.simek@amd.com>
>>> Subject: Re: [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W
>>> Channels
>>>
>>> On Wed, Jun 03, 2026 at 08:11:47PM +0530, Devendra K Verma wrote:
>>>> As per 'Designware Cores PCI Express Controller Databook', Section 7.1
>>>> - Overview, HDMA supports 64 Read and 64 Write channels. Current
>>>> controller driver supports up to 8 read and write channels only. In
>>>> order to utilize all the channels the controller driver need to have
>>>> the channel related structs and variables as per the number of
>>>> channels supported by IP.
>>>> Following changes are made to enable 64 Read / 64 Write channel
>>>> support:
>>>>
>>>> o Defined HDMA specific macros to reflect the channel count.
>>>> o The count of ll_regions and dt_regions in dw_edma_chip and
>>>> dw_edma_pcie_data shall be in accordance to number of read
>>>> and write channels.
>>>> o In dw_edma_probe() configure the channels as per the channels
>>>> of the IP used.
>>>> o Changed mask types to u64 for higher channel counts.
>>>>
>>>> Signed-off-by: Devendra K Verma <devendra.verma@amd.com>
>>>> ---
>>>> Changes in v2:
>>>> o Fixed the pre-existing bug related to GET_CH_32
>>>> interchanging the channel direction and id.
>>>> This bug was not caused by any version of this patch.
>>>> o Fixed the issue when using for_each_set_bit() for mask
>>>> of u64 type.
>>>>
>>>> Changes in v1:
>>>> o On review recommendation of sashiko bot, in the function
>>>> dw_hdma_v0_core_off(), the loop iterates over registers
>>>> as per the number of channels enabled and not on total
>>>> number of channels supported.
>>>> o Changed mask types to u64 for higher channel counts.
>>>> ---
>>> ...
>>>> +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
>>>> @@ -53,13 +53,24 @@ __dw_ch_regs(struct dw_edma *dw, enum
>>> dw_edma_dir
>>>> dir, u16 ch) static void dw_hdma_v0_core_off(struct dw_edma *dw) {
>>>> int id;
>>>> + enum dw_edma_dir dir;
>>>> +
>>>> + dir = EDMA_DIR_WRITE;
>>>> + for (id = 0; id < dw->wr_ch_cnt; id++) {
>>>> + SET_CH_32(dw, dir, id, int_setup,
>>>> + HDMA_V0_STOP_INT_MASK |
>>> HDMA_V0_ABORT_INT_MASK);
>>>> + SET_CH_32(dw, dir, id, int_clear,
>>>> + HDMA_V0_STOP_INT_MASK |
>>> HDMA_V0_ABORT_INT_MASK);
>>>> + SET_CH_32(dw, dir, id, ch_en, 0);
>>>> + }
>>>>
>>>> - for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) {
>>>> - SET_BOTH_CH_32(dw, id, int_setup,
>>>> - HDMA_V0_STOP_INT_MASK |
>>> HDMA_V0_ABORT_INT_MASK);
>>>> - SET_BOTH_CH_32(dw, id, int_clear,
>>>> - HDMA_V0_STOP_INT_MASK |
>>> HDMA_V0_ABORT_INT_MASK);
>>>> - SET_BOTH_CH_32(dw, id, ch_en, 0);
>>>> + dir = EDMA_DIR_READ;
>>>> + for (id = 0; id < dw->rd_ch_cnt; id++) {
>>>> + SET_CH_32(dw, dir, id, int_setup,
>>>> + HDMA_V0_STOP_INT_MASK |
>>> HDMA_V0_ABORT_INT_MASK);
>>>> + SET_CH_32(dw, dir, id, int_clear,
>>>> + HDMA_V0_STOP_INT_MASK |
>>> HDMA_V0_ABORT_INT_MASK);
>>>> + SET_CH_32(dw, dir, id, ch_en, 0);
>>>
>>> why SET_BOTH_CH_32 not work for 64 channel?
>>>
>>
>> SET_BOTH_CH_32 works, but this needs to be done on the channels enabled for the IP.
>> HDMA supports maximum of 64 channels. So if some IP enables 8 or fewer read / write channels only then the number of channels come from dw->wr_ch_cnt and dw->rd_ch_cnt. Now the logic is derived by individual read & write enabled channel count. Earlier, it was assumed that user will enable max of 8 channels which would have worked well using SET_BOTH_CH_32() but as the channels grow, the assumption that equal number of read / write channels and that they are set to max count are enabled might not hold true.
>
> Make sense, please wrap your reply, it is hard to read
>
[Reformatted the comment to fit within the visible window]
SET_BOTH_CH_32 works, but this needs to be done on the channels enabled
for the IP. HDMA supports maximum of 64 channels. So, if some IP enables
8 or fewer read / write channels only, then the number of channels to be
configured shall come from dw->wr_ch_cnt and dw->rd_ch_cnt. In the new
code the logic is derived by individual read & write enabled channel
count. Earlier, it was assumed that user will enable max of 8 channels
which would have worked well using SET_BOTH_CH_32() but as the channels
grow, the assumption that equal number of read / write channels and that
they are set to max count are enabled might not hold true.
>>
>> - Devendra
>>
>>>> }
>>>> }
>>>>
>>>> @@ -79,7 +90,7 @@ static enum dma_status
>>> dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan)
>>>> u32 tmp;
>>>>
>>>> tmp = FIELD_GET(HDMA_V0_CH_STATUS_MASK,
>>>> - GET_CH_32(dw, chan->id, chan->dir, ch_stat));
>>>> + GET_CH_32(dw, chan->dir, chan->id, ch_stat));
>>>
>>> why need swtich id and dir here ?
>>>
>>> Frank
>>
>> This is the correct order of arguments to the GET_CH_32. The second & third arguments shall be direction and channel_id respectively. It is a pre-existing issue reported by AI bot.
>
> AI found existing problem, need seperate patch to fix it.
>
> Frank
Removed this fix. Will include it as part of separate series.
I will upload the next version with the above recommendation.
-Devendra
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-08 11:18 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-03 14:41 [PATCH v3] dmaengine: dw-edma: Enable HDMA 64R/W Channels Devendra K Verma
2026-06-04 19:58 ` Frank Li
2026-06-05 11:48 ` Verma, Devendra
2026-06-05 18:15 ` Frank Li
2026-06-08 11:18 ` Verma, Devendra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox