lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <aW5RmbQ4qIJnAyHz@lizhi-Precision-Tower-5810>
Date: Mon, 19 Jan 2026 10:45:29 -0500
From: Frank Li <Frank.li@....com>
To: "Verma, Devendra" <Devendra.Verma@....com>
Cc: "bhelgaas@...gle.com" <bhelgaas@...gle.com>,
	"mani@...nel.org" <mani@...nel.org>,
	"vkoul@...nel.org" <vkoul@...nel.org>,
	"dmaengine@...r.kernel.org" <dmaengine@...r.kernel.org>,
	"linux-pci@...r.kernel.org" <linux-pci@...r.kernel.org>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
	"Simek, Michal" <michal.simek@....com>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode

On Mon, Jan 19, 2026 at 09:09:17AM +0000, Verma, Devendra wrote:
> [AMD Official Use Only - AMD Internal Distribution Only]
>
> Hi Frank
>
> Please check my response inline.
>
> Regards,
> Devendra
> > -----Original Message-----
> > From: Frank Li <Frank.li@....com>
> > Sent: Thursday, January 15, 2026 10:07 PM
> > To: Verma, Devendra <Devendra.Verma@....com>
> > Cc: bhelgaas@...gle.com; mani@...nel.org; vkoul@...nel.org;
> > dmaengine@...r.kernel.org; linux-pci@...r.kernel.org; linux-
> > kernel@...r.kernel.org; Simek, Michal <michal.simek@....com>
> > Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
> >
> > Caution: This message originated from an External Source. Use proper
> > caution when opening attachments, clicking links, or responding.
> >
> >
> > On Fri, Jan 09, 2026 at 05:33:54PM +0530, Devendra K Verma wrote:
> > > AMD MDB IP supports Linked List (LL) mode as well as non-LL mode.
> > > The current code does not have the mechanisms to enable the DMA
> > > transactions using the non-LL mode. The following two cases are added
> > > with this patch:
> > > - For the AMD (Xilinx) only, when a valid physical base address of
> > >   the device side DDR is not configured, then the IP can still be
> > >   used in non-LL mode. For all the channels DMA transactions will
> >
> > If DDR have not configured, where DATA send to in device side by non-LL
> > mode.
> >
>
> The DDR base address in the VSEC capability is used for driving the DMA
> transfers when used in the LL mode. The DDR is configured and present
> all the time but the DMA PCIe driver uses this DDR base address (physical address)
> to configure the LLP address.
>
> In the scenario, where this DDR base address in VSEC capability is not
> configured then the current controller cannot be used as the default mode
> supported is LL mode only. In order to make the controller usable non-LL mode
> is being added which just needs SAR, DAR, XFERLEN and control register to initiate the
> transfer. So, the DDR is always present, but the DMA PCIe driver need to know
> the DDR base physical address to make the transfer. This is useful in scenarios
> where the memory allocated for LL can be used for DMA transactions as well.

Do you means use DMA transfer LL's context?

>
> > >   be using the non-LL mode only. This, the default non-LL mode,
> > >   is not applicable for Synopsys IP with the current code addition.
> > >
> > > - If the default mode is LL-mode, for both AMD (Xilinx) and Synosys,
> > >   and if user wants to use non-LL mode then user can do so via
> > >   configuring the peripheral_config param of dma_slave_config.
> > >
> > > Signed-off-by: Devendra K Verma <devendra.verma@....com>
> > > ---
> > > Changes in v8
> > >   Cosmetic change related to comment and code.
> > >
> > > Changes in v7
> > >   No change
> > >
> > > Changes in v6
> > >   Gave definition to bits used for channel configuration.
> > >   Removed the comment related to doorbell.
> > >
> > > Changes in v5
> > >   Variable name 'nollp' changed to 'non_ll'.
> > >   In the dw_edma_device_config() WARN_ON replaced with dev_err().
> > >   Comments follow the 80-column guideline.
> > >
> > > Changes in v4
> > >   No change
> > >
> > > Changes in v3
> > >   No change
> > >
> > > Changes in v2
> > >   Reverted the function return type to u64 for
> > >   dw_edma_get_phys_addr().
> > >
> > > Changes in v1
> > >   Changed the function return type for dw_edma_get_phys_addr().
> > >   Corrected the typo raised in review.
> > > ---
> > >  drivers/dma/dw-edma/dw-edma-core.c    | 42 +++++++++++++++++++++---
> > >  drivers/dma/dw-edma/dw-edma-core.h    |  1 +
> > >  drivers/dma/dw-edma/dw-edma-pcie.c    | 46 ++++++++++++++++++--------
> > >  drivers/dma/dw-edma/dw-hdma-v0-core.c | 61
> > > ++++++++++++++++++++++++++++++++++-
> > >  drivers/dma/dw-edma/dw-hdma-v0-regs.h |  1 +
> >
> > edma-v0-core.c have not update, if don't support, at least need return failure
> > at dw_edma_device_config() when backend is eDMA.
> >
> > >  include/linux/dma/edma.h              |  1 +
> > >  6 files changed, 132 insertions(+), 20 deletions(-)
> > >
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c
> > > b/drivers/dma/dw-edma/dw-edma-core.c
> > > index b43255f..d37112b 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -223,8 +223,32 @@ static int dw_edma_device_config(struct
> > dma_chan *dchan,
> > >                                struct dma_slave_config *config)  {
> > >       struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
> > > +     int non_ll = 0;
> > > +
> > > +     if (config->peripheral_config &&
> > > +         config->peripheral_size != sizeof(int)) {
> > > +             dev_err(dchan->device->dev,
> > > +                     "config param peripheral size mismatch\n");
> > > +             return -EINVAL;
> > > +     }
> > >
> > >       memcpy(&chan->config, config, sizeof(*config));
> > > +
> > > +     /*
> > > +      * When there is no valid LLP base address available then the default
> > > +      * DMA ops will use the non-LL mode.
> > > +      *
> > > +      * Cases where LL mode is enabled and client wants to use the non-LL
> > > +      * mode then also client can do so via providing the peripheral_config
> > > +      * param.
> > > +      */
> > > +     if (config->peripheral_config)
> > > +             non_ll = *(int *)config->peripheral_config;
> > > +
> > > +     chan->non_ll = false;
> > > +     if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll && non_ll))
> > > +             chan->non_ll = true;
> > > +
> > >       chan->configured = true;
> > >
> > >       return 0;
> > > @@ -353,7 +377,7 @@ static void dw_edma_device_issue_pending(struct
> > dma_chan *dchan)
> > >       struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
> > >       enum dma_transfer_direction dir = xfer->direction;
> > >       struct scatterlist *sg = NULL;
> > > -     struct dw_edma_chunk *chunk;
> > > +     struct dw_edma_chunk *chunk = NULL;
> > >       struct dw_edma_burst *burst;
> > >       struct dw_edma_desc *desc;
> > >       u64 src_addr, dst_addr;
> > > @@ -419,9 +443,11 @@ static void dw_edma_device_issue_pending(struct
> > dma_chan *dchan)
> > >       if (unlikely(!desc))
> > >               goto err_alloc;
> > >
> > > -     chunk = dw_edma_alloc_chunk(desc);
> > > -     if (unlikely(!chunk))
> > > -             goto err_alloc;
> > > +     if (!chan->non_ll) {
> > > +             chunk = dw_edma_alloc_chunk(desc);
> > > +             if (unlikely(!chunk))
> > > +                     goto err_alloc;
> > > +     }
> >
> > non_ll is the same as ll_max = 1. (or 2, there are link back entry).
> >
> > If you set ll_max = 1, needn't change this code.
> >
>
> The ll_max is defined for the session till the driver is loaded in the kernel.
> This code also enables the non-LL mode dynamically upon input from the
> DMA client. In this scenario, touching ll_max would not be a good idea
> as the ll_max controls the LL entries for all the DMA channels not just for
> a single DMA transaction.

You can use new variable, such as ll_avail.

>
> > >
> > >       if (xfer->type == EDMA_XFER_INTERLEAVED) {
> > >               src_addr = xfer->xfer.il->src_start; @@ -450,7 +476,13
> > > @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)
> > >               if (xfer->type == EDMA_XFER_SCATTER_GATHER && !sg)
> > >                       break;
> > >
> > > -             if (chunk->bursts_alloc == chan->ll_max) {
> > > +             /*
> > > +              * For non-LL mode, only a single burst can be handled
> > > +              * in a single chunk unlike LL mode where multiple bursts
> > > +              * can be configured in a single chunk.
> > > +              */
> > > +             if ((chunk && chunk->bursts_alloc == chan->ll_max) ||
> > > +                 chan->non_ll) {
> > >                       chunk = dw_edma_alloc_chunk(desc);
> > >                       if (unlikely(!chunk))
> > >                               goto err_alloc; diff --git
> > > a/drivers/dma/dw-edma/dw-edma-core.h
> > > b/drivers/dma/dw-edma/dw-edma-core.h
> > > index 71894b9..c8e3d19 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.h
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.h
> > > @@ -86,6 +86,7 @@ struct dw_edma_chan {
> > >       u8                              configured;
> > >
> > >       struct dma_slave_config         config;
> > > +     bool                            non_ll;
> > >  };
> > >
> > >  struct dw_edma_irq {
> > > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c
> > > b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > index 2efd149..277ca50 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > @@ -298,6 +298,15 @@ static void
> > dw_edma_pcie_get_xilinx_dma_data(struct pci_dev *pdev,
> > >       pdata->devmem_phys_off = off;
> > >  }
> > >
> > > +static u64 dw_edma_get_phys_addr(struct pci_dev *pdev,
> > > +                              struct dw_edma_pcie_data *pdata,
> > > +                              enum pci_barno bar) {
> > > +     if (pdev->vendor == PCI_VENDOR_ID_XILINX)
> > > +             return pdata->devmem_phys_off;
> > > +     return pci_bus_address(pdev, bar); }
> > > +
> > >  static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >                             const struct pci_device_id *pid)  { @@
> > > -307,6 +316,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >       struct dw_edma_chip *chip;
> > >       int err, nr_irqs;
> > >       int i, mask;
> > > +     bool non_ll = false;
> > >
> > >       vsec_data = kmalloc(sizeof(*vsec_data), GFP_KERNEL);
> > >       if (!vsec_data)
> > > @@ -331,21 +341,24 @@ static int dw_edma_pcie_probe(struct pci_dev
> > *pdev,
> > >       if (pdev->vendor == PCI_VENDOR_ID_XILINX) {
> > >               /*
> > >                * There is no valid address found for the LL memory
> > > -              * space on the device side.
> > > +              * space on the device side. In the absence of LL base
> > > +              * address use the non-LL mode or simple mode supported by
> > > +              * the HDMA IP.
> > >                */
> > > -             if (vsec_data->devmem_phys_off ==
> > DW_PCIE_XILINX_MDB_INVALID_ADDR)
> > > -                     return -ENOMEM;
> > > +             if (vsec_data->devmem_phys_off ==
> > DW_PCIE_AMD_MDB_INVALID_ADDR)
> > > +                     non_ll = true;
> > >
> > >               /*
> > >                * Configure the channel LL and data blocks if number of
> > >                * channels enabled in VSEC capability are more than the
> > >                * channels configured in xilinx_mdb_data.
> > >                */
> > > -             dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0,
> > > -                                            DW_PCIE_XILINX_MDB_LL_OFF_GAP,
> > > -                                            DW_PCIE_XILINX_MDB_LL_SIZE,
> > > -                                            DW_PCIE_XILINX_MDB_DT_OFF_GAP,
> > > -                                            DW_PCIE_XILINX_MDB_DT_SIZE);
> > > +             if (!non_ll)
> > > +                     dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0,
> > > +                                                    DW_PCIE_XILINX_LL_OFF_GAP,
> > > +                                                    DW_PCIE_XILINX_LL_SIZE,
> > > +                                                    DW_PCIE_XILINX_DT_OFF_GAP,
> > > +
> > > + DW_PCIE_XILINX_DT_SIZE);
> > >       }
> > >
> > >       /* Mapping PCI BAR regions */
> > > @@ -393,6 +406,7 @@ static int dw_edma_pcie_probe(struct pci_dev
> > *pdev,
> > >       chip->mf = vsec_data->mf;
> > >       chip->nr_irqs = nr_irqs;
> > >       chip->ops = &dw_edma_pcie_plat_ops;
> > > +     chip->non_ll = non_ll;
> > >
> > >       chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
> > >       chip->ll_rd_cnt = vsec_data->rd_ch_cnt; @@ -401,7 +415,7 @@
> > > static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >       if (!chip->reg_base)
> > >               return -ENOMEM;
> > >
> > > -     for (i = 0; i < chip->ll_wr_cnt; i++) {
> > > +     for (i = 0; i < chip->ll_wr_cnt && !non_ll; i++) {
> > >               struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
> > >               struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
> > >               struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
> > > @@ -412,7 +426,8 @@ static int dw_edma_pcie_probe(struct pci_dev
> > *pdev,
> > >                       return -ENOMEM;
> > >
> > >               ll_region->vaddr.io += ll_block->off;
> > > -             ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
> > > +             ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> > > +                                                      ll_block->bar);
> >
> > This change need do prepare patch, which only change pci_bus_address() to
> > dw_edma_get_phys_addr().
> >
>
> This is not clear.

why not. only trivial add helper patch, which help reviewer

>
> > >               ll_region->paddr += ll_block->off;
> > >               ll_region->sz = ll_block->sz;
> > >
> > > @@ -421,12 +436,13 @@ static int dw_edma_pcie_probe(struct pci_dev
> > *pdev,
> > >                       return -ENOMEM;
> > >
> > >               dt_region->vaddr.io += dt_block->off;
> > > -             dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
> > > +             dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> > > +                                                      dt_block->bar);
> > >               dt_region->paddr += dt_block->off;
> > >               dt_region->sz = dt_block->sz;
> > >       }
> > >
> > > -     for (i = 0; i < chip->ll_rd_cnt; i++) {
> > > +     for (i = 0; i < chip->ll_rd_cnt && !non_ll; i++) {
> > >               struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
> > >               struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
> > >               struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
> > > @@ -437,7 +453,8 @@ static int dw_edma_pcie_probe(struct pci_dev
> > *pdev,
> > >                       return -ENOMEM;
> > >
> > >               ll_region->vaddr.io += ll_block->off;
> > > -             ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
> > > +             ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> > > +                                                      ll_block->bar);
> > >               ll_region->paddr += ll_block->off;
> > >               ll_region->sz = ll_block->sz;
> > >
> > > @@ -446,7 +463,8 @@ static int dw_edma_pcie_probe(struct pci_dev
> > *pdev,
> > >                       return -ENOMEM;
> > >
> > >               dt_region->vaddr.io += dt_block->off;
> > > -             dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
> > > +             dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> > > +                                                      dt_block->bar);
> > >               dt_region->paddr += dt_block->off;
> > >               dt_region->sz = dt_block->sz;
> > >       }
> > > diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c
> > > b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> > > index e3f8db4..a5d12bc 100644
> > > --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
> > > +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
> > > @@ -225,7 +225,7 @@ static void dw_hdma_v0_sync_ll_data(struct
> > dw_edma_chunk *chunk)
> > >               readl(chunk->ll_region.vaddr.io);  }
> > >
> > > -static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool
> > > first)
> > > +static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk,
> > > +bool first)
> > >  {
> > >       struct dw_edma_chan *chan = chunk->chan;
> > >       struct dw_edma *dw = chan->dw;
> > > @@ -263,6 +263,65 @@ static void dw_hdma_v0_core_start(struct
> > dw_edma_chunk *chunk, bool first)
> > >       SET_CH_32(dw, chan->dir, chan->id, doorbell,
> > > HDMA_V0_DOORBELL_START);  }
> > >
> > > +static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chunk
> > *chunk)
> > > +{
> > > +     struct dw_edma_chan *chan = chunk->chan;
> > > +     struct dw_edma *dw = chan->dw;
> > > +     struct dw_edma_burst *child;
> > > +     u32 val;
> > > +
> > > +     list_for_each_entry(child, &chunk->burst->list, list) {
> >
> > why need iterated list, it doesn't support ll. Need wait for irq to start next one.
> >
> > Frank
>
> Yes, this is true. The format is kept similar to LL mode.

Just fill one. list_for_each_entry() cause confuse.

Frank
>
> >
> > > +             SET_CH_32(dw, chan->dir, chan->id, ch_en,
> > > + HDMA_V0_CH_EN);
> > > +
> > > +             /* Source address */
> > > +             SET_CH_32(dw, chan->dir, chan->id, sar.lsb,
> > > +                       lower_32_bits(child->sar));
> > > +             SET_CH_32(dw, chan->dir, chan->id, sar.msb,
> > > +                       upper_32_bits(child->sar));
> > > +
> > > +             /* Destination address */
> > > +             SET_CH_32(dw, chan->dir, chan->id, dar.lsb,
> > > +                       lower_32_bits(child->dar));
> > > +             SET_CH_32(dw, chan->dir, chan->id, dar.msb,
> > > +                       upper_32_bits(child->dar));
> > > +
> > > +             /* Transfer size */
> > > +             SET_CH_32(dw, chan->dir, chan->id, transfer_size,
> > > + child->sz);
> > > +
> > > +             /* Interrupt setup */
> > > +             val = GET_CH_32(dw, chan->dir, chan->id, int_setup) |
> > > +                             HDMA_V0_STOP_INT_MASK |
> > > +                             HDMA_V0_ABORT_INT_MASK |
> > > +                             HDMA_V0_LOCAL_STOP_INT_EN |
> > > +                             HDMA_V0_LOCAL_ABORT_INT_EN;
> > > +
> > > +             if (!(dw->chip->flags & DW_EDMA_CHIP_LOCAL)) {
> > > +                     val |= HDMA_V0_REMOTE_STOP_INT_EN |
> > > +                            HDMA_V0_REMOTE_ABORT_INT_EN;
> > > +             }
> > > +
> > > +             SET_CH_32(dw, chan->dir, chan->id, int_setup, val);
> > > +
> > > +             /* Channel control setup */
> > > +             val = GET_CH_32(dw, chan->dir, chan->id, control1);
> > > +             val &= ~HDMA_V0_LINKLIST_EN;
> > > +             SET_CH_32(dw, chan->dir, chan->id, control1, val);
> > > +
> > > +             SET_CH_32(dw, chan->dir, chan->id, doorbell,
> > > +                       HDMA_V0_DOORBELL_START);
> > > +     }
> > > +}
> > > +
> > > +static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool
> > > +first) {
> > > +     struct dw_edma_chan *chan = chunk->chan;
> > > +
> > > +     if (chan->non_ll)
> > > +             dw_hdma_v0_core_non_ll_start(chunk);
> > > +     else
> > > +             dw_hdma_v0_core_ll_start(chunk, first); }
> > > +
> > >  static void dw_hdma_v0_core_ch_config(struct dw_edma_chan *chan)  {
> > >       struct dw_edma *dw = chan->dw;
> > > diff --git a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > > b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > > index eab5fd7..7759ba9 100644
> > > --- a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > > +++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
> > > @@ -12,6 +12,7 @@
> > >  #include <linux/dmaengine.h>
> > >
> > >  #define HDMA_V0_MAX_NR_CH                    8
> > > +#define HDMA_V0_CH_EN                                BIT(0)
> > >  #define HDMA_V0_LOCAL_ABORT_INT_EN           BIT(6)
> > >  #define HDMA_V0_REMOTE_ABORT_INT_EN          BIT(5)
> > >  #define HDMA_V0_LOCAL_STOP_INT_EN            BIT(4)
> > > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h index
> > > 3080747..78ce31b 100644
> > > --- a/include/linux/dma/edma.h
> > > +++ b/include/linux/dma/edma.h
> > > @@ -99,6 +99,7 @@ struct dw_edma_chip {
> > >       enum dw_edma_map_format mf;
> > >
> > >       struct dw_edma          *dw;
> > > +     bool                    non_ll;
> > >  };
> > >
> > >  /* Export to the platform drivers */
> > > --
> > > 1.8.3.1
> > >

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ