[PATCH v3 02/13] dmaengine: dw-edma: Add core quiesce operations
From: Koichiro Den
Date: Sat Jun 20 2026 - 13:01:07 EST
Add core operations that quiesce only the resources represented by a
dw-edma instance, separate from the existing full controller off path.
For v0 eDMA and HDMA compatible register layouts, quiescing one channel
must quiesce the whole direction because the enable and interrupt
mask/clear registers are direction-wide. For HDMA native, the operation
can quiesce the represented per-channel registers directly.
No caller is added yet, so this is a no-functional-change preparation
for delegated channel reclaim and partial-owned remove paths.
Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Changes in v3:
- New patch. Add quiesce primitives before delegated-channel release
and partial-owned remove start using them.
- Note: Devendra's under-review "dmaengine: dw-edma: Enable HDMA 64R/W
Channels" series may require a follow-up rebase if it lands first.
drivers/dma/dw-edma/dw-edma-core.h | 14 ++++++++++++++
drivers/dma/dw-edma/dw-edma-v0-core.c | 24 ++++++++++++++++++++++++
drivers/dma/dw-edma/dw-hdma-v0-core.c | 27 +++++++++++++++++++++++++++
3 files changed, 65 insertions(+)
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 42f2f25ef377..f9d4e0411f8f 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -122,6 +122,8 @@ typedef void (*dw_edma_handler_t)(struct dw_edma_chan *);
struct dw_edma_core_ops {
void (*off)(struct dw_edma *dw);
+ void (*quiesce)(struct dw_edma *dw);
+ void (*ch_quiesce)(struct dw_edma_chan *chan);
u16 (*ch_count)(struct dw_edma *dw, enum dw_edma_dir dir);
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,
@@ -174,6 +176,18 @@ void dw_edma_core_off(struct dw_edma *dw)
dw->core->off(dw);
}
+static inline
+void dw_edma_core_quiesce(struct dw_edma *dw)
+{
+ dw->core->quiesce(dw);
+}
+
+static inline
+void dw_edma_core_ch_quiesce(struct dw_edma_chan *chan)
+{
+ chan->dw->core->ch_quiesce(chan);
+}
+
static inline
u16 dw_edma_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
{
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 1781ba4f022e..316d8c94eff9 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -160,6 +160,15 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
/* eDMA management callbacks */
+static void dw_edma_v0_core_dir_off(struct dw_edma *dw, enum dw_edma_dir dir)
+{
+ SET_RW_32(dw, dir, int_mask,
+ EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK);
+ SET_RW_32(dw, dir, int_clear,
+ EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK);
+ SET_RW_32(dw, dir, engine_en, 0);
+}
+
static void dw_edma_v0_core_off(struct dw_edma *dw)
{
SET_BOTH_32(dw, int_mask,
@@ -169,6 +178,19 @@ static void dw_edma_v0_core_off(struct dw_edma *dw)
SET_BOTH_32(dw, engine_en, 0);
}
+static void dw_edma_v0_core_quiesce(struct dw_edma *dw)
+{
+ if (dw->wr_ch_cnt)
+ dw_edma_v0_core_dir_off(dw, EDMA_DIR_WRITE);
+ if (dw->rd_ch_cnt)
+ dw_edma_v0_core_dir_off(dw, EDMA_DIR_READ);
+}
+
+static void dw_edma_v0_core_ch_quiesce(struct dw_edma_chan *chan)
+{
+ dw_edma_v0_core_dir_off(chan->dw, chan->dir);
+}
+
static u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
{
u32 num_ch;
@@ -546,6 +568,8 @@ static resource_size_t dw_edma_v0_core_db_offset(struct dw_edma *dw)
static const struct dw_edma_core_ops dw_edma_v0_core = {
.off = dw_edma_v0_core_off,
+ .quiesce = dw_edma_v0_core_quiesce,
+ .ch_quiesce = dw_edma_v0_core_ch_quiesce,
.ch_count = dw_edma_v0_core_ch_count,
.ch_status = dw_edma_v0_core_ch_status,
.handle_int = dw_edma_v0_core_handle_int,
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index 7ba6bdbffc17..63c30a6eb88c 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -70,6 +70,16 @@ static u32 dw_hdma_v0_core_int_setup(struct dw_edma_chan *chan, u32 val)
}
/* HDMA management callbacks */
+static void dw_hdma_v0_core_ch_off(struct dw_edma *dw, enum dw_edma_dir dir,
+ u16 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);
+}
+
static void dw_hdma_v0_core_off(struct dw_edma *dw)
{
int id;
@@ -83,6 +93,21 @@ static void dw_hdma_v0_core_off(struct dw_edma *dw)
}
}
+static void dw_hdma_v0_core_quiesce(struct dw_edma *dw)
+{
+ int id;
+
+ for (id = 0; id < dw->wr_ch_cnt; id++)
+ dw_hdma_v0_core_ch_off(dw, EDMA_DIR_WRITE, id);
+ for (id = 0; id < dw->rd_ch_cnt; id++)
+ dw_hdma_v0_core_ch_off(dw, EDMA_DIR_READ, id);
+}
+
+static void dw_hdma_v0_core_ch_quiesce(struct dw_edma_chan *chan)
+{
+ dw_hdma_v0_core_ch_off(chan->dw, chan->dir, chan->id);
+}
+
static u16 dw_hdma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
{
/*
@@ -362,6 +387,8 @@ static resource_size_t dw_hdma_v0_core_db_offset(struct dw_edma *dw)
static const struct dw_edma_core_ops dw_hdma_v0_core = {
.off = dw_hdma_v0_core_off,
+ .quiesce = dw_hdma_v0_core_quiesce,
+ .ch_quiesce = dw_hdma_v0_core_ch_quiesce,
.ch_count = dw_hdma_v0_core_ch_count,
.ch_status = dw_hdma_v0_core_ch_status,
.handle_int = dw_hdma_v0_core_handle_int,
--
2.51.0