dmaengine: dw-edma: Enable HDMA 64R/W Channels

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>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260713064854.4065262-1-devverma@amd.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
Devendra K Verma 2026-07-13 12:18:54 +05:30 committed by Vinod Koul
parent 643c1e1ae3
commit 64173b6b76
7 changed files with 49 additions and 28 deletions

View File

@ -840,9 +840,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);
bitmap_set(irq->wr_mask, chan->id, 1);
else
irq->rd_mask |= BIT(chan->id);
bitmap_set(irq->rd_mask, chan->id, 1);
irq->dw = dw;
memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));
@ -983,6 +983,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)
@ -998,20 +1000,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;

View File

@ -84,9 +84,10 @@ struct dw_edma_chan {
struct dw_edma_irq {
struct msi_msg msi;
u32 wr_mask;
u32 rd_mask;
struct dw_edma *dw;
DECLARE_BITMAP(wr_mask, HDMA_MAX_WR_CH);
DECLARE_BITMAP(rd_mask, HDMA_MAX_RD_CH);
};
struct dw_edma {

View File

@ -62,11 +62,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;

View File

@ -239,7 +239,7 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
irqreturn_t ret = IRQ_NONE;
struct dw_edma_chan *chan;
unsigned long off;
u32 mask;
unsigned long *mask;
if (dir == EDMA_DIR_WRITE) {
total = dw->wr_ch_cnt;
@ -252,7 +252,7 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
}
val = dw_edma_v0_core_status_done_int(dw, dir);
val &= mask;
val &= *mask;
for_each_set_bit(pos, &val, total) {
chan = &dw->chan[pos + off];
@ -263,7 +263,7 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
}
val = dw_edma_v0_core_status_abort_int(dw, dir);
val &= mask;
val &= *mask;
for_each_set_bit(pos, &val, total) {
chan = &dw->chan[pos + off];

View File

@ -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;
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_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);
}
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);
}
}
@ -118,7 +129,7 @@ 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, *mask;
if (dir == EDMA_DIR_WRITE) {
total = dw->wr_ch_cnt;
@ -130,7 +141,7 @@ 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) {
for_each_set_bit(pos, mask, total) {
chan = &dw->chan[pos + off];
val = dw_hdma_v0_core_status_int(chan);

View File

@ -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)

View File

@ -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;