Re: [PATCH v6 1/8] dmaengine: dw-edma: Deassert emulated interrupts in the IRQ handler

Frank Li <[email protected]>
Newsgroups dev.linux.lists.ntb,org.kernel.vger.dmaengine,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kernel.vger.linux-pci
Message-ID <aYoFsMclytqtkc9N@lizhi-Precision-Tower-5810>
On Mon, Feb 09, 2026 at 09:53:09PM +0900, Koichiro Den wrote:
> Some DesignWare eDMA instances support "interrupt emulation", where a
> software write can assert the IRQ line without setting the normal
> DONE/ABORT status bits.
>
> With a shared IRQ handler the driver cannot reliably distinguish an
> emulated interrupt from a real one by only looking at DONE/ABORT status
> bits. Leaving the emulated IRQ asserted may leave a level-triggered IRQ
> line permanently asserted.
>
> Add a core callback, .ack_emulated_irq(), to perform the core-specific
> deassert sequence and call it from the read/write/common IRQ handlers.
> Note that previously a direct software write could assert the emulated
> IRQ without DMA activity, leading to the interrupt never getting
> deasserted. This patch resolves it.
>
> For v0, a zero write to INT_CLEAR deasserts the emulated IRQ and is a
> no-op for real interrupts. HDMA is not tested or verified and is
> therefore unsupported for now.
>
> Signed-off-by: Koichiro Den <[email protected]>
> ---

Reviewed-by: Frank Li <[email protected]>

>  drivers/dma/dw-edma/dw-edma-core.c    | 48 ++++++++++++++++++++++++---
>  drivers/dma/dw-edma/dw-edma-core.h    | 10 ++++++
>  drivers/dma/dw-edma/dw-edma-v0-core.c | 11 ++++++
>  3 files changed, 64 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 8e5f7defa6b6..fe131abf1ca3 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -663,7 +663,24 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
>  	chan->status = EDMA_ST_IDLE;
>  }
>
> -static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
> +static inline irqreturn_t dw_edma_interrupt_emulated(void *data)
> +{
> +	struct dw_edma_irq *dw_irq = data;
> +	struct dw_edma *dw = dw_irq->dw;
> +
> +	/*
> +	 * Interrupt emulation may assert the IRQ line without updating the
> +	 * normal DONE/ABORT status bits. With a shared IRQ handler we
> +	 * cannot reliably detect such events by status registers alone, so
> +	 * always perform the core-specific deassert sequence.
> +	 */
> +	if (dw_edma_core_ack_emulated_irq(dw))
> +		return IRQ_NONE;
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static inline irqreturn_t dw_edma_interrupt_write_inner(int irq, void *data)
>  {
>  	struct dw_edma_irq *dw_irq = data;
>
> @@ -672,7 +689,7 @@ static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
>  				       dw_edma_abort_interrupt);
>  }
>
> -static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
> +static inline irqreturn_t dw_edma_interrupt_read_inner(int irq, void *data)
>  {
>  	struct dw_edma_irq *dw_irq = data;
>
> @@ -681,12 +698,33 @@ static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
>  				       dw_edma_abort_interrupt);
>  }
>
> -static irqreturn_t dw_edma_interrupt_common(int irq, void *data)
> +static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
> +{
> +	irqreturn_t ret = IRQ_NONE;
> +
> +	ret |= dw_edma_interrupt_write_inner(irq, data);
> +	ret |= dw_edma_interrupt_emulated(data);
> +
> +	return ret;
> +}
> +
> +static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
> +{
> +	irqreturn_t ret = IRQ_NONE;
> +
> +	ret |= dw_edma_interrupt_read_inner(irq, data);
> +	ret |= dw_edma_interrupt_emulated(data);
> +
> +	return ret;
> +}
> +
> +static inline irqreturn_t dw_edma_interrupt_common(int irq, void *data)
>  {
>  	irqreturn_t ret = IRQ_NONE;
>
> -	ret |= dw_edma_interrupt_write(irq, data);
> -	ret |= dw_edma_interrupt_read(irq, data);
> +	ret |= dw_edma_interrupt_write_inner(irq, data);
> +	ret |= dw_edma_interrupt_read_inner(irq, data);
> +	ret |= dw_edma_interrupt_emulated(data);
>
>  	return ret;
>  }
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index 71894b9e0b15..50b87b63b581 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -126,6 +126,7 @@ 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);
>  };
>
>  struct dw_edma_sg {
> @@ -206,4 +207,13 @@ 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;
> +}
> +
>  #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..82b9c063c10f 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -509,6 +509,16 @@ 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 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 +527,7 @@ 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,
>  };
>
>  void dw_edma_v0_core_register(struct dw_edma *dw)
> --
> 2.51.0
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.