Re: [PATCH v5] dmaengine: dw-edma: Enable HDMA 64R/W Channels

From: Frank Li

Date: Tue Jun 30 2026 - 15:58:36 EST


On Mon, Jun 29, 2026 at 11:27:39AM +0530, Verma, Devendra wrote:
>
> On 26-Jun-26 21:40, Frank Li wrote:
> > On Fri, Jun 26, 2026 at 06:51:51PM +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@xxxxxxx>
> > > ---
> > > Changes in v4:
> > > o Changed 'mask' variable to a bitmap type as per the
> > > review comment.
> > >
> > > Changes in v3:
> > > o Reverted the FIX for AI reported GET_CH_32() issue, as
> > > per the recommendation of reviewers, need to create
> > > separate patch for it.
> > >
> > > 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 | 32 ++++++++++++++++++---------
> > > drivers/dma/dw-edma/dw-hdma-v0-regs.h | 2 +-
> > > include/linux/dma/edma.h | 10 +++++----
> > > 6 files changed, 48 insertions(+), 27 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;
> >
> > Can you direct use DECLARE_BITMAP(rd_mask, 64) here?
> >
> > > 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
> > ...
> > > }
> > > }
> > >
> > > @@ -118,19 +129,20 @@ 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;
> >
> > after change wr_mask to BITMAP
> >
> > mask -> *mask
> >
> > So needn't change this code if support more channel in future.
> >
> > Frank
> >
>
> It looks good to make this piece of code generic and support for more
> channel but I did not push that change as the final limitation comes
> from the HDMA IP which as per the documentation supports upto 64
> channels only. As there is no channel increase BITMAP was not
> implemented for *_mask variable.

DECLARE_BITMAP(rd_mask, 64) the size is the same as u64. needn't call
below two bitmap_from_u64().

irq->wr_mask |= BIT_ULL(chan->id), use bitmap_set().

Everything will be simple and better extendable.

Frank

>
> -Devendra
>
> > > + DECLARE_BITMAP(mask, 64);
> > > + unsigned long off;
> > >
> > > if (dir == EDMA_DIR_WRITE) {
> > > total = dw->wr_ch_cnt;
> > > off = 0;
> > > - mask = dw_irq->wr_mask;
> > > + bitmap_from_u64(mask, dw_irq->wr_mask);
> > > } else {
> > > total = dw->rd_ch_cnt;
> > > off = dw->wr_ch_cnt;
> > > - mask = dw_irq->rd_mask;
> > > + bitmap_from_u64(mask, dw_irq->rd_mask);
> > > }
> > >
> > > - for_each_set_bit(pos, &mask, total) {
> > > + for_each_set_bit(pos, mask, total) {
> > > chan = &dw->chan[pos + off];
> > >
> > > val = dw_hdma_v0_core_status_int(chan);
> > > 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
> > >
>