Re: [PATCH v6 4/6] dmaengine: dw-edma: Add delegated channel request helpers

Frank Li <[email protected]>
Newsgroups gmane.linux.kernel.pci,gmane.linux.kernel
Message-ID <anISE4zj1odwT2aJ@SMW015318>
On Tue, Aug 04, 2026 at 12:38:53PM +0900, Koichiro Den wrote:
> Endpoint functions that expose endpoint-local DesignWare eDMA channels
> to a remote host need to reserve exact hardware channels and hand
> interrupt ownership to the remote side before publishing the channels.
>
> Add DW eDMA-specific helpers that request a write/read hardware channel
> through DMAengine, keep the hardware-channel filter private to dw-edma,
> and switch the selected endpoint-local channel to remote interrupt
> routing after the channel has been successfully reserved. The matching
> release helper can quiesce the channel while it is still remote-routed,
> then restores the channel's default routing before releasing the
> DMAengine reservation. This lets callers skip quiesce when unwinding a
> reservation that was never exposed to host programming.
>
> Release is best-effort because its callers cannot abort teardown. Report
> a quiesce failure locally, but always restore the default routing and
> release the DMAengine reservation.
>
> Signed-off-by: Koichiro Den <[email protected]>
> ---
> Changes in v6:
>   - No changes.
>
>  drivers/dma/dw-edma/dw-edma-core.c | 91 ++++++++++++++++++++++++++++++
>  include/linux/dma/edma.h           | 14 +++++
>  2 files changed, 105 insertions(+)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 1f893dc54c79..4c0d2bba755b 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -1302,6 +1302,97 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  }
>  EXPORT_SYMBOL_GPL(dw_edma_remove);
>
> +struct dw_edma_delegated_chan_filter_args {
> +	struct device *dma_dev;
> +	bool write;
> +	u16 id;
> +};
> +
> +static bool dw_edma_delegated_chan_filter(struct dma_chan *dchan, void *param)
> +{
> +	struct dw_edma_delegated_chan_filter_args *filter = param;
> +	struct dw_edma_chan *chan;
> +
> +	if (!filter || dchan->device->dev != filter->dma_dev)
> +		return false;
> +
> +	chan = dchan2dw_edma_chan(dchan);
> +
> +	return chan->dir == (filter->write ? EDMA_DIR_WRITE : EDMA_DIR_READ) &&
> +	       chan->id == filter->id;
> +}
> +
> +static int dw_edma_delegate_chan(struct dma_chan *dchan)
> +{
> +	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
> +	int ret = 0;
> +
> +	if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
> +		return -EINVAL;
> +
> +	guard(spinlock_irqsave)(&chan->vc.lock);
> +
> +	if (chan->configured || chan->status != EDMA_ST_IDLE ||
> +	    chan->request != EDMA_REQ_NONE)
> +		ret = -EBUSY;
> +	else
> +		chan->irq_mode = DW_EDMA_CH_IRQ_REMOTE;
> +
> +	return ret;
> +}
> +
> +struct dma_chan *dw_edma_request_delegated_chan(struct device *dma_dev,
> +						bool write, u16 id)
> +{
> +	struct dw_edma_delegated_chan_filter_args filter = {
> +		.dma_dev = dma_dev,
> +		.write = write,
> +		.id = id,
> +	};
> +	struct dma_chan *dchan;
> +	dma_cap_mask_t mask;
> +
> +	if (!dma_dev)
> +		return NULL;
> +
> +	dma_cap_zero(mask);
> +	dma_cap_set(DMA_SLAVE, mask);
> +
> +	dchan = dma_request_channel(mask, dw_edma_delegated_chan_filter,
> +				    &filter);
> +	if (!dchan)
> +		return NULL;

I forget, why need export delegrated dma channel to dmanegine? If EP
driver doesn't report delegrated channel to dma engine, what's happen?

Frank

> +
> +	if (dw_edma_delegate_chan(dchan)) {
> +		dma_release_channel(dchan);
> +		return NULL;
> +	}
> +
> +	return dchan;
> +}
> +EXPORT_SYMBOL_GPL(dw_edma_request_delegated_chan);
> +
> +void dw_edma_release_delegated_chan(struct dma_chan *dchan, bool quiesce)
> +{
> +	struct dw_edma_chan *chan;
> +
> +	if (!dchan)
> +		return;
> +
> +	chan = dchan2dw_edma_chan(dchan);
> +	if (quiesce && dw_edma_core_ch_quiesce(chan))
> +		dev_warn(chan->dw->chip->dev,
> +			 "failed to quiesce delegated %s channel %u\n",
> +			 chan->dir == EDMA_DIR_WRITE ? "write" : "read",
> +			 chan->id);
> +
> +	scoped_guard(spinlock_irqsave, &chan->vc.lock)
> +		chan->irq_mode = dw_edma_get_default_irq_mode(chan);
> +
> +	dma_release_channel(dchan);
> +}
> +EXPORT_SYMBOL_GPL(dw_edma_release_delegated_chan);
> +
>  MODULE_LICENSE("GPL v2");
>  MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
>  MODULE_AUTHOR("Gustavo Pimentel <[email protected]>");
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 3c8e2ef9dee0..944469258b8b 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -153,6 +153,9 @@ struct dw_edma_chip {
>  #if IS_REACHABLE(CONFIG_DW_EDMA)
>  int dw_edma_probe(struct dw_edma_chip *chip);
>  int dw_edma_remove(struct dw_edma_chip *chip);
> +struct dma_chan *dw_edma_request_delegated_chan(struct device *dma_dev,
> +						bool write, u16 id);
> +void dw_edma_release_delegated_chan(struct dma_chan *chan, bool quiesce);
>  #else
>  static inline int dw_edma_probe(struct dw_edma_chip *chip)
>  {
> @@ -163,6 +166,17 @@ static inline int dw_edma_remove(struct dw_edma_chip *chip)
>  {
>  	return 0;
>  }
> +
> +static inline struct dma_chan *
> +dw_edma_request_delegated_chan(struct device *dma_dev, bool write, u16 id)
> +{
> +	return NULL;
> +}
> +
> +static inline void dw_edma_release_delegated_chan(struct dma_chan *chan,
> +						  bool quiesce)
> +{
> +}
>  #endif /* CONFIG_DW_EDMA */
>
>  #endif /* _DW_EDMA_H */
> --
> 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.