diff mbox series

[v9,23/27] dmaengine: dw-edma: Add mem-mapped LL-entries support

Message ID 20230113171409.30470-24-Sergey.Semin@baikalelectronics.ru (mailing list archive)
State Handled Elsewhere
Headers show
Series dmaengine: dw-edma: Add RP/EP local DMA controllers support | expand

Commit Message

Serge Semin Jan. 13, 2023, 5:14 p.m. UTC
Currently the DW eDMA driver only supports the linked lists memory
allocated locally with respect to the remote eDMA engine setup. It means
the linked lists will be accessible by the CPU via the MMIO space only. If
eDMA is embedded into the DW PCIe Root Ports or local End-points (which
support will be added in one of the following up commits) the linked lists
are supposed to be allocated in the CPU memory. In that case the
LL-entries can be directly accessed meanwhile the former case implies
using the MMIO-accessors for that.

In order to have both cases supported by the driver the dw_edma_region
descriptor should be fixed to contain the MMIO-backed and just
memory-based virtual addresses. The linked lists initialization procedure
will use one of them depending on the eDMA device nature. If the eDMA
engine is embedded into the local DW PCIe RP/EP controllers then the list
entries will be directly accessed by referencing the corresponding
structure fields.  Otherwise the MMIO accessors usage will be preserved.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Changelog v9:
- This is a new patch added on v9 stage of the series.
---
 drivers/dma/dw-edma/dw-edma-pcie.c    | 32 ++++++-------
 drivers/dma/dw-edma/dw-edma-v0-core.c | 69 +++++++++++++++++----------
 include/linux/dma/edma.h              |  5 +-
 3 files changed, 64 insertions(+), 42 deletions(-)

Comments

Bjorn Helgaas Feb. 21, 2023, 11 p.m. UTC | #1
On Fri, Jan 13, 2023 at 08:14:05PM +0300, Serge Semin wrote:
> Currently the DW eDMA driver only supports the linked lists memory
> allocated locally with respect to the remote eDMA engine setup. It means
> the linked lists will be accessible by the CPU via the MMIO space only. If
> eDMA is embedded into the DW PCIe Root Ports or local End-points (which
> support will be added in one of the following up commits) the linked lists
> are supposed to be allocated in the CPU memory. In that case the
> LL-entries can be directly accessed meanwhile the former case implies
> using the MMIO-accessors for that.
> 
> In order to have both cases supported by the driver the dw_edma_region
> descriptor should be fixed to contain the MMIO-backed and just
> memory-based virtual addresses. The linked lists initialization procedure
> will use one of them depending on the eDMA device nature. If the eDMA
> engine is embedded into the local DW PCIe RP/EP controllers then the list
> entries will be directly accessed by referencing the corresponding
> structure fields.  Otherwise the MMIO accessors usage will be preserved.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Hi Vinod, I just realized that I didn't solicit your ack for this
patch and the following one (which I ended up splitting into two), and
I hate to ask Linus to pull them without your OK.

Here are the current versions in the PCI tree:

  https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?id=b47364a83054
  https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?id=157ce95927c1
  https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?id=536e6529e975

If you ack them, I will update them to reflect that.

Thanks,
  Bjorn

> Changelog v9:
> - This is a new patch added on v9 stage of the series.
> ---
>  drivers/dma/dw-edma/dw-edma-pcie.c    | 32 ++++++-------
>  drivers/dma/dw-edma/dw-edma-v0-core.c | 69 +++++++++++++++++----------
>  include/linux/dma/edma.h              |  5 +-
>  3 files changed, 64 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 3f9dadc73854..2b40f2b44f5e 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -240,20 +240,20 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		struct dw_edma_block *ll_block = &vsec_data.ll_wr[i];
>  		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
>  
> -		ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
> -		if (!ll_region->vaddr)
> +		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
> +		if (!ll_region->vaddr.io)
> ...
Vinod Koul Feb. 22, 2023, 4:16 p.m. UTC | #2
On 21-02-23, 17:00, Bjorn Helgaas wrote:
> On Fri, Jan 13, 2023 at 08:14:05PM +0300, Serge Semin wrote:
> > Currently the DW eDMA driver only supports the linked lists memory
> > allocated locally with respect to the remote eDMA engine setup. It means
> > the linked lists will be accessible by the CPU via the MMIO space only. If
> > eDMA is embedded into the DW PCIe Root Ports or local End-points (which
> > support will be added in one of the following up commits) the linked lists
> > are supposed to be allocated in the CPU memory. In that case the
> > LL-entries can be directly accessed meanwhile the former case implies
> > using the MMIO-accessors for that.
> > 
> > In order to have both cases supported by the driver the dw_edma_region
> > descriptor should be fixed to contain the MMIO-backed and just
> > memory-based virtual addresses. The linked lists initialization procedure
> > will use one of them depending on the eDMA device nature. If the eDMA
> > engine is embedded into the local DW PCIe RP/EP controllers then the list
> > entries will be directly accessed by referencing the corresponding
> > structure fields.  Otherwise the MMIO accessors usage will be preserved.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> Hi Vinod, I just realized that I didn't solicit your ack for this
> patch and the following one (which I ended up splitting into two), and
> I hate to ask Linus to pull them without your OK.
> 
> Here are the current versions in the PCI tree:
> 
>   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?id=b47364a83054
>   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?id=157ce95927c1
>   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?id=536e6529e975
> 
> If you ack them, I will update them to reflect that.

Thanks for letting me know:

Acked-by: Vinod Koul <vkoul@kernel.org>
diff mbox series

Patch

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 3f9dadc73854..2b40f2b44f5e 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -240,20 +240,20 @@  static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		struct dw_edma_block *ll_block = &vsec_data.ll_wr[i];
 		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
 
-		ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
-		if (!ll_region->vaddr)
+		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
+		if (!ll_region->vaddr.io)
 			return -ENOMEM;
 
-		ll_region->vaddr += ll_block->off;
+		ll_region->vaddr.io += ll_block->off;
 		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
-		dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
-		if (!dt_region->vaddr)
+		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
+		if (!dt_region->vaddr.io)
 			return -ENOMEM;
 
-		dt_region->vaddr += dt_block->off;
+		dt_region->vaddr.io += dt_block->off;
 		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
@@ -265,20 +265,20 @@  static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		struct dw_edma_block *ll_block = &vsec_data.ll_rd[i];
 		struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
 
-		ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
-		if (!ll_region->vaddr)
+		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
+		if (!ll_region->vaddr.io)
 			return -ENOMEM;
 
-		ll_region->vaddr += ll_block->off;
+		ll_region->vaddr.io += ll_block->off;
 		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
-		dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
-		if (!dt_region->vaddr)
+		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
+		if (!dt_region->vaddr.io)
 			return -ENOMEM;
 
-		dt_region->vaddr += dt_block->off;
+		dt_region->vaddr.io += dt_block->off;
 		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
@@ -303,24 +303,24 @@  static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
 			i, vsec_data.ll_wr[i].bar,
 			vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
-			chip->ll_region_wr[i].vaddr, &chip->ll_region_wr[i].paddr);
+			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
 
 		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
 			i, vsec_data.dt_wr[i].bar,
 			vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
-			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
+			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
 	}
 
 	for (i = 0; i < chip->ll_rd_cnt; i++) {
 		pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
 			i, vsec_data.ll_rd[i].bar,
 			vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
-			chip->ll_region_rd[i].vaddr, &chip->ll_region_rd[i].paddr);
+			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
 
 		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
 			i, vsec_data.dt_rd[i].bar,
 			vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
-			chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
+			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
 	}
 
 	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 51a34b43434c..7df833873a19 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -159,9 +159,6 @@  static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 #define GET_CH_32(dw, dir, ch, name) \
 	readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
 
-#define SET_LL_32(ll, value) \
-	writel(value, ll)
-
 static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 			     u64 value, void __iomem *addr)
 {
@@ -219,9 +216,6 @@  static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 #define GET_CH_64(dw, dir, ch, name) \
 	readq_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
 
-#define SET_LL_64(ll, value) \
-	writeq(value, ll)
-
 /* eDMA management callbacks */
 void dw_edma_v0_core_off(struct dw_edma *dw)
 {
@@ -293,17 +287,53 @@  u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
 			 GET_RW_32(dw, dir, int_status));
 }
 
+static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
+				     u32 control, u32 size, u64 sar, u64 dar)
+{
+	ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
+
+	if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+		struct dw_edma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;
+
+		lli->control = control;
+		lli->transfer_size = size;
+		lli->sar.reg = sar;
+		lli->dar.reg = dar;
+	} else {
+		struct dw_edma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;
+
+		writel(control, &lli->control);
+		writel(size, &lli->transfer_size);
+		writeq(sar, &lli->sar.reg);
+		writeq(dar, &lli->dar.reg);
+	}
+}
+
+static void dw_edma_v0_write_ll_link(struct dw_edma_chunk *chunk,
+				     int i, u32 control, u64 pointer)
+{
+	ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
+
+	if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+		struct dw_edma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;
+
+		llp->control = control;
+		llp->llp.reg = pointer;
+	} else {
+		struct dw_edma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;
+
+		writel(control, &llp->control);
+		writeq(pointer, &llp->llp.reg);
+	}
+}
+
 static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 {
 	struct dw_edma_burst *child;
 	struct dw_edma_chan *chan = chunk->chan;
-	struct dw_edma_v0_lli __iomem *lli;
-	struct dw_edma_v0_llp __iomem *llp;
 	u32 control = 0, i = 0;
 	int j;
 
-	lli = chunk->ll_region.vaddr;
-
 	if (chunk->cb)
 		control = DW_EDMA_V0_CB;
 
@@ -315,27 +345,16 @@  static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 			if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
 				control |= DW_EDMA_V0_RIE;
 		}
-		/* Channel control */
-		SET_LL_32(&lli[i].control, control);
-		/* Transfer size */
-		SET_LL_32(&lli[i].transfer_size, child->sz);
-		/* SAR */
-		SET_LL_64(&lli[i].sar.reg, child->sar);
-		/* DAR */
-		SET_LL_64(&lli[i].dar.reg, child->dar);
-
-		i++;
+
+		dw_edma_v0_write_ll_data(chunk, i++, control, child->sz,
+					 child->sar, child->dar);
 	}
 
-	llp = (void __iomem *)&lli[i];
 	control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
 	if (!chunk->cb)
 		control |= DW_EDMA_V0_CB;
 
-	/* Channel control */
-	SET_LL_32(&llp->control, control);
-	/* Linked list */
-	SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
+	dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
 }
 
 void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 9d44da4aa59d..08833f12b386 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -19,7 +19,10 @@  struct dw_edma;
 
 struct dw_edma_region {
 	u64		paddr;
-	void __iomem	*vaddr;
+	union {
+		void		*mem;
+		void __iomem	*io;
+	} vaddr;
 	size_t		sz;
 };