Re: [PATCH v2 01/19] dmaengine: dw-edma: Add dw_edma_core_ll_cur_idx() to get current LL entry index
Frank Li <[email protected]>
| Newsgroups | org.kernel.vger.dmaengine,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <amJAY8lV6WbigHOj@SMW015318> |
On Thu, Jul 23, 2026 at 05:41:32PM +0900, Koichiro Den wrote: > From: Frank Li <[email protected]> > > Add dw_edma_core_ll_cur_idx() to get the current LL entry index and > prepare for dynamic addition of DMA requests while the DMA engine is > running. > > Signed-off-by: Frank Li <[email protected]> > Co-developed-by: Koichiro Den <[email protected]> > Signed-off-by: Koichiro Den <[email protected]> > --- Reviewed-by: Frank Li <[email protected]> > Based on Frank's original submission: > https://lore.kernel.org/dmaengine/[email protected]/ > > Changes in v2: > - Handle zero low words and low-word wrap without reading DMA_LLP.MSB > on the normal path, and clarify the lost-context comments. > > drivers/dma/dw-edma/dw-edma-core.h | 10 ++++++++++ > drivers/dma/dw-edma/dw-edma-v0-core.c | 19 +++++++++++++++++++ > drivers/dma/dw-edma/dw-hdma-v0-core.c | 19 +++++++++++++++++++ > 3 files changed, 48 insertions(+) > > diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h > index f6a5ad317567..e50fa7965778 100644 > --- a/drivers/dma/dw-edma/dw-edma-core.h > +++ b/drivers/dma/dw-edma/dw-edma-core.h > @@ -138,6 +138,7 @@ struct dw_edma_core_ops { > void (*ll_data)(struct dw_edma_chan *chan, struct dw_edma_burst *burst, > u32 idx, bool cb, bool irq); > void (*ll_link)(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr); > + int (*ll_cur_idx)(struct dw_edma_chan *chan); > void (*ch_doorbell)(struct dw_edma_chan *chan); > void (*ch_enable)(struct dw_edma_chan *chan); > void (*ch_config)(struct dw_edma_chan *chan); > @@ -181,6 +182,15 @@ struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan) > return vc2dw_edma_chan(to_virt_chan(dchan)); > } > > +/* > + * Return the current LL entry index. A negative value means that the channel > + * context is not initialized or was lost after a link reset. > + */ > +static inline int dw_edma_core_ll_cur_idx(struct dw_edma_chan *chan) > +{ > + return chan->dw->core->ll_cur_idx(chan); > +} > + > static inline u64 dw_edma_core_get_ll_paddr(struct dw_edma_chan *chan) > { > if (chan->dir == EDMA_DIR_WRITE) > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c > index abc1bd4c0be2..ba84811234e1 100644 > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c > @@ -616,6 +616,24 @@ static void dw_edma_v0_core_ch_doorbell(struct dw_edma_chan *chan) > FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id)); > } > > +static int dw_edma_v0_core_ll_cur_idx(struct dw_edma_chan *chan) > +{ > + u32 base, val; > + > + val = GET_CH_32(chan->dw, chan->dir, chan->id, llp.lsb); > + base = lower_32_bits(dw_edma_core_get_ll_paddr(chan)); > + > + /* > + * An all-zero pointer means that the channel context is unavailable, > + * so an LL region starting at DMA address zero is not supported. > + */ > + if (!val && !GET_CH_32(chan->dw, chan->dir, chan->id, llp.msb)) > + return -EINVAL; > + > + /* u32 subtraction handles a low-word wrap at a 4 GiB boundary. */ > + return (val - base) / EDMA_LL_SZ; > +} > + > /* eDMA debugfs callbacks */ > static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw) > { > @@ -650,6 +668,7 @@ static const struct dw_edma_core_ops dw_edma_v0_core = { > .handle_int = dw_edma_v0_core_handle_int, > .ll_data = dw_edma_v0_core_ll_data, > .ll_link = dw_edma_v0_core_ll_link, > + .ll_cur_idx = dw_edma_v0_core_ll_cur_idx, > .ch_doorbell = dw_edma_v0_core_ch_doorbell, > .ch_enable = dw_edma_v0_core_ch_enable, > .ch_config = dw_edma_v0_core_ch_config, > diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c > index 36ee72efcd31..2fc7f8e85b43 100644 > --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c > +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c > @@ -384,6 +384,24 @@ static void dw_hdma_v0_core_ch_doorbell(struct dw_edma_chan *chan) > SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START); > } > > +static int dw_hdma_v0_core_ll_cur_idx(struct dw_edma_chan *chan) > +{ > + u32 base, val; > + > + val = GET_CH_32(chan->dw, chan->dir, chan->id, llp.lsb); > + base = lower_32_bits(dw_edma_core_get_ll_paddr(chan)); > + > + /* > + * An all-zero pointer means that the channel context is unavailable, > + * so an LL region starting at DMA address zero is not supported. > + */ > + if (!val && !GET_CH_32(chan->dw, chan->dir, chan->id, llp.msb)) > + return -EINVAL; > + > + /* u32 subtraction handles a low-word wrap at a 4 GiB boundary. */ > + return (val - base) / EDMA_LL_SZ; > +} > + > /* HDMA debugfs callbacks */ > static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw) > { > @@ -406,6 +424,7 @@ static const struct dw_edma_core_ops dw_hdma_v0_core = { > .non_ll_start = dw_hdma_v0_core_non_ll_start, > .ll_data = dw_hdma_v0_core_ll_data, > .ll_link = dw_hdma_v0_core_ll_link, > + .ll_cur_idx = dw_hdma_v0_core_ll_cur_idx, > .ch_doorbell = dw_hdma_v0_core_ch_doorbell, > .ch_enable = dw_hdma_v0_core_ch_enable, > .ch_config = dw_hdma_v0_core_ch_config, > -- > 2.51.0 >