Re: [PATCH v5 01/24] 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 | <anzAYsh7LuHOC8FL@lizhi-Precision-Tower-5810> |
On Thu, Aug 13, 2026 at 12:56:58AM +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]> > Reviewed-by: Frank Li <[email protected]> > Co-developed-by: Koichiro Den <[email protected]> > Signed-off-by: Koichiro Den <[email protected]> > --- > Changes in v5: > - Reject an all-ones DMA_LLP value before converting it to an LL > index. (Sashiko) > > @Frank, I kept your R-b tag since the v5 change is only a small validation > check. Please let me know if you prefer me to drop it. look good Frank > > drivers/dma/dw-edma/dw-edma-core.h | 10 ++++++++++ > drivers/dma/dw-edma/dw-edma-v0-core.c | 20 ++++++++++++++++++++ > drivers/dma/dw-edma/dw-hdma-v0-core.c | 20 ++++++++++++++++++++ > include/linux/dma/edma.h | 2 +- > 4 files changed, 51 insertions(+), 1 deletion(-) > > 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..cc8059182940 100644 > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c > @@ -616,6 +616,25 @@ 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)); > + > + /* > + * LL regions stay within one 4 GiB address window. Reject an all-ones > + * MMIO value. If the low word is zero, use the high word to distinguish > + * a nonzero boundary address from an unprogrammed all-zero context. > + */ > + if (val == U32_MAX || > + (!val && !GET_CH_32(chan->dw, chan->dir, chan->id, llp.msb))) > + return -EINVAL; > + > + return (val - base) / EDMA_LL_SZ; > +} > + > /* eDMA debugfs callbacks */ > static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw) > { > @@ -650,6 +669,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..19da1c8fd615 100644 > --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c > +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c > @@ -384,6 +384,25 @@ 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)); > + > + /* > + * LL regions stay within one 4 GiB address window. Reject an all-ones > + * MMIO value. If the low word is zero, use the high word to distinguish > + * a nonzero boundary address from an unprogrammed all-zero context. > + */ > + if (val == U32_MAX || > + (!val && !GET_CH_32(chan->dw, chan->dir, chan->id, llp.msb))) > + return -EINVAL; > + > + return (val - base) / EDMA_LL_SZ; > +} > + > /* HDMA debugfs callbacks */ > static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw) > { > @@ -406,6 +425,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, > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h > index 3c8e2ef9dee0..a4e5aab8fddc 100644 > --- a/include/linux/dma/edma.h > +++ b/include/linux/dma/edma.h > @@ -130,7 +130,7 @@ struct dw_edma_chip { > > u16 ll_wr_cnt; > u16 ll_rd_cnt; > - /* link list address */ > + /* Linked-list regions must not cross a 4 GiB address boundary. */ > struct dw_edma_region ll_region_wr[HDMA_MAX_WR_CH]; > struct dw_edma_region ll_region_rd[HDMA_MAX_RD_CH]; > > -- > 2.51.0 >