Re: [PATCH 1/2] dmaengine: dw-edma: Add interrupt-emulation hooks

From: Koichiro Den

Date: Mon Mar 23 2026 - 22:13:39 EST


On Mon, Feb 16, 2026 at 12:22:15AM +0900, Koichiro Den wrote:
> DesignWare eDMA instances support "interrupt emulation", where a
> software write can assert the IRQ line without setting the normal
> DONE/ABORT status bits.
>
> Introduce core callbacks needed to support this feature:
>
> - .ack_emulated_irq(): core-specific sequence to deassert an emulated
> IRQ
> - .db_offset(): offset from the DMA register base that is suitable as a
> host-writable doorbell target for interrupt emulation
>
> Implement both hooks for the v0 register map. For dw-hdma-v0, provide a
> stub .db_offset() returning ~0 until the correct offset is known.
>
> The next patch wires these hooks into the dw-edma IRQ path and exports
> the doorbell resources to platform users.
>
> Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
> ---
> drivers/dma/dw-edma/dw-edma-core.h | 17 +++++++++++++++++
> drivers/dma/dw-edma/dw-edma-v0-core.c | 21 +++++++++++++++++++++
> drivers/dma/dw-edma/dw-hdma-v0-core.c | 7 +++++++
> 3 files changed, 45 insertions(+)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index 71894b9e0b15..59b24973fa7d 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -126,6 +126,8 @@ struct dw_edma_core_ops {
> void (*start)(struct dw_edma_chunk *chunk, bool first);
> void (*ch_config)(struct dw_edma_chan *chan);
> void (*debugfs_on)(struct dw_edma *dw);
> + void (*ack_emulated_irq)(struct dw_edma *dw);
> + resource_size_t (*db_offset)(struct dw_edma *dw);
> };
>
> struct dw_edma_sg {
> @@ -206,4 +208,19 @@ void dw_edma_core_debugfs_on(struct dw_edma *dw)
> dw->core->debugfs_on(dw);
> }
>
> +static inline int dw_edma_core_ack_emulated_irq(struct dw_edma *dw)
> +{
> + if (!dw->core->ack_emulated_irq)
> + return -EOPNOTSUPP;
> +
> + dw->core->ack_emulated_irq(dw);
> + return 0;
> +}
> +
> +static inline resource_size_t
> +dw_edma_core_db_offset(struct dw_edma *dw)
> +{
> + return dw->core->db_offset(dw);
> +}
> +
> #endif /* _DW_EDMA_CORE_H */
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index b75fdaffad9a..69e8279adec8 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -509,6 +509,25 @@ static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw)
> dw_edma_v0_debugfs_on(dw);
> }
>
> +static void dw_edma_v0_core_ack_emulated_irq(struct dw_edma *dw)
> +{
> + /*
> + * Interrupt emulation may assert the IRQ without setting
> + * DONE/ABORT status bits. A zero write to INT_CLEAR deasserts the
> + * emulated IRQ, while being a no-op for real interrupts.
> + */
> + SET_BOTH_32(dw, int_clear, 0);
> +}
> +
> +static resource_size_t dw_edma_v0_core_db_offset(struct dw_edma *dw)
> +{
> + /*
> + * rd_int_status is chosen arbitrarily, but wr_int_status would be
> + * equally suitable.
> + */
> + return offsetof(struct dw_edma_v0_regs, rd_int_status);
> +}
> +
> static const struct dw_edma_core_ops dw_edma_v0_core = {
> .off = dw_edma_v0_core_off,
> .ch_count = dw_edma_v0_core_ch_count,
> @@ -517,6 +536,8 @@ static const struct dw_edma_core_ops dw_edma_v0_core = {
> .start = dw_edma_v0_core_start,
> .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,
> + .db_offset = dw_edma_v0_core_db_offset,
> };
>
> void dw_edma_v0_core_register(struct dw_edma *dw)
> diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> index e3f8db4fe909..1ae8e44f0a67 100644
> --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> @@ -283,6 +283,12 @@ static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw)
> dw_hdma_v0_debugfs_on(dw);
> }
>
> +static resource_size_t dw_hdma_v0_core_db_offset(struct dw_edma *dw)
> +{
> + /* Implement once the correct offset is known. */
> + return ~0;

I now have access to an HDMA-capable device (not set up yet though) and the
databook. According to the PCIe DM Controller databook (6.10a-lca06/6.14a-lca02,
section 7.4.4 "HDMA Debug"):

> Test Interrupt
> HDMA does not support this legacy DMA feature in this release.

It's unclear whether this holds true for all revisions, but assuming so, perhaps
the comment above should be updated for clarity.

Best regards,
Koichiro

> +}
> +
> static const struct dw_edma_core_ops dw_hdma_v0_core = {
> .off = dw_hdma_v0_core_off,
> .ch_count = dw_hdma_v0_core_ch_count,
> @@ -291,6 +297,7 @@ static const struct dw_edma_core_ops dw_hdma_v0_core = {
> .start = dw_hdma_v0_core_start,
> .ch_config = dw_hdma_v0_core_ch_config,
> .debugfs_on = dw_hdma_v0_core_debugfs_on,
> + .db_offset = dw_hdma_v0_core_db_offset,
> };
>
> void dw_hdma_v0_core_register(struct dw_edma *dw)
> --
> 2.51.0
>