Re: [PATCH v6 2/8] dmaengine: dw-edma: Cache per-channel IRQ and emulation doorbell offset

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 <aYoHtP5dsEHQEm7c@lizhi-Precision-Tower-5810>
On Mon, Feb 09, 2026 at 09:53:10PM +0900, Koichiro Den wrote:
> Some DesignWare PCIe endpoint controllers integrate a DesignWare
> eDMA/HDMA instance. In remote eDMA use cases (e.g. exposing the eDMA
> MMIO window and per-channel linked-list regions to a peer via BARs),
> consumers need a stable way to discover:
>   - the Linux IRQ number associated with a given channel's interrupt
>     vector,
>   - an offset within the eDMA register window that can be used as an
>     interrupt-emulation doorbell for that channel.
>
> Store the requested Linux IRQ number in struct dw_edma_irq at IRQ
> request time and cache per-channel metadata in struct dw_edma_chip
> (ch_info_wr/rd) during channel setup. Add a core callback, .ch_info(),
> to fill core-specific metadata such as the doorbell register offset;
> implement it for the v0 eDMA core (use rd_int_status as a suitable
> doorbell target) and provide a placeholder for HDMA until the correct
> offset is known.
>
> No functional change for normal DMA operation. This only makes the
> metadata available to controller/platform drivers that need to expose or
> consume eDMA-related resources.
>
> Signed-off-by: Koichiro Den <[email protected]>
> ---
>  drivers/dma/dw-edma/dw-edma-core.c    |  9 +++++++++
>  drivers/dma/dw-edma/dw-edma-core.h    |  9 +++++++++
>  drivers/dma/dw-edma/dw-edma-v0-core.c | 11 +++++++++++
>  drivers/dma/dw-edma/dw-hdma-v0-core.c |  8 ++++++++
>  include/linux/dma/edma.h              | 17 +++++++++++++++++
>  5 files changed, 54 insertions(+)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index fe131abf1ca3..bd5ff4a4431a 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -760,6 +760,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
>  {
>  	struct dw_edma_chip *chip = dw->chip;
>  	struct device *dev = chip->dev;
> +	struct dw_edma_ch_info *info;
>  	struct dw_edma_chan *chan;
>  	struct dw_edma_irq *irq;
>  	struct dma_device *dma;
> @@ -779,9 +780,11 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
>  		if (i < dw->wr_ch_cnt) {
>  			chan->id = i;
>  			chan->dir = EDMA_DIR_WRITE;
> +			info = &chip->ch_info_wr[chan->id];
>  		} else {
>  			chan->id = i - dw->wr_ch_cnt;
>  			chan->dir = EDMA_DIR_READ;
> +			info = &chip->ch_info_rd[chan->id];
>  		}
>
>  		chan->configured = false;
> @@ -807,6 +810,10 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
>
>  		irq = &dw->irq[pos];
>
> +		/* cache channel-specific info */
> +		dw_edma_core_ch_info(dw, chan, info);
> +		info->irq = irq->irq;
> +
>  		if (chan->dir == EDMA_DIR_WRITE)
>  			irq->wr_mask |= BIT(chan->id);
>  		else
> @@ -910,6 +917,7 @@ static int dw_edma_irq_request(struct dw_edma *dw,
>  		if (irq_get_msi_desc(irq))
>  			get_cached_msi_msg(irq, &dw->irq[0].msi);
>
> +		dw->irq[0].irq = irq;
>  		dw->nr_irqs = 1;
>  	} else {
>  		/* Distribute IRQs equally among all channels */
> @@ -936,6 +944,7 @@ static int dw_edma_irq_request(struct dw_edma *dw,
>
>  			if (irq_get_msi_desc(irq))
>  				get_cached_msi_msg(irq, &dw->irq[i].msi);
> +			dw->irq[i].irq = irq;
>  		}
>
>  		dw->nr_irqs = i;
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index 50b87b63b581..82f8f3b38752 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -93,6 +93,7 @@ struct dw_edma_irq {
>  	u32				wr_mask;
>  	u32				rd_mask;
>  	struct dw_edma			*dw;
> +	int				irq;
>  };
>
>  struct dw_edma {
> @@ -127,6 +128,7 @@ struct dw_edma_core_ops {
>  	void (*ch_config)(struct dw_edma_chan *chan);
>  	void (*debugfs_on)(struct dw_edma *dw);
>  	void (*ack_emulated_irq)(struct dw_edma *dw);
> +	void (*ch_info)(struct dw_edma_chan *chan, struct dw_edma_ch_info *info);
>  };
>
>  struct dw_edma_sg {
> @@ -216,4 +218,11 @@ static inline int dw_edma_core_ack_emulated_irq(struct dw_edma *dw)
>  	return 0;
>  }
>
> +static inline void
> +dw_edma_core_ch_info(struct dw_edma *dw, struct dw_edma_chan *chan,
> +		     struct dw_edma_ch_info *info)
> +{
> +	dw->core->ch_info(chan, info);
> +}
> +
>  #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 82b9c063c10f..0b8d4b6a5e26 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -519,6 +519,16 @@ static void dw_edma_v0_core_ack_emulated_irq(struct dw_edma *dw)
>  	SET_BOTH_32(dw, int_clear, 0);
>  }
>
> +static void dw_edma_v0_core_ch_info(struct dw_edma_chan *chan,
> +				    struct dw_edma_ch_info *info)
> +{
> +	/*
> +	 * rd_int_status is chosen arbitrarily, but wr_int_status would be
> +	 * equally suitable.
> +	 */
> +	info->db_offset = 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,
> @@ -528,6 +538,7 @@ static const struct dw_edma_core_ops dw_edma_v0_core = {
>  	.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,
> +	.ch_info = dw_edma_v0_core_ch_info,
>  };
>
>  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..1076b394c45f 100644
> --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> @@ -283,6 +283,13 @@ static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw)
>  	dw_hdma_v0_debugfs_on(dw);
>  }
>
> +static void dw_hdma_v0_core_ch_info(struct dw_edma_chan *chan,
> +				    struct dw_edma_ch_info *info)
> +{
> +	/* Implement once the correct offset is known. */
> +	info->db_offset = ~0;
> +}
> +
>  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 +298,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,
> +	.ch_info = dw_hdma_v0_core_ch_info,
>  };
>
>  void dw_hdma_v0_core_register(struct dw_edma *dw)
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 3080747689f6..921250204a08 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -60,6 +60,19 @@ enum dw_edma_chip_flags {
>  	DW_EDMA_CHIP_LOCAL	= BIT(0),
>  };
>
> +/**
> + * struct dw_edma_ch_info - DW eDMA channel metadata
> + * @irq:	Linux IRQ number used by this channel's interrupt vector
> + * @db_offset:	offset within the eDMA register window that can be used as
> + *		an interrupt-emulation doorbell for this channel
> + */
> +struct dw_edma_ch_info {
> +	int			irq;
> +
> +	/* Fields below are filled in by dw_edma_core_ops->ch_info() */
> +	resource_size_t		db_offset;
> +};
> +
>  /**
>   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
>   * @dev:		 struct device of the eDMA controller
> @@ -96,6 +109,10 @@ struct dw_edma_chip {
>  	struct dw_edma_region	dt_region_wr[EDMA_MAX_WR_CH];
>  	struct dw_edma_region	dt_region_rd[EDMA_MAX_RD_CH];
>
> +	/* cached channel info */
> +	struct dw_edma_ch_info	ch_info_wr[EDMA_MAX_WR_CH];
> +	struct dw_edma_ch_info	ch_info_rd[EDMA_MAX_RD_CH];
> +

suppose this info only used in side dw edma driver, so it should be in
dw_edma.

dw_edma_chip is useful to exchange informaiton between EPC/PCI controller
and dma engine when call dw_edma_probe().

Frand

>  	enum dw_edma_map_format	mf;
>
>  	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.