DMA Engine development
 help / color / mirror / Atom feed
From: Frank Li <Frank.li@oss.nxp.com>
To: Koichiro Den <den@valinux.co.jp>
Cc: "Vinod Koul" <vkoul@kernel.org>, "Frank Li" <Frank.Li@kernel.org>,
	"Manivannan Sadhasivam" <mani@kernel.org>,
	"Gustavo Pimentel" <Gustavo.Pimentel@synopsys.com>,
	"Kees Cook" <kees@kernel.org>,
	"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
	"Kishon Vijay Abraham I" <kishon@kernel.org>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Christoph Hellwig" <hch@lst.de>,
	"Serge Semin" <fancer.lancer@gmail.com>,
	"Cai Huoqing" <cai.huoqing@linux.dev>,
	"Niklas Cassel" <cassel@kernel.org>,
	"Devendra K Verma" <devendra.verma@amd.com>,
	dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v5 13/24] dmaengine: dw-edma: Reclaim issued descriptors from IRQ-paired LL progress
Date: Wed, 12 Aug 2026 16:54:15 -0400	[thread overview]
Message-ID: <anzdd9kAxBHvuzpo@lizhi-Precision-Tower-5810> (raw)
In-Reply-To: <20260812155721.2807506-14-den@valinux.co.jp>

On Thu, Aug 13, 2026 at 12:57:10AM +0900, Koichiro Den wrote:
> Dynamic append can place entries from several descriptors in one LL
> ring. Track the consumed boundary in ll_done, reuse entries behind it,
> and complete descriptors in issue order as done_burst advances.
>
> Normalize each IRQ-paired LLP sample to the exclusive boundary used by
> ll_done. A stopped sample points to the next entry. Keep a running
> sample one entry behind the raw LLP so an entry is not recycled before
> payload completion is established. For the eDMA-compatible interrupt
> interface, treat DONE as a stopped boundary only when channel status is
> complete and transfer size is zero.
>
> Record the first outstanding physical LL entry in each descriptor and
> verify that it matches ll_done before consuming that descriptor. On a
> mismatch, warn and resynchronize only if the sampled boundary has
> reached the descriptor; otherwise stop without completing it.
>
> Reclaiming entries as they are consumed also lets a descriptor larger
> than the ring advance. Keep one data entry free so a physical index
> remains unambiguous in the active producer window. Clear any published
> ring state on termination or abort before starting another transfer.
>
> LL progress now has its own completion path, so fold the temporary
> lock-held DONE helper back into its only caller.
>
> Suggested-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
> Changes in v5:
>   - Adjust context after moving the issue_pending() snapshot discard to
>     patch 11. dw_edma_ll_snapshot_discard() is no longer re-added here.
>   - Fold dw_edma_ll_clean_pending() into
>     dw_edma_ll_consume_progress(), removing the one-line wrapper
>     (pure refactoring).
>
>  drivers/dma/dw-edma/dw-edma-core.c    | 273 +++++++++++++++++++++-----
>  drivers/dma/dw-edma/dw-edma-core.h    |   4 +
>  drivers/dma/dw-edma/dw-edma-v0-core.c |   6 +
>  3 files changed, 238 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 1deaf2d0da91..363993c64c44 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -53,13 +53,6 @@ dw_edma_alloc_desc(struct dw_edma_chan *chan, size_t nburst)
>  {
>  	struct dw_edma_desc *desc;
>
> -	/*
> -	 * For now, a descriptor that does not fit would stall the channel
> -	 * forever: reject it up front.
> -	 */
> -	if (!chan->non_ll && nburst > chan->ll_max - 1)
> -		return NULL;
> -
>  	desc = kzalloc_flex(*desc, burst, nburst, GFP_NOWAIT);
>  	if (unlikely(!desc))
>  		return NULL;
> @@ -79,6 +72,7 @@ static void dw_edma_ll_snapshot_discard_locked(struct dw_edma_chan *chan)
>  {
>  	lockdep_assert_held(dw_edma_event_lock(chan));
>
> +	chan->ll_irq.idx = -1;
>  	chan->ll_irq.event = DW_EDMA_LL_EVENT_NONE;
>  }
>
> @@ -128,6 +122,7 @@ dw_edma_ll_snapshot_take(struct dw_edma_chan *chan,
>  	if (dw_edma_abort_latch_locked(chan))
>  		return false;
>
> +	/* Consume each snapshot once, even if its boundary is later rejected. */
>  	*snapshot = chan->ll_irq;
>  	dw_edma_ll_snapshot_discard_locked(chan);
>
> @@ -215,7 +210,13 @@ static u32 dw_edma_core_get_used_num(struct dw_edma_chan *chan)
>
>  static u32 dw_edma_core_get_free_num(struct dw_edma_chan *chan)
>  {
> -	/* Keep one data entry free so equal indices mean an empty ring. */
> +	/*
> +	 * ll_done is the consumer boundary, so only the distance from ll_done
> +	 * to ll_head is occupied. Descriptor completion is tracked separately
> +	 * with done_burst.
> +	 *
> +	 * Keep one data entry free so equal indices mean an empty ring.
> +	 */
>  	return chan->ll_max - 1 - dw_edma_core_get_used_num(chan);
>  }
>
> @@ -224,6 +225,25 @@ static bool dw_edma_ll_pending(struct dw_edma_chan *chan)
>  	return chan->ll_head != chan->ll_done;
>  }
>
> +static u32 dw_edma_core_ch_transfer_size(struct dw_edma_chan *chan)
> +{
> +	if (!chan->dw->core->ch_transfer_size)
> +		return U32_MAX;
> +
> +	return chan->dw->core->ch_transfer_size(chan);
> +}
> +
> +static bool dw_edma_ll_done_is_stopped(struct dw_edma_chan *chan)
> +{
> +	/*
> +	 * Native HDMA reports STOP separately. The eDMA-compatible interrupt
> +	 * interface uses DONE for both progress and stop, so confirm a stopped
> +	 * boundary with channel status and transfer size.
> +	 */
> +	return dw_edma_core_ch_status(chan) == DMA_COMPLETE &&
> +	       dw_edma_core_ch_transfer_size(chan) == 0;
> +}
> +
>  static void dw_edma_core_ll_start(struct dw_edma_desc *desc)
>  {
>  	struct dw_edma_chan *chan = desc->chan;
> @@ -231,6 +251,9 @@ static void dw_edma_core_ll_start(struct dw_edma_desc *desc)
>  	u32 free;
>
>  	free = dw_edma_core_get_free_num(chan);
> +	if (free && desc->start_burst == desc->done_burst)
> +		desc->ll_start = chan->ll_head;
> +

should always set ll_start = chan->ll_head, always record current fit into
which ll index.

>  	for (i = desc->start_burst; i < desc->nburst && free; i++, free--) {
>  		/*
>  		 * Refresh the link element before filling the last data slot so
> @@ -252,7 +275,6 @@ static void dw_edma_core_ll_start(struct dw_edma_desc *desc)
>  		}
>  	}
>
> -	desc->done_burst = desc->start_burst;
>  	desc->start_burst = i;
>  }
>
> @@ -352,6 +374,127 @@ static void dw_edma_finish_termination(struct dw_edma_chan *chan)
>  	chan->status = EDMA_ST_IDLE;
>  }
>
> +/*
> + * Must be called with vc.lock held. Consume an LL progress boundary,
> + * advance ll_done and complete descriptors covered by the consumed range.
> + * Return true if ll_done advanced.
> + */
> +static bool dw_edma_ll_consume_progress(struct dw_edma_chan *chan, int idx)
> +{
> +	struct virt_dma_desc *vd, *_vd;
> +	bool advanced = false;
> +	u32 done, gap;
> +
> +	/* Ignore invalid, duplicate or stale progress. */
> +	if (idx < 0 || (u32)idx >= chan->ll_max)
> +		return false;
> +
> +	done = dw_edma_core_get_ll_dist(chan, chan->ll_done, idx);
> +	if (!done || done > dw_edma_core_get_used_num(chan))
> +		return false;
> +
> +	list_for_each_entry_safe(vd, _vd, &chan->vc.desc_issued, node) {
> +		struct dw_edma_desc *desc = vd2dw_edma_desc(vd);
> +		u32 consumed;
> +
> +		if (!done)
> +			break;
> +
> +		if (WARN_ON_ONCE(desc->done_burst > desc->start_burst ||
> +				 desc->start_burst > desc->nburst))
> +			return advanced;
> +
> +		/*
> +		 * start_burst is the next burst to append. done_burst counts
> +		 * bursts already consumed by hardware.
> +		 */
> +		consumed = desc->start_burst - desc->done_burst;
> +		if (!consumed)
> +			break;
> +
> +		/*
> +		 * ll_start ties the descriptor counters to the physical ring.
> +		 * If accounting lost entries before this descriptor, skip them
> +		 * only after the sampled boundary has reached ll_start.
> +		 */
> +		if (WARN_ON_ONCE(desc->ll_start != chan->ll_done)) {
> +			gap = dw_edma_core_get_ll_dist(chan, chan->ll_done,
> +						       desc->ll_start);
> +			if (gap > done)
> +				return advanced;
> +
> +			chan->ll_done = desc->ll_start;
> +			done -= gap;
> +			advanced = true;
> +			if (!done)
> +				break;
> +		}
> +
> +		consumed = min(done, consumed);
> +		desc->done_burst += consumed;
> +		desc->ll_start = (desc->ll_start + consumed) % chan->ll_max;

It'd better update ll_start when fill ll from desc. Here should only
update ll_done.

chan->ll_done = (chan->ll_done +  consumed) % chan->ll_max.

> +		chan->ll_done = desc->ll_start;
> +		done -= consumed;
> +		advanced = true;
> +
> +		/*
> +		 * Descriptors are published and retired in strict list order. A
> +		 * later descriptor cannot complete until this one is fully consumed.
> +		 */
> +		if (desc->done_burst != desc->nburst)
> +			break;
> +
> +		/* Hardware has consumed this descriptor's LL entries. */
> +		dw_hdma_set_callback_result(vd, DMA_TRANS_NOERROR);
> +		list_del(&vd->node);
> +		vchan_cookie_complete(vd);
> +	}
> +
> +	WARN_ON_ONCE(done);
> +
> +	return advanced;
> +}
> +
> +static int
> +dw_edma_ll_recycle_idx(struct dw_edma_chan *chan, int idx,
> +		       enum dw_edma_ll_event event)
> +{
> +	if (idx < 0 || (u32)idx > chan->ll_max)
> +		return -EINVAL;
> +
> +	/*
> +	 * Convert the raw LLP index to the exclusive boundary used by ll_done.
> +	 * For both eDMA and HDMA, once the engine has stopped, LLP points to
> +	 * the next element. ll_max is the link element, hence the following
> +	 * data boundary is 0.
> +	 */
> +	if (event == DW_EDMA_LL_EVENT_STOP)
> +		return idx == chan->ll_max ? 0 : idx;

regardless state. we can always treat link element as 0. ll_max have not
include link entry.

in calculate distance between two point A, B.  (B - A) % ll_max.

It is the same when A or B is ll_max or 0.


> +
> +	/*
> +	 * Moving a running index one entry back cannot represent index 0
> +	 * without wrapping it to ll_max - 1. That could falsely consume a full
> +	 * producer window, so wait for another sample or STOP.
> +	 */
> +	if (!idx)
> +		return -EINVAL;
> +
> +	/*
> +	 * A running eDMA LLP can move ahead of payload completion, so keep the
> +	 * boundary one entry behind it.
> +	 *
> +	 * DWC PCIe Controller Databook 6.10a-lca06, Section 7.2.1, Table 7-3
> +	 * describes an HDMA watermark LLP as an inclusive LLE recycling
> +	 * boundary, which would normally translate to idx + 1. During testing
> +	 * on a DWC HDMA 6.30a integration, using that boundary for DMAengine
> +	 * completion let clients release DMA mappings while hardware still
> +	 * accessed them, causing IOMMU faults. Keep the boundary one entry
> +	 * behind the raw LLP for HDMA as well. Stopped samples continue to use
> +	 * the next-entry boundary above.
> +	 */
> +	return idx == chan->ll_max ? chan->ll_max - 1 : idx - 1;

LLP should point current DMA working LL, always stop at which controller bit
have not set yet.

If your logic always treat idx as unfinished, you needn't idx - 1 here.

[ll_done, idx)

> +}
> +
>  static void dw_edma_core_ll_sync(struct dw_edma_chan *chan)
>  {
>  	/*
> @@ -834,31 +977,30 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan,
>  	return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
>  }
>
> -/* Must be called with vc.lock held. */
> -static void dw_edma_done_interrupt_locked(struct dw_edma_chan *chan)
> +static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
>  {
>  	struct dw_edma_desc *desc;
>  	struct virt_dma_desc *vd;
> +	unsigned long flags;
>
> -	lockdep_assert_held(&chan->vc.lock);
> -
> -	if (chan->status == EDMA_ST_PAUSE)
> +	spin_lock_irqsave(&chan->vc.lock, flags);
> +	if (chan->status == EDMA_ST_PAUSE) {
> +		spin_unlock_irqrestore(&chan->vc.lock, flags);
>  		return;
> +	}
>
>  	switch (chan->request) {
>  	case EDMA_REQ_NONE:
>  	case EDMA_REQ_PAUSE:
>  		vd = vchan_next_desc(&chan->vc);
> -		if (!vd)
> -			break;
> -
> -		desc = vd2dw_edma_desc(vd);
> -		if (desc->start_burst >= desc->nburst) {
> -			dw_hdma_set_callback_result(vd, DMA_TRANS_NOERROR);
> -			list_del(&vd->node);
> -			vchan_cookie_complete(vd);
> -			if (!chan->non_ll)
> -				chan->ll_done = chan->ll_head;
> +		if (vd) {
> +			desc = vd2dw_edma_desc(vd);
> +			if (desc->start_burst >= desc->nburst) {
> +				dw_hdma_set_callback_result(vd,
> +							    DMA_TRANS_NOERROR);
> +				list_del(&vd->node);
> +				vchan_cookie_complete(vd);
> +			}
>  		}
>
>  		if (chan->request == EDMA_REQ_PAUSE) {
> @@ -871,25 +1013,12 @@ static void dw_edma_done_interrupt_locked(struct dw_edma_chan *chan)
>  		break;
>
>  	case EDMA_REQ_STOP:
> -		vd = vchan_next_desc(&chan->vc);
> -		if (!vd)
> -			break;
> -
>  		dw_edma_finish_termination(chan);
>  		break;
>
>  	default:
>  		break;
>  	}
> -	dw_edma_core_ch_maybe_doorbell(chan);
> -}
> -
> -static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
> -{
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&chan->vc.lock, flags);
> -	dw_edma_done_interrupt_locked(chan);
>  	spin_unlock_irqrestore(&chan->vc.lock, flags);
>  }
>
> @@ -902,7 +1031,37 @@ static void dw_edma_ll_interrupt(struct dw_edma_chan *chan)
>  	if (!dw_edma_ll_snapshot_take(chan, &snapshot))
>  		return;
>
> -	dw_edma_done_interrupt_locked(chan);
> +	if (chan->status == EDMA_ST_PAUSE)
> +		return;
> +
> +	dw_edma_ll_consume_progress(chan, snapshot.idx);
> +
> +	if (snapshot.event == DW_EDMA_LL_EVENT_PROGRESS &&
> +	    chan->request != EDMA_REQ_NONE)
> +		goto out;
> +
> +	switch (chan->request) {
> +	case EDMA_REQ_NONE:
> +		dw_edma_start_transfer(chan);
> +		chan->status = dw_edma_ll_pending(chan) ?
> +			       EDMA_ST_BUSY : EDMA_ST_IDLE;
> +		break;
> +
> +	case EDMA_REQ_PAUSE:
> +		dw_edma_set_request(chan, EDMA_REQ_NONE);
> +		chan->status = EDMA_ST_PAUSE;
> +		break;
> +
> +	case EDMA_REQ_STOP:
> +		dw_edma_finish_termination(chan);
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +out:
> +	dw_edma_core_ch_maybe_doorbell(chan);
>  }
>
>  static bool dw_edma_abort_interrupt(struct dw_edma_chan *chan)
> @@ -965,21 +1124,44 @@ static void dw_edma_queue_irq_work(struct dw_edma_chan *chan,
>  static void dw_edma_record_irq(struct dw_edma_chan *chan, unsigned int events)
>  {
>  	struct dw_edma_ll_snapshot snapshot = {
> -		.event = events & DW_EDMA_IRQ_STOP ?
> -			 DW_EDMA_LL_EVENT_STOP : DW_EDMA_LL_EVENT_PROGRESS,
> +		.idx = -1,
> +		.event = DW_EDMA_LL_EVENT_NONE,
>  	};
>  	unsigned int pending = 0;
>
>  	lockdep_assert_held(dw_edma_event_lock(chan));
>
> +	/*
> +	 * Classify the LL event before normalizing its LLP sample to the
> +	 * exclusive consumer boundary. Keep STOP even without a valid
> +	 * boundary so deferred handling still sees that the run ended.
> +	 */
> +	if (!chan->non_ll &&
> +	    (events & (DW_EDMA_IRQ_DONE | DW_EDMA_IRQ_PROGRESS |
> +		       DW_EDMA_IRQ_STOP))) {
> +		if ((events & DW_EDMA_IRQ_STOP) ||
> +		    ((events & DW_EDMA_IRQ_DONE) &&
> +		     dw_edma_ll_done_is_stopped(chan)))
> +			snapshot.event = DW_EDMA_LL_EVENT_STOP;
> +		else
> +			snapshot.event = DW_EDMA_LL_EVENT_PROGRESS;
> +
> +		snapshot.idx = dw_edma_ll_recycle_idx(chan,
> +						      dw_edma_core_ll_cur_idx(chan),
> +						      snapshot.event);
> +		if (snapshot.idx < 0 &&
> +		    snapshot.event != DW_EDMA_LL_EVENT_STOP)
> +			snapshot.event = DW_EDMA_LL_EVENT_NONE;
> +	}
> +
>  	if ((events & DW_EDMA_IRQ_ABORT) && chan->abort_pending)
>  		pending |= DW_EDMA_DEFERRED_ABORT;
>
> -	if (chan->non_ll) {
> -		if (events & (DW_EDMA_IRQ_DONE | DW_EDMA_IRQ_STOP))
> -			pending |= DW_EDMA_DEFERRED_DONE;
> -	} else if (events & (DW_EDMA_IRQ_DONE | DW_EDMA_IRQ_PROGRESS |
> -			     DW_EDMA_IRQ_STOP)) {
> +	if (chan->non_ll &&
> +	    (events & (DW_EDMA_IRQ_DONE | DW_EDMA_IRQ_STOP)))
> +		pending |= DW_EDMA_DEFERRED_DONE;
> +
> +	if (snapshot.event != DW_EDMA_LL_EVENT_NONE) {
>  		/* STOP is final for this run; do not replace it with progress. */
>  		if (chan->ll_irq.event != DW_EDMA_LL_EVENT_STOP ||
>  		    snapshot.event == DW_EDMA_LL_EVENT_STOP)
> @@ -1227,6 +1409,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
>  		chan->irq_mode = dw_edma_get_default_irq_mode(chan);
>  		INIT_WORK(&chan->irq_work, dw_edma_irq_work);
>  		atomic_set(&chan->irq_pending, 0);
> +		chan->ll_irq.idx = -1;
>  		chan->ll_irq.event = DW_EDMA_LL_EVENT_NONE;
>  		chan->abort_pending = false;
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index d709aa274300..27cab6ca5e67 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -71,6 +71,7 @@ struct dw_edma_desc {
>
>  	u32				alloc_sz;
>
> +	u32				ll_start;	/* First outstanding LL entry */
>  	size_t				done_burst;
>  	size_t				start_burst;
>  	size_t				nburst;
> @@ -78,6 +79,7 @@ struct dw_edma_desc {
>  };
>
>  struct dw_edma_ll_snapshot {
> +	int				idx;
>  	enum dw_edma_ll_event		event;
>  };
>
> @@ -113,6 +115,7 @@ struct dw_edma_chan {
>  	 * LL event recorded by the hard IRQ handler. The event lock
>  	 * serializes its capture with a new hardware run; vc.lock serializes
>  	 * its consumption with LL state.
> +	 * Valid indices use the exclusive boundary convention of ll_done.
>  	 */
>  	struct dw_edma_ll_snapshot	ll_irq;
>  	/* ABORT is terminal and remains pending across LL state changes. */
> @@ -189,6 +192,7 @@ struct dw_edma_core_ops {
>  	enum dma_status (*ch_status)(struct dw_edma_chan *chan);
>  	/* Called with dw_edma_event_lock(chan) held. */
>  	bool (*ch_abort_int_pending)(struct dw_edma_chan *chan);
> +	u32 (*ch_transfer_size)(struct dw_edma_chan *chan);
>  	irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
>  				  dw_edma_handler_t handler);
>  	void (*non_ll_start)(struct dw_edma_chan *chan, struct dw_edma_burst *child);
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index 20dff21a0603..b9d6205157b3 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -318,6 +318,11 @@ static enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
>  		return DMA_ERROR;
>  }
>
> +static u32 dw_edma_v0_core_ch_transfer_size(struct dw_edma_chan *chan)
> +{
> +	return GET_CH_32(chan->dw, chan->dir, chan->id, transfer_size);
> +}
> +
>  static bool dw_edma_v0_core_ch_abort_int_pending(struct dw_edma_chan *chan)
>  {
>  	u32 sts = GET_RW_32(chan->dw, chan->dir, int_status);
> @@ -677,6 +682,7 @@ static const struct dw_edma_core_ops dw_edma_v0_core = {
>  	.ch_count = dw_edma_v0_core_ch_count,
>  	.ch_status = dw_edma_v0_core_ch_status,
>  	.ch_abort_int_pending = dw_edma_v0_core_ch_abort_int_pending,
> +	.ch_transfer_size = dw_edma_v0_core_ch_transfer_size,
>  	.handle_int = dw_edma_v0_core_handle_int,
>  	.ll_data = dw_edma_v0_core_ll_data,
>  	.ll_link = dw_edma_v0_core_ll_link,
> --
> 2.51.0
>

  reply	other threads:[~2026-08-12 20:54 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-12 15:56 [PATCH v5 00/24] dmaengine: dw-edma: Support dynamic LL appends Koichiro Den
2026-08-12 15:56 ` [PATCH v5 01/24] dmaengine: dw-edma: Add dw_edma_core_ll_cur_idx() to get current LL entry index Koichiro Den
2026-08-12 18:50   ` Frank Li
2026-08-12 15:56 ` [PATCH v5 02/24] dmaengine: dw-edma: Add dw_edma_core_ll_clear() to clear LL control-word Koichiro Den
2026-08-12 15:57 ` [PATCH v5 03/24] dmaengine: dw-edma: Factor out linked-list transfer start Koichiro Den
2026-08-12 15:57 ` [PATCH v5 04/24] dmaengine: dw-edma: Make DMA link list work as a circular buffer Koichiro Den
2026-08-12 16:14   ` sashiko-bot
2026-08-13  8:31     ` Koichiro Den
2026-08-12 15:57 ` [PATCH v5 05/24] dmaengine: dw-edma: Move callback result helper before LL helpers Koichiro Den
2026-08-12 15:57 ` [PATCH v5 06/24] dmaengine: dw-edma: Dispatch DONE interrupts by channel request Koichiro Den
2026-08-12 15:57 ` [PATCH v5 07/24] dmaengine: dw-edma: Centralize LL doorbell decisions Koichiro Den
2026-08-12 15:57 ` [PATCH v5 08/24] dmaengine: dw-edma: Prepare LL progress event handling Koichiro Den
2026-08-12 15:57 ` [PATCH v5 09/24] dmaengine: dw-edma: Prepare deferred IRQ reporting for LL events Koichiro Den
2026-08-12 15:57 ` [PATCH v5 10/24] dmaengine: dw-edma: Prepare LL kicks for event serialization Koichiro Den
2026-08-12 15:57 ` [PATCH v5 11/24] dmaengine: dw-edma: Serialize LL event capture with channel kicks Koichiro Den
2026-08-12 15:57 ` [PATCH v5 12/24] dmaengine: dw-edma: Keep channels stopped while ABORT is pending Koichiro Den
2026-08-12 15:57 ` [PATCH v5 13/24] dmaengine: dw-edma: Reclaim issued descriptors from IRQ-paired LL progress Koichiro Den
2026-08-12 20:54   ` Frank Li [this message]
2026-08-14  8:48     ` Koichiro Den
2026-08-14 15:47       ` Frank Li
2026-08-15 14:36         ` Koichiro Den
2026-08-21 20:17           ` Frank Li
2026-08-22 14:26             ` Koichiro Den
2026-08-12 15:57 ` [PATCH v5 14/24] dmaengine: dw-edma: Add LL interrupt placement policy Koichiro Den
2026-08-12 15:57 ` [PATCH v5 15/24] dmaengine: dw-edma: Recheck stopped LL channels before restart Koichiro Den
2026-08-12 16:33   ` sashiko-bot
2026-08-12 15:57 ` [PATCH v5 16/24] dmaengine: dw-edma: Use HDMA watermarks as progress events Koichiro Den
2026-08-12 15:57 ` [PATCH v5 17/24] dmaengine: dw-edma: Recover stopped channels from tx_status() Koichiro Den
2026-08-12 15:57 ` [PATCH v5 18/24] dmaengine: dw-edma: Make the LL ring reset a full channel resync Koichiro Den
2026-08-12 15:57 ` [PATCH v5 19/24] dmaengine: dw-edma: Drain LL entries for STOP and PAUSE Koichiro Den
2026-08-12 16:29   ` sashiko-bot
2026-08-12 15:57 ` [PATCH v5 20/24] dmaengine: dw-edma: Dynamically append requests while running Koichiro Den
2026-08-12 15:57 ` [PATCH v5 21/24] dmaengine: dw-edma: Add engine reset and enable operations Koichiro Den
2026-08-12 15:57 ` [PATCH v5 22/24] dmaengine: dw-edma: Add engine recovery infrastructure Koichiro Den
2026-08-12 15:57 ` [PATCH v5 23/24] dmaengine: dw-edma: Detect and recover a stalled eDMA engine Koichiro Den
2026-08-12 15:57 ` [PATCH v5 24/24] dmaengine: dw-edma: Add trace support Koichiro Den
2026-08-12 21:05 ` [PATCH v5 00/24] dmaengine: dw-edma: Support dynamic LL appends Frank Li
2026-08-13  1:04   ` Koichiro Den
2026-08-13 16:39 ` Koichiro Den

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=anzdd9kAxBHvuzpo@lizhi-Precision-Tower-5810 \
    --to=frank.li@oss.nxp.com \
    --cc=Frank.Li@kernel.org \
    --cc=Gustavo.Pimentel@synopsys.com \
    --cc=bhelgaas@google.com \
    --cc=cai.huoqing@linux.dev \
    --cc=cassel@kernel.org \
    --cc=den@valinux.co.jp \
    --cc=devendra.verma@amd.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=fancer.lancer@gmail.com \
    --cc=hch@lst.de \
    --cc=kees@kernel.org \
    --cc=kishon@kernel.org \
    --cc=kwilczynski@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mani@kernel.org \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox