dmaengine.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/8] Enable designware PCI EP EDMA locally.
@ 2022-03-09 21:11 Frank Li
  2022-03-09 21:11 ` [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures Frank Li
                   ` (7 more replies)
  0 siblings, 8 replies; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:11 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

Default Designware EDMA just probe remotely at host side.
This patch allow EDMA driver can probe at EP side.

1. Clean up patch
   dmaengine: dw-edma: Detach the private data and chip info structures
   dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip
   dmaengine: dw-edma: change rg_region to reg_base in struct
   dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt in struct

2. Enhance EDMA driver to allow prode eDMA at EP side
   dmaengine: dw-edma: add flags at struct dw_edma_chip

3. Bugs fix at EDMA driver when probe eDMA at EP side
   dmaengine: dw-edma: Fix programming the source & dest addresses for ep
   dmaengine: dw-edma: Don't rely on the deprecated "direction" member

4. change pci-epf-test to use EDMA driver to transfer data.
   PCI: endpoint: functions/pci-epf-test: Support PCI controller DMA

5. Using imx8dxl to do test, but some EP functions still have not
upstream yet. So below patch show how probe eDMA driver at EP
controller driver.
https://lore.kernel.org/linux-pci/20220309120149.GB134091@thinkpad/T/#m979eb506c73ab3cfca2e7a43635ecdaec18d8097


Frank Li (6):
  dmaengine: dw-edma: Detach the private data and chip info structures
  dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip
  dmaengine: dw-edma: change rg_region to reg_base in struct
    dw_edma_chip
  dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt in struct
    dw_edma_chip
  dmaengine: dw-edma: add flags at struct dw_edma_chip
  PCI: endpoint: functions/pci-epf-test: Support PCI controller DMA

Manivannan Sadhasivam (2):
  dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  dmaengine: dw-edma: Don't rely on the deprecated "direction" member

 drivers/dma/dw-edma/dw-edma-core.c            | 130 +++++++++++-------
 drivers/dma/dw-edma/dw-edma-core.h            |  32 +----
 drivers/dma/dw-edma/dw-edma-pcie.c            |  83 +++++------
 drivers/dma/dw-edma/dw-edma-v0-core.c         |  44 +++---
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c      |  10 +-
 drivers/pci/endpoint/functions/pci-epf-test.c | 108 +++++++++++++--
 include/linux/dma/edma.h                      |  56 +++++++-
 7 files changed, 297 insertions(+), 166 deletions(-)

-- 
2.24.0.rc1


^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
@ 2022-03-09 21:11 ` Frank Li
  2022-03-10 12:50   ` Serge Semin
                     ` (2 more replies)
  2022-03-09 21:11 ` [PATCH v4 2/8] dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip Frank Li
                   ` (6 subsequent siblings)
  7 siblings, 3 replies; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:11 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

"struct dw_edma_chip" contains an internal structure "struct dw_edma" that
is used by the eDMA core internally. This structure should not be touched
by the eDMA controller drivers themselves. But currently, the eDMA
controller drivers like "dw-edma-pci" allocates and populates this
internal structure then passes it on to eDMA core. The eDMA core further
populates the structure and uses it. This is wrong!

Hence, move all the "struct dw_edma" specifics from controller drivers
to the eDMA core.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from v3 to v4
 - Accept most suggestions of Serge Semin
Change from v2 to v3
 - none
Change from v1 to v2
 - rework commit message
 - remove duplicate field in struct dw_edma

 drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
 drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
 drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
 drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
 include/linux/dma/edma.h                 | 44 +++++++++++++
 6 files changed, 144 insertions(+), 130 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 53289927dd0d6..1abf41d49f75b 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
 static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
 {
 	struct dw_edma_chan *chan = desc->chan;
-	struct dw_edma *dw = chan->chip->dw;
+	struct dw_edma_chip *chip = chan->dw->chip;
 	struct dw_edma_chunk *chunk;
 
 	chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
@@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
 	 */
 	chunk->cb = !(desc->chunks_alloc % 2);
 	if (chan->dir == EDMA_DIR_WRITE) {
-		chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
-		chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
+		chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
+		chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
 	} else {
-		chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
-		chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
+		chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
+		chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
 	}
 
 	if (desc->chunk) {
@@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
 	if (chan->status != EDMA_ST_IDLE)
 		return -EBUSY;
 
-	pm_runtime_get(chan->chip->dev);
+	pm_runtime_get(chan->dw->chip->dev);
 
 	return 0;
 }
@@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
 		cpu_relax();
 	}
 
-	pm_runtime_put(chan->chip->dev);
+	pm_runtime_put(chan->dw->chip->dev);
 }
 
 static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
@@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 	}
 
 	INIT_LIST_HEAD(&dma->channels);
-	for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
+	for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
 		chan = &dw->chan[i];
 
 		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
@@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 
 		chan->vc.chan.private = dt_region;
 
-		chan->chip = chip;
+		chan->dw = dw;
 		chan->id = j;
 		chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
 		chan->configured = false;
@@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 		chan->status = EDMA_ST_IDLE;
 
 		if (write)
-			chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
+			chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
 		else
-			chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
+			chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
 		chan->ll_max -= 1;
 
 		dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
 			 write ? "write" : "read", j, chan->ll_max);
 
-		if (dw->nr_irqs == 1)
+		if (chip->nr_irqs == 1)
 			pos = 0;
 		else
 			pos = off_alloc + (j % alloc);
@@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 		vchan_init(&chan->vc, dma);
 
 		if (write) {
-			dt_region->paddr = dw->dt_region_wr[j].paddr;
-			dt_region->vaddr = dw->dt_region_wr[j].vaddr;
-			dt_region->sz = dw->dt_region_wr[j].sz;
+			dt_region->paddr = chip->dt_region_wr[j].paddr;
+			dt_region->vaddr = chip->dt_region_wr[j].vaddr;
+			dt_region->sz = chip->dt_region_wr[j].sz;
 		} else {
-			dt_region->paddr = dw->dt_region_rd[j].paddr;
-			dt_region->vaddr = dw->dt_region_rd[j].vaddr;
-			dt_region->sz = dw->dt_region_rd[j].sz;
+			dt_region->paddr = chip->dt_region_rd[j].paddr;
+			dt_region->vaddr = chip->dt_region_rd[j].vaddr;
+			dt_region->sz = chip->dt_region_rd[j].sz;
 		}
 
 		dw_edma_v0_core_device_config(chan);
@@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
 
 	ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
 
-	if (dw->nr_irqs < 1)
+	if (chip->nr_irqs < 1)
 		return -EINVAL;
 
-	if (dw->nr_irqs == 1) {
+	if (chip->nr_irqs == 1) {
 		/* Common IRQ shared among all channels */
-		irq = dw->ops->irq_vector(dev, 0);
+		irq = chip->ops->irq_vector(dev, 0);
 		err = request_irq(irq, dw_edma_interrupt_common,
 				  IRQF_SHARED, dw->name, &dw->irq[0]);
 		if (err) {
-			dw->nr_irqs = 0;
+			chip->nr_irqs = 0;
 			return err;
 		}
 
@@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
 			get_cached_msi_msg(irq, &dw->irq[0].msi);
 	} else {
 		/* Distribute IRQs equally among all channels */
-		int tmp = dw->nr_irqs;
+		int tmp = chip->nr_irqs;
 
 		while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
 			dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
@@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
 		dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
 
 		for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
-			irq = dw->ops->irq_vector(dev, i);
+			irq = chip->ops->irq_vector(dev, i);
 			err = request_irq(irq,
 					  i < *wr_alloc ?
 						dw_edma_interrupt_write :
@@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
 					  IRQF_SHARED, dw->name,
 					  &dw->irq[i]);
 			if (err) {
-				dw->nr_irqs = i;
+				chip->nr_irqs = i;
 				return err;
 			}
 
@@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
 				get_cached_msi_msg(irq, &dw->irq[i].msi);
 		}
 
-		dw->nr_irqs = i;
+		chip->nr_irqs = i;
 	}
 
 	return err;
@@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	if (!dev)
 		return -EINVAL;
 
-	dw = chip->dw;
-	if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
+	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
+	if (!dw)
+		return -ENOMEM;
+
+	chip->dw = dw;
+	dw->chip = chip;
+
+	if (!chip->nr_irqs || !chip->ops)
 		return -EINVAL;
 
 	raw_spin_lock_init(&dw->lock);
 
-	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,
+
+	dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
 			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
 	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
 
-	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
+	dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
 			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
 	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
 
@@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	/* Disable eDMA, only to establish the ideal initial conditions */
 	dw_edma_v0_core_off(dw);
 
+	dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
+	if (!dw->irq)
+		return -ENOMEM;
+
 	/* Request IRQs */
 	err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
 	if (err)
@@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	return 0;
 
 err_irq_free:
-	for (i = (dw->nr_irqs - 1); i >= 0; i--)
-		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
+	for (i = (chip->nr_irqs - 1); i >= 0; i--)
+		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
 
-	dw->nr_irqs = 0;
+	chip->nr_irqs = 0;
 
 	return err;
 }
@@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 	dw_edma_v0_core_off(dw);
 
 	/* Free irqs */
-	for (i = (dw->nr_irqs - 1); i >= 0; i--)
-		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
+	for (i = (chip->nr_irqs - 1); i >= 0; i--)
+		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
 
 	/* Power management */
 	pm_runtime_disable(dev);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 60316d408c3e0..e254c2fc3d9cf 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -15,20 +15,12 @@
 #include "../virt-dma.h"
 
 #define EDMA_LL_SZ					24
-#define EDMA_MAX_WR_CH					8
-#define EDMA_MAX_RD_CH					8
 
 enum dw_edma_dir {
 	EDMA_DIR_WRITE = 0,
 	EDMA_DIR_READ
 };
 
-enum dw_edma_map_format {
-	EDMA_MF_EDMA_LEGACY = 0x0,
-	EDMA_MF_EDMA_UNROLL = 0x1,
-	EDMA_MF_HDMA_COMPAT = 0x5
-};
-
 enum dw_edma_request {
 	EDMA_REQ_NONE = 0,
 	EDMA_REQ_STOP,
@@ -57,12 +49,6 @@ struct dw_edma_burst {
 	u32				sz;
 };
 
-struct dw_edma_region {
-	phys_addr_t			paddr;
-	void				__iomem *vaddr;
-	size_t				sz;
-};
-
 struct dw_edma_chunk {
 	struct list_head		list;
 	struct dw_edma_chan		*chan;
@@ -87,7 +73,7 @@ struct dw_edma_desc {
 
 struct dw_edma_chan {
 	struct virt_dma_chan		vc;
-	struct dw_edma_chip		*chip;
+	struct dw_edma			*dw;
 	int				id;
 	enum dw_edma_dir		dir;
 
@@ -109,10 +95,6 @@ struct dw_edma_irq {
 	struct dw_edma			*dw;
 };
 
-struct dw_edma_core_ops {
-	int	(*irq_vector)(struct device *dev, unsigned int nr);
-};
-
 struct dw_edma {
 	char				name[20];
 
@@ -122,21 +104,13 @@ struct dw_edma {
 	struct dma_device		rd_edma;
 	u16				rd_ch_cnt;
 
-	struct dw_edma_region		rg_region;	/* Registers */
-	struct dw_edma_region		ll_region_wr[EDMA_MAX_WR_CH];
-	struct dw_edma_region		ll_region_rd[EDMA_MAX_RD_CH];
-	struct dw_edma_region		dt_region_wr[EDMA_MAX_WR_CH];
-	struct dw_edma_region		dt_region_rd[EDMA_MAX_RD_CH];
-
 	struct dw_edma_irq		*irq;
-	int				nr_irqs;
-
-	enum dw_edma_map_format		mf;
 
 	struct dw_edma_chan		*chan;
-	const struct dw_edma_core_ops	*ops;
 
 	raw_spinlock_t			lock;		/* Only for legacy */
+
+	struct dw_edma_chip             *chip;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry			*debugfs;
 #endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 44f6e09bdb531..2c1c5fa4e9f28 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	struct dw_edma_pcie_data vsec_data;
 	struct device *dev = &pdev->dev;
 	struct dw_edma_chip *chip;
-	struct dw_edma *dw;
 	int err, nr_irqs;
 	int i, mask;
 
@@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	if (!chip)
 		return -ENOMEM;
 
-	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
-	if (!dw)
-		return -ENOMEM;
-
 	/* IRQs allocation */
 	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
 					PCI_IRQ_MSI | PCI_IRQ_MSIX);
@@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	}
 
 	/* Data structure initialization */
-	chip->dw = dw;
 	chip->dev = dev;
 	chip->id = pdev->devfn;
-	chip->irq = pdev->irq;
 
-	dw->mf = vsec_data.mf;
-	dw->nr_irqs = nr_irqs;
-	dw->ops = &dw_edma_pcie_core_ops;
-	dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
-	dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
+	chip->mf = vsec_data.mf;
+	chip->nr_irqs = nr_irqs;
+	chip->ops = &dw_edma_pcie_core_ops;
 
-	dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
-	if (!dw->rg_region.vaddr)
-		return -ENOMEM;
+	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
+	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
 
-	dw->rg_region.vaddr += vsec_data.rg.off;
-	dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
-	dw->rg_region.paddr += vsec_data.rg.off;
-	dw->rg_region.sz = vsec_data.rg.sz;
+	chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
+	if (!chip->rg_region.vaddr)
+		return -ENOMEM;
 
-	for (i = 0; i < dw->wr_ch_cnt; i++) {
-		struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
-		struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
+	for (i = 0; i < chip->wr_ch_cnt; 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];
 		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
 
@@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		dt_region->sz = dt_block->sz;
 	}
 
-	for (i = 0; i < dw->rd_ch_cnt; i++) {
-		struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
-		struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
+	for (i = 0; i < chip->rd_ch_cnt; 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];
 		struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
 
@@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	}
 
 	/* Debug info */
-	if (dw->mf == EDMA_MF_EDMA_LEGACY)
-		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
-	else if (dw->mf == EDMA_MF_EDMA_UNROLL)
-		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
-	else if (dw->mf == EDMA_MF_HDMA_COMPAT)
-		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
+	if (chip->mf == EDMA_MF_EDMA_LEGACY)
+		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
+	else if (chip->mf == EDMA_MF_EDMA_UNROLL)
+		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
+	else if (chip->mf == EDMA_MF_HDMA_COMPAT)
+		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
 	else
-		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
+		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
 
-	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
+	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
 		vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
-		dw->rg_region.vaddr, &dw->rg_region.paddr);
+		chip->rg_region.vaddr);
 
 
-	for (i = 0; i < dw->wr_ch_cnt; i++) {
+	for (i = 0; i < chip->wr_ch_cnt; i++) {
 		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, dw->ll_region_wr[i].sz,
-			dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
+			vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
+			chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
-			dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
+			vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
+			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
 	}
 
-	for (i = 0; i < dw->rd_ch_cnt; i++) {
+	for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
-			dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
+			vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
+			chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
-			dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
+			vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
+			chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
 	}
 
-	pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
+	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
 
 	/* Validating if PCI interrupts were enabled */
 	if (!pci_dev_msi_enabled(pdev)) {
@@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		return -EPERM;
 	}
 
-	dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
-	if (!dw->irq)
-		return -ENOMEM;
-
 	/* Starting eDMA driver */
 	err = dw_edma_probe(chip);
 	if (err) {
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 329fc2e57b703..e507e076fad16 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -25,7 +25,7 @@ enum dw_edma_control {
 
 static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
 {
-	return dw->rg_region.vaddr;
+	return dw->chip->rg_region.vaddr;
 }
 
 #define SET_32(dw, name, value)				\
@@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
 static inline struct dw_edma_v0_ch_regs __iomem *
 __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
 {
-	if (dw->mf == EDMA_MF_EDMA_LEGACY)
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
 		return &(__dw_regs(dw)->type.legacy.ch);
 
 	if (dir == EDMA_DIR_WRITE)
@@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
 static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 			     u32 value, void __iomem *addr)
 {
-	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
 		u32 viewport_sel;
 		unsigned long flags;
 
@@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 {
 	u32 value;
 
-	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
 		u32 viewport_sel;
 		unsigned long flags;
 
@@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 			     u64 value, void __iomem *addr)
 {
-	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
 		u32 viewport_sel;
 		unsigned long flags;
 
@@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 {
 	u32 value;
 
-	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
 		u32 viewport_sel;
 		unsigned long flags;
 
@@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
 
 enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
 {
-	struct dw_edma *dw = chan->chip->dw;
+	struct dw_edma *dw = chan->dw;
 	u32 tmp;
 
 	tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
@@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
 
 void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
 {
-	struct dw_edma *dw = chan->chip->dw;
+	struct dw_edma *dw = chan->dw;
 
 	SET_RW_32(dw, chan->dir, int_clear,
 		  FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
@@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
 
 void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
 {
-	struct dw_edma *dw = chan->chip->dw;
+	struct dw_edma *dw = chan->dw;
 
 	SET_RW_32(dw, chan->dir, int_clear,
 		  FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
@@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
 {
 	struct dw_edma_chan *chan = chunk->chan;
-	struct dw_edma *dw = chan->chip->dw;
+	struct dw_edma *dw = chan->dw;
 	u32 tmp;
 
 	dw_edma_v0_core_write_chunk(chunk);
@@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
 	if (first) {
 		/* Enable engine */
 		SET_RW_32(dw, chan->dir, engine_en, BIT(0));
-		if (dw->mf == EDMA_MF_HDMA_COMPAT) {
+		if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
 			switch (chan->id) {
 			case 0:
 				SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
@@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
 
 int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
 {
-	struct dw_edma *dw = chan->chip->dw;
+	struct dw_edma *dw = chan->dw;
 	u32 tmp = 0;
 
 	/* MSI done addr - low, high */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index 4b3bcffd15ef1..edb7e137cb35a 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -54,7 +54,7 @@ struct debugfs_entries {
 static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 {
 	void __iomem *reg = (void __force __iomem *)data;
-	if (dw->mf == EDMA_MF_EDMA_LEGACY &&
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
 	    reg >= (void __iomem *)&regs->type.legacy.ch) {
 		void __iomem *ptr = &regs->type.legacy.ch;
 		u32 viewport_sel = 0;
@@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 	nr_entries = ARRAY_SIZE(debugfs_regs);
 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
 
-	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
+	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
 		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
 		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
 					   regs_dir);
@@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 	nr_entries = ARRAY_SIZE(debugfs_regs);
 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
 
-	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
+	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
 		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
 		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
 					   regs_dir);
@@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 	if (!dw)
 		return;
 
-	regs = dw->rg_region.vaddr;
+	regs = dw->chip->rg_region.vaddr;
 	if (!regs)
 		return;
 
@@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 	if (!dw->debugfs)
 		return;
 
-	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
+	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
 	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
 	debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
 
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index cab6e18773dad..a9bee4aeb2eee 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -12,19 +12,63 @@
 #include <linux/device.h>
 #include <linux/dmaengine.h>
 
+#define EDMA_MAX_WR_CH                                  8
+#define EDMA_MAX_RD_CH                                  8
+
 struct dw_edma;
 
+struct dw_edma_region {
+	phys_addr_t	paddr;
+	void __iomem	*vaddr;
+	size_t		sz;
+};
+
+struct dw_edma_core_ops {
+	int (*irq_vector)(struct device *dev, unsigned int nr);
+};
+
+enum dw_edma_map_format {
+	EDMA_MF_EDMA_LEGACY = 0x0,
+	EDMA_MF_EDMA_UNROLL = 0x1,
+	EDMA_MF_HDMA_COMPAT = 0x5
+};
+
 /**
  * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
  * @dev:		 struct device of the eDMA controller
  * @id:			 instance ID
  * @irq:		 irq line
+ * @nr_irqs:		 total dma irq number
+ * @ops			 DMA channel to IRQ number mapping
+ * @wr_ch_cnt		 DMA write channel number
+ * @rd_ch_cnt		 DMA read channel number
+ * @rg_region		 DMA register region
+ * @ll_region_wr	 DMA descriptor link list memory for write channel
+ * @ll_region_rd	 DMA descriptor link list memory for read channel
+ * @mf			 DMA register map format
  * @dw:			 struct dw_edma that is filed by dw_edma_probe()
  */
 struct dw_edma_chip {
 	struct device		*dev;
 	int			id;
 	int			irq;
+	int			nr_irqs;
+	const struct dw_edma_core_ops   *ops;
+
+	struct dw_edma_region	rg_region;
+
+	u16			wr_ch_cnt;
+	u16			rd_ch_cnt;
+	/* link list address */
+	struct dw_edma_region	ll_region_wr[EDMA_MAX_WR_CH];
+	struct dw_edma_region	ll_region_rd[EDMA_MAX_RD_CH];
+
+	/* data region */
+	struct dw_edma_region	dt_region_wr[EDMA_MAX_WR_CH];
+	struct dw_edma_region	dt_region_rd[EDMA_MAX_RD_CH];
+
+	enum dw_edma_map_format	mf;
+
 	struct dw_edma		*dw;
 };
 
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v4 2/8] dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
  2022-03-09 21:11 ` [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures Frank Li
@ 2022-03-09 21:11 ` Frank Li
  2022-03-10 12:52   ` Serge Semin
  2022-03-09 21:11 ` [PATCH v4 3/8] dmaengine: dw-edma: change rg_region to reg_base " Frank Li
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:11 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

irq of struct dw_edma_chip was never used.
It can be removed safely.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
new patch at v4

 include/linux/dma/edma.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index a9bee4aeb2eee..6fd374cc72c8e 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -37,7 +37,6 @@ enum dw_edma_map_format {
  * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
  * @dev:		 struct device of the eDMA controller
  * @id:			 instance ID
- * @irq:		 irq line
  * @nr_irqs:		 total dma irq number
  * @ops			 DMA channel to IRQ number mapping
  * @wr_ch_cnt		 DMA write channel number
@@ -51,7 +50,6 @@ enum dw_edma_map_format {
 struct dw_edma_chip {
 	struct device		*dev;
 	int			id;
-	int			irq;
 	int			nr_irqs;
 	const struct dw_edma_core_ops   *ops;
 
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v4 3/8] dmaengine: dw-edma: change rg_region to reg_base in struct dw_edma_chip
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
  2022-03-09 21:11 ` [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures Frank Li
  2022-03-09 21:11 ` [PATCH v4 2/8] dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip Frank Li
@ 2022-03-09 21:11 ` Frank Li
  2022-03-10 12:56   ` Serge Semin
  2022-03-09 21:12 ` [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt " Frank Li
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:11 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

struct dw_edma_region rg_region included virtual address, physical
address and size informaiton. But only virtual address is used by EDMA
driver. Change it to void __iomem *reg_base to clean up code.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
New patch at v4

 drivers/dma/dw-edma/dw-edma-pcie.c       | 6 +++---
 drivers/dma/dw-edma/dw-edma-v0-core.c    | 2 +-
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 2 +-
 include/linux/dma/edma.h                 | 3 ++-
 4 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 2c1c5fa4e9f28..ae42bad24dd5a 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -233,8 +233,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
 	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
 
-	chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
-	if (!chip->rg_region.vaddr)
+	chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
+	if (!chip->reg_base)
 		return -ENOMEM;
 
 	for (i = 0; i < chip->wr_ch_cnt; i++) {
@@ -299,7 +299,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
 	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
 		vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
-		chip->rg_region.vaddr);
+		chip->reg_base);
 
 
 	for (i = 0; i < chip->wr_ch_cnt; i++) {
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index e507e076fad16..35f2adac93e46 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -25,7 +25,7 @@ enum dw_edma_control {
 
 static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
 {
-	return dw->chip->rg_region.vaddr;
+	return dw->chip->reg_base;
 }
 
 #define SET_32(dw, name, value)				\
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index edb7e137cb35a..3a899f7f4e8d8 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 	if (!dw)
 		return;
 
-	regs = dw->chip->rg_region.vaddr;
+	regs = dw->chip->reg_base;
 	if (!regs)
 		return;
 
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 6fd374cc72c8e..e9ce652b88233 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -39,6 +39,7 @@ enum dw_edma_map_format {
  * @id:			 instance ID
  * @nr_irqs:		 total dma irq number
  * @ops			 DMA channel to IRQ number mapping
+ * @reg_base		 DMA register base address
  * @wr_ch_cnt		 DMA write channel number
  * @rd_ch_cnt		 DMA read channel number
  * @rg_region		 DMA register region
@@ -53,7 +54,7 @@ struct dw_edma_chip {
 	int			nr_irqs;
 	const struct dw_edma_core_ops   *ops;
 
-	struct dw_edma_region	rg_region;
+	void __iomem		*reg_base;
 
 	u16			wr_ch_cnt;
 	u16			rd_ch_cnt;
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt in struct dw_edma_chip
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
                   ` (2 preceding siblings ...)
  2022-03-09 21:11 ` [PATCH v4 3/8] dmaengine: dw-edma: change rg_region to reg_base " Frank Li
@ 2022-03-09 21:12 ` Frank Li
  2022-03-10 12:37   ` Serge Semin
  2022-03-09 21:12 ` [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep Frank Li
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:12 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

There are same name wr(rd)_ch_cnt in struct dw_edma. EDMA driver get
write(read) channel number from register, then save these into dw_edma.
Old wr(rd)_ch_cnt in dw_edma_chip actuall means how many link list memory
are avaiable in ll_region_wr(rd)[EDMA_MAX_WR_CH]. So rename it to
ll_wr(rd)_cnt to indicate actual usage.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
new patch at v4

 drivers/dma/dw-edma/dw-edma-core.c |  4 ++--
 drivers/dma/dw-edma/dw-edma-pcie.c | 12 ++++++------
 include/linux/dma/edma.h           |  8 ++++----
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 1abf41d49f75b..66dc650577919 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -918,11 +918,11 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	raw_spin_lock_init(&dw->lock);
 
 
-	dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
+	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
 			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
 	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
 
-	dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
+	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
 			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
 	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
 
diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index ae42bad24dd5a..7732537f96086 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -230,14 +230,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	chip->nr_irqs = nr_irqs;
 	chip->ops = &dw_edma_pcie_core_ops;
 
-	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
-	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
+	chip->ll_wr_cnt = vsec_data.wr_ch_cnt;
+	chip->ll_rd_cnt = vsec_data.rd_ch_cnt;
 
 	chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
 	if (!chip->reg_base)
 		return -ENOMEM;
 
-	for (i = 0; i < chip->wr_ch_cnt; i++) {
+	for (i = 0; i < chip->ll_wr_cnt; 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];
@@ -262,7 +262,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		dt_region->sz = dt_block->sz;
 	}
 
-	for (i = 0; i < chip->rd_ch_cnt; i++) {
+	for (i = 0; i < chip->ll_rd_cnt; 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];
@@ -302,7 +302,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		chip->reg_base);
 
 
-	for (i = 0; i < chip->wr_ch_cnt; i++) {
+	for (i = 0; i < chip->ll_wr_cnt; i++) {
 		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,
@@ -314,7 +314,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
 	}
 
-	for (i = 0; i < chip->rd_ch_cnt; i++) {
+	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,
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index e9ce652b88233..c2039246fc08c 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -40,8 +40,8 @@ enum dw_edma_map_format {
  * @nr_irqs:		 total dma irq number
  * @ops			 DMA channel to IRQ number mapping
  * @reg_base		 DMA register base address
- * @wr_ch_cnt		 DMA write channel number
- * @rd_ch_cnt		 DMA read channel number
+ * @ll_wr_cnt		 DMA write link list number
+ * @ll_rd_cnt		 DMA read link list number
  * @rg_region		 DMA register region
  * @ll_region_wr	 DMA descriptor link list memory for write channel
  * @ll_region_rd	 DMA descriptor link list memory for read channel
@@ -56,8 +56,8 @@ struct dw_edma_chip {
 
 	void __iomem		*reg_base;
 
-	u16			wr_ch_cnt;
-	u16			rd_ch_cnt;
+	u16			ll_wr_cnt;
+	u16			ll_rd_cnt;
 	/* link list address */
 	struct dw_edma_region	ll_region_wr[EDMA_MAX_WR_CH];
 	struct dw_edma_region	ll_region_rd[EDMA_MAX_RD_CH];
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
                   ` (3 preceding siblings ...)
  2022-03-09 21:12 ` [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt " Frank Li
@ 2022-03-09 21:12 ` Frank Li
  2022-03-10 16:31   ` Serge Semin
  2022-03-09 21:12 ` [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member Frank Li
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:12 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
programs the source and destination addresses for read and write. Since the
Root complex and Endpoint uses the opposite channels for read/write, fix the
issue by finding out the read operation first and program the eDMA accordingly.

Cc: stable@vger.kernel.org
Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
No change between v1 to v4

 drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 66dc650577919..507f08db1aad3 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 	struct dw_edma_chunk *chunk;
 	struct dw_edma_burst *burst;
 	struct dw_edma_desc *desc;
+	bool read = false;
 	u32 cnt = 0;
 	int i;
 
@@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 		chunk->ll_region.sz += burst->sz;
 		desc->alloc_sz += burst->sz;
 
-		if (chan->dir == EDMA_DIR_WRITE) {
+		/****************************************************************
+		 *
+		 *        Root Complex                           Endpoint
+		 * +-----------------------+             +----------------------+
+		 * |                       |    TX CH    |                      |
+		 * |                       |             |                      |
+		 * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
+		 * |                       |             |                      |
+		 * |                       |             |                      |
+		 * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
+		 * |                       |             |                      |
+		 * |                       |    RX CH    |                      |
+		 * +-----------------------+             +----------------------+
+		 *
+		 * If eDMA is controlled by the Root complex, TX channel
+		 * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
+		 * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
+		 *
+		 * If eDMA is controlled by the endpoint, RX channel
+		 * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
+		 * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
+		 *
+		 ****************************************************************/
+
+		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
+		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
+			read = true;
+
+		/* Program the source and destination addresses for DMA read/write */
+		if (read) {
 			burst->sar = src_addr;
 			if (xfer->type == EDMA_XFER_CYCLIC) {
 				burst->dar = xfer->xfer.cyclic.paddr;
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
                   ` (4 preceding siblings ...)
  2022-03-09 21:12 ` [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep Frank Li
@ 2022-03-09 21:12 ` Frank Li
  2022-03-10 17:29   ` Serge Semin
  2022-03-09 21:12 ` [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip Frank Li
  2022-03-09 21:12 ` [PATCH v4 8/8] PCI: endpoint: functions/pci-epf-test: Support PCI controller DMA Frank Li
  7 siblings, 1 reply; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:12 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

The "direction" member of the "dma_slave_config" structure is deprecated.
The clients no longer use this field to specify the direction of the slave
channel. But in the eDMA core, this field is used to differentiate between the
Root complex (remote) and Endpoint (local) DMA accesses.

Nevertheless, we can't differentiate between local and remote accesses without
a dedicated flag. So let's get rid of the old check and add a new check for
verifying the DMA operation between local and remote memory instead.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
no chang between v1 to v4
 drivers/dma/dw-edma/dw-edma-core.c | 17 ++---------------
 1 file changed, 2 insertions(+), 15 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 507f08db1aad3..47c6a52929fcd 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -341,22 +341,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 	if (!chan->configured)
 		return NULL;
 
-	switch (chan->config.direction) {
-	case DMA_DEV_TO_MEM: /* local DMA */
-		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ)
-			break;
-		return NULL;
-	case DMA_MEM_TO_DEV: /* local DMA */
-		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE)
-			break;
+	/* eDMA supports only read and write between local and remote memory */
+	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
 		return NULL;
-	default: /* remote DMA */
-		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_READ)
-			break;
-		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE)
-			break;
-		return NULL;
-	}
 
 	if (xfer->type == EDMA_XFER_CYCLIC) {
 		if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt)
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
                   ` (5 preceding siblings ...)
  2022-03-09 21:12 ` [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member Frank Li
@ 2022-03-09 21:12 ` Frank Li
  2022-03-10  1:07   ` kernel test robot
                     ` (2 more replies)
  2022-03-09 21:12 ` [PATCH v4 8/8] PCI: endpoint: functions/pci-epf-test: Support PCI controller DMA Frank Li
  7 siblings, 3 replies; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:12 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

Allow PCI EP probe DMA locally and prevent use of remote MSI
to remote PCI host.

Add option to force 32bit DBI register access even on
64-bit systems. i.MX8 hardware only allowed 32bit register
access.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from v3 to v4
 - None
Change from v2 to v3
 - rework commit message
 - Change to DW_EDMA_CHIP_32BIT_DBI
 - using DW_EDMA_CHIP_LOCAL control msi
 - Apply Bjorn's comments,
        if (!j) {
               control |= DW_EDMA_V0_LIE;
               if (!(chan->chip->flags & DW_EDMA_CHIP_LOCAL))
                               control |= DW_EDMA_V0_RIE;
        }

        if ((chan->chip->flags & DW_EDMA_CHIP_REG32BIT) ||
              !IS_ENABLED(CONFIG_64BIT)) {
          SET_CH_32(...);
          SET_CH_32(...);
       } else {
          SET_CH_64(...);
       }


Change from v1 to v2
- none
 drivers/dma/dw-edma/dw-edma-v0-core.c | 20 ++++++++++++--------
 include/linux/dma/edma.h              |  9 +++++++++
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 35f2adac93e46..00a00d68d44e7 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -301,6 +301,7 @@ u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
 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;
@@ -314,9 +315,11 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 	j = chunk->bursts_alloc;
 	list_for_each_entry(child, &chunk->burst->list, list) {
 		j--;
-		if (!j)
-			control |= (DW_EDMA_V0_LIE | DW_EDMA_V0_RIE);
-
+		if (!j) {
+			control |= DW_EDMA_V0_LIE;
+			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 */
@@ -414,15 +417,16 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
 		SET_CH_32(dw, chan->dir, chan->id, ch_control1,
 			  (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
 		/* Linked list */
-		#ifdef CONFIG_64BIT
-			SET_CH_64(dw, chan->dir, chan->id, llp.reg,
-				  chunk->ll_region.paddr);
-		#else /* CONFIG_64BIT */
+		if ((chan->dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI) ||
+		    !IS_ENABLED(CONFIG_64BIT)) {
 			SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
 				  lower_32_bits(chunk->ll_region.paddr));
 			SET_CH_32(dw, chan->dir, chan->id, llp.msb,
 				  upper_32_bits(chunk->ll_region.paddr));
-		#endif /* CONFIG_64BIT */
+		} else {
+			SET_CH_64(dw, chan->dir, chan->id, llp.reg,
+				  chunk->ll_region.paddr);
+		}
 	}
 	/* Doorbell */
 	SET_RW_32(dw, chan->dir, doorbell,
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index c2039246fc08c..eea11b1d9e688 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -33,6 +33,12 @@ enum dw_edma_map_format {
 	EDMA_MF_HDMA_COMPAT = 0x5
 };
 
+/* Probe EDMA engine locally and prevent generate MSI to host side*/
+#define DW_EDMA_CHIP_LOCAL	BIT(0)
+
+/* Only support 32bit DBI register access */
+#define DW_EDMA_CHIP_32BIT_DBI	BIT(1)
+
 /**
  * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
  * @dev:		 struct device of the eDMA controller
@@ -40,6 +46,8 @@ enum dw_edma_map_format {
  * @nr_irqs:		 total dma irq number
  * @ops			 DMA channel to IRQ number mapping
  * @reg_base		 DMA register base address
+ * @flags		   - DW_EDMA_CHIP_LOCAL
+ *			   - DW_EDMA_CHIP_32BIT_DBI
  * @ll_wr_cnt		 DMA write link list number
  * @ll_rd_cnt		 DMA read link list number
  * @rg_region		 DMA register region
@@ -53,6 +61,7 @@ struct dw_edma_chip {
 	int			id;
 	int			nr_irqs;
 	const struct dw_edma_core_ops   *ops;
+	u32			flags;
 
 	void __iomem		*reg_base;
 
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v4 8/8] PCI: endpoint: functions/pci-epf-test: Support PCI controller DMA
  2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
                   ` (6 preceding siblings ...)
  2022-03-09 21:12 ` [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip Frank Li
@ 2022-03-09 21:12 ` Frank Li
  7 siblings, 0 replies; 52+ messages in thread
From: Frank Li @ 2022-03-09 21:12 UTC (permalink / raw)
  To: gustavo.pimentel, hongxing.zhu, l.stach, linux-imx, linux-pci,
	dmaengine, fancer.lancer, lznuaa
  Cc: vkoul, lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo,
	manivannan.sadhasivam

Designware provided eDMA support in controller. This enabled use
this eDMA controller to transfer data.

The whole flow align with standard DMA usage module

1. Using dma_request_channel() and filter function to find correct
RX and TX Channel.
2. dmaengine_slave_config() config remote side physcial address.
3. using dmaengine_prep_slave_single() create transfer descriptor
4. tx_submit();
5. dma_async_issue_pending();

Tested at i.MX8DXL platform.

root@imx8qmmek:~# /usr/bin/pcitest -d -w
WRITE ( 102400 bytes):          OKAY
root@imx8qmmek:~# /usr/bin/pcitest -d -r
READ ( 102400 bytes):           OKAY

WRITE => Size: 102400 bytes DMA: YES  Time: 0.000180145 seconds Rate: 555108 KB/s
READ => Size: 102400 bytes  DMA: YES  Time: 0.000194397 seconds Rate: 514411 KB/s

READ => Size: 102400 bytes  DMA: NO   Time: 0.013532597 seconds Rate: 7389 KB/s
WRITE => Size: 102400 bytes DMA: NO   Time: 0.000857090 seconds Rate: 116673 KB/s

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from v3 to v4:
 - reverse Xmas tree order
 - local -> dma_local
 - change error message
 - IS_ERR -> IS_ERR_OR_NULL
 - check return value of dmaengine_slave_config()
Change from v1 to v2:
 - none

 drivers/pci/endpoint/functions/pci-epf-test.c | 108 ++++++++++++++++--
 1 file changed, 98 insertions(+), 10 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 90d84d3bc868f..f26afd02f3a86 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -52,9 +52,11 @@ struct pci_epf_test {
 	enum pci_barno		test_reg_bar;
 	size_t			msix_table_offset;
 	struct delayed_work	cmd_handler;
-	struct dma_chan		*dma_chan;
+	struct dma_chan		*dma_chan_tx;
+	struct dma_chan		*dma_chan_rx;
 	struct completion	transfer_complete;
 	bool			dma_supported;
+	bool			dma_private;
 	const struct pci_epc_features *epc_features;
 };
 
@@ -105,12 +107,15 @@ static void pci_epf_test_dma_callback(void *param)
  */
 static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
 				      dma_addr_t dma_dst, dma_addr_t dma_src,
-				      size_t len)
+				      size_t len, dma_addr_t dma_remote,
+				      enum dma_transfer_direction dir)
 {
+	struct dma_chan *chan = (dir == DMA_DEV_TO_MEM) ? epf_test->dma_chan_tx : epf_test->dma_chan_rx;
+	dma_addr_t dma_local = (dir == DMA_MEM_TO_DEV) ? dma_src : dma_dst;
 	enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
-	struct dma_chan *chan = epf_test->dma_chan;
 	struct pci_epf *epf = epf_test->epf;
 	struct dma_async_tx_descriptor *tx;
+	struct dma_slave_config sconf = {};
 	struct device *dev = &epf->dev;
 	dma_cookie_t cookie;
 	int ret;
@@ -120,7 +125,22 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
 		return -EINVAL;
 	}
 
-	tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
+	if (epf_test->dma_private) {
+		sconf.direction = dir;
+		if (dir == DMA_MEM_TO_DEV)
+			sconf.dst_addr = dma_remote;
+		else
+			sconf.src_addr = dma_remote;
+
+		if (dmaengine_slave_config(chan, &sconf)) {
+			dev_err(dev, "DMA slave config fail\n");
+			return -EIO;
+		}
+		tx = dmaengine_prep_slave_single(chan, dma_local, len, dir, flags);
+	} else {
+		tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
+	}
+
 	if (!tx) {
 		dev_err(dev, "Failed to prepare DMA memcpy\n");
 		return -EIO;
@@ -148,6 +168,23 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
 	return 0;
 }
 
+struct epf_dma_filter {
+	struct device *dev;
+	u32 dma_mask;
+};
+
+static bool epf_dma_filter_fn(struct dma_chan *chan, void *node)
+{
+	struct epf_dma_filter *filter = node;
+	struct dma_slave_caps caps;
+
+	memset(&caps, 0, sizeof(caps));
+	dma_get_slave_caps(chan, &caps);
+
+	return chan->device->dev == filter->dev
+		&& (filter->dma_mask & caps.directions);
+}
+
 /**
  * pci_epf_test_init_dma_chan() - Function to initialize EPF test DMA channel
  * @epf_test: the EPF test device that performs data transfer operation
@@ -158,10 +195,44 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test)
 {
 	struct pci_epf *epf = epf_test->epf;
 	struct device *dev = &epf->dev;
+	struct epf_dma_filter filter;
 	struct dma_chan *dma_chan;
 	dma_cap_mask_t mask;
 	int ret;
 
+	filter.dev = epf->epc->dev.parent;
+	filter.dma_mask = BIT(DMA_DEV_TO_MEM);
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_chan = dma_request_channel(mask, epf_dma_filter_fn, &filter);
+	if (IS_ERR_OR_NULL(dma_chan)) {
+		dev_info(dev, "Failed to get private DMA channel. Falling back to generic one\n");
+		goto fail_back_tx;
+	}
+
+	epf_test->dma_chan_rx = dma_chan;
+
+	filter.dma_mask = BIT(DMA_MEM_TO_DEV);
+	dma_chan = dma_request_channel(mask, epf_dma_filter_fn, &filter);
+
+	if (IS_ERR(dma_chan)) {
+		dev_info(dev, "Failed to get private DMA channel. Falling back to generic one\n");
+		goto fail_back_rx;
+	}
+
+	epf_test->dma_chan_tx = dma_chan;
+	epf_test->dma_private = true;
+
+	init_completion(&epf_test->transfer_complete);
+
+	return 0;
+
+fail_back_rx:
+	dma_release_channel(epf_test->dma_chan_rx);
+	epf_test->dma_chan_tx = NULL;
+
+fail_back_tx:
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_MEMCPY, mask);
 
@@ -174,7 +245,7 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test)
 	}
 	init_completion(&epf_test->transfer_complete);
 
-	epf_test->dma_chan = dma_chan;
+	epf_test->dma_chan_tx = epf_test->dma_chan_rx = dma_chan;
 
 	return 0;
 }
@@ -190,8 +261,17 @@ static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test)
 	if (!epf_test->dma_supported)
 		return;
 
-	dma_release_channel(epf_test->dma_chan);
-	epf_test->dma_chan = NULL;
+	dma_release_channel(epf_test->dma_chan_tx);
+	if (epf_test->dma_chan_tx == epf_test->dma_chan_rx) {
+		epf_test->dma_chan_tx = NULL;
+		epf_test->dma_chan_rx = NULL;
+		return;
+	}
+
+	dma_release_channel(epf_test->dma_chan_rx);
+	epf_test->dma_chan_rx = NULL;
+
+	return;
 }
 
 static void pci_epf_test_print_rate(const char *ops, u64 size,
@@ -280,8 +360,14 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
 			goto err_map_addr;
 		}
 
+		if (epf_test->dma_private) {
+			dev_err(dev, "Cannot transfer data using DMA\n");
+			ret = -EINVAL;
+			goto err_map_addr;
+		}
+
 		ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
-						 src_phys_addr, reg->size);
+						 src_phys_addr, reg->size, 0, DMA_MEM_TO_MEM);
 		if (ret)
 			dev_err(dev, "Data transfer failed\n");
 	} else {
@@ -363,7 +449,8 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
 
 		ktime_get_ts64(&start);
 		ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
-						 phys_addr, reg->size);
+						 phys_addr, reg->size,
+						 reg->src_addr, DMA_DEV_TO_MEM);
 		if (ret)
 			dev_err(dev, "Data transfer failed\n");
 		ktime_get_ts64(&end);
@@ -453,8 +540,9 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
 		}
 
 		ktime_get_ts64(&start);
+
 		ret = pci_epf_test_data_transfer(epf_test, phys_addr,
-						 src_phys_addr, reg->size);
+						 src_phys_addr, reg->size, reg->dst_addr, DMA_MEM_TO_DEV);
 		if (ret)
 			dev_err(dev, "Data transfer failed\n");
 		ktime_get_ts64(&end);
-- 
2.24.0.rc1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip
  2022-03-09 21:12 ` [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip Frank Li
@ 2022-03-10  1:07   ` kernel test robot
  2022-03-10  1:07   ` kernel test robot
  2022-03-10 17:46   ` Serge Semin
  2 siblings, 0 replies; 52+ messages in thread
From: kernel test robot @ 2022-03-10  1:07 UTC (permalink / raw)
  To: Frank Li, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, fancer.lancer, lznuaa
  Cc: kbuild-all, vkoul, lorenzo.pieralisi, robh, kw, bhelgaas,
	shawnguo, manivannan.sadhasivam

Hi Frank,

I love your patch! Yet something to improve:

[auto build test ERROR on vkoul-dmaengine/next]
[also build test ERROR on helgaas-pci/next linus/master v5.17-rc7 next-20220309]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Frank-Li/Enable-designware-PCI-EP-EDMA-locally/20220310-051510
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git next
config: csky-buildonly-randconfig-r004-20220309 (https://download.01.org/0day-ci/archive/20220310/202203100843.qzRV56ko-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/f7947d784b0fe089bdaef2fee8e57f84e390d3f2
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Frank-Li/Enable-designware-PCI-EP-EDMA-locally/20220310-051510
        git checkout f7947d784b0fe089bdaef2fee8e57f84e390d3f2
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=csky SHELL=/bin/bash drivers/dma/dw-edma/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/dma/dw-edma/dw-edma-v0-core.c: In function 'dw_edma_v0_core_start':
>> drivers/dma/dw-edma/dw-edma-v0-core.c:427:25: error: implicit declaration of function 'SET_CH_64'; did you mean 'SET_CH_32'? [-Werror=implicit-function-declaration]
     427 |                         SET_CH_64(dw, chan->dir, chan->id, llp.reg,
         |                         ^~~~~~~~~
         |                         SET_CH_32
>> drivers/dma/dw-edma/dw-edma-v0-core.c:427:60: error: 'llp' undeclared (first use in this function)
     427 |                         SET_CH_64(dw, chan->dir, chan->id, llp.reg,
         |                                                            ^~~
   drivers/dma/dw-edma/dw-edma-v0-core.c:427:60: note: each undeclared identifier is reported only once for each function it appears in
   cc1: some warnings being treated as errors


vim +427 drivers/dma/dw-edma/dw-edma-v0-core.c

   359	
   360	void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
   361	{
   362		struct dw_edma_chan *chan = chunk->chan;
   363		struct dw_edma *dw = chan->dw;
   364		u32 tmp;
   365	
   366		dw_edma_v0_core_write_chunk(chunk);
   367	
   368		if (first) {
   369			/* Enable engine */
   370			SET_RW_32(dw, chan->dir, engine_en, BIT(0));
   371			if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
   372				switch (chan->id) {
   373				case 0:
   374					SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
   375						      BIT(0));
   376					break;
   377				case 1:
   378					SET_RW_COMPAT(dw, chan->dir, ch1_pwr_en,
   379						      BIT(0));
   380					break;
   381				case 2:
   382					SET_RW_COMPAT(dw, chan->dir, ch2_pwr_en,
   383						      BIT(0));
   384					break;
   385				case 3:
   386					SET_RW_COMPAT(dw, chan->dir, ch3_pwr_en,
   387						      BIT(0));
   388					break;
   389				case 4:
   390					SET_RW_COMPAT(dw, chan->dir, ch4_pwr_en,
   391						      BIT(0));
   392					break;
   393				case 5:
   394					SET_RW_COMPAT(dw, chan->dir, ch5_pwr_en,
   395						      BIT(0));
   396					break;
   397				case 6:
   398					SET_RW_COMPAT(dw, chan->dir, ch6_pwr_en,
   399						      BIT(0));
   400					break;
   401				case 7:
   402					SET_RW_COMPAT(dw, chan->dir, ch7_pwr_en,
   403						      BIT(0));
   404					break;
   405				}
   406			}
   407			/* Interrupt unmask - done, abort */
   408			tmp = GET_RW_32(dw, chan->dir, int_mask);
   409			tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
   410			tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
   411			SET_RW_32(dw, chan->dir, int_mask, tmp);
   412			/* Linked list error */
   413			tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
   414			tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
   415			SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
   416			/* Channel control */
   417			SET_CH_32(dw, chan->dir, chan->id, ch_control1,
   418				  (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
   419			/* Linked list */
   420			if ((chan->dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI) ||
   421			    !IS_ENABLED(CONFIG_64BIT)) {
   422				SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
   423					  lower_32_bits(chunk->ll_region.paddr));
   424				SET_CH_32(dw, chan->dir, chan->id, llp.msb,
   425					  upper_32_bits(chunk->ll_region.paddr));
   426			} else {
 > 427				SET_CH_64(dw, chan->dir, chan->id, llp.reg,
   428					  chunk->ll_region.paddr);
   429			}
   430		}
   431		/* Doorbell */
   432		SET_RW_32(dw, chan->dir, doorbell,
   433			  FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
   434	}
   435	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip
  2022-03-09 21:12 ` [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip Frank Li
  2022-03-10  1:07   ` kernel test robot
@ 2022-03-10  1:07   ` kernel test robot
  2022-03-10 17:46   ` Serge Semin
  2 siblings, 0 replies; 52+ messages in thread
From: kernel test robot @ 2022-03-10  1:07 UTC (permalink / raw)
  To: Frank Li, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, fancer.lancer, lznuaa
  Cc: llvm, kbuild-all, vkoul, lorenzo.pieralisi, robh, kw, bhelgaas,
	shawnguo, manivannan.sadhasivam

Hi Frank,

I love your patch! Yet something to improve:

[auto build test ERROR on vkoul-dmaengine/next]
[also build test ERROR on helgaas-pci/next linus/master v5.17-rc7 next-20220309]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Frank-Li/Enable-designware-PCI-EP-EDMA-locally/20220310-051510
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git next
config: i386-randconfig-a015 (https://download.01.org/0day-ci/archive/20220310/202203100909.fpkA804r-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 276ca87382b8f16a65bddac700202924228982f6)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/f7947d784b0fe089bdaef2fee8e57f84e390d3f2
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Frank-Li/Enable-designware-PCI-EP-EDMA-locally/20220310-051510
        git checkout f7947d784b0fe089bdaef2fee8e57f84e390d3f2
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/dma/dw-edma/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/dma/dw-edma/dw-edma-v0-core.c:427:4: error: implicit declaration of function 'SET_CH_64' [-Werror,-Wimplicit-function-declaration]
                           SET_CH_64(dw, chan->dir, chan->id, llp.reg,
                           ^
>> drivers/dma/dw-edma/dw-edma-v0-core.c:427:39: error: use of undeclared identifier 'llp'
                           SET_CH_64(dw, chan->dir, chan->id, llp.reg,
                                                              ^
   2 errors generated.


vim +/SET_CH_64 +427 drivers/dma/dw-edma/dw-edma-v0-core.c

   359	
   360	void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
   361	{
   362		struct dw_edma_chan *chan = chunk->chan;
   363		struct dw_edma *dw = chan->dw;
   364		u32 tmp;
   365	
   366		dw_edma_v0_core_write_chunk(chunk);
   367	
   368		if (first) {
   369			/* Enable engine */
   370			SET_RW_32(dw, chan->dir, engine_en, BIT(0));
   371			if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
   372				switch (chan->id) {
   373				case 0:
   374					SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
   375						      BIT(0));
   376					break;
   377				case 1:
   378					SET_RW_COMPAT(dw, chan->dir, ch1_pwr_en,
   379						      BIT(0));
   380					break;
   381				case 2:
   382					SET_RW_COMPAT(dw, chan->dir, ch2_pwr_en,
   383						      BIT(0));
   384					break;
   385				case 3:
   386					SET_RW_COMPAT(dw, chan->dir, ch3_pwr_en,
   387						      BIT(0));
   388					break;
   389				case 4:
   390					SET_RW_COMPAT(dw, chan->dir, ch4_pwr_en,
   391						      BIT(0));
   392					break;
   393				case 5:
   394					SET_RW_COMPAT(dw, chan->dir, ch5_pwr_en,
   395						      BIT(0));
   396					break;
   397				case 6:
   398					SET_RW_COMPAT(dw, chan->dir, ch6_pwr_en,
   399						      BIT(0));
   400					break;
   401				case 7:
   402					SET_RW_COMPAT(dw, chan->dir, ch7_pwr_en,
   403						      BIT(0));
   404					break;
   405				}
   406			}
   407			/* Interrupt unmask - done, abort */
   408			tmp = GET_RW_32(dw, chan->dir, int_mask);
   409			tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
   410			tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
   411			SET_RW_32(dw, chan->dir, int_mask, tmp);
   412			/* Linked list error */
   413			tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
   414			tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
   415			SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
   416			/* Channel control */
   417			SET_CH_32(dw, chan->dir, chan->id, ch_control1,
   418				  (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
   419			/* Linked list */
   420			if ((chan->dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI) ||
   421			    !IS_ENABLED(CONFIG_64BIT)) {
   422				SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
   423					  lower_32_bits(chunk->ll_region.paddr));
   424				SET_CH_32(dw, chan->dir, chan->id, llp.msb,
   425					  upper_32_bits(chunk->ll_region.paddr));
   426			} else {
 > 427				SET_CH_64(dw, chan->dir, chan->id, llp.reg,
   428					  chunk->ll_region.paddr);
   429			}
   430		}
   431		/* Doorbell */
   432		SET_RW_32(dw, chan->dir, doorbell,
   433			  FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
   434	}
   435	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt in struct dw_edma_chip
  2022-03-09 21:12 ` [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt " Frank Li
@ 2022-03-10 12:37   ` Serge Semin
  2022-03-10 16:26     ` Zhi Li
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-10 12:37 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:12:00PM -0600, Frank Li wrote:
> There are same name wr(rd)_ch_cnt in struct dw_edma. EDMA driver get
> write(read) channel number from register, then save these into dw_edma.
> Old wr(rd)_ch_cnt in dw_edma_chip actuall means how many link list memory
> are avaiable in ll_region_wr(rd)[EDMA_MAX_WR_CH]. So rename it to
> ll_wr(rd)_cnt to indicate actual usage.

Hmm, I am not sure you are right here. AFAICS the
drivers/dma/dw-edma/dw-edma-pcie.c driver either uses a statically
defined number or Rd/Wr channels or just gets the number from the
specific vsec PCIe capability. Then based on that the driver just
redistributes the BARs memory amongst all the detected channels in
accordance with the statically defined snps_edda_data structure.
Basically the BARs memory serves as the Local/CPU/Application memory
for the case if the controller is embedded into the PCIe Host/EP
controller. See the patches which implicitly prove that:
31fb8c1ff962 ("dmaengine: dw-edma: Improve the linked list and data blocks definition")
da6e0dd54135 ("dmaengine: dw-edma: Change linked list and data blocks offset and sizes")

(That's why the logic of the DEV_TO_MEM/MEM_TO_DEV is inverted for the
the drivers/dma/dw-edma/dw-edma-pcie.c platform.)

So basically the wr_ch_cnt/rd_ch_cnt fields have been and is used as
the number of actually available channels, not linked-list. While the
notation suggested by you can be confusing, since the ll-memory allocated for
each channel can be split up and initialized with numerous linked lists
each of which is used one after another.

I don't really see a well justified reason to additionally have the
@wr_ch_cnt and @rd_ch_cnt fields in the dw_edma_chip seeing the number
of channels can be auto-detected from the corresponding registers, except
that to workaround a bogus hardware. So we can keep it, but please no
renaming. It will only cause additional confusion.

-Sergey

> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> new patch at v4
> 
>  drivers/dma/dw-edma/dw-edma-core.c |  4 ++--
>  drivers/dma/dw-edma/dw-edma-pcie.c | 12 ++++++------
>  include/linux/dma/edma.h           |  8 ++++----
>  3 files changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 1abf41d49f75b..66dc650577919 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -918,11 +918,11 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	raw_spin_lock_init(&dw->lock);
>  
>  
> -	dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> +	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
>  	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
>  
> -	dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> +	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
>  	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
>  
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index ae42bad24dd5a..7732537f96086 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -230,14 +230,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	chip->nr_irqs = nr_irqs;
>  	chip->ops = &dw_edma_pcie_core_ops;
>  
> -	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> -	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> +	chip->ll_wr_cnt = vsec_data.wr_ch_cnt;
> +	chip->ll_rd_cnt = vsec_data.rd_ch_cnt;
>  
>  	chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
>  	if (!chip->reg_base)
>  		return -ENOMEM;
>  
> -	for (i = 0; i < chip->wr_ch_cnt; i++) {
> +	for (i = 0; i < chip->ll_wr_cnt; 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];
> @@ -262,7 +262,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		dt_region->sz = dt_block->sz;
>  	}
>  
> -	for (i = 0; i < chip->rd_ch_cnt; i++) {
> +	for (i = 0; i < chip->ll_rd_cnt; 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];
> @@ -302,7 +302,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		chip->reg_base);
>  
>  
> -	for (i = 0; i < chip->wr_ch_cnt; i++) {
> +	for (i = 0; i < chip->ll_wr_cnt; i++) {
>  		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,
> @@ -314,7 +314,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
>  	}
>  
> -	for (i = 0; i < chip->rd_ch_cnt; i++) {
> +	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,
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index e9ce652b88233..c2039246fc08c 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -40,8 +40,8 @@ enum dw_edma_map_format {
>   * @nr_irqs:		 total dma irq number
>   * @ops			 DMA channel to IRQ number mapping
>   * @reg_base		 DMA register base address
> - * @wr_ch_cnt		 DMA write channel number
> - * @rd_ch_cnt		 DMA read channel number
> + * @ll_wr_cnt		 DMA write link list number
> + * @ll_rd_cnt		 DMA read link list number
>   * @rg_region		 DMA register region
>   * @ll_region_wr	 DMA descriptor link list memory for write channel
>   * @ll_region_rd	 DMA descriptor link list memory for read channel
> @@ -56,8 +56,8 @@ struct dw_edma_chip {
>  
>  	void __iomem		*reg_base;
>  
> -	u16			wr_ch_cnt;
> -	u16			rd_ch_cnt;
> +	u16			ll_wr_cnt;
> +	u16			ll_rd_cnt;
>  	/* link list address */
>  	struct dw_edma_region	ll_region_wr[EDMA_MAX_WR_CH];
>  	struct dw_edma_region	ll_region_rd[EDMA_MAX_RD_CH];
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-09 21:11 ` [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures Frank Li
@ 2022-03-10 12:50   ` Serge Semin
  2022-03-10 20:20   ` Serge Semin
  2022-03-12 19:54   ` Serge Semin
  2 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-10 12:50 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:11:57PM -0600, Frank Li wrote:
> "struct dw_edma_chip" contains an internal structure "struct dw_edma" that
> is used by the eDMA core internally. This structure should not be touched
> by the eDMA controller drivers themselves. But currently, the eDMA
> controller drivers like "dw-edma-pci" allocates and populates this
> internal structure then passes it on to eDMA core. The eDMA core further
> populates the structure and uses it. This is wrong!
> 
> Hence, move all the "struct dw_edma" specifics from controller drivers
> to the eDMA core.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> Change from v3 to v4
>  - Accept most suggestions of Serge Semin
> Change from v2 to v3
>  - none
> Change from v1 to v2
>  - rework commit message
>  - remove duplicate field in struct dw_edma
> 
>  drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
>  drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
>  drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
>  drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
>  include/linux/dma/edma.h                 | 44 +++++++++++++
>  6 files changed, 144 insertions(+), 130 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 53289927dd0d6..1abf41d49f75b 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
>  static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
>  {
>  	struct dw_edma_chan *chan = desc->chan;
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma_chip *chip = chan->dw->chip;
>  	struct dw_edma_chunk *chunk;
>  
>  	chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
> @@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
>  	 */
>  	chunk->cb = !(desc->chunks_alloc % 2);
>  	if (chan->dir == EDMA_DIR_WRITE) {
> -		chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
> -		chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
> +		chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
> +		chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
>  	} else {
> -		chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
> -		chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
> +		chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
> +		chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
>  	}
>  
>  	if (desc->chunk) {
> @@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
>  	if (chan->status != EDMA_ST_IDLE)
>  		return -EBUSY;
>  
> -	pm_runtime_get(chan->chip->dev);
> +	pm_runtime_get(chan->dw->chip->dev);
>  
>  	return 0;
>  }
> @@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
>  		cpu_relax();
>  	}
>  
> -	pm_runtime_put(chan->chip->dev);
> +	pm_runtime_put(chan->dw->chip->dev);
>  }
>  
>  static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> @@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  	}
>  
>  	INIT_LIST_HEAD(&dma->channels);
> -	for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
> +	for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
>  		chan = &dw->chan[i];
>  
>  		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> @@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  
>  		chan->vc.chan.private = dt_region;
>  
> -		chan->chip = chip;
> +		chan->dw = dw;
>  		chan->id = j;
>  		chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
>  		chan->configured = false;
> @@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  		chan->status = EDMA_ST_IDLE;
>  
>  		if (write)
> -			chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
> +			chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
>  		else
> -			chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
> +			chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
>  		chan->ll_max -= 1;
>  
>  		dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
>  			 write ? "write" : "read", j, chan->ll_max);
>  
> -		if (dw->nr_irqs == 1)
> +		if (chip->nr_irqs == 1)
>  			pos = 0;
>  		else
>  			pos = off_alloc + (j % alloc);
> @@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  		vchan_init(&chan->vc, dma);
>  
>  		if (write) {
> -			dt_region->paddr = dw->dt_region_wr[j].paddr;
> -			dt_region->vaddr = dw->dt_region_wr[j].vaddr;
> -			dt_region->sz = dw->dt_region_wr[j].sz;
> +			dt_region->paddr = chip->dt_region_wr[j].paddr;
> +			dt_region->vaddr = chip->dt_region_wr[j].vaddr;
> +			dt_region->sz = chip->dt_region_wr[j].sz;
>  		} else {
> -			dt_region->paddr = dw->dt_region_rd[j].paddr;
> -			dt_region->vaddr = dw->dt_region_rd[j].vaddr;
> -			dt_region->sz = dw->dt_region_rd[j].sz;
> +			dt_region->paddr = chip->dt_region_rd[j].paddr;
> +			dt_region->vaddr = chip->dt_region_rd[j].vaddr;
> +			dt_region->sz = chip->dt_region_rd[j].sz;
>  		}
>  
>  		dw_edma_v0_core_device_config(chan);
> @@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  
>  	ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
>  
> -	if (dw->nr_irqs < 1)
> +	if (chip->nr_irqs < 1)
>  		return -EINVAL;
>  
> -	if (dw->nr_irqs == 1) {
> +	if (chip->nr_irqs == 1) {
>  		/* Common IRQ shared among all channels */
> -		irq = dw->ops->irq_vector(dev, 0);
> +		irq = chip->ops->irq_vector(dev, 0);
>  		err = request_irq(irq, dw_edma_interrupt_common,
>  				  IRQF_SHARED, dw->name, &dw->irq[0]);
>  		if (err) {
> -			dw->nr_irqs = 0;
> +			chip->nr_irqs = 0;
>  			return err;
>  		}
>  
> @@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  			get_cached_msi_msg(irq, &dw->irq[0].msi);
>  	} else {
>  		/* Distribute IRQs equally among all channels */
> -		int tmp = dw->nr_irqs;
> +		int tmp = chip->nr_irqs;
>  
>  		while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
>  			dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
> @@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  		dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
>  
>  		for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
> -			irq = dw->ops->irq_vector(dev, i);
> +			irq = chip->ops->irq_vector(dev, i);
>  			err = request_irq(irq,
>  					  i < *wr_alloc ?
>  						dw_edma_interrupt_write :
> @@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  					  IRQF_SHARED, dw->name,
>  					  &dw->irq[i]);
>  			if (err) {
> -				dw->nr_irqs = i;
> +				chip->nr_irqs = i;
>  				return err;
>  			}
>  
> @@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  				get_cached_msi_msg(irq, &dw->irq[i].msi);
>  		}
>  
> -		dw->nr_irqs = i;
> +		chip->nr_irqs = i;
>  	}
>  
>  	return err;
> @@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)

>  	if (!dev)
>  		return -EINVAL;
        ^
        | See my next comment...
>  
> -	dw = chip->dw;
> -	if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
> +	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	chip->dw = dw;
> +	dw->chip = chip;
> +

> +	if (!chip->nr_irqs || !chip->ops)

Please, join this with the "if (!dev)" statement above. As I said in
my comment to v3, there is no point in allocating anything if the
chip info is invalid.

-Sergey

>  		return -EINVAL;
>  
>  	raw_spin_lock_init(&dw->lock);
>  
> -	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,
> +
> +	dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
>  	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
>  
> -	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
> +	dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
>  	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
>  
> @@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	/* Disable eDMA, only to establish the ideal initial conditions */
>  	dw_edma_v0_core_off(dw);
>  
> +	dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> +	if (!dw->irq)
> +		return -ENOMEM;
> +
>  	/* Request IRQs */
>  	err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
>  	if (err)
> @@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	return 0;
>  
>  err_irq_free:
> -	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> -		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> +	for (i = (chip->nr_irqs - 1); i >= 0; i--)
> +		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
>  
> -	dw->nr_irqs = 0;
> +	chip->nr_irqs = 0;
>  
>  	return err;
>  }
> @@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  	dw_edma_v0_core_off(dw);
>  
>  	/* Free irqs */
> -	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> -		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> +	for (i = (chip->nr_irqs - 1); i >= 0; i--)
> +		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
>  
>  	/* Power management */
>  	pm_runtime_disable(dev);
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index 60316d408c3e0..e254c2fc3d9cf 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -15,20 +15,12 @@
>  #include "../virt-dma.h"
>  
>  #define EDMA_LL_SZ					24
> -#define EDMA_MAX_WR_CH					8
> -#define EDMA_MAX_RD_CH					8
>  
>  enum dw_edma_dir {
>  	EDMA_DIR_WRITE = 0,
>  	EDMA_DIR_READ
>  };
>  
> -enum dw_edma_map_format {
> -	EDMA_MF_EDMA_LEGACY = 0x0,
> -	EDMA_MF_EDMA_UNROLL = 0x1,
> -	EDMA_MF_HDMA_COMPAT = 0x5
> -};
> -
>  enum dw_edma_request {
>  	EDMA_REQ_NONE = 0,
>  	EDMA_REQ_STOP,
> @@ -57,12 +49,6 @@ struct dw_edma_burst {
>  	u32				sz;
>  };
>  
> -struct dw_edma_region {
> -	phys_addr_t			paddr;
> -	void				__iomem *vaddr;
> -	size_t				sz;
> -};
> -
>  struct dw_edma_chunk {
>  	struct list_head		list;
>  	struct dw_edma_chan		*chan;
> @@ -87,7 +73,7 @@ struct dw_edma_desc {
>  
>  struct dw_edma_chan {
>  	struct virt_dma_chan		vc;
> -	struct dw_edma_chip		*chip;
> +	struct dw_edma			*dw;
>  	int				id;
>  	enum dw_edma_dir		dir;
>  
> @@ -109,10 +95,6 @@ struct dw_edma_irq {
>  	struct dw_edma			*dw;
>  };
>  
> -struct dw_edma_core_ops {
> -	int	(*irq_vector)(struct device *dev, unsigned int nr);
> -};
> -
>  struct dw_edma {
>  	char				name[20];
>  
> @@ -122,21 +104,13 @@ struct dw_edma {
>  	struct dma_device		rd_edma;
>  	u16				rd_ch_cnt;
>  
> -	struct dw_edma_region		rg_region;	/* Registers */
> -	struct dw_edma_region		ll_region_wr[EDMA_MAX_WR_CH];
> -	struct dw_edma_region		ll_region_rd[EDMA_MAX_RD_CH];
> -	struct dw_edma_region		dt_region_wr[EDMA_MAX_WR_CH];
> -	struct dw_edma_region		dt_region_rd[EDMA_MAX_RD_CH];
> -
>  	struct dw_edma_irq		*irq;
> -	int				nr_irqs;
> -
> -	enum dw_edma_map_format		mf;
>  
>  	struct dw_edma_chan		*chan;
> -	const struct dw_edma_core_ops	*ops;
>  
>  	raw_spinlock_t			lock;		/* Only for legacy */
> +
> +	struct dw_edma_chip             *chip;
>  #ifdef CONFIG_DEBUG_FS
>  	struct dentry			*debugfs;
>  #endif /* CONFIG_DEBUG_FS */
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 44f6e09bdb531..2c1c5fa4e9f28 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	struct dw_edma_pcie_data vsec_data;
>  	struct device *dev = &pdev->dev;
>  	struct dw_edma_chip *chip;
> -	struct dw_edma *dw;
>  	int err, nr_irqs;
>  	int i, mask;
>  
> @@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	if (!chip)
>  		return -ENOMEM;
>  
> -	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> -	if (!dw)
> -		return -ENOMEM;
> -
>  	/* IRQs allocation */
>  	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
>  					PCI_IRQ_MSI | PCI_IRQ_MSIX);
> @@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	}
>  
>  	/* Data structure initialization */
> -	chip->dw = dw;
>  	chip->dev = dev;
>  	chip->id = pdev->devfn;
> -	chip->irq = pdev->irq;
>  
> -	dw->mf = vsec_data.mf;
> -	dw->nr_irqs = nr_irqs;
> -	dw->ops = &dw_edma_pcie_core_ops;
> -	dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
> -	dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
> +	chip->mf = vsec_data.mf;
> +	chip->nr_irqs = nr_irqs;
> +	chip->ops = &dw_edma_pcie_core_ops;
>  
> -	dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> -	if (!dw->rg_region.vaddr)
> -		return -ENOMEM;
> +	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> +	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
>  
> -	dw->rg_region.vaddr += vsec_data.rg.off;
> -	dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
> -	dw->rg_region.paddr += vsec_data.rg.off;
> -	dw->rg_region.sz = vsec_data.rg.sz;
> +	chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> +	if (!chip->rg_region.vaddr)
> +		return -ENOMEM;
>  
> -	for (i = 0; i < dw->wr_ch_cnt; i++) {
> -		struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
> -		struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
> +	for (i = 0; i < chip->wr_ch_cnt; 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];
>  		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
>  
> @@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		dt_region->sz = dt_block->sz;
>  	}
>  
> -	for (i = 0; i < dw->rd_ch_cnt; i++) {
> -		struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
> -		struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
> +	for (i = 0; i < chip->rd_ch_cnt; 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];
>  		struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
>  
> @@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	}
>  
>  	/* Debug info */
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY)
> -		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
> -	else if (dw->mf == EDMA_MF_EDMA_UNROLL)
> -		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
> -	else if (dw->mf == EDMA_MF_HDMA_COMPAT)
> -		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
> +	if (chip->mf == EDMA_MF_EDMA_LEGACY)
> +		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
> +	else if (chip->mf == EDMA_MF_EDMA_UNROLL)
> +		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
> +	else if (chip->mf == EDMA_MF_HDMA_COMPAT)
> +		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
>  	else
> -		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
> +		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
>  
> -	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> +	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
>  		vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> -		dw->rg_region.vaddr, &dw->rg_region.paddr);
> +		chip->rg_region.vaddr);
>  
>  
> -	for (i = 0; i < dw->wr_ch_cnt; i++) {
> +	for (i = 0; i < chip->wr_ch_cnt; i++) {
>  		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, dw->ll_region_wr[i].sz,
> -			dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
> +			vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
> +			chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
> -			dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
> +			vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
> +			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
>  	}
>  
> -	for (i = 0; i < dw->rd_ch_cnt; i++) {
> +	for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
> -			dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
> +			vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
> +			chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
> -			dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
> +			vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
> +			chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
>  	}
>  
> -	pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
> +	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
>  
>  	/* Validating if PCI interrupts were enabled */
>  	if (!pci_dev_msi_enabled(pdev)) {
> @@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		return -EPERM;
>  	}
>  
> -	dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> -	if (!dw->irq)
> -		return -ENOMEM;
> -
>  	/* Starting eDMA driver */
>  	err = dw_edma_probe(chip);
>  	if (err) {
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index 329fc2e57b703..e507e076fad16 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -25,7 +25,7 @@ enum dw_edma_control {
>  
>  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  {
> -	return dw->rg_region.vaddr;
> +	return dw->chip->rg_region.vaddr;
>  }
>  
>  #define SET_32(dw, name, value)				\
> @@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  static inline struct dw_edma_v0_ch_regs __iomem *
>  __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY)
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
>  		return &(__dw_regs(dw)->type.legacy.ch);
>  
>  	if (dir == EDMA_DIR_WRITE)
> @@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
>  static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			     u32 value, void __iomem *addr)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  {
>  	u32 value;
>  
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			     u64 value, void __iomem *addr)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  {
>  	u32 value;
>  
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
>  
>  enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp;
>  
>  	tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
> @@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
>  
>  void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  
>  	SET_RW_32(dw, chan->dir, int_clear,
>  		  FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
> @@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
>  
>  void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  
>  	SET_RW_32(dw, chan->dir, int_clear,
>  		  FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
> @@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
>  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  {
>  	struct dw_edma_chan *chan = chunk->chan;
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp;
>  
>  	dw_edma_v0_core_write_chunk(chunk);
> @@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  	if (first) {
>  		/* Enable engine */
>  		SET_RW_32(dw, chan->dir, engine_en, BIT(0));
> -		if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +		if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  			switch (chan->id) {
>  			case 0:
>  				SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
> @@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  
>  int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp = 0;
>  
>  	/* MSI done addr - low, high */
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 4b3bcffd15ef1..edb7e137cb35a 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -54,7 +54,7 @@ struct debugfs_entries {
>  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  {
>  	void __iomem *reg = (void __force __iomem *)data;
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY &&
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
>  	    reg >= (void __iomem *)&regs->type.legacy.ch) {
>  		void __iomem *ptr = &regs->type.legacy.ch;
>  		u32 viewport_sel = 0;
> @@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
>  
> -	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
>  		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
> @@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
>  
> -	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
>  		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
> @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!dw)
>  		return;
>  
> -	regs = dw->rg_region.vaddr;
> +	regs = dw->chip->rg_region.vaddr;
>  	if (!regs)
>  		return;
>  
> @@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!dw->debugfs)
>  		return;
>  
> -	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
> +	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
>  	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
>  	debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
>  
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index cab6e18773dad..a9bee4aeb2eee 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -12,19 +12,63 @@
>  #include <linux/device.h>
>  #include <linux/dmaengine.h>
>  
> +#define EDMA_MAX_WR_CH                                  8
> +#define EDMA_MAX_RD_CH                                  8
> +
>  struct dw_edma;
>  
> +struct dw_edma_region {
> +	phys_addr_t	paddr;
> +	void __iomem	*vaddr;
> +	size_t		sz;
> +};
> +
> +struct dw_edma_core_ops {
> +	int (*irq_vector)(struct device *dev, unsigned int nr);
> +};
> +
> +enum dw_edma_map_format {
> +	EDMA_MF_EDMA_LEGACY = 0x0,
> +	EDMA_MF_EDMA_UNROLL = 0x1,
> +	EDMA_MF_HDMA_COMPAT = 0x5
> +};
> +
>  /**
>   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
>   * @dev:		 struct device of the eDMA controller
>   * @id:			 instance ID
>   * @irq:		 irq line
> + * @nr_irqs:		 total dma irq number
> + * @ops			 DMA channel to IRQ number mapping
> + * @wr_ch_cnt		 DMA write channel number
> + * @rd_ch_cnt		 DMA read channel number
> + * @rg_region		 DMA register region
> + * @ll_region_wr	 DMA descriptor link list memory for write channel
> + * @ll_region_rd	 DMA descriptor link list memory for read channel
> + * @mf			 DMA register map format
>   * @dw:			 struct dw_edma that is filed by dw_edma_probe()
>   */
>  struct dw_edma_chip {
>  	struct device		*dev;
>  	int			id;
>  	int			irq;
> +	int			nr_irqs;
> +	const struct dw_edma_core_ops   *ops;
> +
> +	struct dw_edma_region	rg_region;
> +
> +	u16			wr_ch_cnt;
> +	u16			rd_ch_cnt;
> +	/* link list address */
> +	struct dw_edma_region	ll_region_wr[EDMA_MAX_WR_CH];
> +	struct dw_edma_region	ll_region_rd[EDMA_MAX_RD_CH];
> +
> +	/* data region */
> +	struct dw_edma_region	dt_region_wr[EDMA_MAX_WR_CH];
> +	struct dw_edma_region	dt_region_rd[EDMA_MAX_RD_CH];
> +
> +	enum dw_edma_map_format	mf;
> +
>  	struct dw_edma		*dw;
>  };
>  
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 2/8] dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip
  2022-03-09 21:11 ` [PATCH v4 2/8] dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip Frank Li
@ 2022-03-10 12:52   ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-10 12:52 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:11:58PM -0600, Frank Li wrote:

> irq of struct dw_edma_chip was never used.
> It can be removed safely.

The patch is incomplete. See drivers/dma/dw-edma/dw-edma-pcie.c:234.
The irq field is initialized there. But it's never used afterwards. So
you need to fix the dw-edma-pcie.c driver too by dropping the
corresponding initialization, otherwise the driver will fail to be
built.

-Sergey

> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> new patch at v4
> 
>  include/linux/dma/edma.h | 2 --
>  1 file changed, 2 deletions(-)
> 
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index a9bee4aeb2eee..6fd374cc72c8e 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -37,7 +37,6 @@ enum dw_edma_map_format {
>   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
>   * @dev:		 struct device of the eDMA controller
>   * @id:			 instance ID
> - * @irq:		 irq line
>   * @nr_irqs:		 total dma irq number
>   * @ops			 DMA channel to IRQ number mapping
>   * @wr_ch_cnt		 DMA write channel number
> @@ -51,7 +50,6 @@ enum dw_edma_map_format {
>  struct dw_edma_chip {
>  	struct device		*dev;
>  	int			id;
> -	int			irq;
>  	int			nr_irqs;
>  	const struct dw_edma_core_ops   *ops;
>  
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 3/8] dmaengine: dw-edma: change rg_region to reg_base in struct dw_edma_chip
  2022-03-09 21:11 ` [PATCH v4 3/8] dmaengine: dw-edma: change rg_region to reg_base " Frank Li
@ 2022-03-10 12:56   ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-10 12:56 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:11:59PM -0600, Frank Li wrote:
> struct dw_edma_region rg_region included virtual address, physical
> address and size informaiton. But only virtual address is used by EDMA
> driver. Change it to void __iomem *reg_base to clean up code.

Right, the driver doesn't use neither physical address nor size of the
CSRs MMIO region, and most likely will never start using it. They are
just redundant for the CSR space.

Reviewed-by: Serge Semin <fancer.lancer@gmail.com>

> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> New patch at v4
> 
>  drivers/dma/dw-edma/dw-edma-pcie.c       | 6 +++---
>  drivers/dma/dw-edma/dw-edma-v0-core.c    | 2 +-
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 2 +-
>  include/linux/dma/edma.h                 | 3 ++-
>  4 files changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 2c1c5fa4e9f28..ae42bad24dd5a 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -233,8 +233,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
>  	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
>  
> -	chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> -	if (!chip->rg_region.vaddr)
> +	chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> +	if (!chip->reg_base)
>  		return -ENOMEM;
>  
>  	for (i = 0; i < chip->wr_ch_cnt; i++) {
> @@ -299,7 +299,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  
>  	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
>  		vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> -		chip->rg_region.vaddr);
> +		chip->reg_base);
>  
>  
>  	for (i = 0; i < chip->wr_ch_cnt; i++) {
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index e507e076fad16..35f2adac93e46 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -25,7 +25,7 @@ enum dw_edma_control {
>  
>  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  {
> -	return dw->chip->rg_region.vaddr;
> +	return dw->chip->reg_base;
>  }
>  
>  #define SET_32(dw, name, value)				\
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index edb7e137cb35a..3a899f7f4e8d8 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!dw)
>  		return;
>  
> -	regs = dw->chip->rg_region.vaddr;
> +	regs = dw->chip->reg_base;
>  	if (!regs)
>  		return;
>  
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 6fd374cc72c8e..e9ce652b88233 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -39,6 +39,7 @@ enum dw_edma_map_format {
>   * @id:			 instance ID
>   * @nr_irqs:		 total dma irq number
>   * @ops			 DMA channel to IRQ number mapping
> + * @reg_base		 DMA register base address
>   * @wr_ch_cnt		 DMA write channel number
>   * @rd_ch_cnt		 DMA read channel number
>   * @rg_region		 DMA register region
> @@ -53,7 +54,7 @@ struct dw_edma_chip {
>  	int			nr_irqs;
>  	const struct dw_edma_core_ops   *ops;
>  
> -	struct dw_edma_region	rg_region;
> +	void __iomem		*reg_base;
>  
>  	u16			wr_ch_cnt;
>  	u16			rd_ch_cnt;
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt in struct dw_edma_chip
  2022-03-10 12:37   ` Serge Semin
@ 2022-03-10 16:26     ` Zhi Li
  2022-03-10 16:51       ` Zhi Li
  0 siblings, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-10 16:26 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 6:37 AM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> On Wed, Mar 09, 2022 at 03:12:00PM -0600, Frank Li wrote:
> > There are same name wr(rd)_ch_cnt in struct dw_edma. EDMA driver get
> > write(read) channel number from register, then save these into dw_edma.
> > Old wr(rd)_ch_cnt in dw_edma_chip actuall means how many link list memory
> > are avaiable in ll_region_wr(rd)[EDMA_MAX_WR_CH]. So rename it to
> > ll_wr(rd)_cnt to indicate actual usage.
>
> Hmm, I am not sure you are right here. AFAICS the
> drivers/dma/dw-edma/dw-edma-pcie.c driver either uses a statically
> defined number or Rd/Wr channels or just gets the number from the
> specific vsec PCIe capability. Then based on that the driver just
> redistributes the BARs memory amongst all the detected channels in
> accordance with the statically defined snps_edda_data structure.
> Basically the BARs memory serves as the Local/CPU/Application memory
> for the case if the controller is embedded into the PCIe Host/EP
> controller. See the patches which implicitly prove that:
> 31fb8c1ff962 ("dmaengine: dw-edma: Improve the linked list and data blocks definition")
> da6e0dd54135 ("dmaengine: dw-edma: Change linked list and data blocks offset and sizes")
>
> (That's why the logic of the DEV_TO_MEM/MEM_TO_DEV is inverted for the
> the drivers/dma/dw-edma/dw-edma-pcie.c platform.)
>
> So basically the wr_ch_cnt/rd_ch_cnt fields have been and is used as
> the number of actually available channels, not linked-list. While the
> notation suggested by you can be confusing, since the ll-memory allocated for
> each channel can be split up and initialized with numerous linked lists
> each of which is used one after another.
>
> I don't really see a well justified reason to additionally have the
> @wr_ch_cnt and @rd_ch_cnt fields in the dw_edma_chip seeing the number
> of channels can be auto-detected from the corresponding registers, except
> that to workaround a bogus hardware. So we can keep it, but please no
> renaming. It will only cause additional confusion.

I agree that channel numbers can be obtained from the register.
but Caller don't know the channel number before calling dw_edma_probe.

Caller may not init all ll_region_wr[EDMA_MAX_WR_CH],

That's the reason I need a field to indicate how many ll_region_w
actually initialized.

old wr_ch_cnt just plays the same role.

>
> -Sergey
>
> >
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > new patch at v4
> >
> >  drivers/dma/dw-edma/dw-edma-core.c |  4 ++--
> >  drivers/dma/dw-edma/dw-edma-pcie.c | 12 ++++++------
> >  include/linux/dma/edma.h           |  8 ++++----
> >  3 files changed, 12 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 1abf41d49f75b..66dc650577919 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -918,11 +918,11 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >       raw_spin_lock_init(&dw->lock);
> >
> >
> > -     dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> > +     dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
> >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
> >       dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> >
> > -     dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> > +     dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
> >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
> >       dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > index ae42bad24dd5a..7732537f96086 100644
> > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > @@ -230,14 +230,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >       chip->nr_irqs = nr_irqs;
> >       chip->ops = &dw_edma_pcie_core_ops;
> >
> > -     chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > -     chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > +     chip->ll_wr_cnt = vsec_data.wr_ch_cnt;
> > +     chip->ll_rd_cnt = vsec_data.rd_ch_cnt;
> >
> >       chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> >       if (!chip->reg_base)
> >               return -ENOMEM;
> >
> > -     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > +     for (i = 0; i < chip->ll_wr_cnt; 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];
> > @@ -262,7 +262,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >               dt_region->sz = dt_block->sz;
> >       }
> >
> > -     for (i = 0; i < chip->rd_ch_cnt; i++) {
> > +     for (i = 0; i < chip->ll_rd_cnt; 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];
> > @@ -302,7 +302,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >               chip->reg_base);
> >
> >
> > -     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > +     for (i = 0; i < chip->ll_wr_cnt; i++) {
> >               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,
> > @@ -314,7 +314,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >                       chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
> >       }
> >
> > -     for (i = 0; i < chip->rd_ch_cnt; i++) {
> > +     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,
> > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > index e9ce652b88233..c2039246fc08c 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -40,8 +40,8 @@ enum dw_edma_map_format {
> >   * @nr_irqs:          total dma irq number
> >   * @ops                       DMA channel to IRQ number mapping
> >   * @reg_base          DMA register base address
> > - * @wr_ch_cnt                 DMA write channel number
> > - * @rd_ch_cnt                 DMA read channel number
> > + * @ll_wr_cnt                 DMA write link list number
> > + * @ll_rd_cnt                 DMA read link list number
> >   * @rg_region                 DMA register region
> >   * @ll_region_wr      DMA descriptor link list memory for write channel
> >   * @ll_region_rd      DMA descriptor link list memory for read channel
> > @@ -56,8 +56,8 @@ struct dw_edma_chip {
> >
> >       void __iomem            *reg_base;
> >
> > -     u16                     wr_ch_cnt;
> > -     u16                     rd_ch_cnt;
> > +     u16                     ll_wr_cnt;
> > +     u16                     ll_rd_cnt;
> >       /* link list address */
> >       struct dw_edma_region   ll_region_wr[EDMA_MAX_WR_CH];
> >       struct dw_edma_region   ll_region_rd[EDMA_MAX_RD_CH];
> > --
> > 2.24.0.rc1
> >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-09 21:12 ` [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep Frank Li
@ 2022-03-10 16:31   ` Serge Semin
  2022-03-10 16:50     ` Zhi Li
  2022-03-11 17:41     ` Manivannan Sadhasivam
  0 siblings, 2 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-10 16:31 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> 
> When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> programs the source and destination addresses for read and write. Since the
> Root complex and Endpoint uses the opposite channels for read/write, fix the
> issue by finding out the read operation first and program the eDMA accordingly.
> 
> Cc: stable@vger.kernel.org
> Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> No change between v1 to v4
> 
>  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
>  1 file changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 66dc650577919..507f08db1aad3 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  	struct dw_edma_chunk *chunk;
>  	struct dw_edma_burst *burst;
>  	struct dw_edma_desc *desc;
> +	bool read = false;
>  	u32 cnt = 0;
>  	int i;
>  
> @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  		chunk->ll_region.sz += burst->sz;
>  		desc->alloc_sz += burst->sz;
>  
> -		if (chan->dir == EDMA_DIR_WRITE) {
> +		/****************************************************************
> +		 *

> +		 *        Root Complex                           Endpoint
> +		 * +-----------------------+             +----------------------+
> +		 * |                       |    TX CH    |                      |
> +		 * |                       |             |                      |
> +		 * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> +		 * |                       |             |                      |
> +		 * |                       |             |                      |
> +		 * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> +		 * |                       |             |                      |
> +		 * |                       |    RX CH    |                      |
> +		 * +-----------------------+             +----------------------+
> +		 *
> +		 * If eDMA is controlled by the Root complex, TX channel
> +		 * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> +		 * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> +		 *
> +		 * If eDMA is controlled by the endpoint, RX channel
> +		 * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> +		 * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).

Either I have some wrong notion about this issue, or something wrong
with the explanation above and with this fix below.

From my understanding of the possible DW eDMA IP-core setups the
scatch above and the text below it are incorrect. Here is the way the
DW eDMA can be used:
1) Embedded into the DW PCIe Host/EP controller. In this case
CPU/Application Memory is the memory of the CPU attached to the
host/EP controller, while the remote (link partner) memory is the PCIe
bus memory. In this case MEM_TO_DEV operation is supposed to be
performed by the Tx/Write channels, while the DEV_TO_MEM operation -
by the Rx/Read channels.

Note it's applicable for both Host and End-point case, when Linux is
running on the CPU-side of the eDMA controller. So if it's DW PCIe
end-point, then MEM_TO_DEV means copying data from the local CPU
memory into the remote memory. In general the remote memory can be
either some PCIe device on the bus or the Root Complex' CPU memory,
each of which is some remote device anyway from the Local CPU
perspective.

2) Embedded into the PCIe EP. This case is implemented in the
drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
and from the driver code, that device is a Synopsys PCIe EndPoint IP
prototype kit. It is a normal PCIe peripheral device with eDMA
embedded, which CPU/Application interface is connected to some
embedded SRAM while remote (link partner) interface is directed
towards the PCIe bus. At the same time the device is setup and handled
by the code running on a CPU connected to the PCIe Host controller.  I
think that in order to preserve the normal DMA operations semantics we
still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
host CPU perspective, since that's the side the DMA controller is
supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
to copy data from the host CPU memory into the remote device memory.
It means to allocate Rx/Read channel on the eDMA controller, so one
would be read data from the Local CPU memory and copied it to the PCIe
device SRAM. The logic of the DEV_TO_MEM direction would be just
flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
from it's SRAM into the Host CPU memory.

Please note as I understand the case 2) describes the Synopsys PCIe
EndPoint IP prototype kit, which is based on some FPGA code. It's just
a test setup with no real application, while the case 1) is a real setup
available on our SoC and I guess on yours.

So what I suggest in the framework of this patch is just to implement
the case 1) only. While the case 2) as it's an artificial one can be
manually handled by the DMA client drivers. BTW There aren't ones available
in the kernel anyway. The only exception is an old-time attempt to get
an eDMA IP test-driver mainlined into the kernel:
https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
But it was long time ago. So it's unlikely to be accepted at all.

What do you think?

-Sergey

> +		 *
> +		 ****************************************************************/
> +

> +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> +			read = true;

Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
redundant.

> +
> +		/* Program the source and destination addresses for DMA read/write */
> +		if (read) {
>  			burst->sar = src_addr;
>  			if (xfer->type == EDMA_XFER_CYCLIC) {
>  				burst->dar = xfer->xfer.cyclic.paddr;
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-10 16:31   ` Serge Semin
@ 2022-03-10 16:50     ` Zhi Li
  2022-03-10 19:37       ` Serge Semin
  2022-03-11 17:41     ` Manivannan Sadhasivam
  1 sibling, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-10 16:50 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> >
> > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > programs the source and destination addresses for read and write. Since the
> > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > issue by finding out the read operation first and program the eDMA accordingly.
> >
> > Cc: stable@vger.kernel.org
> > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > No change between v1 to v4
> >
> >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> >  1 file changed, 31 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 66dc650577919..507f08db1aad3 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> >       struct dw_edma_chunk *chunk;
> >       struct dw_edma_burst *burst;
> >       struct dw_edma_desc *desc;
> > +     bool read = false;
> >       u32 cnt = 0;
> >       int i;
> >
> > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> >               chunk->ll_region.sz += burst->sz;
> >               desc->alloc_sz += burst->sz;
> >
> > -             if (chan->dir == EDMA_DIR_WRITE) {
> > +             /****************************************************************
> > +              *
>
> > +              *        Root Complex                           Endpoint
> > +              * +-----------------------+             +----------------------+
> > +              * |                       |    TX CH    |                      |
> > +              * |                       |             |                      |
> > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > +              * |                       |             |                      |
> > +              * |                       |             |                      |
> > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > +              * |                       |             |                      |
> > +              * |                       |    RX CH    |                      |
> > +              * +-----------------------+             +----------------------+
> > +              *
> > +              * If eDMA is controlled by the Root complex, TX channel
> > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > +              *
> > +              * If eDMA is controlled by the endpoint, RX channel
> > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
>
> Either I have some wrong notion about this issue, or something wrong
> with the explanation above and with this fix below.
>
> From my understanding of the possible DW eDMA IP-core setups the
> scatch above and the text below it are incorrect. Here is the way the
> DW eDMA can be used:
> 1) Embedded into the DW PCIe Host/EP controller. In this case
> CPU/Application Memory is the memory of the CPU attached to the
> host/EP controller, while the remote (link partner) memory is the PCIe
> bus memory. In this case MEM_TO_DEV operation is supposed to be
> performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> by the Rx/Read channels.
>
> Note it's applicable for both Host and End-point case, when Linux is
> running on the CPU-side of the eDMA controller. So if it's DW PCIe
> end-point, then MEM_TO_DEV means copying data from the local CPU
> memory into the remote memory. In general the remote memory can be
> either some PCIe device on the bus or the Root Complex' CPU memory,
> each of which is some remote device anyway from the Local CPU
> perspective.
>
> 2) Embedded into the PCIe EP. This case is implemented in the
> drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> and from the driver code, that device is a Synopsys PCIe EndPoint IP
> prototype kit. It is a normal PCIe peripheral device with eDMA
> embedded, which CPU/Application interface is connected to some
> embedded SRAM while remote (link partner) interface is directed
> towards the PCIe bus. At the same time the device is setup and handled
> by the code running on a CPU connected to the PCIe Host controller.  I
> think that in order to preserve the normal DMA operations semantics we
> still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> host CPU perspective, since that's the side the DMA controller is
> supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> to copy data from the host CPU memory into the remote device memory.
> It means to allocate Rx/Read channel on the eDMA controller, so one
> would be read data from the Local CPU memory and copied it to the PCIe
> device SRAM. The logic of the DEV_TO_MEM direction would be just
> flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> from it's SRAM into the Host CPU memory.
>
> Please note as I understand the case 2) describes the Synopsys PCIe
> EndPoint IP prototype kit, which is based on some FPGA code. It's just
> a test setup with no real application, while the case 1) is a real setup
> available on our SoC and I guess on yours.

I think yes. But Remote EP also is a one kind of usage module. Just no one
writes an EP functional driver for it yet.  Even pci-epf-test was just
a test function.
I previously sent vNTB patches to implement a virtual network between
RC and EP,
you can look if you have interest.

>
> So what I suggest in the framework of this patch is just to implement
> the case 1) only. While the case 2) as it's an artificial one can be
> manually handled by the DMA client drivers. BTW There aren't ones available
> in the kernel anyway. The only exception is an old-time attempt to get
> an eDMA IP test-driver mainlined into the kernel:
> https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> But it was long time ago. So it's unlikely to be accepted at all.
>
> What do you think?
>
> -Sergey
>
> > +              *
> > +              ****************************************************************/
> > +
>
> > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > +                     read = true;
>
> Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> redundant.
>
> > +
> > +             /* Program the source and destination addresses for DMA read/write */
> > +             if (read) {
> >                       burst->sar = src_addr;
> >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> >                               burst->dar = xfer->xfer.cyclic.paddr;
> > --
> > 2.24.0.rc1
> >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt in struct dw_edma_chip
  2022-03-10 16:26     ` Zhi Li
@ 2022-03-10 16:51       ` Zhi Li
  2022-03-10 18:45         ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-10 16:51 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 10:26 AM Zhi Li <lznuaa@gmail.com> wrote:
>
> On Thu, Mar 10, 2022 at 6:37 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > On Wed, Mar 09, 2022 at 03:12:00PM -0600, Frank Li wrote:
> > > There are same name wr(rd)_ch_cnt in struct dw_edma. EDMA driver get
> > > write(read) channel number from register, then save these into dw_edma.
> > > Old wr(rd)_ch_cnt in dw_edma_chip actuall means how many link list memory
> > > are avaiable in ll_region_wr(rd)[EDMA_MAX_WR_CH]. So rename it to
> > > ll_wr(rd)_cnt to indicate actual usage.
> >
> > Hmm, I am not sure you are right here. AFAICS the
> > drivers/dma/dw-edma/dw-edma-pcie.c driver either uses a statically
> > defined number or Rd/Wr channels or just gets the number from the
> > specific vsec PCIe capability. Then based on that the driver just
> > redistributes the BARs memory amongst all the detected channels in
> > accordance with the statically defined snps_edda_data structure.
> > Basically the BARs memory serves as the Local/CPU/Application memory
> > for the case if the controller is embedded into the PCIe Host/EP
> > controller. See the patches which implicitly prove that:
> > 31fb8c1ff962 ("dmaengine: dw-edma: Improve the linked list and data blocks definition")
> > da6e0dd54135 ("dmaengine: dw-edma: Change linked list and data blocks offset and sizes")
> >
> > (That's why the logic of the DEV_TO_MEM/MEM_TO_DEV is inverted for the
> > the drivers/dma/dw-edma/dw-edma-pcie.c platform.)
> >
> > So basically the wr_ch_cnt/rd_ch_cnt fields have been and is used as
> > the number of actually available channels, not linked-list. While the
> > notation suggested by you can be confusing, since the ll-memory allocated for
> > each channel can be split up and initialized with numerous linked lists
> > each of which is used one after another.
> >
> > I don't really see a well justified reason to additionally have the
> > @wr_ch_cnt and @rd_ch_cnt fields in the dw_edma_chip seeing the number
> > of channels can be auto-detected from the corresponding registers, except
> > that to workaround a bogus hardware. So we can keep it, but please no
> > renaming. It will only cause additional confusion.
>
> I agree that channel numbers can be obtained from the register.
> but Caller don't know the channel number before calling dw_edma_probe.
>
> Caller may not init all ll_region_wr[EDMA_MAX_WR_CH],
>
> That's the reason I need a field to indicate how many ll_region_w
> actually initialized.
>
> old wr_ch_cnt just plays the same role.

Anyway, it is not a big deal. I can skip this patch.

>
> >
> > -Sergey
> >
> > >
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > new patch at v4
> > >
> > >  drivers/dma/dw-edma/dw-edma-core.c |  4 ++--
> > >  drivers/dma/dw-edma/dw-edma-pcie.c | 12 ++++++------
> > >  include/linux/dma/edma.h           |  8 ++++----
> > >  3 files changed, 12 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > index 1abf41d49f75b..66dc650577919 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -918,11 +918,11 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > >       raw_spin_lock_init(&dw->lock);
> > >
> > >
> > > -     dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> > > +     dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
> > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
> > >       dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> > >
> > > -     dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> > > +     dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
> > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
> > >       dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> > >
> > > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > index ae42bad24dd5a..7732537f96086 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > @@ -230,14 +230,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >       chip->nr_irqs = nr_irqs;
> > >       chip->ops = &dw_edma_pcie_core_ops;
> > >
> > > -     chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > -     chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > > +     chip->ll_wr_cnt = vsec_data.wr_ch_cnt;
> > > +     chip->ll_rd_cnt = vsec_data.rd_ch_cnt;
> > >
> > >       chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > >       if (!chip->reg_base)
> > >               return -ENOMEM;
> > >
> > > -     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > > +     for (i = 0; i < chip->ll_wr_cnt; 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];
> > > @@ -262,7 +262,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >               dt_region->sz = dt_block->sz;
> > >       }
> > >
> > > -     for (i = 0; i < chip->rd_ch_cnt; i++) {
> > > +     for (i = 0; i < chip->ll_rd_cnt; 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];
> > > @@ -302,7 +302,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >               chip->reg_base);
> > >
> > >
> > > -     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > > +     for (i = 0; i < chip->ll_wr_cnt; i++) {
> > >               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,
> > > @@ -314,7 +314,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >                       chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
> > >       }
> > >
> > > -     for (i = 0; i < chip->rd_ch_cnt; i++) {
> > > +     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,
> > > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > > index e9ce652b88233..c2039246fc08c 100644
> > > --- a/include/linux/dma/edma.h
> > > +++ b/include/linux/dma/edma.h
> > > @@ -40,8 +40,8 @@ enum dw_edma_map_format {
> > >   * @nr_irqs:          total dma irq number
> > >   * @ops                       DMA channel to IRQ number mapping
> > >   * @reg_base          DMA register base address
> > > - * @wr_ch_cnt                 DMA write channel number
> > > - * @rd_ch_cnt                 DMA read channel number
> > > + * @ll_wr_cnt                 DMA write link list number
> > > + * @ll_rd_cnt                 DMA read link list number
> > >   * @rg_region                 DMA register region
> > >   * @ll_region_wr      DMA descriptor link list memory for write channel
> > >   * @ll_region_rd      DMA descriptor link list memory for read channel
> > > @@ -56,8 +56,8 @@ struct dw_edma_chip {
> > >
> > >       void __iomem            *reg_base;
> > >
> > > -     u16                     wr_ch_cnt;
> > > -     u16                     rd_ch_cnt;
> > > +     u16                     ll_wr_cnt;
> > > +     u16                     ll_rd_cnt;
> > >       /* link list address */
> > >       struct dw_edma_region   ll_region_wr[EDMA_MAX_WR_CH];
> > >       struct dw_edma_region   ll_region_rd[EDMA_MAX_RD_CH];
> > > --
> > > 2.24.0.rc1
> > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
  2022-03-09 21:12 ` [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member Frank Li
@ 2022-03-10 17:29   ` Serge Semin
  2022-03-10 17:41     ` Manivannan Sadhasivam
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-10 17:29 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:12:02PM -0600, Frank Li wrote:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> 
> The "direction" member of the "dma_slave_config" structure is deprecated.
> The clients no longer use this field to specify the direction of the slave
> channel. But in the eDMA core, this field is used to differentiate between the
> Root complex (remote) and Endpoint (local) DMA accesses.
> 
> Nevertheless, we can't differentiate between local and remote accesses without
> a dedicated flag. So let's get rid of the old check and add a new check for
> verifying the DMA operation between local and remote memory instead.
> 
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> no chang between v1 to v4
>  drivers/dma/dw-edma/dw-edma-core.c | 17 ++---------------
>  1 file changed, 2 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 507f08db1aad3..47c6a52929fcd 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -341,22 +341,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  	if (!chan->configured)
>  		return NULL;
>  
> -	switch (chan->config.direction) {
> -	case DMA_DEV_TO_MEM: /* local DMA */
> -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ)
> -			break;
> -		return NULL;
> -	case DMA_MEM_TO_DEV: /* local DMA */
> -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE)
> -			break;

> +	/* eDMA supports only read and write between local and remote memory */

The comment is a bit confusing because both cases are named as
"memory" while the permitted directions contains DEV-part, which
means "device". What I would suggest to write here is something like:
"DW eDMA supports transferring data from/to the CPU/Application memory
to/from the PCIe link partner device by injecting the PCIe MWr/MRd TLPs."

-Sergey

> +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
>  		return NULL;
> -	default: /* remote DMA */
> -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_READ)
> -			break;
> -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE)
> -			break;
> -		return NULL;
> -	}
>  
>  	if (xfer->type == EDMA_XFER_CYCLIC) {
>  		if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt)
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
  2022-03-10 17:29   ` Serge Semin
@ 2022-03-10 17:41     ` Manivannan Sadhasivam
  2022-03-10 17:52       ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-10 17:41 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Thu, Mar 10, 2022 at 08:29:30PM +0300, Serge Semin wrote:
> On Wed, Mar 09, 2022 at 03:12:02PM -0600, Frank Li wrote:
> > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > 
> > The "direction" member of the "dma_slave_config" structure is deprecated.
> > The clients no longer use this field to specify the direction of the slave
> > channel. But in the eDMA core, this field is used to differentiate between the
> > Root complex (remote) and Endpoint (local) DMA accesses.
> > 
> > Nevertheless, we can't differentiate between local and remote accesses without
> > a dedicated flag. So let's get rid of the old check and add a new check for
> > verifying the DMA operation between local and remote memory instead.
> > 
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > no chang between v1 to v4
> >  drivers/dma/dw-edma/dw-edma-core.c | 17 ++---------------
> >  1 file changed, 2 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 507f08db1aad3..47c6a52929fcd 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -341,22 +341,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> >  	if (!chan->configured)
> >  		return NULL;
> >  
> > -	switch (chan->config.direction) {
> > -	case DMA_DEV_TO_MEM: /* local DMA */
> > -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ)
> > -			break;
> > -		return NULL;
> > -	case DMA_MEM_TO_DEV: /* local DMA */
> > -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE)
> > -			break;
> 
> > +	/* eDMA supports only read and write between local and remote memory */
> 
> The comment is a bit confusing because both cases are named as
> "memory" while the permitted directions contains DEV-part, which
> means "device". What I would suggest to write here is something like:
> "DW eDMA supports transferring data from/to the CPU/Application memory
> to/from the PCIe link partner device by injecting the PCIe MWr/MRd TLPs."
> 

End of the day, you'd be transferring data between remote and local memory
only and the terms (local and remote) are also used in the databook. So I think
the comment is fine.

Thanks,
Mani

> -Sergey
> 
> > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> >  		return NULL;
> > -	default: /* remote DMA */
> > -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_READ)
> > -			break;
> > -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE)
> > -			break;
> > -		return NULL;
> > -	}
> >  
> >  	if (xfer->type == EDMA_XFER_CYCLIC) {
> >  		if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt)
> > -- 
> > 2.24.0.rc1
> > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip
  2022-03-09 21:12 ` [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip Frank Li
  2022-03-10  1:07   ` kernel test robot
  2022-03-10  1:07   ` kernel test robot
@ 2022-03-10 17:46   ` Serge Semin
  2022-03-10 17:54     ` Zhi Li
  2 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-10 17:46 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:12:03PM -0600, Frank Li wrote:
> Allow PCI EP probe DMA locally and prevent use of remote MSI
> to remote PCI host.
> 
> Add option to force 32bit DBI register access even on
> 64-bit systems. i.MX8 hardware only allowed 32bit register
> access.

Could you please split this patch up into two? These flags are
unrelated thus adding them is two unrelated changes. That can be
implicitly inferred from your commit log and the patch title.

-Sergey

> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> Change from v3 to v4
>  - None
> Change from v2 to v3
>  - rework commit message
>  - Change to DW_EDMA_CHIP_32BIT_DBI
>  - using DW_EDMA_CHIP_LOCAL control msi
>  - Apply Bjorn's comments,
>         if (!j) {
>                control |= DW_EDMA_V0_LIE;
>                if (!(chan->chip->flags & DW_EDMA_CHIP_LOCAL))
>                                control |= DW_EDMA_V0_RIE;
>         }
> 
>         if ((chan->chip->flags & DW_EDMA_CHIP_REG32BIT) ||
>               !IS_ENABLED(CONFIG_64BIT)) {
>           SET_CH_32(...);
>           SET_CH_32(...);
>        } else {
>           SET_CH_64(...);
>        }
> 
> 
> Change from v1 to v2
> - none
>  drivers/dma/dw-edma/dw-edma-v0-core.c | 20 ++++++++++++--------
>  include/linux/dma/edma.h              |  9 +++++++++
>  2 files changed, 21 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index 35f2adac93e46..00a00d68d44e7 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -301,6 +301,7 @@ u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
>  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;
> @@ -314,9 +315,11 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
>  	j = chunk->bursts_alloc;
>  	list_for_each_entry(child, &chunk->burst->list, list) {
>  		j--;
> -		if (!j)
> -			control |= (DW_EDMA_V0_LIE | DW_EDMA_V0_RIE);
> -
> +		if (!j) {
> +			control |= DW_EDMA_V0_LIE;
> +			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 */
> @@ -414,15 +417,16 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  		SET_CH_32(dw, chan->dir, chan->id, ch_control1,
>  			  (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
>  		/* Linked list */
> -		#ifdef CONFIG_64BIT
> -			SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> -				  chunk->ll_region.paddr);
> -		#else /* CONFIG_64BIT */
> +		if ((chan->dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI) ||
> +		    !IS_ENABLED(CONFIG_64BIT)) {
>  			SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
>  				  lower_32_bits(chunk->ll_region.paddr));
>  			SET_CH_32(dw, chan->dir, chan->id, llp.msb,
>  				  upper_32_bits(chunk->ll_region.paddr));
> -		#endif /* CONFIG_64BIT */
> +		} else {
> +			SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> +				  chunk->ll_region.paddr);
> +		}
>  	}
>  	/* Doorbell */
>  	SET_RW_32(dw, chan->dir, doorbell,
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index c2039246fc08c..eea11b1d9e688 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -33,6 +33,12 @@ enum dw_edma_map_format {
>  	EDMA_MF_HDMA_COMPAT = 0x5
>  };
>  
> +/* Probe EDMA engine locally and prevent generate MSI to host side*/
> +#define DW_EDMA_CHIP_LOCAL	BIT(0)
> +
> +/* Only support 32bit DBI register access */
> +#define DW_EDMA_CHIP_32BIT_DBI	BIT(1)
> +
>  /**
>   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
>   * @dev:		 struct device of the eDMA controller
> @@ -40,6 +46,8 @@ enum dw_edma_map_format {
>   * @nr_irqs:		 total dma irq number
>   * @ops			 DMA channel to IRQ number mapping
>   * @reg_base		 DMA register base address
> + * @flags		   - DW_EDMA_CHIP_LOCAL
> + *			   - DW_EDMA_CHIP_32BIT_DBI
>   * @ll_wr_cnt		 DMA write link list number
>   * @ll_rd_cnt		 DMA read link list number
>   * @rg_region		 DMA register region
> @@ -53,6 +61,7 @@ struct dw_edma_chip {
>  	int			id;
>  	int			nr_irqs;
>  	const struct dw_edma_core_ops   *ops;
> +	u32			flags;
>  
>  	void __iomem		*reg_base;
>  
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
  2022-03-10 17:41     ` Manivannan Sadhasivam
@ 2022-03-10 17:52       ` Serge Semin
  2022-03-11 17:58         ` Manivannan Sadhasivam
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-10 17:52 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Thu, Mar 10, 2022 at 11:11:59PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 10, 2022 at 08:29:30PM +0300, Serge Semin wrote:
> > On Wed, Mar 09, 2022 at 03:12:02PM -0600, Frank Li wrote:
> > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > 
> > > The "direction" member of the "dma_slave_config" structure is deprecated.
> > > The clients no longer use this field to specify the direction of the slave
> > > channel. But in the eDMA core, this field is used to differentiate between the
> > > Root complex (remote) and Endpoint (local) DMA accesses.
> > > 
> > > Nevertheless, we can't differentiate between local and remote accesses without
> > > a dedicated flag. So let's get rid of the old check and add a new check for
> > > verifying the DMA operation between local and remote memory instead.
> > > 
> > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > no chang between v1 to v4
> > >  drivers/dma/dw-edma/dw-edma-core.c | 17 ++---------------
> > >  1 file changed, 2 insertions(+), 15 deletions(-)
> > > 
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > index 507f08db1aad3..47c6a52929fcd 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -341,22 +341,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > >  	if (!chan->configured)
> > >  		return NULL;
> > >  
> > > -	switch (chan->config.direction) {
> > > -	case DMA_DEV_TO_MEM: /* local DMA */
> > > -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ)
> > > -			break;
> > > -		return NULL;
> > > -	case DMA_MEM_TO_DEV: /* local DMA */
> > > -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE)
> > > -			break;
> > 
> > > +	/* eDMA supports only read and write between local and remote memory */
> > 
> > The comment is a bit confusing because both cases are named as
> > "memory" while the permitted directions contains DEV-part, which
> > means "device". What I would suggest to write here is something like:
> > "DW eDMA supports transferring data from/to the CPU/Application memory
> > to/from the PCIe link partner device by injecting the PCIe MWr/MRd TLPs."
> > 
> 

> End of the day, you'd be transferring data between remote and local memory
> only and the terms (local and remote) are also used in the databook. So I think
> the comment is fine.

Yes, but the databook either adds a note regarding what memory it is
or it can be inferred from the text context. So at least it would be
appropriate to preserve the notes here two:
"eDMA supports only read and write between local (CPU/application) and
remote (PCIe/link partner) memory." Otherwise it's hard to understand
what memory the comment states about.

-Sergey

> 
> Thanks,
> Mani
> 
> > -Sergey
> > 
> > > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> > >  		return NULL;
> > > -	default: /* remote DMA */
> > > -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_READ)
> > > -			break;
> > > -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE)
> > > -			break;
> > > -		return NULL;
> > > -	}
> > >  
> > >  	if (xfer->type == EDMA_XFER_CYCLIC) {
> > >  		if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt)
> > > -- 
> > > 2.24.0.rc1
> > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip
  2022-03-10 17:46   ` Serge Semin
@ 2022-03-10 17:54     ` Zhi Li
  2022-03-10 18:25       ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-10 17:54 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 11:47 AM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> On Wed, Mar 09, 2022 at 03:12:03PM -0600, Frank Li wrote:
> > Allow PCI EP probe DMA locally and prevent use of remote MSI
> > to remote PCI host.
> >
> > Add option to force 32bit DBI register access even on
> > 64-bit systems. i.MX8 hardware only allowed 32bit register
> > access.
>
> Could you please split this patch up into two? These flags are
> unrelated thus adding them is two unrelated changes. That can be
> implicitly inferred from your commit log and the patch title.

I don't think it needs to be separated.  It also show why need 32bit mask to
control features and reserved futured extension capability .

The two flags were descriptions for EDMA chip features.

>
> -Sergey
>
> >
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > Change from v3 to v4
> >  - None
> > Change from v2 to v3
> >  - rework commit message
> >  - Change to DW_EDMA_CHIP_32BIT_DBI
> >  - using DW_EDMA_CHIP_LOCAL control msi
> >  - Apply Bjorn's comments,
> >         if (!j) {
> >                control |= DW_EDMA_V0_LIE;
> >                if (!(chan->chip->flags & DW_EDMA_CHIP_LOCAL))
> >                                control |= DW_EDMA_V0_RIE;
> >         }
> >
> >         if ((chan->chip->flags & DW_EDMA_CHIP_REG32BIT) ||
> >               !IS_ENABLED(CONFIG_64BIT)) {
> >           SET_CH_32(...);
> >           SET_CH_32(...);
> >        } else {
> >           SET_CH_64(...);
> >        }
> >
> >
> > Change from v1 to v2
> > - none
> >  drivers/dma/dw-edma/dw-edma-v0-core.c | 20 ++++++++++++--------
> >  include/linux/dma/edma.h              |  9 +++++++++
> >  2 files changed, 21 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > index 35f2adac93e46..00a00d68d44e7 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > @@ -301,6 +301,7 @@ u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
> >  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;
> > @@ -314,9 +315,11 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> >       j = chunk->bursts_alloc;
> >       list_for_each_entry(child, &chunk->burst->list, list) {
> >               j--;
> > -             if (!j)
> > -                     control |= (DW_EDMA_V0_LIE | DW_EDMA_V0_RIE);
> > -
> > +             if (!j) {
> > +                     control |= DW_EDMA_V0_LIE;
> > +                     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 */
> > @@ -414,15 +417,16 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> >               SET_CH_32(dw, chan->dir, chan->id, ch_control1,
> >                         (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
> >               /* Linked list */
> > -             #ifdef CONFIG_64BIT
> > -                     SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> > -                               chunk->ll_region.paddr);
> > -             #else /* CONFIG_64BIT */
> > +             if ((chan->dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI) ||
> > +                 !IS_ENABLED(CONFIG_64BIT)) {
> >                       SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
> >                                 lower_32_bits(chunk->ll_region.paddr));
> >                       SET_CH_32(dw, chan->dir, chan->id, llp.msb,
> >                                 upper_32_bits(chunk->ll_region.paddr));
> > -             #endif /* CONFIG_64BIT */
> > +             } else {
> > +                     SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> > +                               chunk->ll_region.paddr);
> > +             }
> >       }
> >       /* Doorbell */
> >       SET_RW_32(dw, chan->dir, doorbell,
> > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > index c2039246fc08c..eea11b1d9e688 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -33,6 +33,12 @@ enum dw_edma_map_format {
> >       EDMA_MF_HDMA_COMPAT = 0x5
> >  };
> >
> > +/* Probe EDMA engine locally and prevent generate MSI to host side*/
> > +#define DW_EDMA_CHIP_LOCAL   BIT(0)
> > +
> > +/* Only support 32bit DBI register access */
> > +#define DW_EDMA_CHIP_32BIT_DBI       BIT(1)
> > +
> >  /**
> >   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
> >   * @dev:              struct device of the eDMA controller
> > @@ -40,6 +46,8 @@ enum dw_edma_map_format {
> >   * @nr_irqs:          total dma irq number
> >   * @ops                       DMA channel to IRQ number mapping
> >   * @reg_base          DMA register base address
> > + * @flags               - DW_EDMA_CHIP_LOCAL
> > + *                      - DW_EDMA_CHIP_32BIT_DBI
> >   * @ll_wr_cnt                 DMA write link list number
> >   * @ll_rd_cnt                 DMA read link list number
> >   * @rg_region                 DMA register region
> > @@ -53,6 +61,7 @@ struct dw_edma_chip {
> >       int                     id;
> >       int                     nr_irqs;
> >       const struct dw_edma_core_ops   *ops;
> > +     u32                     flags;
> >
> >       void __iomem            *reg_base;
> >
> > --
> > 2.24.0.rc1
> >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip
  2022-03-10 17:54     ` Zhi Li
@ 2022-03-10 18:25       ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-10 18:25 UTC (permalink / raw)
  To: Zhi Li
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 11:54:30AM -0600, Zhi Li wrote:
> On Thu, Mar 10, 2022 at 11:47 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > On Wed, Mar 09, 2022 at 03:12:03PM -0600, Frank Li wrote:
> > > Allow PCI EP probe DMA locally and prevent use of remote MSI
> > > to remote PCI host.
> > >
> > > Add option to force 32bit DBI register access even on
> > > 64-bit systems. i.MX8 hardware only allowed 32bit register
> > > access.
> >
> > Could you please split this patch up into two? These flags are
> > unrelated thus adding them is two unrelated changes. That can be
> > implicitly inferred from your commit log and the patch title.
> 

> I don't think it needs to be separated.  It also show why need 32bit mask to
> control features and reserved futured extension capability .
> 
> The two flags were descriptions for EDMA chip features.

Both of these flags define separate platform features. Each of which
can be distinctively specific for a particular SoC, not only for the
i.MX8. Even though your log messages does mention i.MX8 hardware the
corresponding flag is defined as generic in the patch. As I said both
flags are unrelated to each other and can be independently specific to
one or another platform. So one SoC can be restricted to use 32bits
DBI IOs and do have the Synopsys PCIe End-point IP prototype kit
detected on the PCIe bus. Another SoC can have the eDMA core embedded
into the DW PCIe EP/Host controller, but with no 32-bits DBI IOs
requirement.

Secondly since both of these flags are unrelated then having a
monolithic patch as you suggest will harden the bisection procedure in
case of a bug is caused by one of these modifications. Bisecting will
lead straight to the bogus change if the patch is split up into two.

Thirdly as I said before your commit log states two distinctive
changes, which means the log can be split up into two together with
the logical changes. In addition referring to a particular change in
further commits will be more informative.

Finally please see [1] regarding the patches splitting up, logical changes,
bisection, etc.

[1] Documentation/process/submitting-patches.rst: "Separate your changes"

-Sergey

> 
> >
> > -Sergey
> >
> > >
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > Change from v3 to v4
> > >  - None
> > > Change from v2 to v3
> > >  - rework commit message
> > >  - Change to DW_EDMA_CHIP_32BIT_DBI
> > >  - using DW_EDMA_CHIP_LOCAL control msi
> > >  - Apply Bjorn's comments,
> > >         if (!j) {
> > >                control |= DW_EDMA_V0_LIE;
> > >                if (!(chan->chip->flags & DW_EDMA_CHIP_LOCAL))
> > >                                control |= DW_EDMA_V0_RIE;
> > >         }
> > >
> > >         if ((chan->chip->flags & DW_EDMA_CHIP_REG32BIT) ||
> > >               !IS_ENABLED(CONFIG_64BIT)) {
> > >           SET_CH_32(...);
> > >           SET_CH_32(...);
> > >        } else {
> > >           SET_CH_64(...);
> > >        }
> > >
> > >
> > > Change from v1 to v2
> > > - none
> > >  drivers/dma/dw-edma/dw-edma-v0-core.c | 20 ++++++++++++--------
> > >  include/linux/dma/edma.h              |  9 +++++++++
> > >  2 files changed, 21 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > index 35f2adac93e46..00a00d68d44e7 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > @@ -301,6 +301,7 @@ u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
> > >  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;
> > > @@ -314,9 +315,11 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> > >       j = chunk->bursts_alloc;
> > >       list_for_each_entry(child, &chunk->burst->list, list) {
> > >               j--;
> > > -             if (!j)
> > > -                     control |= (DW_EDMA_V0_LIE | DW_EDMA_V0_RIE);
> > > -
> > > +             if (!j) {
> > > +                     control |= DW_EDMA_V0_LIE;
> > > +                     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 */
> > > @@ -414,15 +417,16 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > >               SET_CH_32(dw, chan->dir, chan->id, ch_control1,
> > >                         (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
> > >               /* Linked list */
> > > -             #ifdef CONFIG_64BIT
> > > -                     SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> > > -                               chunk->ll_region.paddr);
> > > -             #else /* CONFIG_64BIT */
> > > +             if ((chan->dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI) ||
> > > +                 !IS_ENABLED(CONFIG_64BIT)) {
> > >                       SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
> > >                                 lower_32_bits(chunk->ll_region.paddr));
> > >                       SET_CH_32(dw, chan->dir, chan->id, llp.msb,
> > >                                 upper_32_bits(chunk->ll_region.paddr));
> > > -             #endif /* CONFIG_64BIT */
> > > +             } else {
> > > +                     SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> > > +                               chunk->ll_region.paddr);
> > > +             }
> > >       }
> > >       /* Doorbell */
> > >       SET_RW_32(dw, chan->dir, doorbell,
> > > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > > index c2039246fc08c..eea11b1d9e688 100644
> > > --- a/include/linux/dma/edma.h
> > > +++ b/include/linux/dma/edma.h
> > > @@ -33,6 +33,12 @@ enum dw_edma_map_format {
> > >       EDMA_MF_HDMA_COMPAT = 0x5
> > >  };
> > >
> > > +/* Probe EDMA engine locally and prevent generate MSI to host side*/
> > > +#define DW_EDMA_CHIP_LOCAL   BIT(0)
> > > +
> > > +/* Only support 32bit DBI register access */
> > > +#define DW_EDMA_CHIP_32BIT_DBI       BIT(1)
> > > +
> > >  /**
> > >   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
> > >   * @dev:              struct device of the eDMA controller
> > > @@ -40,6 +46,8 @@ enum dw_edma_map_format {
> > >   * @nr_irqs:          total dma irq number
> > >   * @ops                       DMA channel to IRQ number mapping
> > >   * @reg_base          DMA register base address
> > > + * @flags               - DW_EDMA_CHIP_LOCAL
> > > + *                      - DW_EDMA_CHIP_32BIT_DBI
> > >   * @ll_wr_cnt                 DMA write link list number
> > >   * @ll_rd_cnt                 DMA read link list number
> > >   * @rg_region                 DMA register region
> > > @@ -53,6 +61,7 @@ struct dw_edma_chip {
> > >       int                     id;
> > >       int                     nr_irqs;
> > >       const struct dw_edma_core_ops   *ops;
> > > +     u32                     flags;
> > >
> > >       void __iomem            *reg_base;
> > >
> > > --
> > > 2.24.0.rc1
> > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt in struct dw_edma_chip
  2022-03-10 16:51       ` Zhi Li
@ 2022-03-10 18:45         ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-10 18:45 UTC (permalink / raw)
  To: Zhi Li
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 10:51:51AM -0600, Zhi Li wrote:
> On Thu, Mar 10, 2022 at 10:26 AM Zhi Li <lznuaa@gmail.com> wrote:
> >
> > On Thu, Mar 10, 2022 at 6:37 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > On Wed, Mar 09, 2022 at 03:12:00PM -0600, Frank Li wrote:
> > > > There are same name wr(rd)_ch_cnt in struct dw_edma. EDMA driver get
> > > > write(read) channel number from register, then save these into dw_edma.
> > > > Old wr(rd)_ch_cnt in dw_edma_chip actuall means how many link list memory
> > > > are avaiable in ll_region_wr(rd)[EDMA_MAX_WR_CH]. So rename it to
> > > > ll_wr(rd)_cnt to indicate actual usage.
> > >
> > > Hmm, I am not sure you are right here. AFAICS the
> > > drivers/dma/dw-edma/dw-edma-pcie.c driver either uses a statically
> > > defined number or Rd/Wr channels or just gets the number from the
> > > specific vsec PCIe capability. Then based on that the driver just
> > > redistributes the BARs memory amongst all the detected channels in
> > > accordance with the statically defined snps_edda_data structure.
> > > Basically the BARs memory serves as the Local/CPU/Application memory
> > > for the case if the controller is embedded into the PCIe Host/EP
> > > controller. See the patches which implicitly prove that:
> > > 31fb8c1ff962 ("dmaengine: dw-edma: Improve the linked list and data blocks definition")
> > > da6e0dd54135 ("dmaengine: dw-edma: Change linked list and data blocks offset and sizes")
> > >
> > > (That's why the logic of the DEV_TO_MEM/MEM_TO_DEV is inverted for the
> > > the drivers/dma/dw-edma/dw-edma-pcie.c platform.)
> > >
> > > So basically the wr_ch_cnt/rd_ch_cnt fields have been and is used as
> > > the number of actually available channels, not linked-list. While the
> > > notation suggested by you can be confusing, since the ll-memory allocated for
> > > each channel can be split up and initialized with numerous linked lists
> > > each of which is used one after another.
> > >
> > > I don't really see a well justified reason to additionally have the
> > > @wr_ch_cnt and @rd_ch_cnt fields in the dw_edma_chip seeing the number
> > > of channels can be auto-detected from the corresponding registers, except
> > > that to workaround a bogus hardware. So we can keep it, but please no
> > > renaming. It will only cause additional confusion.
> >

> > I agree that channel numbers can be obtained from the register.
> > but Caller don't know the channel number before calling dw_edma_probe.
> >
> > Caller may not init all ll_region_wr[EDMA_MAX_WR_CH],
> >
> > That's the reason I need a field to indicate how many ll_region_w
> > actually initialized.
> >
> > old wr_ch_cnt just plays the same role.
> 
> Anyway, it is not a big deal. I can skip this patch.

Ah, finally I see what you mean here. The patch seems reasonable now. No
objection against it then.

Reviewed-by: Serge Semin <fancer.lancer@gmail.com>

-Sergey

> 
> >
> > >
> > > -Sergey
> > >
> > > >
> > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > ---
> > > > new patch at v4
> > > >
> > > >  drivers/dma/dw-edma/dw-edma-core.c |  4 ++--
> > > >  drivers/dma/dw-edma/dw-edma-pcie.c | 12 ++++++------
> > > >  include/linux/dma/edma.h           |  8 ++++----
> > > >  3 files changed, 12 insertions(+), 12 deletions(-)
> > > >
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > index 1abf41d49f75b..66dc650577919 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > @@ -918,11 +918,11 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > > >       raw_spin_lock_init(&dw->lock);
> > > >
> > > >
> > > > -     dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> > > > +     dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
> > > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
> > > >       dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> > > >
> > > > -     dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> > > > +     dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
> > > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
> > > >       dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> > > >
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > index ae42bad24dd5a..7732537f96086 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > @@ -230,14 +230,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >       chip->nr_irqs = nr_irqs;
> > > >       chip->ops = &dw_edma_pcie_core_ops;
> > > >
> > > > -     chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > > -     chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > > > +     chip->ll_wr_cnt = vsec_data.wr_ch_cnt;
> > > > +     chip->ll_rd_cnt = vsec_data.rd_ch_cnt;
> > > >
> > > >       chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > > >       if (!chip->reg_base)
> > > >               return -ENOMEM;
> > > >
> > > > -     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > > > +     for (i = 0; i < chip->ll_wr_cnt; 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];
> > > > @@ -262,7 +262,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >               dt_region->sz = dt_block->sz;
> > > >       }
> > > >
> > > > -     for (i = 0; i < chip->rd_ch_cnt; i++) {
> > > > +     for (i = 0; i < chip->ll_rd_cnt; 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];
> > > > @@ -302,7 +302,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >               chip->reg_base);
> > > >
> > > >
> > > > -     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > > > +     for (i = 0; i < chip->ll_wr_cnt; i++) {
> > > >               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,
> > > > @@ -314,7 +314,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >                       chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
> > > >       }
> > > >
> > > > -     for (i = 0; i < chip->rd_ch_cnt; i++) {
> > > > +     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,
> > > > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > > > index e9ce652b88233..c2039246fc08c 100644
> > > > --- a/include/linux/dma/edma.h
> > > > +++ b/include/linux/dma/edma.h
> > > > @@ -40,8 +40,8 @@ enum dw_edma_map_format {
> > > >   * @nr_irqs:          total dma irq number
> > > >   * @ops                       DMA channel to IRQ number mapping
> > > >   * @reg_base          DMA register base address
> > > > - * @wr_ch_cnt                 DMA write channel number
> > > > - * @rd_ch_cnt                 DMA read channel number
> > > > + * @ll_wr_cnt                 DMA write link list number
> > > > + * @ll_rd_cnt                 DMA read link list number
> > > >   * @rg_region                 DMA register region
> > > >   * @ll_region_wr      DMA descriptor link list memory for write channel
> > > >   * @ll_region_rd      DMA descriptor link list memory for read channel
> > > > @@ -56,8 +56,8 @@ struct dw_edma_chip {
> > > >
> > > >       void __iomem            *reg_base;
> > > >
> > > > -     u16                     wr_ch_cnt;
> > > > -     u16                     rd_ch_cnt;
> > > > +     u16                     ll_wr_cnt;
> > > > +     u16                     ll_rd_cnt;
> > > >       /* link list address */
> > > >       struct dw_edma_region   ll_region_wr[EDMA_MAX_WR_CH];
> > > >       struct dw_edma_region   ll_region_rd[EDMA_MAX_RD_CH];
> > > > --
> > > > 2.24.0.rc1
> > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-10 16:50     ` Zhi Li
@ 2022-03-10 19:37       ` Serge Semin
  2022-03-10 20:16         ` Zhi Li
  2022-03-11 17:46         ` Manivannan Sadhasivam
  0 siblings, 2 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-10 19:37 UTC (permalink / raw)
  To: Zhi Li
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > >
> > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > programs the source and destination addresses for read and write. Since the
> > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > issue by finding out the read operation first and program the eDMA accordingly.
> > >
> > > Cc: stable@vger.kernel.org
> > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > No change between v1 to v4
> > >
> > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > index 66dc650577919..507f08db1aad3 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > >       struct dw_edma_chunk *chunk;
> > >       struct dw_edma_burst *burst;
> > >       struct dw_edma_desc *desc;
> > > +     bool read = false;
> > >       u32 cnt = 0;
> > >       int i;
> > >
> > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > >               chunk->ll_region.sz += burst->sz;
> > >               desc->alloc_sz += burst->sz;
> > >
> > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > +             /****************************************************************
> > > +              *
> >
> > > +              *        Root Complex                           Endpoint
> > > +              * +-----------------------+             +----------------------+
> > > +              * |                       |    TX CH    |                      |
> > > +              * |                       |             |                      |
> > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > +              * |                       |             |                      |
> > > +              * |                       |             |                      |
> > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > +              * |                       |             |                      |
> > > +              * |                       |    RX CH    |                      |
> > > +              * +-----------------------+             +----------------------+
> > > +              *
> > > +              * If eDMA is controlled by the Root complex, TX channel
> > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > +              *
> > > +              * If eDMA is controlled by the endpoint, RX channel
> > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> >
> > Either I have some wrong notion about this issue, or something wrong
> > with the explanation above and with this fix below.
> >
> > From my understanding of the possible DW eDMA IP-core setups the
> > scatch above and the text below it are incorrect. Here is the way the
> > DW eDMA can be used:
> > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > CPU/Application Memory is the memory of the CPU attached to the
> > host/EP controller, while the remote (link partner) memory is the PCIe
> > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > by the Rx/Read channels.
> >
> > Note it's applicable for both Host and End-point case, when Linux is
> > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > end-point, then MEM_TO_DEV means copying data from the local CPU
> > memory into the remote memory. In general the remote memory can be
> > either some PCIe device on the bus or the Root Complex' CPU memory,
> > each of which is some remote device anyway from the Local CPU
> > perspective.
> >
> > 2) Embedded into the PCIe EP. This case is implemented in the
> > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > prototype kit. It is a normal PCIe peripheral device with eDMA
> > embedded, which CPU/Application interface is connected to some
> > embedded SRAM while remote (link partner) interface is directed
> > towards the PCIe bus. At the same time the device is setup and handled
> > by the code running on a CPU connected to the PCIe Host controller.  I
> > think that in order to preserve the normal DMA operations semantics we
> > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > host CPU perspective, since that's the side the DMA controller is
> > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > to copy data from the host CPU memory into the remote device memory.
> > It means to allocate Rx/Read channel on the eDMA controller, so one
> > would be read data from the Local CPU memory and copied it to the PCIe
> > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > from it's SRAM into the Host CPU memory.
> >
> > Please note as I understand the case 2) describes the Synopsys PCIe
> > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > a test setup with no real application, while the case 1) is a real setup
> > available on our SoC and I guess on yours.
> 

> I think yes. But Remote EP also is a one kind of usage module. Just no one
> writes an EP functional driver for it yet.  Even pci-epf-test was just
> a test function.
> I previously sent vNTB patches to implement a virtual network between
> RC and EP,
> you can look if you have interest.

AFAIU the remote EP case is the same as 1) anyway. The remote EP is
handled by its own CPU, which sets up the DW PCIe EP controller
together with eDMA synthesized into the CPU' SoC. Am I right? While
the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
FPGA with PCIe interface and eDMA IP-core installed. In that case all
the setups are performed by the PCIe Host CPU. That's the root problem
that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.

So to speak I would suggest for at least to have the scatch fixed in
accordance with the logic explained in my message.

> 
> >
> > So what I suggest in the framework of this patch is just to implement
> > the case 1) only. While the case 2) as it's an artificial one can be
> > manually handled by the DMA client drivers. BTW There aren't ones available
> > in the kernel anyway. The only exception is an old-time attempt to get
> > an eDMA IP test-driver mainlined into the kernel:
> > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > But it was long time ago. So it's unlikely to be accepted at all.
> >
> > What do you think?
> >
> > -Sergey
> >
> > > +              *
> > > +              ****************************************************************/
> > > +
> >
> > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > +                     read = true;
> >

> > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > redundant.

Am I getting a response on this comment? In accordance with that
conditional statement having dir == DMA_DEV_TO_MEM means performing
read operation. If dir equals DMA_MEM_TO_DEV then a write operation
will be performed. The code path doesn't depend on the chan->dir
value.

-Sergey

> >
> > > +
> > > +             /* Program the source and destination addresses for DMA read/write */
> > > +             if (read) {
> > >                       burst->sar = src_addr;
> > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > --
> > > 2.24.0.rc1
> > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-10 19:37       ` Serge Semin
@ 2022-03-10 20:16         ` Zhi Li
  2022-03-11 12:38           ` Serge Semin
  2022-03-11 17:46         ` Manivannan Sadhasivam
  1 sibling, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-10 20:16 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 1:38 PM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > >
> > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > programs the source and destination addresses for read and write. Since the
> > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > >
> > > > Cc: stable@vger.kernel.org
> > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > ---
> > > > No change between v1 to v4
> > > >
> > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > index 66dc650577919..507f08db1aad3 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > >       struct dw_edma_chunk *chunk;
> > > >       struct dw_edma_burst *burst;
> > > >       struct dw_edma_desc *desc;
> > > > +     bool read = false;
> > > >       u32 cnt = 0;
> > > >       int i;
> > > >
> > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > >               chunk->ll_region.sz += burst->sz;
> > > >               desc->alloc_sz += burst->sz;
> > > >
> > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > +             /****************************************************************
> > > > +              *
> > >
> > > > +              *        Root Complex                           Endpoint
> > > > +              * +-----------------------+             +----------------------+
> > > > +              * |                       |    TX CH    |                      |
> > > > +              * |                       |             |                      |
> > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > +              * |                       |             |                      |
> > > > +              * |                       |             |                      |
> > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > +              * |                       |             |                      |
> > > > +              * |                       |    RX CH    |                      |
> > > > +              * +-----------------------+             +----------------------+
> > > > +              *
> > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > +              *
> > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > >
> > > Either I have some wrong notion about this issue, or something wrong
> > > with the explanation above and with this fix below.
> > >
> > > From my understanding of the possible DW eDMA IP-core setups the
> > > scatch above and the text below it are incorrect. Here is the way the
> > > DW eDMA can be used:
> > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > CPU/Application Memory is the memory of the CPU attached to the
> > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > by the Rx/Read channels.
> > >
> > > Note it's applicable for both Host and End-point case, when Linux is
> > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > memory into the remote memory. In general the remote memory can be
> > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > each of which is some remote device anyway from the Local CPU
> > > perspective.
> > >
> > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > embedded, which CPU/Application interface is connected to some
> > > embedded SRAM while remote (link partner) interface is directed
> > > towards the PCIe bus. At the same time the device is setup and handled
> > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > think that in order to preserve the normal DMA operations semantics we
> > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > host CPU perspective, since that's the side the DMA controller is
> > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > to copy data from the host CPU memory into the remote device memory.
> > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > would be read data from the Local CPU memory and copied it to the PCIe
> > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > from it's SRAM into the Host CPU memory.
> > >
> > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > a test setup with no real application, while the case 1) is a real setup
> > > available on our SoC and I guess on yours.
> >
>
> > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > a test function.
> > I previously sent vNTB patches to implement a virtual network between
> > RC and EP,
> > you can look if you have interest.
>
> AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> handled by its own CPU, which sets up the DW PCIe EP controller
> together with eDMA synthesized into the CPU' SoC. Am I right? While
> the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> FPGA with PCIe interface and eDMA IP-core installed. In that case all
> the setups are performed by the PCIe Host CPU. That's the root problem
> that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
>
> So to speak I would suggest for at least to have the scatch fixed in
> accordance with the logic explained in my message.
>
> >
> > >
> > > So what I suggest in the framework of this patch is just to implement
> > > the case 1) only. While the case 2) as it's an artificial one can be
> > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > in the kernel anyway. The only exception is an old-time attempt to get
> > > an eDMA IP test-driver mainlined into the kernel:
> > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > But it was long time ago. So it's unlikely to be accepted at all.
> > >
> > > What do you think?
> > >
> > > -Sergey
> > >
> > > > +              *
> > > > +              ****************************************************************/
> > > > +
> > >
> > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > +                     read = true;
> > >
>
> > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > redundant.
>
> Am I getting a response on this comment? In accordance with that
> conditional statement having dir == DMA_DEV_TO_MEM means performing
> read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> will be performed. The code path doesn't depend on the chan->dir
> value.

Only dir is enough.
Remote Read,  DMA_DEV_TO_MEM, it is a write channel.
SAR is the continual address at EP Side, DAR is a scatter list. RC side

Local Read,  DMA_DEV_TO_MEM, it is a reading channel.
SAR is the continual address at RC side,  DAR is a scatter list at EP side

Actually,  both sides should support a scatter list. Like
device_prep_dma_memcpy_sg
but it is beyond this patch series.

>
> -Sergey
>
> > >
> > > > +
> > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > +             if (read) {
> > > >                       burst->sar = src_addr;
> > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > --
> > > > 2.24.0.rc1
> > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-09 21:11 ` [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures Frank Li
  2022-03-10 12:50   ` Serge Semin
@ 2022-03-10 20:20   ` Serge Semin
  2022-03-10 20:29     ` Zhi Li
  2022-03-12 19:54   ` Serge Semin
  2 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-10 20:20 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:11:57PM -0600, Frank Li wrote:
> "struct dw_edma_chip" contains an internal structure "struct dw_edma" that
> is used by the eDMA core internally. This structure should not be touched
> by the eDMA controller drivers themselves. But currently, the eDMA
> controller drivers like "dw-edma-pci" allocates and populates this
> internal structure then passes it on to eDMA core. The eDMA core further
> populates the structure and uses it. This is wrong!
> 
> Hence, move all the "struct dw_edma" specifics from controller drivers
> to the eDMA core.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> Change from v3 to v4
>  - Accept most suggestions of Serge Semin
> Change from v2 to v3
>  - none
> Change from v1 to v2
>  - rework commit message
>  - remove duplicate field in struct dw_edma
> 
>  drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
>  drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
>  drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
>  drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
>  include/linux/dma/edma.h                 | 44 +++++++++++++
>  6 files changed, 144 insertions(+), 130 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 53289927dd0d6..1abf41d49f75b 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
>  static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
>  {
>  	struct dw_edma_chan *chan = desc->chan;
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma_chip *chip = chan->dw->chip;
>  	struct dw_edma_chunk *chunk;
>  
>  	chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
> @@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
>  	 */
>  	chunk->cb = !(desc->chunks_alloc % 2);
>  	if (chan->dir == EDMA_DIR_WRITE) {
> -		chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
> -		chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
> +		chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
> +		chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
>  	} else {
> -		chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
> -		chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
> +		chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
> +		chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
>  	}
>  
>  	if (desc->chunk) {
> @@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
>  	if (chan->status != EDMA_ST_IDLE)
>  		return -EBUSY;
>  
> -	pm_runtime_get(chan->chip->dev);
> +	pm_runtime_get(chan->dw->chip->dev);
>  
>  	return 0;
>  }
> @@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
>  		cpu_relax();
>  	}
>  
> -	pm_runtime_put(chan->chip->dev);
> +	pm_runtime_put(chan->dw->chip->dev);
>  }
>  
>  static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> @@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  	}
>  
>  	INIT_LIST_HEAD(&dma->channels);
> -	for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
> +	for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
>  		chan = &dw->chan[i];
>  
>  		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> @@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  
>  		chan->vc.chan.private = dt_region;
>  
> -		chan->chip = chip;
> +		chan->dw = dw;
>  		chan->id = j;
>  		chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
>  		chan->configured = false;
> @@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  		chan->status = EDMA_ST_IDLE;
>  
>  		if (write)
> -			chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
> +			chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
>  		else
> -			chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
> +			chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
>  		chan->ll_max -= 1;
>  
>  		dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
>  			 write ? "write" : "read", j, chan->ll_max);
>  
> -		if (dw->nr_irqs == 1)
> +		if (chip->nr_irqs == 1)
>  			pos = 0;
>  		else
>  			pos = off_alloc + (j % alloc);
> @@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  		vchan_init(&chan->vc, dma);
>  
>  		if (write) {
> -			dt_region->paddr = dw->dt_region_wr[j].paddr;
> -			dt_region->vaddr = dw->dt_region_wr[j].vaddr;
> -			dt_region->sz = dw->dt_region_wr[j].sz;
> +			dt_region->paddr = chip->dt_region_wr[j].paddr;
> +			dt_region->vaddr = chip->dt_region_wr[j].vaddr;
> +			dt_region->sz = chip->dt_region_wr[j].sz;
>  		} else {
> -			dt_region->paddr = dw->dt_region_rd[j].paddr;
> -			dt_region->vaddr = dw->dt_region_rd[j].vaddr;
> -			dt_region->sz = dw->dt_region_rd[j].sz;
> +			dt_region->paddr = chip->dt_region_rd[j].paddr;
> +			dt_region->vaddr = chip->dt_region_rd[j].vaddr;
> +			dt_region->sz = chip->dt_region_rd[j].sz;
>  		}
>  
>  		dw_edma_v0_core_device_config(chan);
> @@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  
>  	ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
>  
> -	if (dw->nr_irqs < 1)
> +	if (chip->nr_irqs < 1)
>  		return -EINVAL;
>  
> -	if (dw->nr_irqs == 1) {
> +	if (chip->nr_irqs == 1) {
>  		/* Common IRQ shared among all channels */
> -		irq = dw->ops->irq_vector(dev, 0);
> +		irq = chip->ops->irq_vector(dev, 0);
>  		err = request_irq(irq, dw_edma_interrupt_common,
>  				  IRQF_SHARED, dw->name, &dw->irq[0]);
>  		if (err) {
> -			dw->nr_irqs = 0;
> +			chip->nr_irqs = 0;
>  			return err;
>  		}
>  
> @@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  			get_cached_msi_msg(irq, &dw->irq[0].msi);
>  	} else {
>  		/* Distribute IRQs equally among all channels */
> -		int tmp = dw->nr_irqs;
> +		int tmp = chip->nr_irqs;
>  
>  		while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
>  			dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
> @@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  		dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
>  
>  		for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
> -			irq = dw->ops->irq_vector(dev, i);
> +			irq = chip->ops->irq_vector(dev, i);
>  			err = request_irq(irq,
>  					  i < *wr_alloc ?
>  						dw_edma_interrupt_write :
> @@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  					  IRQF_SHARED, dw->name,
>  					  &dw->irq[i]);
>  			if (err) {
> -				dw->nr_irqs = i;
> +				chip->nr_irqs = i;
>  				return err;
>  			}
>  
> @@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  				get_cached_msi_msg(irq, &dw->irq[i].msi);
>  		}
>  
> -		dw->nr_irqs = i;
> +		chip->nr_irqs = i;
>  	}
>  
>  	return err;
> @@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	if (!dev)
>  		return -EINVAL;
>  
> -	dw = chip->dw;
> -	if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
> +	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	chip->dw = dw;
> +	dw->chip = chip;
> +
> +	if (!chip->nr_irqs || !chip->ops)
>  		return -EINVAL;
>  
>  	raw_spin_lock_init(&dw->lock);
>  
> -	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,
> +
> +	dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
>  	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
>  
> -	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
> +	dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
>  	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
>  
> @@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	/* Disable eDMA, only to establish the ideal initial conditions */
>  	dw_edma_v0_core_off(dw);
>  
> +	dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> +	if (!dw->irq)
> +		return -ENOMEM;
> +
>  	/* Request IRQs */
>  	err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
>  	if (err)
> @@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	return 0;
>  
>  err_irq_free:
> -	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> -		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> +	for (i = (chip->nr_irqs - 1); i >= 0; i--)
> +		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
>  
> -	dw->nr_irqs = 0;
> +	chip->nr_irqs = 0;
>  
>  	return err;
>  }
> @@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  	dw_edma_v0_core_off(dw);
>  
>  	/* Free irqs */
> -	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> -		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> +	for (i = (chip->nr_irqs - 1); i >= 0; i--)
> +		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
>  
>  	/* Power management */
>  	pm_runtime_disable(dev);
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index 60316d408c3e0..e254c2fc3d9cf 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -15,20 +15,12 @@
>  #include "../virt-dma.h"
>  
>  #define EDMA_LL_SZ					24
> -#define EDMA_MAX_WR_CH					8
> -#define EDMA_MAX_RD_CH					8
>  
>  enum dw_edma_dir {
>  	EDMA_DIR_WRITE = 0,
>  	EDMA_DIR_READ
>  };
>  
> -enum dw_edma_map_format {
> -	EDMA_MF_EDMA_LEGACY = 0x0,
> -	EDMA_MF_EDMA_UNROLL = 0x1,
> -	EDMA_MF_HDMA_COMPAT = 0x5
> -};
> -
>  enum dw_edma_request {
>  	EDMA_REQ_NONE = 0,
>  	EDMA_REQ_STOP,
> @@ -57,12 +49,6 @@ struct dw_edma_burst {
>  	u32				sz;
>  };
>  
> -struct dw_edma_region {
> -	phys_addr_t			paddr;
> -	void				__iomem *vaddr;
> -	size_t				sz;
> -};
> -
>  struct dw_edma_chunk {
>  	struct list_head		list;
>  	struct dw_edma_chan		*chan;
> @@ -87,7 +73,7 @@ struct dw_edma_desc {
>  
>  struct dw_edma_chan {
>  	struct virt_dma_chan		vc;
> -	struct dw_edma_chip		*chip;
> +	struct dw_edma			*dw;
>  	int				id;
>  	enum dw_edma_dir		dir;
>  
> @@ -109,10 +95,6 @@ struct dw_edma_irq {
>  	struct dw_edma			*dw;
>  };
>  
> -struct dw_edma_core_ops {
> -	int	(*irq_vector)(struct device *dev, unsigned int nr);
> -};
> -
>  struct dw_edma {
>  	char				name[20];
>  
> @@ -122,21 +104,13 @@ struct dw_edma {
>  	struct dma_device		rd_edma;
>  	u16				rd_ch_cnt;
>  
> -	struct dw_edma_region		rg_region;	/* Registers */
> -	struct dw_edma_region		ll_region_wr[EDMA_MAX_WR_CH];
> -	struct dw_edma_region		ll_region_rd[EDMA_MAX_RD_CH];
> -	struct dw_edma_region		dt_region_wr[EDMA_MAX_WR_CH];
> -	struct dw_edma_region		dt_region_rd[EDMA_MAX_RD_CH];
> -
>  	struct dw_edma_irq		*irq;
> -	int				nr_irqs;
> -
> -	enum dw_edma_map_format		mf;
>  
>  	struct dw_edma_chan		*chan;
> -	const struct dw_edma_core_ops	*ops;
>  
>  	raw_spinlock_t			lock;		/* Only for legacy */
> +
> +	struct dw_edma_chip             *chip;
>  #ifdef CONFIG_DEBUG_FS
>  	struct dentry			*debugfs;
>  #endif /* CONFIG_DEBUG_FS */
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 44f6e09bdb531..2c1c5fa4e9f28 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	struct dw_edma_pcie_data vsec_data;
>  	struct device *dev = &pdev->dev;
>  	struct dw_edma_chip *chip;
> -	struct dw_edma *dw;
>  	int err, nr_irqs;
>  	int i, mask;
>  
> @@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	if (!chip)
>  		return -ENOMEM;
>  
> -	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> -	if (!dw)
> -		return -ENOMEM;
> -
>  	/* IRQs allocation */
>  	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
>  					PCI_IRQ_MSI | PCI_IRQ_MSIX);
> @@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	}
>  
>  	/* Data structure initialization */
> -	chip->dw = dw;
>  	chip->dev = dev;
>  	chip->id = pdev->devfn;
> -	chip->irq = pdev->irq;
>  
> -	dw->mf = vsec_data.mf;
> -	dw->nr_irqs = nr_irqs;
> -	dw->ops = &dw_edma_pcie_core_ops;
> -	dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
> -	dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
> +	chip->mf = vsec_data.mf;
> +	chip->nr_irqs = nr_irqs;
> +	chip->ops = &dw_edma_pcie_core_ops;
>  
> -	dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> -	if (!dw->rg_region.vaddr)
> -		return -ENOMEM;
> +	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> +	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
>  
> -	dw->rg_region.vaddr += vsec_data.rg.off;
> -	dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
> -	dw->rg_region.paddr += vsec_data.rg.off;
> -	dw->rg_region.sz = vsec_data.rg.sz;
> +	chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> +	if (!chip->rg_region.vaddr)
> +		return -ENOMEM;
>  
> -	for (i = 0; i < dw->wr_ch_cnt; i++) {
> -		struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
> -		struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
> +	for (i = 0; i < chip->wr_ch_cnt; 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];
>  		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
>  
> @@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		dt_region->sz = dt_block->sz;
>  	}
>  
> -	for (i = 0; i < dw->rd_ch_cnt; i++) {
> -		struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
> -		struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
> +	for (i = 0; i < chip->rd_ch_cnt; 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];
>  		struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
>  
> @@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	}
>  
>  	/* Debug info */
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY)
> -		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
> -	else if (dw->mf == EDMA_MF_EDMA_UNROLL)
> -		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
> -	else if (dw->mf == EDMA_MF_HDMA_COMPAT)
> -		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
> +	if (chip->mf == EDMA_MF_EDMA_LEGACY)
> +		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
> +	else if (chip->mf == EDMA_MF_EDMA_UNROLL)
> +		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
> +	else if (chip->mf == EDMA_MF_HDMA_COMPAT)
> +		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
>  	else
> -		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
> +		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
>  
> -	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> +	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
>  		vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> -		dw->rg_region.vaddr, &dw->rg_region.paddr);
> +		chip->rg_region.vaddr);
>  
>  
> -	for (i = 0; i < dw->wr_ch_cnt; i++) {
> +	for (i = 0; i < chip->wr_ch_cnt; i++) {
>  		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, dw->ll_region_wr[i].sz,
> -			dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
> +			vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
> +			chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
> -			dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
> +			vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
> +			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
>  	}
>  
> -	for (i = 0; i < dw->rd_ch_cnt; i++) {
> +	for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
> -			dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
> +			vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
> +			chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
> -			dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
> +			vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
> +			chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
>  	}
>  
> -	pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
> +	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
>  
>  	/* Validating if PCI interrupts were enabled */
>  	if (!pci_dev_msi_enabled(pdev)) {
> @@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		return -EPERM;
>  	}
>  
> -	dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> -	if (!dw->irq)
> -		return -ENOMEM;
> -
>  	/* Starting eDMA driver */
>  	err = dw_edma_probe(chip);
>  	if (err) {
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index 329fc2e57b703..e507e076fad16 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -25,7 +25,7 @@ enum dw_edma_control {
>  
>  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  {
> -	return dw->rg_region.vaddr;
> +	return dw->chip->rg_region.vaddr;
>  }
>  
>  #define SET_32(dw, name, value)				\
> @@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  static inline struct dw_edma_v0_ch_regs __iomem *
>  __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY)
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
>  		return &(__dw_regs(dw)->type.legacy.ch);
>  
>  	if (dir == EDMA_DIR_WRITE)
> @@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
>  static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			     u32 value, void __iomem *addr)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  {
>  	u32 value;
>  
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			     u64 value, void __iomem *addr)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  {
>  	u32 value;
>  
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
>  
>  enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp;
>  
>  	tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
> @@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
>  
>  void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  
>  	SET_RW_32(dw, chan->dir, int_clear,
>  		  FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
> @@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
>  
>  void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  
>  	SET_RW_32(dw, chan->dir, int_clear,
>  		  FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
> @@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
>  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  {
>  	struct dw_edma_chan *chan = chunk->chan;
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp;
>  
>  	dw_edma_v0_core_write_chunk(chunk);
> @@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  	if (first) {
>  		/* Enable engine */
>  		SET_RW_32(dw, chan->dir, engine_en, BIT(0));
> -		if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +		if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  			switch (chan->id) {
>  			case 0:
>  				SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
> @@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  
>  int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp = 0;
>  
>  	/* MSI done addr - low, high */
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 4b3bcffd15ef1..edb7e137cb35a 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -54,7 +54,7 @@ struct debugfs_entries {
>  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  {
>  	void __iomem *reg = (void __force __iomem *)data;
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY &&
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
>  	    reg >= (void __iomem *)&regs->type.legacy.ch) {
>  		void __iomem *ptr = &regs->type.legacy.ch;
>  		u32 viewport_sel = 0;
> @@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
>  
> -	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
>  		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
> @@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
>  
> -	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
>  		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
> @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!dw)
>  		return;
>  
> -	regs = dw->rg_region.vaddr;
> +	regs = dw->chip->rg_region.vaddr;
>  	if (!regs)
>  		return;
>  
> @@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!dw->debugfs)
>  		return;
>  
> -	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
> +	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
>  	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
>  	debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
>  
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index cab6e18773dad..a9bee4aeb2eee 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -12,19 +12,63 @@
>  #include <linux/device.h>
>  #include <linux/dmaengine.h>
>  
> +#define EDMA_MAX_WR_CH                                  8
> +#define EDMA_MAX_RD_CH                                  8
> +
>  struct dw_edma;
>  
> +struct dw_edma_region {
> +	phys_addr_t	paddr;
> +	void __iomem	*vaddr;
> +	size_t		sz;
> +};
> +
> +struct dw_edma_core_ops {
> +	int (*irq_vector)(struct device *dev, unsigned int nr);
> +};
> +
> +enum dw_edma_map_format {
> +	EDMA_MF_EDMA_LEGACY = 0x0,
> +	EDMA_MF_EDMA_UNROLL = 0x1,
> +	EDMA_MF_HDMA_COMPAT = 0x5
> +};
> +
>  /**
>   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
>   * @dev:		 struct device of the eDMA controller
>   * @id:			 instance ID
>   * @irq:		 irq line
> + * @nr_irqs:		 total dma irq number
> + * @ops			 DMA channel to IRQ number mapping
> + * @wr_ch_cnt		 DMA write channel number
> + * @rd_ch_cnt		 DMA read channel number
> + * @rg_region		 DMA register region
> + * @ll_region_wr	 DMA descriptor link list memory for write channel
> + * @ll_region_rd	 DMA descriptor link list memory for read channel
> + * @mf			 DMA register map format
>   * @dw:			 struct dw_edma that is filed by dw_edma_probe()
>   */
>  struct dw_edma_chip {
>  	struct device		*dev;
>  	int			id;
>  	int			irq;
> +	int			nr_irqs;
> +	const struct dw_edma_core_ops   *ops;
> +
> +	struct dw_edma_region	rg_region;
> +
> +	u16			wr_ch_cnt;
> +	u16			rd_ch_cnt;
> +	/* link list address */
> +	struct dw_edma_region	ll_region_wr[EDMA_MAX_WR_CH];
> +	struct dw_edma_region	ll_region_rd[EDMA_MAX_RD_CH];
> +
> +	/* data region */
> +	struct dw_edma_region	dt_region_wr[EDMA_MAX_WR_CH];
> +	struct dw_edma_region	dt_region_rd[EDMA_MAX_RD_CH];
> +
> +	enum dw_edma_map_format	mf;
> +

>  	struct dw_edma		*dw;

Please drop this field from here and just change the dw_edma_probe()
prototype to returning a pointer to the struct dw_edma structure. Like
this:
struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
void dw_edma_remove(struct dw_edma *dw);

By doing so we'll be able to have the chip data being const and at least
statically defined.

-Sergey

>  };
>  
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-10 20:20   ` Serge Semin
@ 2022-03-10 20:29     ` Zhi Li
  2022-03-11 11:03       ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-10 20:29 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

 in

On Thu, Mar 10, 2022 at 2:20 PM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> On Wed, Mar 09, 2022 at 03:11:57PM -0600, Frank Li wrote:
> > "struct dw_edma_chip" contains an internal structure "struct dw_edma" that
> > is used by the eDMA core internally. This structure should not be touched
> > by the eDMA controller drivers themselves. But currently, the eDMA
> > controller drivers like "dw-edma-pci" allocates and populates this
> > internal structure then passes it on to eDMA core. The eDMA core further
> > populates the structure and uses it. This is wrong!
> >
> > Hence, move all the "struct dw_edma" specifics from controller drivers
> > to the eDMA core.
> >
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > Change from v3 to v4
> >  - Accept most suggestions of Serge Semin
> > Change from v2 to v3
> >  - none
> > Change from v1 to v2
> >  - rework commit message
> >  - remove duplicate field in struct dw_edma
> >
> >  drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
> >  drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
> >  drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
> >  drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
> >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
> >  include/linux/dma/edma.h                 | 44 +++++++++++++
> >  6 files changed, 144 insertions(+), 130 deletions(-)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 53289927dd0d6..1abf41d49f75b 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
> >  static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> >  {
> >       struct dw_edma_chan *chan = desc->chan;
> > -     struct dw_edma *dw = chan->chip->dw;
> > +     struct dw_edma_chip *chip = chan->dw->chip;
> >       struct dw_edma_chunk *chunk;
> >
> >       chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
> > @@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> >        */
> >       chunk->cb = !(desc->chunks_alloc % 2);
> >       if (chan->dir == EDMA_DIR_WRITE) {
> > -             chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
> > -             chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
> > +             chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
> > +             chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
> >       } else {
> > -             chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
> > -             chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
> > +             chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
> > +             chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
> >       }
> >
> >       if (desc->chunk) {
> > @@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
> >       if (chan->status != EDMA_ST_IDLE)
> >               return -EBUSY;
> >
> > -     pm_runtime_get(chan->chip->dev);
> > +     pm_runtime_get(chan->dw->chip->dev);
> >
> >       return 0;
> >  }
> > @@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
> >               cpu_relax();
> >       }
> >
> > -     pm_runtime_put(chan->chip->dev);
> > +     pm_runtime_put(chan->dw->chip->dev);
> >  }
> >
> >  static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > @@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> >       }
> >
> >       INIT_LIST_HEAD(&dma->channels);
> > -     for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
> > +     for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
> >               chan = &dw->chan[i];
> >
> >               dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> > @@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> >
> >               chan->vc.chan.private = dt_region;
> >
> > -             chan->chip = chip;
> > +             chan->dw = dw;
> >               chan->id = j;
> >               chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
> >               chan->configured = false;
> > @@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> >               chan->status = EDMA_ST_IDLE;
> >
> >               if (write)
> > -                     chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
> > +                     chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
> >               else
> > -                     chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
> > +                     chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
> >               chan->ll_max -= 1;
> >
> >               dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
> >                        write ? "write" : "read", j, chan->ll_max);
> >
> > -             if (dw->nr_irqs == 1)
> > +             if (chip->nr_irqs == 1)
> >                       pos = 0;
> >               else
> >                       pos = off_alloc + (j % alloc);
> > @@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> >               vchan_init(&chan->vc, dma);
> >
> >               if (write) {
> > -                     dt_region->paddr = dw->dt_region_wr[j].paddr;
> > -                     dt_region->vaddr = dw->dt_region_wr[j].vaddr;
> > -                     dt_region->sz = dw->dt_region_wr[j].sz;
> > +                     dt_region->paddr = chip->dt_region_wr[j].paddr;
> > +                     dt_region->vaddr = chip->dt_region_wr[j].vaddr;
> > +                     dt_region->sz = chip->dt_region_wr[j].sz;
> >               } else {
> > -                     dt_region->paddr = dw->dt_region_rd[j].paddr;
> > -                     dt_region->vaddr = dw->dt_region_rd[j].vaddr;
> > -                     dt_region->sz = dw->dt_region_rd[j].sz;
> > +                     dt_region->paddr = chip->dt_region_rd[j].paddr;
> > +                     dt_region->vaddr = chip->dt_region_rd[j].vaddr;
> > +                     dt_region->sz = chip->dt_region_rd[j].sz;
> >               }
> >
> >               dw_edma_v0_core_device_config(chan);
> > @@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> >
> >       ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
> >
> > -     if (dw->nr_irqs < 1)
> > +     if (chip->nr_irqs < 1)
> >               return -EINVAL;
> >
> > -     if (dw->nr_irqs == 1) {
> > +     if (chip->nr_irqs == 1) {
> >               /* Common IRQ shared among all channels */
> > -             irq = dw->ops->irq_vector(dev, 0);
> > +             irq = chip->ops->irq_vector(dev, 0);
> >               err = request_irq(irq, dw_edma_interrupt_common,
> >                                 IRQF_SHARED, dw->name, &dw->irq[0]);
> >               if (err) {
> > -                     dw->nr_irqs = 0;
> > +                     chip->nr_irqs = 0;
> >                       return err;
> >               }
> >
> > @@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> >                       get_cached_msi_msg(irq, &dw->irq[0].msi);
> >       } else {
> >               /* Distribute IRQs equally among all channels */
> > -             int tmp = dw->nr_irqs;
> > +             int tmp = chip->nr_irqs;
> >
> >               while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
> >                       dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
> > @@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> >               dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
> >
> >               for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
> > -                     irq = dw->ops->irq_vector(dev, i);
> > +                     irq = chip->ops->irq_vector(dev, i);
> >                       err = request_irq(irq,
> >                                         i < *wr_alloc ?
> >                                               dw_edma_interrupt_write :
> > @@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> >                                         IRQF_SHARED, dw->name,
> >                                         &dw->irq[i]);
> >                       if (err) {
> > -                             dw->nr_irqs = i;
> > +                             chip->nr_irqs = i;
> >                               return err;
> >                       }
> >
> > @@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> >                               get_cached_msi_msg(irq, &dw->irq[i].msi);
> >               }
> >
> > -             dw->nr_irqs = i;
> > +             chip->nr_irqs = i;
> >       }
> >
> >       return err;
> > @@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >       if (!dev)
> >               return -EINVAL;
> >
> > -     dw = chip->dw;
> > -     if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
> > +     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > +     if (!dw)
> > +             return -ENOMEM;
> > +
> > +     chip->dw = dw;
> > +     dw->chip = chip;
> > +
> > +     if (!chip->nr_irqs || !chip->ops)
> >               return -EINVAL;
> >
> >       raw_spin_lock_init(&dw->lock);
> >
> > -     dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,
> > +
> > +     dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
> >       dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> >
> > -     dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
> > +     dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
> >       dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> >
> > @@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >       /* Disable eDMA, only to establish the ideal initial conditions */
> >       dw_edma_v0_core_off(dw);
> >
> > +     dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > +     if (!dw->irq)
> > +             return -ENOMEM;
> > +
> >       /* Request IRQs */
> >       err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
> >       if (err)
> > @@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >       return 0;
> >
> >  err_irq_free:
> > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> >
> > -     dw->nr_irqs = 0;
> > +     chip->nr_irqs = 0;
> >
> >       return err;
> >  }
> > @@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> >       dw_edma_v0_core_off(dw);
> >
> >       /* Free irqs */
> > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> >
> >       /* Power management */
> >       pm_runtime_disable(dev);
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> > index 60316d408c3e0..e254c2fc3d9cf 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.h
> > +++ b/drivers/dma/dw-edma/dw-edma-core.h
> > @@ -15,20 +15,12 @@
> >  #include "../virt-dma.h"
> >
> >  #define EDMA_LL_SZ                                   24
> > -#define EDMA_MAX_WR_CH                                       8
> > -#define EDMA_MAX_RD_CH                                       8
> >
> >  enum dw_edma_dir {
> >       EDMA_DIR_WRITE = 0,
> >       EDMA_DIR_READ
> >  };
> >
> > -enum dw_edma_map_format {
> > -     EDMA_MF_EDMA_LEGACY = 0x0,
> > -     EDMA_MF_EDMA_UNROLL = 0x1,
> > -     EDMA_MF_HDMA_COMPAT = 0x5
> > -};
> > -
> >  enum dw_edma_request {
> >       EDMA_REQ_NONE = 0,
> >       EDMA_REQ_STOP,
> > @@ -57,12 +49,6 @@ struct dw_edma_burst {
> >       u32                             sz;
> >  };
> >
> > -struct dw_edma_region {
> > -     phys_addr_t                     paddr;
> > -     void                            __iomem *vaddr;
> > -     size_t                          sz;
> > -};
> > -
> >  struct dw_edma_chunk {
> >       struct list_head                list;
> >       struct dw_edma_chan             *chan;
> > @@ -87,7 +73,7 @@ struct dw_edma_desc {
> >
> >  struct dw_edma_chan {
> >       struct virt_dma_chan            vc;
> > -     struct dw_edma_chip             *chip;
> > +     struct dw_edma                  *dw;
> >       int                             id;
> >       enum dw_edma_dir                dir;
> >
> > @@ -109,10 +95,6 @@ struct dw_edma_irq {
> >       struct dw_edma                  *dw;
> >  };
> >
> > -struct dw_edma_core_ops {
> > -     int     (*irq_vector)(struct device *dev, unsigned int nr);
> > -};
> > -
> >  struct dw_edma {
> >       char                            name[20];
> >
> > @@ -122,21 +104,13 @@ struct dw_edma {
> >       struct dma_device               rd_edma;
> >       u16                             rd_ch_cnt;
> >
> > -     struct dw_edma_region           rg_region;      /* Registers */
> > -     struct dw_edma_region           ll_region_wr[EDMA_MAX_WR_CH];
> > -     struct dw_edma_region           ll_region_rd[EDMA_MAX_RD_CH];
> > -     struct dw_edma_region           dt_region_wr[EDMA_MAX_WR_CH];
> > -     struct dw_edma_region           dt_region_rd[EDMA_MAX_RD_CH];
> > -
> >       struct dw_edma_irq              *irq;
> > -     int                             nr_irqs;
> > -
> > -     enum dw_edma_map_format         mf;
> >
> >       struct dw_edma_chan             *chan;
> > -     const struct dw_edma_core_ops   *ops;
> >
> >       raw_spinlock_t                  lock;           /* Only for legacy */
> > +
> > +     struct dw_edma_chip             *chip;
> >  #ifdef CONFIG_DEBUG_FS
> >       struct dentry                   *debugfs;
> >  #endif /* CONFIG_DEBUG_FS */
> > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > index 44f6e09bdb531..2c1c5fa4e9f28 100644
> > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > @@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >       struct dw_edma_pcie_data vsec_data;
> >       struct device *dev = &pdev->dev;
> >       struct dw_edma_chip *chip;
> > -     struct dw_edma *dw;
> >       int err, nr_irqs;
> >       int i, mask;
> >
> > @@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >       if (!chip)
> >               return -ENOMEM;
> >
> > -     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > -     if (!dw)
> > -             return -ENOMEM;
> > -
> >       /* IRQs allocation */
> >       nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
> >                                       PCI_IRQ_MSI | PCI_IRQ_MSIX);
> > @@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >       }
> >
> >       /* Data structure initialization */
> > -     chip->dw = dw;
> >       chip->dev = dev;
> >       chip->id = pdev->devfn;
> > -     chip->irq = pdev->irq;
> >
> > -     dw->mf = vsec_data.mf;
> > -     dw->nr_irqs = nr_irqs;
> > -     dw->ops = &dw_edma_pcie_core_ops;
> > -     dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > -     dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > +     chip->mf = vsec_data.mf;
> > +     chip->nr_irqs = nr_irqs;
> > +     chip->ops = &dw_edma_pcie_core_ops;
> >
> > -     dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > -     if (!dw->rg_region.vaddr)
> > -             return -ENOMEM;
> > +     chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > +     chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> >
> > -     dw->rg_region.vaddr += vsec_data.rg.off;
> > -     dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
> > -     dw->rg_region.paddr += vsec_data.rg.off;
> > -     dw->rg_region.sz = vsec_data.rg.sz;
> > +     chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > +     if (!chip->rg_region.vaddr)
> > +             return -ENOMEM;
> >
> > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > -             struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
> > -             struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
> > +     for (i = 0; i < chip->wr_ch_cnt; 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];
> >               struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
> >
> > @@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >               dt_region->sz = dt_block->sz;
> >       }
> >
> > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > -             struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
> > -             struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
> > +     for (i = 0; i < chip->rd_ch_cnt; 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];
> >               struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
> >
> > @@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >       }
> >
> >       /* Debug info */
> > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > -             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
> > -     else if (dw->mf == EDMA_MF_EDMA_UNROLL)
> > -             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
> > -     else if (dw->mf == EDMA_MF_HDMA_COMPAT)
> > -             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
> > +     if (chip->mf == EDMA_MF_EDMA_LEGACY)
> > +             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
> > +     else if (chip->mf == EDMA_MF_EDMA_UNROLL)
> > +             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
> > +     else if (chip->mf == EDMA_MF_HDMA_COMPAT)
> > +             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
> >       else
> > -             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
> > +             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
> >
> > -     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > +     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
> >               vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> > -             dw->rg_region.vaddr, &dw->rg_region.paddr);
> > +             chip->rg_region.vaddr);
> >
> >
> > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > +     for (i = 0; i < chip->wr_ch_cnt; i++) {
> >               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, dw->ll_region_wr[i].sz,
> > -                     dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
> > +                     vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
> > +                     chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
> > -                     dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
> > +                     vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
> > +                     chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
> >       }
> >
> > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > +     for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
> > -                     dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
> > +                     vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
> > +                     chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
> > -                     dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
> > +                     vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
> > +                     chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
> >       }
> >
> > -     pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
> > +     pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
> >
> >       /* Validating if PCI interrupts were enabled */
> >       if (!pci_dev_msi_enabled(pdev)) {
> > @@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >               return -EPERM;
> >       }
> >
> > -     dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > -     if (!dw->irq)
> > -             return -ENOMEM;
> > -
> >       /* Starting eDMA driver */
> >       err = dw_edma_probe(chip);
> >       if (err) {
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > index 329fc2e57b703..e507e076fad16 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > @@ -25,7 +25,7 @@ enum dw_edma_control {
> >
> >  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> >  {
> > -     return dw->rg_region.vaddr;
> > +     return dw->chip->rg_region.vaddr;
> >  }
> >
> >  #define SET_32(dw, name, value)                              \
> > @@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> >  static inline struct dw_edma_v0_ch_regs __iomem *
> >  __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> >  {
> > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
> >               return &(__dw_regs(dw)->type.legacy.ch);
> >
> >       if (dir == EDMA_DIR_WRITE)
> > @@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> >  static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >                            u32 value, void __iomem *addr)
> >  {
> > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> >               u32 viewport_sel;
> >               unsigned long flags;
> >
> > @@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  {
> >       u32 value;
> >
> > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> >               u32 viewport_sel;
> >               unsigned long flags;
> >
> > @@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >                            u64 value, void __iomem *addr)
> >  {
> > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> >               u32 viewport_sel;
> >               unsigned long flags;
> >
> > @@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  {
> >       u32 value;
> >
> > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> >               u32 viewport_sel;
> >               unsigned long flags;
> >
> > @@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
> >
> >  enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> >  {
> > -     struct dw_edma *dw = chan->chip->dw;
> > +     struct dw_edma *dw = chan->dw;
> >       u32 tmp;
> >
> >       tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
> > @@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> >
> >  void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> >  {
> > -     struct dw_edma *dw = chan->chip->dw;
> > +     struct dw_edma *dw = chan->dw;
> >
> >       SET_RW_32(dw, chan->dir, int_clear,
> >                 FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
> > @@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> >
> >  void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
> >  {
> > -     struct dw_edma *dw = chan->chip->dw;
> > +     struct dw_edma *dw = chan->dw;
> >
> >       SET_RW_32(dw, chan->dir, int_clear,
> >                 FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
> > @@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> >  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> >  {
> >       struct dw_edma_chan *chan = chunk->chan;
> > -     struct dw_edma *dw = chan->chip->dw;
> > +     struct dw_edma *dw = chan->dw;
> >       u32 tmp;
> >
> >       dw_edma_v0_core_write_chunk(chunk);
> > @@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> >       if (first) {
> >               /* Enable engine */
> >               SET_RW_32(dw, chan->dir, engine_en, BIT(0));
> > -             if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > +             if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> >                       switch (chan->id) {
> >                       case 0:
> >                               SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
> > @@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> >
> >  int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
> >  {
> > -     struct dw_edma *dw = chan->chip->dw;
> > +     struct dw_edma *dw = chan->dw;
> >       u32 tmp = 0;
> >
> >       /* MSI done addr - low, high */
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > index 4b3bcffd15ef1..edb7e137cb35a 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > @@ -54,7 +54,7 @@ struct debugfs_entries {
> >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> >  {
> >       void __iomem *reg = (void __force __iomem *)data;
> > -     if (dw->mf == EDMA_MF_EDMA_LEGACY &&
> > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
> >           reg >= (void __iomem *)&regs->type.legacy.ch) {
> >               void __iomem *ptr = &regs->type.legacy.ch;
> >               u32 viewport_sel = 0;
> > @@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
> >       nr_entries = ARRAY_SIZE(debugfs_regs);
> >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> >
> > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> >                                          regs_dir);
> > @@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
> >       nr_entries = ARRAY_SIZE(debugfs_regs);
> >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> >
> > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> >                                          regs_dir);
> > @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> >       if (!dw)
> >               return;
> >
> > -     regs = dw->rg_region.vaddr;
> > +     regs = dw->chip->rg_region.vaddr;
> >       if (!regs)
> >               return;
> >
> > @@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> >       if (!dw->debugfs)
> >               return;
> >
> > -     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
> > +     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
> >       debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
> >       debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
> >
> > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > index cab6e18773dad..a9bee4aeb2eee 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -12,19 +12,63 @@
> >  #include <linux/device.h>
> >  #include <linux/dmaengine.h>
> >
> > +#define EDMA_MAX_WR_CH                                  8
> > +#define EDMA_MAX_RD_CH                                  8
> > +
> >  struct dw_edma;
> >
> > +struct dw_edma_region {
> > +     phys_addr_t     paddr;
> > +     void __iomem    *vaddr;
> > +     size_t          sz;
> > +};
> > +
> > +struct dw_edma_core_ops {
> > +     int (*irq_vector)(struct device *dev, unsigned int nr);
> > +};
> > +
> > +enum dw_edma_map_format {
> > +     EDMA_MF_EDMA_LEGACY = 0x0,
> > +     EDMA_MF_EDMA_UNROLL = 0x1,
> > +     EDMA_MF_HDMA_COMPAT = 0x5
> > +};
> > +
> >  /**
> >   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
> >   * @dev:              struct device of the eDMA controller
> >   * @id:                       instance ID
> >   * @irq:              irq line
> > + * @nr_irqs:          total dma irq number
> > + * @ops                       DMA channel to IRQ number mapping
> > + * @wr_ch_cnt                 DMA write channel number
> > + * @rd_ch_cnt                 DMA read channel number
> > + * @rg_region                 DMA register region
> > + * @ll_region_wr      DMA descriptor link list memory for write channel
> > + * @ll_region_rd      DMA descriptor link list memory for read channel
> > + * @mf                        DMA register map format
> >   * @dw:                       struct dw_edma that is filed by dw_edma_probe()
> >   */
> >  struct dw_edma_chip {
> >       struct device           *dev;
> >       int                     id;
> >       int                     irq;
> > +     int                     nr_irqs;
> > +     const struct dw_edma_core_ops   *ops;
> > +
> > +     struct dw_edma_region   rg_region;
> > +
> > +     u16                     wr_ch_cnt;
> > +     u16                     rd_ch_cnt;
> > +     /* link list address */
> > +     struct dw_edma_region   ll_region_wr[EDMA_MAX_WR_CH];
> > +     struct dw_edma_region   ll_region_rd[EDMA_MAX_RD_CH];
> > +
> > +     /* data region */
> > +     struct dw_edma_region   dt_region_wr[EDMA_MAX_WR_CH];
> > +     struct dw_edma_region   dt_region_rd[EDMA_MAX_RD_CH];
> > +
> > +     enum dw_edma_map_format mf;
> > +
>
> >       struct dw_edma          *dw;
>
> Please drop this field from here and just change the dw_edma_probe()
> prototype to returning a pointer to the struct dw_edma structure. Like
> this:
> struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
> void dw_edma_remove(struct dw_edma *dw);

Actually, I don't think it is good to drop it now.

struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);

Users likely put struct dw_edma_chip in stack.
foo()
{
        struct dw_edma_chip chip
        dw = dw_edma_proble(&chip);
}

but now, edma_core_driver still does not save chip information to dw_edma

>
> By doing so we'll be able to have the chip data being const and at least
> statically defined.
>
> -Sergey
>
> >  };
> >
> > --
> > 2.24.0.rc1
> >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-10 20:29     ` Zhi Li
@ 2022-03-11 11:03       ` Serge Semin
  2022-03-11 15:29         ` Zhi Li
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-11 11:03 UTC (permalink / raw)
  To: Zhi Li
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Thu, Mar 10, 2022 at 02:29:15PM -0600, Zhi Li wrote:
>  in
> 
> On Thu, Mar 10, 2022 at 2:20 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > On Wed, Mar 09, 2022 at 03:11:57PM -0600, Frank Li wrote:
> > > "struct dw_edma_chip" contains an internal structure "struct dw_edma" that
> > > is used by the eDMA core internally. This structure should not be touched
> > > by the eDMA controller drivers themselves. But currently, the eDMA
> > > controller drivers like "dw-edma-pci" allocates and populates this
> > > internal structure then passes it on to eDMA core. The eDMA core further
> > > populates the structure and uses it. This is wrong!
> > >
> > > Hence, move all the "struct dw_edma" specifics from controller drivers
> > > to the eDMA core.
> > >
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > Change from v3 to v4
> > >  - Accept most suggestions of Serge Semin
> > > Change from v2 to v3
> > >  - none
> > > Change from v1 to v2
> > >  - rework commit message
> > >  - remove duplicate field in struct dw_edma
> > >
> > >  drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
> > >  drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
> > >  drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
> > >  drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
> > >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
> > >  include/linux/dma/edma.h                 | 44 +++++++++++++
> > >  6 files changed, 144 insertions(+), 130 deletions(-)
> > >
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > index 53289927dd0d6..1abf41d49f75b 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
> > >  static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> > >  {
> > >       struct dw_edma_chan *chan = desc->chan;
> > > -     struct dw_edma *dw = chan->chip->dw;
> > > +     struct dw_edma_chip *chip = chan->dw->chip;
> > >       struct dw_edma_chunk *chunk;
> > >
> > >       chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
> > > @@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> > >        */
> > >       chunk->cb = !(desc->chunks_alloc % 2);
> > >       if (chan->dir == EDMA_DIR_WRITE) {
> > > -             chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
> > > -             chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
> > > +             chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
> > > +             chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
> > >       } else {
> > > -             chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
> > > -             chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
> > > +             chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
> > > +             chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
> > >       }
> > >
> > >       if (desc->chunk) {
> > > @@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
> > >       if (chan->status != EDMA_ST_IDLE)
> > >               return -EBUSY;
> > >
> > > -     pm_runtime_get(chan->chip->dev);
> > > +     pm_runtime_get(chan->dw->chip->dev);
> > >
> > >       return 0;
> > >  }
> > > @@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
> > >               cpu_relax();
> > >       }
> > >
> > > -     pm_runtime_put(chan->chip->dev);
> > > +     pm_runtime_put(chan->dw->chip->dev);
> > >  }
> > >
> > >  static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > @@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > >       }
> > >
> > >       INIT_LIST_HEAD(&dma->channels);
> > > -     for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
> > > +     for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
> > >               chan = &dw->chan[i];
> > >
> > >               dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> > > @@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > >
> > >               chan->vc.chan.private = dt_region;
> > >
> > > -             chan->chip = chip;
> > > +             chan->dw = dw;
> > >               chan->id = j;
> > >               chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
> > >               chan->configured = false;
> > > @@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > >               chan->status = EDMA_ST_IDLE;
> > >
> > >               if (write)
> > > -                     chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
> > > +                     chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
> > >               else
> > > -                     chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
> > > +                     chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
> > >               chan->ll_max -= 1;
> > >
> > >               dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
> > >                        write ? "write" : "read", j, chan->ll_max);
> > >
> > > -             if (dw->nr_irqs == 1)
> > > +             if (chip->nr_irqs == 1)
> > >                       pos = 0;
> > >               else
> > >                       pos = off_alloc + (j % alloc);
> > > @@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > >               vchan_init(&chan->vc, dma);
> > >
> > >               if (write) {
> > > -                     dt_region->paddr = dw->dt_region_wr[j].paddr;
> > > -                     dt_region->vaddr = dw->dt_region_wr[j].vaddr;
> > > -                     dt_region->sz = dw->dt_region_wr[j].sz;
> > > +                     dt_region->paddr = chip->dt_region_wr[j].paddr;
> > > +                     dt_region->vaddr = chip->dt_region_wr[j].vaddr;
> > > +                     dt_region->sz = chip->dt_region_wr[j].sz;
> > >               } else {
> > > -                     dt_region->paddr = dw->dt_region_rd[j].paddr;
> > > -                     dt_region->vaddr = dw->dt_region_rd[j].vaddr;
> > > -                     dt_region->sz = dw->dt_region_rd[j].sz;
> > > +                     dt_region->paddr = chip->dt_region_rd[j].paddr;
> > > +                     dt_region->vaddr = chip->dt_region_rd[j].vaddr;
> > > +                     dt_region->sz = chip->dt_region_rd[j].sz;
> > >               }
> > >
> > >               dw_edma_v0_core_device_config(chan);
> > > @@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > >
> > >       ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
> > >
> > > -     if (dw->nr_irqs < 1)
> > > +     if (chip->nr_irqs < 1)
> > >               return -EINVAL;
> > >
> > > -     if (dw->nr_irqs == 1) {
> > > +     if (chip->nr_irqs == 1) {
> > >               /* Common IRQ shared among all channels */
> > > -             irq = dw->ops->irq_vector(dev, 0);
> > > +             irq = chip->ops->irq_vector(dev, 0);
> > >               err = request_irq(irq, dw_edma_interrupt_common,
> > >                                 IRQF_SHARED, dw->name, &dw->irq[0]);
> > >               if (err) {
> > > -                     dw->nr_irqs = 0;
> > > +                     chip->nr_irqs = 0;
> > >                       return err;
> > >               }
> > >
> > > @@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > >                       get_cached_msi_msg(irq, &dw->irq[0].msi);
> > >       } else {
> > >               /* Distribute IRQs equally among all channels */
> > > -             int tmp = dw->nr_irqs;
> > > +             int tmp = chip->nr_irqs;
> > >
> > >               while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
> > >                       dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
> > > @@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > >               dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
> > >
> > >               for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
> > > -                     irq = dw->ops->irq_vector(dev, i);
> > > +                     irq = chip->ops->irq_vector(dev, i);
> > >                       err = request_irq(irq,
> > >                                         i < *wr_alloc ?
> > >                                               dw_edma_interrupt_write :
> > > @@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > >                                         IRQF_SHARED, dw->name,
> > >                                         &dw->irq[i]);
> > >                       if (err) {
> > > -                             dw->nr_irqs = i;
> > > +                             chip->nr_irqs = i;
> > >                               return err;
> > >                       }
> > >
> > > @@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > >                               get_cached_msi_msg(irq, &dw->irq[i].msi);
> > >               }
> > >
> > > -             dw->nr_irqs = i;
> > > +             chip->nr_irqs = i;
> > >       }
> > >
> > >       return err;
> > > @@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > >       if (!dev)
> > >               return -EINVAL;
> > >
> > > -     dw = chip->dw;
> > > -     if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
> > > +     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > > +     if (!dw)
> > > +             return -ENOMEM;
> > > +
> > > +     chip->dw = dw;
> > > +     dw->chip = chip;
> > > +
> > > +     if (!chip->nr_irqs || !chip->ops)
> > >               return -EINVAL;
> > >
> > >       raw_spin_lock_init(&dw->lock);
> > >
> > > -     dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,
> > > +
> > > +     dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
> > >       dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> > >
> > > -     dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
> > > +     dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
> > >       dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> > >
> > > @@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > >       /* Disable eDMA, only to establish the ideal initial conditions */
> > >       dw_edma_v0_core_off(dw);
> > >
> > > +     dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > > +     if (!dw->irq)
> > > +             return -ENOMEM;
> > > +
> > >       /* Request IRQs */
> > >       err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
> > >       if (err)
> > > @@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > >       return 0;
> > >
> > >  err_irq_free:
> > > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> > >
> > > -     dw->nr_irqs = 0;
> > > +     chip->nr_irqs = 0;
> > >
> > >       return err;
> > >  }
> > > @@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> > >       dw_edma_v0_core_off(dw);
> > >
> > >       /* Free irqs */
> > > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> > >
> > >       /* Power management */
> > >       pm_runtime_disable(dev);
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> > > index 60316d408c3e0..e254c2fc3d9cf 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.h
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.h
> > > @@ -15,20 +15,12 @@
> > >  #include "../virt-dma.h"
> > >
> > >  #define EDMA_LL_SZ                                   24
> > > -#define EDMA_MAX_WR_CH                                       8
> > > -#define EDMA_MAX_RD_CH                                       8
> > >
> > >  enum dw_edma_dir {
> > >       EDMA_DIR_WRITE = 0,
> > >       EDMA_DIR_READ
> > >  };
> > >
> > > -enum dw_edma_map_format {
> > > -     EDMA_MF_EDMA_LEGACY = 0x0,
> > > -     EDMA_MF_EDMA_UNROLL = 0x1,
> > > -     EDMA_MF_HDMA_COMPAT = 0x5
> > > -};
> > > -
> > >  enum dw_edma_request {
> > >       EDMA_REQ_NONE = 0,
> > >       EDMA_REQ_STOP,
> > > @@ -57,12 +49,6 @@ struct dw_edma_burst {
> > >       u32                             sz;
> > >  };
> > >
> > > -struct dw_edma_region {
> > > -     phys_addr_t                     paddr;
> > > -     void                            __iomem *vaddr;
> > > -     size_t                          sz;
> > > -};
> > > -
> > >  struct dw_edma_chunk {
> > >       struct list_head                list;
> > >       struct dw_edma_chan             *chan;
> > > @@ -87,7 +73,7 @@ struct dw_edma_desc {
> > >
> > >  struct dw_edma_chan {
> > >       struct virt_dma_chan            vc;
> > > -     struct dw_edma_chip             *chip;
> > > +     struct dw_edma                  *dw;
> > >       int                             id;
> > >       enum dw_edma_dir                dir;
> > >
> > > @@ -109,10 +95,6 @@ struct dw_edma_irq {
> > >       struct dw_edma                  *dw;
> > >  };
> > >
> > > -struct dw_edma_core_ops {
> > > -     int     (*irq_vector)(struct device *dev, unsigned int nr);
> > > -};
> > > -
> > >  struct dw_edma {
> > >       char                            name[20];
> > >
> > > @@ -122,21 +104,13 @@ struct dw_edma {
> > >       struct dma_device               rd_edma;
> > >       u16                             rd_ch_cnt;
> > >
> > > -     struct dw_edma_region           rg_region;      /* Registers */
> > > -     struct dw_edma_region           ll_region_wr[EDMA_MAX_WR_CH];
> > > -     struct dw_edma_region           ll_region_rd[EDMA_MAX_RD_CH];
> > > -     struct dw_edma_region           dt_region_wr[EDMA_MAX_WR_CH];
> > > -     struct dw_edma_region           dt_region_rd[EDMA_MAX_RD_CH];
> > > -
> > >       struct dw_edma_irq              *irq;
> > > -     int                             nr_irqs;
> > > -
> > > -     enum dw_edma_map_format         mf;
> > >
> > >       struct dw_edma_chan             *chan;
> > > -     const struct dw_edma_core_ops   *ops;
> > >
> > >       raw_spinlock_t                  lock;           /* Only for legacy */
> > > +
> > > +     struct dw_edma_chip             *chip;
> > >  #ifdef CONFIG_DEBUG_FS
> > >       struct dentry                   *debugfs;
> > >  #endif /* CONFIG_DEBUG_FS */
> > > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > index 44f6e09bdb531..2c1c5fa4e9f28 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > @@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >       struct dw_edma_pcie_data vsec_data;
> > >       struct device *dev = &pdev->dev;
> > >       struct dw_edma_chip *chip;
> > > -     struct dw_edma *dw;
> > >       int err, nr_irqs;
> > >       int i, mask;
> > >
> > > @@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >       if (!chip)
> > >               return -ENOMEM;
> > >
> > > -     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > > -     if (!dw)
> > > -             return -ENOMEM;
> > > -
> > >       /* IRQs allocation */
> > >       nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
> > >                                       PCI_IRQ_MSI | PCI_IRQ_MSIX);
> > > @@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >       }
> > >
> > >       /* Data structure initialization */
> > > -     chip->dw = dw;
> > >       chip->dev = dev;
> > >       chip->id = pdev->devfn;
> > > -     chip->irq = pdev->irq;
> > >
> > > -     dw->mf = vsec_data.mf;
> > > -     dw->nr_irqs = nr_irqs;
> > > -     dw->ops = &dw_edma_pcie_core_ops;
> > > -     dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > -     dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > > +     chip->mf = vsec_data.mf;
> > > +     chip->nr_irqs = nr_irqs;
> > > +     chip->ops = &dw_edma_pcie_core_ops;
> > >
> > > -     dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > > -     if (!dw->rg_region.vaddr)
> > > -             return -ENOMEM;
> > > +     chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > +     chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > >
> > > -     dw->rg_region.vaddr += vsec_data.rg.off;
> > > -     dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
> > > -     dw->rg_region.paddr += vsec_data.rg.off;
> > > -     dw->rg_region.sz = vsec_data.rg.sz;
> > > +     chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > > +     if (!chip->rg_region.vaddr)
> > > +             return -ENOMEM;
> > >
> > > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > > -             struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
> > > -             struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
> > > +     for (i = 0; i < chip->wr_ch_cnt; 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];
> > >               struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
> > >
> > > @@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >               dt_region->sz = dt_block->sz;
> > >       }
> > >
> > > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > > -             struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
> > > -             struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
> > > +     for (i = 0; i < chip->rd_ch_cnt; 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];
> > >               struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
> > >
> > > @@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >       }
> > >
> > >       /* Debug info */
> > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > > -             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
> > > -     else if (dw->mf == EDMA_MF_EDMA_UNROLL)
> > > -             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
> > > -     else if (dw->mf == EDMA_MF_HDMA_COMPAT)
> > > -             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
> > > +     if (chip->mf == EDMA_MF_EDMA_LEGACY)
> > > +             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
> > > +     else if (chip->mf == EDMA_MF_EDMA_UNROLL)
> > > +             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
> > > +     else if (chip->mf == EDMA_MF_HDMA_COMPAT)
> > > +             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
> > >       else
> > > -             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
> > > +             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
> > >
> > > -     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > > +     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
> > >               vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> > > -             dw->rg_region.vaddr, &dw->rg_region.paddr);
> > > +             chip->rg_region.vaddr);
> > >
> > >
> > > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > > +     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > >               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, dw->ll_region_wr[i].sz,
> > > -                     dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
> > > +                     vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
> > > +                     chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
> > > -                     dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
> > > +                     vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
> > > +                     chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
> > >       }
> > >
> > > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > > +     for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
> > > -                     dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
> > > +                     vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
> > > +                     chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
> > > -                     dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
> > > +                     vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
> > > +                     chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
> > >       }
> > >
> > > -     pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
> > > +     pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
> > >
> > >       /* Validating if PCI interrupts were enabled */
> > >       if (!pci_dev_msi_enabled(pdev)) {
> > > @@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > >               return -EPERM;
> > >       }
> > >
> > > -     dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > > -     if (!dw->irq)
> > > -             return -ENOMEM;
> > > -
> > >       /* Starting eDMA driver */
> > >       err = dw_edma_probe(chip);
> > >       if (err) {
> > > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > index 329fc2e57b703..e507e076fad16 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > @@ -25,7 +25,7 @@ enum dw_edma_control {
> > >
> > >  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> > >  {
> > > -     return dw->rg_region.vaddr;
> > > +     return dw->chip->rg_region.vaddr;
> > >  }
> > >
> > >  #define SET_32(dw, name, value)                              \
> > > @@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> > >  static inline struct dw_edma_v0_ch_regs __iomem *
> > >  __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> > >  {
> > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
> > >               return &(__dw_regs(dw)->type.legacy.ch);
> > >
> > >       if (dir == EDMA_DIR_WRITE)
> > > @@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> > >  static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > >                            u32 value, void __iomem *addr)
> > >  {
> > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > >               u32 viewport_sel;
> > >               unsigned long flags;
> > >
> > > @@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > >  {
> > >       u32 value;
> > >
> > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > >               u32 viewport_sel;
> > >               unsigned long flags;
> > >
> > > @@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > >  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > >                            u64 value, void __iomem *addr)
> > >  {
> > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > >               u32 viewport_sel;
> > >               unsigned long flags;
> > >
> > > @@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > >  {
> > >       u32 value;
> > >
> > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > >               u32 viewport_sel;
> > >               unsigned long flags;
> > >
> > > @@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
> > >
> > >  enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> > >  {
> > > -     struct dw_edma *dw = chan->chip->dw;
> > > +     struct dw_edma *dw = chan->dw;
> > >       u32 tmp;
> > >
> > >       tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
> > > @@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> > >
> > >  void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> > >  {
> > > -     struct dw_edma *dw = chan->chip->dw;
> > > +     struct dw_edma *dw = chan->dw;
> > >
> > >       SET_RW_32(dw, chan->dir, int_clear,
> > >                 FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
> > > @@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> > >
> > >  void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
> > >  {
> > > -     struct dw_edma *dw = chan->chip->dw;
> > > +     struct dw_edma *dw = chan->dw;
> > >
> > >       SET_RW_32(dw, chan->dir, int_clear,
> > >                 FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
> > > @@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> > >  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > >  {
> > >       struct dw_edma_chan *chan = chunk->chan;
> > > -     struct dw_edma *dw = chan->chip->dw;
> > > +     struct dw_edma *dw = chan->dw;
> > >       u32 tmp;
> > >
> > >       dw_edma_v0_core_write_chunk(chunk);
> > > @@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > >       if (first) {
> > >               /* Enable engine */
> > >               SET_RW_32(dw, chan->dir, engine_en, BIT(0));
> > > -             if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > +             if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > >                       switch (chan->id) {
> > >                       case 0:
> > >                               SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
> > > @@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > >
> > >  int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
> > >  {
> > > -     struct dw_edma *dw = chan->chip->dw;
> > > +     struct dw_edma *dw = chan->dw;
> > >       u32 tmp = 0;
> > >
> > >       /* MSI done addr - low, high */
> > > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > index 4b3bcffd15ef1..edb7e137cb35a 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > @@ -54,7 +54,7 @@ struct debugfs_entries {
> > >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> > >  {
> > >       void __iomem *reg = (void __force __iomem *)data;
> > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY &&
> > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
> > >           reg >= (void __iomem *)&regs->type.legacy.ch) {
> > >               void __iomem *ptr = &regs->type.legacy.ch;
> > >               u32 viewport_sel = 0;
> > > @@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
> > >       nr_entries = ARRAY_SIZE(debugfs_regs);
> > >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> > >
> > > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> > >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> > >                                          regs_dir);
> > > @@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
> > >       nr_entries = ARRAY_SIZE(debugfs_regs);
> > >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> > >
> > > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> > >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> > >                                          regs_dir);
> > > @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> > >       if (!dw)
> > >               return;
> > >
> > > -     regs = dw->rg_region.vaddr;
> > > +     regs = dw->chip->rg_region.vaddr;
> > >       if (!regs)
> > >               return;
> > >
> > > @@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> > >       if (!dw->debugfs)
> > >               return;
> > >
> > > -     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
> > > +     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
> > >       debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
> > >       debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
> > >
> > > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > > index cab6e18773dad..a9bee4aeb2eee 100644
> > > --- a/include/linux/dma/edma.h
> > > +++ b/include/linux/dma/edma.h
> > > @@ -12,19 +12,63 @@
> > >  #include <linux/device.h>
> > >  #include <linux/dmaengine.h>
> > >
> > > +#define EDMA_MAX_WR_CH                                  8
> > > +#define EDMA_MAX_RD_CH                                  8
> > > +
> > >  struct dw_edma;
> > >
> > > +struct dw_edma_region {
> > > +     phys_addr_t     paddr;
> > > +     void __iomem    *vaddr;
> > > +     size_t          sz;
> > > +};
> > > +
> > > +struct dw_edma_core_ops {
> > > +     int (*irq_vector)(struct device *dev, unsigned int nr);
> > > +};
> > > +
> > > +enum dw_edma_map_format {
> > > +     EDMA_MF_EDMA_LEGACY = 0x0,
> > > +     EDMA_MF_EDMA_UNROLL = 0x1,
> > > +     EDMA_MF_HDMA_COMPAT = 0x5
> > > +};
> > > +
> > >  /**
> > >   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
> > >   * @dev:              struct device of the eDMA controller
> > >   * @id:                       instance ID
> > >   * @irq:              irq line
> > > + * @nr_irqs:          total dma irq number
> > > + * @ops                       DMA channel to IRQ number mapping
> > > + * @wr_ch_cnt                 DMA write channel number
> > > + * @rd_ch_cnt                 DMA read channel number
> > > + * @rg_region                 DMA register region
> > > + * @ll_region_wr      DMA descriptor link list memory for write channel
> > > + * @ll_region_rd      DMA descriptor link list memory for read channel
> > > + * @mf                        DMA register map format
> > >   * @dw:                       struct dw_edma that is filed by dw_edma_probe()
> > >   */
> > >  struct dw_edma_chip {
> > >       struct device           *dev;
> > >       int                     id;
> > >       int                     irq;
> > > +     int                     nr_irqs;
> > > +     const struct dw_edma_core_ops   *ops;
> > > +
> > > +     struct dw_edma_region   rg_region;
> > > +
> > > +     u16                     wr_ch_cnt;
> > > +     u16                     rd_ch_cnt;
> > > +     /* link list address */
> > > +     struct dw_edma_region   ll_region_wr[EDMA_MAX_WR_CH];
> > > +     struct dw_edma_region   ll_region_rd[EDMA_MAX_RD_CH];
> > > +
> > > +     /* data region */
> > > +     struct dw_edma_region   dt_region_wr[EDMA_MAX_WR_CH];
> > > +     struct dw_edma_region   dt_region_rd[EDMA_MAX_RD_CH];
> > > +
> > > +     enum dw_edma_map_format mf;
> > > +
> >
> > >       struct dw_edma          *dw;
> >
> > Please drop this field from here and just change the dw_edma_probe()
> > prototype to returning a pointer to the struct dw_edma structure. Like
> > this:
> > struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
> > void dw_edma_remove(struct dw_edma *dw);
> 

> Actually, I don't think it is good to drop it now.
> 
> struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
> 
> Users likely put struct dw_edma_chip in stack.
> foo()
> {
>         struct dw_edma_chip chip
>         dw = dw_edma_proble(&chip);
> }
> 
> but now, edma_core_driver still does not save chip information to dw_edma

Neither current implementation nor implementation suggested by me
permits having the struct dw_edma_chip structure instance allocated on
stack, since the pointer to the structure is then preserved in the
dw_edma all the way until the device/driver isn't removed (it will
require some more modifications, which I can't request from you).
What approach proposed by me provides is a way to statically define
the struct dw_edma_chip object. Seeing the eDMA driver doesn't change
the structure fields we can extend the API functionality. In this
case the probe()/remote() methods semantics turns to be cleaner and
looking more like the i2c-board-info design. That we'll be able to
gain almost with no much efforts. Just fix the
dw_edma_probe()/dw_edma_remove() method prototype as I suggested
(Don't forget the const-modifier in the probe argument and in the
dw_edma.dw field).

-Sergey

> 
> >
> > By doing so we'll be able to have the chip data being const and at least
> > statically defined.
> >
> > -Sergey
> >
> > >  };
> > >
> > > --
> > > 2.24.0.rc1
> > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-10 20:16         ` Zhi Li
@ 2022-03-11 12:38           ` Serge Semin
  2022-03-11 15:37             ` Zhi Li
  2022-03-11 17:55             ` Manivannan Sadhasivam
  0 siblings, 2 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-11 12:38 UTC (permalink / raw)
  To: Zhi Li, Manivannan Sadhasivam
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

@Manivannan could you join the discussion?

On Thu, Mar 10, 2022 at 02:16:17PM -0600, Zhi Li wrote:
> On Thu, Mar 10, 2022 at 1:38 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > >
> > > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > >
> > > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > > programs the source and destination addresses for read and write. Since the
> > > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > > >
> > > > > Cc: stable@vger.kernel.org
> > > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > > ---
> > > > > No change between v1 to v4
> > > > >
> > > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > index 66dc650577919..507f08db1aad3 100644
> > > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > >       struct dw_edma_chunk *chunk;
> > > > >       struct dw_edma_burst *burst;
> > > > >       struct dw_edma_desc *desc;
> > > > > +     bool read = false;
> > > > >       u32 cnt = 0;
> > > > >       int i;
> > > > >
> > > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > >               chunk->ll_region.sz += burst->sz;
> > > > >               desc->alloc_sz += burst->sz;
> > > > >
> > > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > > +             /****************************************************************
> > > > > +              *
> > > >
> > > > > +              *        Root Complex                           Endpoint
> > > > > +              * +-----------------------+             +----------------------+
> > > > > +              * |                       |    TX CH    |                      |
> > > > > +              * |                       |             |                      |
> > > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > > +              * |                       |             |                      |
> > > > > +              * |                       |             |                      |
> > > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > > +              * |                       |             |                      |
> > > > > +              * |                       |    RX CH    |                      |
> > > > > +              * +-----------------------+             +----------------------+
> > > > > +              *
> > > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > > +              *
> > > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > >
> > > > Either I have some wrong notion about this issue, or something wrong
> > > > with the explanation above and with this fix below.
> > > >
> > > > From my understanding of the possible DW eDMA IP-core setups the
> > > > scatch above and the text below it are incorrect. Here is the way the
> > > > DW eDMA can be used:
> > > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > > CPU/Application Memory is the memory of the CPU attached to the
> > > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > > by the Rx/Read channels.
> > > >
> > > > Note it's applicable for both Host and End-point case, when Linux is
> > > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > > memory into the remote memory. In general the remote memory can be
> > > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > > each of which is some remote device anyway from the Local CPU
> > > > perspective.
> > > >
> > > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > > embedded, which CPU/Application interface is connected to some
> > > > embedded SRAM while remote (link partner) interface is directed
> > > > towards the PCIe bus. At the same time the device is setup and handled
> > > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > > think that in order to preserve the normal DMA operations semantics we
> > > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > > host CPU perspective, since that's the side the DMA controller is
> > > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > > to copy data from the host CPU memory into the remote device memory.
> > > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > > would be read data from the Local CPU memory and copied it to the PCIe
> > > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > > from it's SRAM into the Host CPU memory.
> > > >
> > > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > > a test setup with no real application, while the case 1) is a real setup
> > > > available on our SoC and I guess on yours.
> > >
> >
> > > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > > a test function.
> > > I previously sent vNTB patches to implement a virtual network between
> > > RC and EP,
> > > you can look if you have interest.
> >
> > AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> > handled by its own CPU, which sets up the DW PCIe EP controller
> > together with eDMA synthesized into the CPU' SoC. Am I right? While
> > the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> > FPGA with PCIe interface and eDMA IP-core installed. In that case all
> > the setups are performed by the PCIe Host CPU. That's the root problem
> > that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
> >
> > So to speak I would suggest for at least to have the scatch fixed in
> > accordance with the logic explained in my message.
> >
> > >
> > > >
> > > > So what I suggest in the framework of this patch is just to implement
> > > > the case 1) only. While the case 2) as it's an artificial one can be
> > > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > > in the kernel anyway. The only exception is an old-time attempt to get
> > > > an eDMA IP test-driver mainlined into the kernel:
> > > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > > But it was long time ago. So it's unlikely to be accepted at all.
> > > >
> > > > What do you think?
> > > >
> > > > -Sergey
> > > >
> > > > > +              *
> > > > > +              ****************************************************************/
> > > > > +
> > > >
> > > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > +                     read = true;
> > > >
> >
> > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > redundant.
> >
> > Am I getting a response on this comment? In accordance with that
> > conditional statement having dir == DMA_DEV_TO_MEM means performing
> > read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> > will be performed. The code path doesn't depend on the chan->dir
> > value.
> 

> Only dir is enough.

Right, in this case the fix is much simpler than suggested here. There
is no need in additional local variable and complex conditional
statement. It's supposed to be like this:

-             if (chan->dir == edma_dir_write) {
+             if (dir == DMA_DEV_TO_MEM) {

See my next comment for a detailed explanation.

> Remote Read,  DMA_DEV_TO_MEM, it is a write channel.
> SAR is the continual address at EP Side, DAR is a scatter list. RC side
> 
> Local Read,  DMA_DEV_TO_MEM, it is a reading channel.
> SAR is the continual address at RC side,  DAR is a scatter list at EP side

Right, it's a caller responsibility to use a right channel for the
operation (by flipping the channel the caller will invert the whole
logic). But As I see it what you explain and my notion don't match to what
is depicted on the scatch and written in the text below it. Don't you see?

-              *        Root Complex                           Endpoint
+              * Linux Root Port/End-point                  PCIe End-point
               * +-----------------------+             +----------------------+
-              * |                       |    TX CH    |                      |
-              * |                       |             |                      |
-              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
+              * |                       |             |                      |
+              * |                       |             |                      |
+              * |    DEV_TO_MEM   Rx Ch <-------------+ Tx Ch  DEV_TO_MEM    |
               * |                       |             |                      |
               * |                       |             |                      |
-              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
-              * |                       |             |                      |
-              * |                       |    RX CH    |                      |
+              * |    MEM_TO_DEV   Tx Ch +-------------> Rx Ch  MEM_TO_DEV    |
+              * |                       |             |                      |
+              * |                       |             |                      |
               * +-----------------------+             +----------------------+
               *
-              * If eDMA is controlled by the Root complex, TX channel
-              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
-              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
+              * If eDMA is controlled by the RP/EP, Rx channel
+              * (EDMA_DIR_READ) is used for device read (DEV_TO_MEM) and Tx
+              * channel (EDMA_DIR_WRITE) is used for device write (MEM_TO_DEV).
+              * (Straightforward case.)
               *
-              * If eDMA is controlled by the endpoint, RX channel
-              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
-              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
+              * If eDMA is embedded into an independent PCIe EP, Tx channel
+              * (EDMA_DIR_WRITE) is used for device read (DEV_TO_MEM) and Rx
+              * channel (EDMA_DIR_READ) is used for device write (MEM_TO_DEV).

I think what was suggested above explains well the semantics you are
trying to implement here in the framework of this patch.

> 
> Actually,  both sides should support a scatter list. Like
> device_prep_dma_memcpy_sg
> but it is beyond this patch series.

Right, it's beyond your series too, because that feature requires
additional modifications. I am not asking about that.

-Sergey

> 
> >
> > -Sergey
> >
> > > >
> > > > > +
> > > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > > +             if (read) {
> > > > >                       burst->sar = src_addr;
> > > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > > --
> > > > > 2.24.0.rc1
> > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-11 11:03       ` Serge Semin
@ 2022-03-11 15:29         ` Zhi Li
  2022-03-12 19:56           ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-11 15:29 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Fri, Mar 11, 2022 at 5:03 AM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> On Thu, Mar 10, 2022 at 02:29:15PM -0600, Zhi Li wrote:
> >  in
> >
> > On Thu, Mar 10, 2022 at 2:20 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > On Wed, Mar 09, 2022 at 03:11:57PM -0600, Frank Li wrote:
> > > > "struct dw_edma_chip" contains an internal structure "struct dw_edma" that
> > > > is used by the eDMA core internally. This structure should not be touched
> > > > by the eDMA controller drivers themselves. But currently, the eDMA
> > > > controller drivers like "dw-edma-pci" allocates and populates this
> > > > internal structure then passes it on to eDMA core. The eDMA core further
> > > > populates the structure and uses it. This is wrong!
> > > >
> > > > Hence, move all the "struct dw_edma" specifics from controller drivers
> > > > to the eDMA core.
> > > >
> > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > ---
> > > > Change from v3 to v4
> > > >  - Accept most suggestions of Serge Semin
> > > > Change from v2 to v3
> > > >  - none
> > > > Change from v1 to v2
> > > >  - rework commit message
> > > >  - remove duplicate field in struct dw_edma
> > > >
> > > >  drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
> > > >  drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
> > > >  drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
> > > >  drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
> > > >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
> > > >  include/linux/dma/edma.h                 | 44 +++++++++++++
> > > >  6 files changed, 144 insertions(+), 130 deletions(-)
> > > >
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > index 53289927dd0d6..1abf41d49f75b 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > @@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
> > > >  static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> > > >  {
> > > >       struct dw_edma_chan *chan = desc->chan;
> > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > +     struct dw_edma_chip *chip = chan->dw->chip;
> > > >       struct dw_edma_chunk *chunk;
> > > >
> > > >       chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
> > > > @@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> > > >        */
> > > >       chunk->cb = !(desc->chunks_alloc % 2);
> > > >       if (chan->dir == EDMA_DIR_WRITE) {
> > > > -             chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
> > > > -             chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
> > > > +             chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
> > > > +             chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
> > > >       } else {
> > > > -             chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
> > > > -             chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
> > > > +             chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
> > > > +             chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
> > > >       }
> > > >
> > > >       if (desc->chunk) {
> > > > @@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
> > > >       if (chan->status != EDMA_ST_IDLE)
> > > >               return -EBUSY;
> > > >
> > > > -     pm_runtime_get(chan->chip->dev);
> > > > +     pm_runtime_get(chan->dw->chip->dev);
> > > >
> > > >       return 0;
> > > >  }
> > > > @@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
> > > >               cpu_relax();
> > > >       }
> > > >
> > > > -     pm_runtime_put(chan->chip->dev);
> > > > +     pm_runtime_put(chan->dw->chip->dev);
> > > >  }
> > > >
> > > >  static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > > @@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > >       }
> > > >
> > > >       INIT_LIST_HEAD(&dma->channels);
> > > > -     for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
> > > > +     for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
> > > >               chan = &dw->chan[i];
> > > >
> > > >               dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> > > > @@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > >
> > > >               chan->vc.chan.private = dt_region;
> > > >
> > > > -             chan->chip = chip;
> > > > +             chan->dw = dw;
> > > >               chan->id = j;
> > > >               chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
> > > >               chan->configured = false;
> > > > @@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > >               chan->status = EDMA_ST_IDLE;
> > > >
> > > >               if (write)
> > > > -                     chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
> > > > +                     chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
> > > >               else
> > > > -                     chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
> > > > +                     chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
> > > >               chan->ll_max -= 1;
> > > >
> > > >               dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
> > > >                        write ? "write" : "read", j, chan->ll_max);
> > > >
> > > > -             if (dw->nr_irqs == 1)
> > > > +             if (chip->nr_irqs == 1)
> > > >                       pos = 0;
> > > >               else
> > > >                       pos = off_alloc + (j % alloc);
> > > > @@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > >               vchan_init(&chan->vc, dma);
> > > >
> > > >               if (write) {
> > > > -                     dt_region->paddr = dw->dt_region_wr[j].paddr;
> > > > -                     dt_region->vaddr = dw->dt_region_wr[j].vaddr;
> > > > -                     dt_region->sz = dw->dt_region_wr[j].sz;
> > > > +                     dt_region->paddr = chip->dt_region_wr[j].paddr;
> > > > +                     dt_region->vaddr = chip->dt_region_wr[j].vaddr;
> > > > +                     dt_region->sz = chip->dt_region_wr[j].sz;
> > > >               } else {
> > > > -                     dt_region->paddr = dw->dt_region_rd[j].paddr;
> > > > -                     dt_region->vaddr = dw->dt_region_rd[j].vaddr;
> > > > -                     dt_region->sz = dw->dt_region_rd[j].sz;
> > > > +                     dt_region->paddr = chip->dt_region_rd[j].paddr;
> > > > +                     dt_region->vaddr = chip->dt_region_rd[j].vaddr;
> > > > +                     dt_region->sz = chip->dt_region_rd[j].sz;
> > > >               }
> > > >
> > > >               dw_edma_v0_core_device_config(chan);
> > > > @@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > >
> > > >       ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
> > > >
> > > > -     if (dw->nr_irqs < 1)
> > > > +     if (chip->nr_irqs < 1)
> > > >               return -EINVAL;
> > > >
> > > > -     if (dw->nr_irqs == 1) {
> > > > +     if (chip->nr_irqs == 1) {
> > > >               /* Common IRQ shared among all channels */
> > > > -             irq = dw->ops->irq_vector(dev, 0);
> > > > +             irq = chip->ops->irq_vector(dev, 0);
> > > >               err = request_irq(irq, dw_edma_interrupt_common,
> > > >                                 IRQF_SHARED, dw->name, &dw->irq[0]);
> > > >               if (err) {
> > > > -                     dw->nr_irqs = 0;
> > > > +                     chip->nr_irqs = 0;
> > > >                       return err;
> > > >               }
> > > >
> > > > @@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > >                       get_cached_msi_msg(irq, &dw->irq[0].msi);
> > > >       } else {
> > > >               /* Distribute IRQs equally among all channels */
> > > > -             int tmp = dw->nr_irqs;
> > > > +             int tmp = chip->nr_irqs;
> > > >
> > > >               while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
> > > >                       dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
> > > > @@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > >               dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
> > > >
> > > >               for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
> > > > -                     irq = dw->ops->irq_vector(dev, i);
> > > > +                     irq = chip->ops->irq_vector(dev, i);
> > > >                       err = request_irq(irq,
> > > >                                         i < *wr_alloc ?
> > > >                                               dw_edma_interrupt_write :
> > > > @@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > >                                         IRQF_SHARED, dw->name,
> > > >                                         &dw->irq[i]);
> > > >                       if (err) {
> > > > -                             dw->nr_irqs = i;
> > > > +                             chip->nr_irqs = i;
> > > >                               return err;
> > > >                       }
> > > >
> > > > @@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > >                               get_cached_msi_msg(irq, &dw->irq[i].msi);
> > > >               }
> > > >
> > > > -             dw->nr_irqs = i;
> > > > +             chip->nr_irqs = i;
> > > >       }
> > > >
> > > >       return err;
> > > > @@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > > >       if (!dev)
> > > >               return -EINVAL;
> > > >
> > > > -     dw = chip->dw;
> > > > -     if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
> > > > +     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > > > +     if (!dw)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     chip->dw = dw;
> > > > +     dw->chip = chip;
> > > > +
> > > > +     if (!chip->nr_irqs || !chip->ops)
> > > >               return -EINVAL;
> > > >
> > > >       raw_spin_lock_init(&dw->lock);
> > > >
> > > > -     dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,
> > > > +
> > > > +     dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> > > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
> > > >       dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> > > >
> > > > -     dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
> > > > +     dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> > > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
> > > >       dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> > > >
> > > > @@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > > >       /* Disable eDMA, only to establish the ideal initial conditions */
> > > >       dw_edma_v0_core_off(dw);
> > > >
> > > > +     dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > > > +     if (!dw->irq)
> > > > +             return -ENOMEM;
> > > > +
> > > >       /* Request IRQs */
> > > >       err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
> > > >       if (err)
> > > > @@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > > >       return 0;
> > > >
> > > >  err_irq_free:
> > > > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > > > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > > > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > > > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> > > >
> > > > -     dw->nr_irqs = 0;
> > > > +     chip->nr_irqs = 0;
> > > >
> > > >       return err;
> > > >  }
> > > > @@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> > > >       dw_edma_v0_core_off(dw);
> > > >
> > > >       /* Free irqs */
> > > > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > > > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > > > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > > > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> > > >
> > > >       /* Power management */
> > > >       pm_runtime_disable(dev);
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> > > > index 60316d408c3e0..e254c2fc3d9cf 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-core.h
> > > > +++ b/drivers/dma/dw-edma/dw-edma-core.h
> > > > @@ -15,20 +15,12 @@
> > > >  #include "../virt-dma.h"
> > > >
> > > >  #define EDMA_LL_SZ                                   24
> > > > -#define EDMA_MAX_WR_CH                                       8
> > > > -#define EDMA_MAX_RD_CH                                       8
> > > >
> > > >  enum dw_edma_dir {
> > > >       EDMA_DIR_WRITE = 0,
> > > >       EDMA_DIR_READ
> > > >  };
> > > >
> > > > -enum dw_edma_map_format {
> > > > -     EDMA_MF_EDMA_LEGACY = 0x0,
> > > > -     EDMA_MF_EDMA_UNROLL = 0x1,
> > > > -     EDMA_MF_HDMA_COMPAT = 0x5
> > > > -};
> > > > -
> > > >  enum dw_edma_request {
> > > >       EDMA_REQ_NONE = 0,
> > > >       EDMA_REQ_STOP,
> > > > @@ -57,12 +49,6 @@ struct dw_edma_burst {
> > > >       u32                             sz;
> > > >  };
> > > >
> > > > -struct dw_edma_region {
> > > > -     phys_addr_t                     paddr;
> > > > -     void                            __iomem *vaddr;
> > > > -     size_t                          sz;
> > > > -};
> > > > -
> > > >  struct dw_edma_chunk {
> > > >       struct list_head                list;
> > > >       struct dw_edma_chan             *chan;
> > > > @@ -87,7 +73,7 @@ struct dw_edma_desc {
> > > >
> > > >  struct dw_edma_chan {
> > > >       struct virt_dma_chan            vc;
> > > > -     struct dw_edma_chip             *chip;
> > > > +     struct dw_edma                  *dw;
> > > >       int                             id;
> > > >       enum dw_edma_dir                dir;
> > > >
> > > > @@ -109,10 +95,6 @@ struct dw_edma_irq {
> > > >       struct dw_edma                  *dw;
> > > >  };
> > > >
> > > > -struct dw_edma_core_ops {
> > > > -     int     (*irq_vector)(struct device *dev, unsigned int nr);
> > > > -};
> > > > -
> > > >  struct dw_edma {
> > > >       char                            name[20];
> > > >
> > > > @@ -122,21 +104,13 @@ struct dw_edma {
> > > >       struct dma_device               rd_edma;
> > > >       u16                             rd_ch_cnt;
> > > >
> > > > -     struct dw_edma_region           rg_region;      /* Registers */
> > > > -     struct dw_edma_region           ll_region_wr[EDMA_MAX_WR_CH];
> > > > -     struct dw_edma_region           ll_region_rd[EDMA_MAX_RD_CH];
> > > > -     struct dw_edma_region           dt_region_wr[EDMA_MAX_WR_CH];
> > > > -     struct dw_edma_region           dt_region_rd[EDMA_MAX_RD_CH];
> > > > -
> > > >       struct dw_edma_irq              *irq;
> > > > -     int                             nr_irqs;
> > > > -
> > > > -     enum dw_edma_map_format         mf;
> > > >
> > > >       struct dw_edma_chan             *chan;
> > > > -     const struct dw_edma_core_ops   *ops;
> > > >
> > > >       raw_spinlock_t                  lock;           /* Only for legacy */
> > > > +
> > > > +     struct dw_edma_chip             *chip;
> > > >  #ifdef CONFIG_DEBUG_FS
> > > >       struct dentry                   *debugfs;
> > > >  #endif /* CONFIG_DEBUG_FS */
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > index 44f6e09bdb531..2c1c5fa4e9f28 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > @@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >       struct dw_edma_pcie_data vsec_data;
> > > >       struct device *dev = &pdev->dev;
> > > >       struct dw_edma_chip *chip;
> > > > -     struct dw_edma *dw;
> > > >       int err, nr_irqs;
> > > >       int i, mask;
> > > >
> > > > @@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >       if (!chip)
> > > >               return -ENOMEM;
> > > >
> > > > -     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > > > -     if (!dw)
> > > > -             return -ENOMEM;
> > > > -
> > > >       /* IRQs allocation */
> > > >       nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
> > > >                                       PCI_IRQ_MSI | PCI_IRQ_MSIX);
> > > > @@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >       }
> > > >
> > > >       /* Data structure initialization */
> > > > -     chip->dw = dw;
> > > >       chip->dev = dev;
> > > >       chip->id = pdev->devfn;
> > > > -     chip->irq = pdev->irq;
> > > >
> > > > -     dw->mf = vsec_data.mf;
> > > > -     dw->nr_irqs = nr_irqs;
> > > > -     dw->ops = &dw_edma_pcie_core_ops;
> > > > -     dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > > -     dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > > > +     chip->mf = vsec_data.mf;
> > > > +     chip->nr_irqs = nr_irqs;
> > > > +     chip->ops = &dw_edma_pcie_core_ops;
> > > >
> > > > -     dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > > > -     if (!dw->rg_region.vaddr)
> > > > -             return -ENOMEM;
> > > > +     chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > > +     chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > > >
> > > > -     dw->rg_region.vaddr += vsec_data.rg.off;
> > > > -     dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
> > > > -     dw->rg_region.paddr += vsec_data.rg.off;
> > > > -     dw->rg_region.sz = vsec_data.rg.sz;
> > > > +     chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > > > +     if (!chip->rg_region.vaddr)
> > > > +             return -ENOMEM;
> > > >
> > > > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > > > -             struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
> > > > -             struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
> > > > +     for (i = 0; i < chip->wr_ch_cnt; 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];
> > > >               struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
> > > >
> > > > @@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >               dt_region->sz = dt_block->sz;
> > > >       }
> > > >
> > > > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > > > -             struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
> > > > -             struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
> > > > +     for (i = 0; i < chip->rd_ch_cnt; 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];
> > > >               struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
> > > >
> > > > @@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >       }
> > > >
> > > >       /* Debug info */
> > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > > > -             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
> > > > -     else if (dw->mf == EDMA_MF_EDMA_UNROLL)
> > > > -             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
> > > > -     else if (dw->mf == EDMA_MF_HDMA_COMPAT)
> > > > -             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
> > > > +     if (chip->mf == EDMA_MF_EDMA_LEGACY)
> > > > +             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
> > > > +     else if (chip->mf == EDMA_MF_EDMA_UNROLL)
> > > > +             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
> > > > +     else if (chip->mf == EDMA_MF_HDMA_COMPAT)
> > > > +             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
> > > >       else
> > > > -             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
> > > > +             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
> > > >
> > > > -     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > > > +     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
> > > >               vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> > > > -             dw->rg_region.vaddr, &dw->rg_region.paddr);
> > > > +             chip->rg_region.vaddr);
> > > >
> > > >
> > > > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > > > +     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > > >               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, dw->ll_region_wr[i].sz,
> > > > -                     dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
> > > > +                     vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
> > > > +                     chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
> > > > -                     dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
> > > > +                     vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
> > > > +                     chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
> > > >       }
> > > >
> > > > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > > > +     for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
> > > > -                     dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
> > > > +                     vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
> > > > +                     chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
> > > > -                     dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
> > > > +                     vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
> > > > +                     chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
> > > >       }
> > > >
> > > > -     pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
> > > > +     pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
> > > >
> > > >       /* Validating if PCI interrupts were enabled */
> > > >       if (!pci_dev_msi_enabled(pdev)) {
> > > > @@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > >               return -EPERM;
> > > >       }
> > > >
> > > > -     dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > > > -     if (!dw->irq)
> > > > -             return -ENOMEM;
> > > > -
> > > >       /* Starting eDMA driver */
> > > >       err = dw_edma_probe(chip);
> > > >       if (err) {
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > > index 329fc2e57b703..e507e076fad16 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > > @@ -25,7 +25,7 @@ enum dw_edma_control {
> > > >
> > > >  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> > > >  {
> > > > -     return dw->rg_region.vaddr;
> > > > +     return dw->chip->rg_region.vaddr;
> > > >  }
> > > >
> > > >  #define SET_32(dw, name, value)                              \
> > > > @@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> > > >  static inline struct dw_edma_v0_ch_regs __iomem *
> > > >  __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> > > >  {
> > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
> > > >               return &(__dw_regs(dw)->type.legacy.ch);
> > > >
> > > >       if (dir == EDMA_DIR_WRITE)
> > > > @@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> > > >  static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > >                            u32 value, void __iomem *addr)
> > > >  {
> > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > >               u32 viewport_sel;
> > > >               unsigned long flags;
> > > >
> > > > @@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > >  {
> > > >       u32 value;
> > > >
> > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > >               u32 viewport_sel;
> > > >               unsigned long flags;
> > > >
> > > > @@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > >  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > >                            u64 value, void __iomem *addr)
> > > >  {
> > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > >               u32 viewport_sel;
> > > >               unsigned long flags;
> > > >
> > > > @@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > >  {
> > > >       u32 value;
> > > >
> > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > >               u32 viewport_sel;
> > > >               unsigned long flags;
> > > >
> > > > @@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
> > > >
> > > >  enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> > > >  {
> > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > +     struct dw_edma *dw = chan->dw;
> > > >       u32 tmp;
> > > >
> > > >       tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
> > > > @@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> > > >
> > > >  void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> > > >  {
> > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > +     struct dw_edma *dw = chan->dw;
> > > >
> > > >       SET_RW_32(dw, chan->dir, int_clear,
> > > >                 FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
> > > > @@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> > > >
> > > >  void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
> > > >  {
> > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > +     struct dw_edma *dw = chan->dw;
> > > >
> > > >       SET_RW_32(dw, chan->dir, int_clear,
> > > >                 FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
> > > > @@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> > > >  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > > >  {
> > > >       struct dw_edma_chan *chan = chunk->chan;
> > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > +     struct dw_edma *dw = chan->dw;
> > > >       u32 tmp;
> > > >
> > > >       dw_edma_v0_core_write_chunk(chunk);
> > > > @@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > > >       if (first) {
> > > >               /* Enable engine */
> > > >               SET_RW_32(dw, chan->dir, engine_en, BIT(0));
> > > > -             if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > > +             if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > > >                       switch (chan->id) {
> > > >                       case 0:
> > > >                               SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
> > > > @@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > > >
> > > >  int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
> > > >  {
> > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > +     struct dw_edma *dw = chan->dw;
> > > >       u32 tmp = 0;
> > > >
> > > >       /* MSI done addr - low, high */
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > > index 4b3bcffd15ef1..edb7e137cb35a 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > > @@ -54,7 +54,7 @@ struct debugfs_entries {
> > > >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> > > >  {
> > > >       void __iomem *reg = (void __force __iomem *)data;
> > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY &&
> > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
> > > >           reg >= (void __iomem *)&regs->type.legacy.ch) {
> > > >               void __iomem *ptr = &regs->type.legacy.ch;
> > > >               u32 viewport_sel = 0;
> > > > @@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
> > > >       nr_entries = ARRAY_SIZE(debugfs_regs);
> > > >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> > > >
> > > > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > > >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> > > >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> > > >                                          regs_dir);
> > > > @@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
> > > >       nr_entries = ARRAY_SIZE(debugfs_regs);
> > > >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> > > >
> > > > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > > >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> > > >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> > > >                                          regs_dir);
> > > > @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> > > >       if (!dw)
> > > >               return;
> > > >
> > > > -     regs = dw->rg_region.vaddr;
> > > > +     regs = dw->chip->rg_region.vaddr;
> > > >       if (!regs)
> > > >               return;
> > > >
> > > > @@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> > > >       if (!dw->debugfs)
> > > >               return;
> > > >
> > > > -     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
> > > > +     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
> > > >       debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
> > > >       debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
> > > >
> > > > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > > > index cab6e18773dad..a9bee4aeb2eee 100644
> > > > --- a/include/linux/dma/edma.h
> > > > +++ b/include/linux/dma/edma.h
> > > > @@ -12,19 +12,63 @@
> > > >  #include <linux/device.h>
> > > >  #include <linux/dmaengine.h>
> > > >
> > > > +#define EDMA_MAX_WR_CH                                  8
> > > > +#define EDMA_MAX_RD_CH                                  8
> > > > +
> > > >  struct dw_edma;
> > > >
> > > > +struct dw_edma_region {
> > > > +     phys_addr_t     paddr;
> > > > +     void __iomem    *vaddr;
> > > > +     size_t          sz;
> > > > +};
> > > > +
> > > > +struct dw_edma_core_ops {
> > > > +     int (*irq_vector)(struct device *dev, unsigned int nr);
> > > > +};
> > > > +
> > > > +enum dw_edma_map_format {
> > > > +     EDMA_MF_EDMA_LEGACY = 0x0,
> > > > +     EDMA_MF_EDMA_UNROLL = 0x1,
> > > > +     EDMA_MF_HDMA_COMPAT = 0x5
> > > > +};
> > > > +
> > > >  /**
> > > >   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
> > > >   * @dev:              struct device of the eDMA controller
> > > >   * @id:                       instance ID
> > > >   * @irq:              irq line
> > > > + * @nr_irqs:          total dma irq number
> > > > + * @ops                       DMA channel to IRQ number mapping
> > > > + * @wr_ch_cnt                 DMA write channel number
> > > > + * @rd_ch_cnt                 DMA read channel number
> > > > + * @rg_region                 DMA register region
> > > > + * @ll_region_wr      DMA descriptor link list memory for write channel
> > > > + * @ll_region_rd      DMA descriptor link list memory for read channel
> > > > + * @mf                        DMA register map format
> > > >   * @dw:                       struct dw_edma that is filed by dw_edma_probe()
> > > >   */
> > > >  struct dw_edma_chip {
> > > >       struct device           *dev;
> > > >       int                     id;
> > > >       int                     irq;
> > > > +     int                     nr_irqs;
> > > > +     const struct dw_edma_core_ops   *ops;
> > > > +
> > > > +     struct dw_edma_region   rg_region;
> > > > +
> > > > +     u16                     wr_ch_cnt;
> > > > +     u16                     rd_ch_cnt;
> > > > +     /* link list address */
> > > > +     struct dw_edma_region   ll_region_wr[EDMA_MAX_WR_CH];
> > > > +     struct dw_edma_region   ll_region_rd[EDMA_MAX_RD_CH];
> > > > +
> > > > +     /* data region */
> > > > +     struct dw_edma_region   dt_region_wr[EDMA_MAX_WR_CH];
> > > > +     struct dw_edma_region   dt_region_rd[EDMA_MAX_RD_CH];
> > > > +
> > > > +     enum dw_edma_map_format mf;
> > > > +
> > >
> > > >       struct dw_edma          *dw;
> > >
> > > Please drop this field from here and just change the dw_edma_probe()
> > > prototype to returning a pointer to the struct dw_edma structure. Like
> > > this:
> > > struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
> > > void dw_edma_remove(struct dw_edma *dw);
> >
>
> > Actually, I don't think it is good to drop it now.
> >
> > struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
> >
> > Users likely put struct dw_edma_chip in stack.
> > foo()
> > {
> >         struct dw_edma_chip chip
> >         dw = dw_edma_proble(&chip);
> > }
> >
> > but now, edma_core_driver still does not save chip information to dw_edma
>
> Neither current implementation nor implementation suggested by me
> permits having the struct dw_edma_chip structure instance allocated on
> stack,

Yes, but original implement
     int dw_edma_probe(struct dw_edma_chip *chip)
     int dw_edma_remove (struct dw_edma_chip *chip)

User knows the chip will be used at remove, so it will be saved in a safe place.

struct dw_edma* dw_edma_probe(struct dw_edma_chip*chip)
look like chip only use once when call dw_edma_probe,
User most like use stack if he don't read dw_edma_probe's implement.

>  since the pointer to the structure is then preserved in the
> dw_edma all the way until the device/driver isn't removed (it will
> require some more modifications, which I can't request from you).
> What approach proposed by me provides is a way to statically define
> the struct dw_edma_chip object. Seeing the eDMA driver doesn't change
> the structure fields we can extend the API functionality. In this
> case the probe()/remote() methods semantics turns to be cleaner and
> looking more like the i2c-board-info design.

I grep probe under include/*, I found most *_probe() function return int,
I think a benefit is It can return different error codes, especially
EPROBE_DEFER.
Of course,  EPROBE_DEFER will not happen in this case.  But I think
it'd be better
to follow common sense.

> That we'll be able to
> gain almost with no much efforts. Just fix the
> dw_edma_probe()/dw_edma_remove() method prototype as I suggested
> (Don't forget the const-modifier in the probe argument and in the
> dw_edma.dw field).

It is not an effort problem.  Just which one is better and prevents
some protiental
problems and is easy to use.

I suggest we can move this change to future patch, which save chip
info to dw_edma
and don't direct refer chip, which pass down at dw_edma_probe()

>
> -Sergey
>
> >
> > >
> > > By doing so we'll be able to have the chip data being const and at least
> > > statically defined.
> > >
> > > -Sergey
> > >
> > > >  };
> > > >
> > > > --
> > > > 2.24.0.rc1
> > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-11 12:38           ` Serge Semin
@ 2022-03-11 15:37             ` Zhi Li
  2022-03-11 16:03               ` Zhi Li
  2022-03-11 17:55             ` Manivannan Sadhasivam
  1 sibling, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-11 15:37 UTC (permalink / raw)
  To: Serge Semin
  Cc: Manivannan Sadhasivam, Frank Li, Serge Semin, gustavo.pimentel,
	hongxing.zhu, Lucas Stach, dl-linux-imx, linux-pci, dmaengine,
	vkoul, lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	alan.mikhak

On Fri, Mar 11, 2022 at 6:39 AM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> @Manivannan could you join the discussion?
>
> On Thu, Mar 10, 2022 at 02:16:17PM -0600, Zhi Li wrote:
> > On Thu, Mar 10, 2022 at 1:38 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > > > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > > >
> > > > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > >
> > > > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > > > programs the source and destination addresses for read and write. Since the
> > > > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > > > >
> > > > > > Cc: stable@vger.kernel.org
> > > > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > > > ---
> > > > > > No change between v1 to v4
> > > > > >
> > > > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > index 66dc650577919..507f08db1aad3 100644
> > > > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > >       struct dw_edma_chunk *chunk;
> > > > > >       struct dw_edma_burst *burst;
> > > > > >       struct dw_edma_desc *desc;
> > > > > > +     bool read = false;
> > > > > >       u32 cnt = 0;
> > > > > >       int i;
> > > > > >
> > > > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > >               chunk->ll_region.sz += burst->sz;
> > > > > >               desc->alloc_sz += burst->sz;
> > > > > >
> > > > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > > > +             /****************************************************************
> > > > > > +              *
> > > > >
> > > > > > +              *        Root Complex                           Endpoint
> > > > > > +              * +-----------------------+             +----------------------+
> > > > > > +              * |                       |    TX CH    |                      |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |                       |    RX CH    |                      |
> > > > > > +              * +-----------------------+             +----------------------+
> > > > > > +              *
> > > > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > > > +              *
> > > > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > > >
> > > > > Either I have some wrong notion about this issue, or something wrong
> > > > > with the explanation above and with this fix below.
> > > > >
> > > > > From my understanding of the possible DW eDMA IP-core setups the
> > > > > scatch above and the text below it are incorrect. Here is the way the
> > > > > DW eDMA can be used:
> > > > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > > > CPU/Application Memory is the memory of the CPU attached to the
> > > > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > > > by the Rx/Read channels.
> > > > >
> > > > > Note it's applicable for both Host and End-point case, when Linux is
> > > > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > > > memory into the remote memory. In general the remote memory can be
> > > > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > > > each of which is some remote device anyway from the Local CPU
> > > > > perspective.
> > > > >
> > > > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > > > embedded, which CPU/Application interface is connected to some
> > > > > embedded SRAM while remote (link partner) interface is directed
> > > > > towards the PCIe bus. At the same time the device is setup and handled
> > > > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > > > think that in order to preserve the normal DMA operations semantics we
> > > > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > > > host CPU perspective, since that's the side the DMA controller is
> > > > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > > > to copy data from the host CPU memory into the remote device memory.
> > > > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > > > would be read data from the Local CPU memory and copied it to the PCIe
> > > > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > > > from it's SRAM into the Host CPU memory.
> > > > >
> > > > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > > > a test setup with no real application, while the case 1) is a real setup
> > > > > available on our SoC and I guess on yours.
> > > >
> > >
> > > > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > > > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > > > a test function.
> > > > I previously sent vNTB patches to implement a virtual network between
> > > > RC and EP,
> > > > you can look if you have interest.
> > >
> > > AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> > > handled by its own CPU, which sets up the DW PCIe EP controller
> > > together with eDMA synthesized into the CPU' SoC. Am I right? While
> > > the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> > > FPGA with PCIe interface and eDMA IP-core installed. In that case all
> > > the setups are performed by the PCIe Host CPU. That's the root problem
> > > that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
> > >
> > > So to speak I would suggest for at least to have the scatch fixed in
> > > accordance with the logic explained in my message.
> > >
> > > >
> > > > >
> > > > > So what I suggest in the framework of this patch is just to implement
> > > > > the case 1) only. While the case 2) as it's an artificial one can be
> > > > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > > > in the kernel anyway. The only exception is an old-time attempt to get
> > > > > an eDMA IP test-driver mainlined into the kernel:
> > > > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > > > But it was long time ago. So it's unlikely to be accepted at all.
> > > > >
> > > > > What do you think?
> > > > >
> > > > > -Sergey
> > > > >
> > > > > > +              *
> > > > > > +              ****************************************************************/
> > > > > > +
> > > > >
> > > > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > +                     read = true;
> > > > >
> > >
> > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > redundant.
> > >
> > > Am I getting a response on this comment? In accordance with that
> > > conditional statement having dir == DMA_DEV_TO_MEM means performing
> > > read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> > > will be performed. The code path doesn't depend on the chan->dir
> > > value.
> >
>
> > Only dir is enough.
>
> Right, in this case the fix is much simpler than suggested here. There
> is no need in additional local variable and complex conditional
> statement. It's supposed to be like this:
>
> -             if (chan->dir == edma_dir_write) {

> +             if (dir == DMA_DEV_TO_MEM)
> See my next comment for a detailed explanation.

Actually directly revert patch

commit bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
Author: Alan Mikhak <alan.mikhak@sifive.com>
Date:   Tue Apr 28 18:10:33 2020 -0700

@Alan Mikhak, welcome to join the discussion.  We think the original code is
correct  for both remote DMA and local DMA. Can you help join the discussion to
descript what's your test case when you upstream?  Actually pci-epf-test.c have
not enable local EP dma. How do you test your code?

>
> > Remote Read,  DMA_DEV_TO_MEM, it is a write channel.
> > SAR is the continual address at EP Side, DAR is a scatter list. RC side
> >
> > Local Read,  DMA_DEV_TO_MEM, it is a reading channel.
> > SAR is the continual address at RC side,  DAR is a scatter list at EP side
>
> Right, it's a caller responsibility to use a right channel for the
> operation (by flipping the channel the caller will invert the whole
> logic). But As I see it what you explain and my notion don't match to what
> is depicted on the scatch and written in the text below it. Don't you see?
>
> -              *        Root Complex                           Endpoint
> +              * Linux Root Port/End-point                  PCIe End-point
>                * +-----------------------+             +----------------------+
> -              * |                       |    TX CH    |                      |
> -              * |                       |             |                      |
> -              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> +              * |                       |             |                      |
> +              * |                       |             |                      |
> +              * |    DEV_TO_MEM   Rx Ch <-------------+ Tx Ch  DEV_TO_MEM    |
>                * |                       |             |                      |
>                * |                       |             |                      |
> -              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> -              * |                       |             |                      |
> -              * |                       |    RX CH    |                      |
> +              * |    MEM_TO_DEV   Tx Ch +-------------> Rx Ch  MEM_TO_DEV    |
> +              * |                       |             |                      |
> +              * |                       |             |                      |
>                * +-----------------------+             +----------------------+
>                *
> -              * If eDMA is controlled by the Root complex, TX channel
> -              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> -              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> +              * If eDMA is controlled by the RP/EP, Rx channel
> +              * (EDMA_DIR_READ) is used for device read (DEV_TO_MEM) and Tx
> +              * channel (EDMA_DIR_WRITE) is used for device write (MEM_TO_DEV).
> +              * (Straightforward case.)
>                *
> -              * If eDMA is controlled by the endpoint, RX channel
> -              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> -              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> +              * If eDMA is embedded into an independent PCIe EP, Tx channel
> +              * (EDMA_DIR_WRITE) is used for device read (DEV_TO_MEM) and Rx
> +              * channel (EDMA_DIR_READ) is used for device write (MEM_TO_DEV).
>
> I think what was suggested above explains well the semantics you are
> trying to implement here in the framework of this patch.
>
> >
> > Actually,  both sides should support a scatter list. Like
> > device_prep_dma_memcpy_sg
> > but it is beyond this patch series.
>
> Right, it's beyond your series too, because that feature requires
> additional modifications. I am not asking about that.
>
> -Sergey
>
> >
> > >
> > > -Sergey
> > >
> > > > >
> > > > > > +
> > > > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > > > +             if (read) {
> > > > > >                       burst->sar = src_addr;
> > > > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > --
> > > > > > 2.24.0.rc1
> > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-11 15:37             ` Zhi Li
@ 2022-03-11 16:03               ` Zhi Li
  2022-03-11 17:14                 ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-11 16:03 UTC (permalink / raw)
  To: Serge Semin
  Cc: Manivannan Sadhasivam, Frank Li, Serge Semin, gustavo.pimentel,
	hongxing.zhu, Lucas Stach, dl-linux-imx, linux-pci, dmaengine,
	vkoul, lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Fri, Mar 11, 2022 at 9:37 AM Zhi Li <lznuaa@gmail.com> wrote:
>
> On Fri, Mar 11, 2022 at 6:39 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > @Manivannan could you join the discussion?
> >
> > On Thu, Mar 10, 2022 at 02:16:17PM -0600, Zhi Li wrote:
> > > On Thu, Mar 10, 2022 at 1:38 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > >
> > > > On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > > > > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > > > >
> > > > > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > >
> > > > > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > > > > programs the source and destination addresses for read and write. Since the
> > > > > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > > > > >
> > > > > > > Cc: stable@vger.kernel.org
> > > > > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > > > > ---
> > > > > > > No change between v1 to v4
> > > > > > >
> > > > > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > > > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > > > > >
> > > > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > index 66dc650577919..507f08db1aad3 100644
> > > > > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > > >       struct dw_edma_chunk *chunk;
> > > > > > >       struct dw_edma_burst *burst;
> > > > > > >       struct dw_edma_desc *desc;
> > > > > > > +     bool read = false;
> > > > > > >       u32 cnt = 0;
> > > > > > >       int i;
> > > > > > >
> > > > > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > > >               chunk->ll_region.sz += burst->sz;
> > > > > > >               desc->alloc_sz += burst->sz;
> > > > > > >
> > > > > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > > > > +             /****************************************************************
> > > > > > > +              *
> > > > > >
> > > > > > > +              *        Root Complex                           Endpoint
> > > > > > > +              * +-----------------------+             +----------------------+
> > > > > > > +              * |                       |    TX CH    |                      |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |                       |    RX CH    |                      |
> > > > > > > +              * +-----------------------+             +----------------------+
> > > > > > > +              *
> > > > > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > > > > +              *
> > > > > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > > > >
> > > > > > Either I have some wrong notion about this issue, or something wrong
> > > > > > with the explanation above and with this fix below.
> > > > > >
> > > > > > From my understanding of the possible DW eDMA IP-core setups the
> > > > > > scatch above and the text below it are incorrect. Here is the way the
> > > > > > DW eDMA can be used:
> > > > > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > > > > CPU/Application Memory is the memory of the CPU attached to the
> > > > > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > > > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > > > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > > > > by the Rx/Read channels.
> > > > > >
> > > > > > Note it's applicable for both Host and End-point case, when Linux is
> > > > > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > > > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > > > > memory into the remote memory. In general the remote memory can be
> > > > > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > > > > each of which is some remote device anyway from the Local CPU
> > > > > > perspective.
> > > > > >
> > > > > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > > > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > > > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > > > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > > > > embedded, which CPU/Application interface is connected to some
> > > > > > embedded SRAM while remote (link partner) interface is directed
> > > > > > towards the PCIe bus. At the same time the device is setup and handled
> > > > > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > > > > think that in order to preserve the normal DMA operations semantics we
> > > > > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > > > > host CPU perspective, since that's the side the DMA controller is
> > > > > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > > > > to copy data from the host CPU memory into the remote device memory.
> > > > > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > > > > would be read data from the Local CPU memory and copied it to the PCIe
> > > > > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > > > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > > > > from it's SRAM into the Host CPU memory.
> > > > > >
> > > > > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > > > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > > > > a test setup with no real application, while the case 1) is a real setup
> > > > > > available on our SoC and I guess on yours.
> > > > >
> > > >
> > > > > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > > > > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > > > > a test function.
> > > > > I previously sent vNTB patches to implement a virtual network between
> > > > > RC and EP,
> > > > > you can look if you have interest.
> > > >
> > > > AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> > > > handled by its own CPU, which sets up the DW PCIe EP controller
> > > > together with eDMA synthesized into the CPU' SoC. Am I right? While
> > > > the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> > > > FPGA with PCIe interface and eDMA IP-core installed. In that case all
> > > > the setups are performed by the PCIe Host CPU. That's the root problem
> > > > that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
> > > >
> > > > So to speak I would suggest for at least to have the scatch fixed in
> > > > accordance with the logic explained in my message.
> > > >
> > > > >
> > > > > >
> > > > > > So what I suggest in the framework of this patch is just to implement
> > > > > > the case 1) only. While the case 2) as it's an artificial one can be
> > > > > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > > > > in the kernel anyway. The only exception is an old-time attempt to get
> > > > > > an eDMA IP test-driver mainlined into the kernel:
> > > > > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > > > > But it was long time ago. So it's unlikely to be accepted at all.
> > > > > >
> > > > > > What do you think?
> > > > > >
> > > > > > -Sergey
> > > > > >
> > > > > > > +              *
> > > > > > > +              ****************************************************************/
> > > > > > > +
> > > > > >
> > > > > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > +                     read = true;
> > > > > >
> > > >
> > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > redundant.
> > > >
> > > > Am I getting a response on this comment? In accordance with that
> > > > conditional statement having dir == DMA_DEV_TO_MEM means performing
> > > > read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> > > > will be performed. The code path doesn't depend on the chan->dir
> > > > value.
> > >
> >
> > > Only dir is enough.
> >
> > Right, in this case the fix is much simpler than suggested here. There
> > is no need in additional local variable and complex conditional
> > statement. It's supposed to be like this:
> >
> > -             if (chan->dir == edma_dir_write) {
>
> > +             if (dir == DMA_DEV_TO_MEM)
> > See my next comment for a detailed explanation.
>
> Actually directly revert patch
>
> commit bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> Author: Alan Mikhak <alan.mikhak@sifive.com>
> Date:   Tue Apr 28 18:10:33 2020 -0700
>
> @Alan Mikhak, welcome to join the discussion.  We think the original code is
> correct  for both remote DMA and local DMA. Can you help join the discussion to
> descript what's your test case when you upstream?  Actually pci-epf-test.c have
> not enable local EP dma. How do you test your code?

Alan Mikhank's email address does not exist now!.
@Serge Semin  @Manivannan Sadhasivam , how do you think revert
bd96f1b2f43a39310cc576bb4faf2ea24317a4c9

>
> >
> > > Remote Read,  DMA_DEV_TO_MEM, it is a write channel.
> > > SAR is the continual address at EP Side, DAR is a scatter list. RC side
> > >
> > > Local Read,  DMA_DEV_TO_MEM, it is a reading channel.
> > > SAR is the continual address at RC side,  DAR is a scatter list at EP side
> >
> > Right, it's a caller responsibility to use a right channel for the
> > operation (by flipping the channel the caller will invert the whole
> > logic). But As I see it what you explain and my notion don't match to what
> > is depicted on the scatch and written in the text below it. Don't you see?
> >
> > -              *        Root Complex                           Endpoint
> > +              * Linux Root Port/End-point                  PCIe End-point
> >                * +-----------------------+             +----------------------+
> > -              * |                       |    TX CH    |                      |
> > -              * |                       |             |                      |
> > -              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > +              * |                       |             |                      |
> > +              * |                       |             |                      |
> > +              * |    DEV_TO_MEM   Rx Ch <-------------+ Tx Ch  DEV_TO_MEM    |
> >                * |                       |             |                      |
> >                * |                       |             |                      |
> > -              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > -              * |                       |             |                      |
> > -              * |                       |    RX CH    |                      |
> > +              * |    MEM_TO_DEV   Tx Ch +-------------> Rx Ch  MEM_TO_DEV    |
> > +              * |                       |             |                      |
> > +              * |                       |             |                      |
> >                * +-----------------------+             +----------------------+
> >                *
> > -              * If eDMA is controlled by the Root complex, TX channel
> > -              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > -              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > +              * If eDMA is controlled by the RP/EP, Rx channel
> > +              * (EDMA_DIR_READ) is used for device read (DEV_TO_MEM) and Tx
> > +              * channel (EDMA_DIR_WRITE) is used for device write (MEM_TO_DEV).
> > +              * (Straightforward case.)
> >                *
> > -              * If eDMA is controlled by the endpoint, RX channel
> > -              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > -              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > +              * If eDMA is embedded into an independent PCIe EP, Tx channel
> > +              * (EDMA_DIR_WRITE) is used for device read (DEV_TO_MEM) and Rx
> > +              * channel (EDMA_DIR_READ) is used for device write (MEM_TO_DEV).
> >
> > I think what was suggested above explains well the semantics you are
> > trying to implement here in the framework of this patch.
> >
> > >
> > > Actually,  both sides should support a scatter list. Like
> > > device_prep_dma_memcpy_sg
> > > but it is beyond this patch series.
> >
> > Right, it's beyond your series too, because that feature requires
> > additional modifications. I am not asking about that.
> >
> > -Sergey
> >
> > >
> > > >
> > > > -Sergey
> > > >
> > > > > >
> > > > > > > +
> > > > > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > > > > +             if (read) {
> > > > > > >                       burst->sar = src_addr;
> > > > > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > --
> > > > > > > 2.24.0.rc1
> > > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-11 16:03               ` Zhi Li
@ 2022-03-11 17:14                 ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-11 17:14 UTC (permalink / raw)
  To: Zhi Li
  Cc: Serge Semin, Manivannan Sadhasivam, Frank Li, gustavo.pimentel,
	hongxing.zhu, Lucas Stach, dl-linux-imx, linux-pci, dmaengine,
	vkoul, lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Fri, Mar 11, 2022 at 10:03:48AM -0600, Zhi Li wrote:
> On Fri, Mar 11, 2022 at 9:37 AM Zhi Li <lznuaa@gmail.com> wrote:
> >
> > On Fri, Mar 11, 2022 at 6:39 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > @Manivannan could you join the discussion?
> > >
> > > On Thu, Mar 10, 2022 at 02:16:17PM -0600, Zhi Li wrote:
> > > > On Thu, Mar 10, 2022 at 1:38 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > > >
> > > > > On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > > > > > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > > > > >
> > > > > > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > > > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > > >
> > > > > > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > > > > > programs the source and destination addresses for read and write. Since the
> > > > > > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > > > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > > > > > >
> > > > > > > > Cc: stable@vger.kernel.org
> > > > > > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > > > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > > > > > ---
> > > > > > > > No change between v1 to v4
> > > > > > > >
> > > > > > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > > > > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > > > > > >
> > > > > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > > index 66dc650577919..507f08db1aad3 100644
> > > > > > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > > > >       struct dw_edma_chunk *chunk;
> > > > > > > >       struct dw_edma_burst *burst;
> > > > > > > >       struct dw_edma_desc *desc;
> > > > > > > > +     bool read = false;
> > > > > > > >       u32 cnt = 0;
> > > > > > > >       int i;
> > > > > > > >
> > > > > > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > > > >               chunk->ll_region.sz += burst->sz;
> > > > > > > >               desc->alloc_sz += burst->sz;
> > > > > > > >
> > > > > > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > > > > > +             /****************************************************************
> > > > > > > > +              *
> > > > > > >
> > > > > > > > +              *        Root Complex                           Endpoint
> > > > > > > > +              * +-----------------------+             +----------------------+
> > > > > > > > +              * |                       |    TX CH    |                      |
> > > > > > > > +              * |                       |             |                      |
> > > > > > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > > > > > +              * |                       |             |                      |
> > > > > > > > +              * |                       |             |                      |
> > > > > > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > > > > > +              * |                       |             |                      |
> > > > > > > > +              * |                       |    RX CH    |                      |
> > > > > > > > +              * +-----------------------+             +----------------------+
> > > > > > > > +              *
> > > > > > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > > > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > > > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > > > > > +              *
> > > > > > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > > > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > > > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > > > > >
> > > > > > > Either I have some wrong notion about this issue, or something wrong
> > > > > > > with the explanation above and with this fix below.
> > > > > > >
> > > > > > > From my understanding of the possible DW eDMA IP-core setups the
> > > > > > > scatch above and the text below it are incorrect. Here is the way the
> > > > > > > DW eDMA can be used:
> > > > > > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > > > > > CPU/Application Memory is the memory of the CPU attached to the
> > > > > > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > > > > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > > > > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > > > > > by the Rx/Read channels.
> > > > > > >
> > > > > > > Note it's applicable for both Host and End-point case, when Linux is
> > > > > > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > > > > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > > > > > memory into the remote memory. In general the remote memory can be
> > > > > > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > > > > > each of which is some remote device anyway from the Local CPU
> > > > > > > perspective.
> > > > > > >
> > > > > > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > > > > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > > > > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > > > > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > > > > > embedded, which CPU/Application interface is connected to some
> > > > > > > embedded SRAM while remote (link partner) interface is directed
> > > > > > > towards the PCIe bus. At the same time the device is setup and handled
> > > > > > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > > > > > think that in order to preserve the normal DMA operations semantics we
> > > > > > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > > > > > host CPU perspective, since that's the side the DMA controller is
> > > > > > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > > > > > to copy data from the host CPU memory into the remote device memory.
> > > > > > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > > > > > would be read data from the Local CPU memory and copied it to the PCIe
> > > > > > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > > > > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > > > > > from it's SRAM into the Host CPU memory.
> > > > > > >
> > > > > > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > > > > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > > > > > a test setup with no real application, while the case 1) is a real setup
> > > > > > > available on our SoC and I guess on yours.
> > > > > >
> > > > >
> > > > > > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > > > > > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > > > > > a test function.
> > > > > > I previously sent vNTB patches to implement a virtual network between
> > > > > > RC and EP,
> > > > > > you can look if you have interest.
> > > > >
> > > > > AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> > > > > handled by its own CPU, which sets up the DW PCIe EP controller
> > > > > together with eDMA synthesized into the CPU' SoC. Am I right? While
> > > > > the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> > > > > FPGA with PCIe interface and eDMA IP-core installed. In that case all
> > > > > the setups are performed by the PCIe Host CPU. That's the root problem
> > > > > that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
> > > > >
> > > > > So to speak I would suggest for at least to have the scatch fixed in
> > > > > accordance with the logic explained in my message.
> > > > >
> > > > > >
> > > > > > >
> > > > > > > So what I suggest in the framework of this patch is just to implement
> > > > > > > the case 1) only. While the case 2) as it's an artificial one can be
> > > > > > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > > > > > in the kernel anyway. The only exception is an old-time attempt to get
> > > > > > > an eDMA IP test-driver mainlined into the kernel:
> > > > > > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > > > > > But it was long time ago. So it's unlikely to be accepted at all.
> > > > > > >
> > > > > > > What do you think?
> > > > > > >
> > > > > > > -Sergey
> > > > > > >
> > > > > > > > +              *
> > > > > > > > +              ****************************************************************/
> > > > > > > > +
> > > > > > >
> > > > > > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > > +                     read = true;
> > > > > > >
> > > > >
> > > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > > redundant.
> > > > >
> > > > > Am I getting a response on this comment? In accordance with that
> > > > > conditional statement having dir == DMA_DEV_TO_MEM means performing
> > > > > read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> > > > > will be performed. The code path doesn't depend on the chan->dir
> > > > > value.
> > > >
> > >
> > > > Only dir is enough.
> > >
> > > Right, in this case the fix is much simpler than suggested here. There
> > > is no need in additional local variable and complex conditional
> > > statement. It's supposed to be like this:
> > >
> > > -             if (chan->dir == edma_dir_write) {
> >
> > > +             if (dir == DMA_DEV_TO_MEM)
> > > See my next comment for a detailed explanation.
> >
> > Actually directly revert patch
> >
> > commit bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > Author: Alan Mikhak <alan.mikhak@sifive.com>
> > Date:   Tue Apr 28 18:10:33 2020 -0700
> >
> > @Alan Mikhak, welcome to join the discussion.  We think the original code is
> > correct  for both remote DMA and local DMA. Can you help join the discussion to
> > descript what's your test case when you upstream?  Actually pci-epf-test.c have
> > not enable local EP dma. How do you test your code?
> 

> Alan Mikhank's email address does not exist now!.
> @Serge Semin  @Manivannan Sadhasivam , how do you think revert
> bd96f1b2f43a39310cc576bb4faf2ea24317a4c9

AFAIU reversion won't solve the problem, since it will get back the
statement:
-	if ((direction == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE) ||
-	    (direction == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ))
		return NULL;

That will prevent the code from supporting the Linux Root
Port/End-point case in the notation of my scatch. So we need to add a
well-justified fix with clear explanation and in-line comment.

Let's wait for the @Manivannan's response.

-Sergey

> 
> >
> > >
> > > > Remote Read,  DMA_DEV_TO_MEM, it is a write channel.
> > > > SAR is the continual address at EP Side, DAR is a scatter list. RC side
> > > >
> > > > Local Read,  DMA_DEV_TO_MEM, it is a reading channel.
> > > > SAR is the continual address at RC side,  DAR is a scatter list at EP side
> > >
> > > Right, it's a caller responsibility to use a right channel for the
> > > operation (by flipping the channel the caller will invert the whole
> > > logic). But As I see it what you explain and my notion don't match to what
> > > is depicted on the scatch and written in the text below it. Don't you see?
> > >
> > > -              *        Root Complex                           Endpoint
> > > +              * Linux Root Port/End-point                  PCIe End-point
> > >                * +-----------------------+             +----------------------+
> > > -              * |                       |    TX CH    |                      |
> > > -              * |                       |             |                      |
> > > -              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > +              * |                       |             |                      |
> > > +              * |                       |             |                      |
> > > +              * |    DEV_TO_MEM   Rx Ch <-------------+ Tx Ch  DEV_TO_MEM    |
> > >                * |                       |             |                      |
> > >                * |                       |             |                      |
> > > -              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > -              * |                       |             |                      |
> > > -              * |                       |    RX CH    |                      |
> > > +              * |    MEM_TO_DEV   Tx Ch +-------------> Rx Ch  MEM_TO_DEV    |
> > > +              * |                       |             |                      |
> > > +              * |                       |             |                      |
> > >                * +-----------------------+             +----------------------+
> > >                *
> > > -              * If eDMA is controlled by the Root complex, TX channel
> > > -              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > -              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > +              * If eDMA is controlled by the RP/EP, Rx channel
> > > +              * (EDMA_DIR_READ) is used for device read (DEV_TO_MEM) and Tx
> > > +              * channel (EDMA_DIR_WRITE) is used for device write (MEM_TO_DEV).
> > > +              * (Straightforward case.)
> > >                *
> > > -              * If eDMA is controlled by the endpoint, RX channel
> > > -              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > -              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > +              * If eDMA is embedded into an independent PCIe EP, Tx channel
> > > +              * (EDMA_DIR_WRITE) is used for device read (DEV_TO_MEM) and Rx
> > > +              * channel (EDMA_DIR_READ) is used for device write (MEM_TO_DEV).
> > >
> > > I think what was suggested above explains well the semantics you are
> > > trying to implement here in the framework of this patch.
> > >
> > > >
> > > > Actually,  both sides should support a scatter list. Like
> > > > device_prep_dma_memcpy_sg
> > > > but it is beyond this patch series.
> > >
> > > Right, it's beyond your series too, because that feature requires
> > > additional modifications. I am not asking about that.
> > >
> > > -Sergey
> > >
> > > >
> > > > >
> > > > > -Sergey
> > > > >
> > > > > > >
> > > > > > > > +
> > > > > > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > > > > > +             if (read) {
> > > > > > > >                       burst->sar = src_addr;
> > > > > > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > > --
> > > > > > > > 2.24.0.rc1
> > > > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-10 16:31   ` Serge Semin
  2022-03-10 16:50     ` Zhi Li
@ 2022-03-11 17:41     ` Manivannan Sadhasivam
  2022-03-11 19:01       ` Serge Semin
  1 sibling, 1 reply; 52+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-11 17:41 UTC (permalink / raw)
  To: Serge Semin
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Thu, Mar 10, 2022 at 07:31:23PM +0300, Serge Semin wrote:
> On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > 
> > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > programs the source and destination addresses for read and write. Since the
> > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > issue by finding out the read operation first and program the eDMA accordingly.
> > 
> > Cc: stable@vger.kernel.org
> > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > No change between v1 to v4
> > 
> >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> >  1 file changed, 31 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 66dc650577919..507f08db1aad3 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> >  	struct dw_edma_chunk *chunk;
> >  	struct dw_edma_burst *burst;
> >  	struct dw_edma_desc *desc;
> > +	bool read = false;
> >  	u32 cnt = 0;
> >  	int i;
> >  
> > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> >  		chunk->ll_region.sz += burst->sz;
> >  		desc->alloc_sz += burst->sz;
> >  
> > -		if (chan->dir == EDMA_DIR_WRITE) {
> > +		/****************************************************************
> > +		 *
> 
> > +		 *        Root Complex                           Endpoint
> > +		 * +-----------------------+             +----------------------+
> > +		 * |                       |    TX CH    |                      |
> > +		 * |                       |             |                      |
> > +		 * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > +		 * |                       |             |                      |
> > +		 * |                       |             |                      |
> > +		 * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > +		 * |                       |             |                      |
> > +		 * |                       |    RX CH    |                      |
> > +		 * +-----------------------+             +----------------------+
> > +		 *
> > +		 * If eDMA is controlled by the Root complex, TX channel
> > +		 * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > +		 * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > +		 *
> > +		 * If eDMA is controlled by the endpoint, RX channel
> > +		 * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > +		 * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> 
> Either I have some wrong notion about this issue, or something wrong
> with the explanation above and with this fix below.
> 
> From my understanding of the possible DW eDMA IP-core setups the
> scatch above and the text below it are incorrect. Here is the way the
> DW eDMA can be used:
> 1) Embedded into the DW PCIe Host/EP controller. In this case
> CPU/Application Memory is the memory of the CPU attached to the
> host/EP controller, while the remote (link partner) memory is the PCIe
> bus memory. In this case MEM_TO_DEV operation is supposed to be
> performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> by the Rx/Read channels.
> 

I'm not aware or even not sure about the use of eDMA in the PCIe host.
If that's the case, how the endpoint can access it from remote perspective?
Do you have a usecase or an example where used or even documented?

> Note it's applicable for both Host and End-point case, when Linux is
> running on the CPU-side of the eDMA controller. So if it's DW PCIe
> end-point, then MEM_TO_DEV means copying data from the local CPU
> memory into the remote memory. In general the remote memory can be
> either some PCIe device on the bus or the Root Complex' CPU memory,
> each of which is some remote device anyway from the Local CPU
> perspective.
> 
> 2) Embedded into the PCIe EP. This case is implemented in the
> drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> and from the driver code, that device is a Synopsys PCIe EndPoint IP
> prototype kit. It is a normal PCIe peripheral device with eDMA
> embedded, which CPU/Application interface is connected to some
> embedded SRAM while remote (link partner) interface is directed
> towards the PCIe bus. At the same time the device is setup and handled
> by the code running on a CPU connected to the PCIe Host controller.  I
> think that in order to preserve the normal DMA operations semantics we
> still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> host CPU perspective, since that's the side the DMA controller is
> supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> to copy data from the host CPU memory into the remote device memory.
> It means to allocate Rx/Read channel on the eDMA controller, so one
> would be read data from the Local CPU memory and copied it to the PCIe
> device SRAM. The logic of the DEV_TO_MEM direction would be just
> flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> from it's SRAM into the Host CPU memory.
> 
> Please note as I understand the case 2) describes the Synopsys PCIe
> EndPoint IP prototype kit, which is based on some FPGA code. It's just
> a test setup with no real application, while the case 1) is a real setup
> available on our SoC and I guess on yours.
> 
> So what I suggest in the framework of this patch is just to implement
> the case 1) only. While the case 2) as it's an artificial one can be
> manually handled by the DMA client drivers. BTW There aren't ones available
> in the kernel anyway. The only exception is an old-time attempt to get
> an eDMA IP test-driver mainlined into the kernel:
> https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> But it was long time ago. So it's unlikely to be accepted at all.
> 
> What do you think?
> 

As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
access to it happens over PCIe bus or by the local CPU.

The commit from Alan Mikhak is what I took as a reference since the patch was
already merged:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9

Thanks,
Mani

> -Sergey
> 
> > +		 *
> > +		 ****************************************************************/
> > +
> 
> > +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > +			read = true;
> 
> Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> redundant.
> 
> > +
> > +		/* Program the source and destination addresses for DMA read/write */
> > +		if (read) {
> >  			burst->sar = src_addr;
> >  			if (xfer->type == EDMA_XFER_CYCLIC) {
> >  				burst->dar = xfer->xfer.cyclic.paddr;
> > -- 
> > 2.24.0.rc1
> > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-10 19:37       ` Serge Semin
  2022-03-10 20:16         ` Zhi Li
@ 2022-03-11 17:46         ` Manivannan Sadhasivam
  1 sibling, 0 replies; 52+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-11 17:46 UTC (permalink / raw)
  To: Serge Semin
  Cc: Zhi Li, Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Thu, Mar 10, 2022 at 10:37:59PM +0300, Serge Semin wrote:
> On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > >
> > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > programs the source and destination addresses for read and write. Since the
> > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > >
> > > > Cc: stable@vger.kernel.org
> > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > ---
> > > > No change between v1 to v4
> > > >
> > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > index 66dc650577919..507f08db1aad3 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > >       struct dw_edma_chunk *chunk;
> > > >       struct dw_edma_burst *burst;
> > > >       struct dw_edma_desc *desc;
> > > > +     bool read = false;
> > > >       u32 cnt = 0;
> > > >       int i;
> > > >
> > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > >               chunk->ll_region.sz += burst->sz;
> > > >               desc->alloc_sz += burst->sz;
> > > >
> > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > +             /****************************************************************
> > > > +              *
> > >
> > > > +              *        Root Complex                           Endpoint
> > > > +              * +-----------------------+             +----------------------+
> > > > +              * |                       |    TX CH    |                      |
> > > > +              * |                       |             |                      |
> > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > +              * |                       |             |                      |
> > > > +              * |                       |             |                      |
> > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > +              * |                       |             |                      |
> > > > +              * |                       |    RX CH    |                      |
> > > > +              * +-----------------------+             +----------------------+
> > > > +              *
> > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > +              *
> > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > >
> > > Either I have some wrong notion about this issue, or something wrong
> > > with the explanation above and with this fix below.
> > >
> > > From my understanding of the possible DW eDMA IP-core setups the
> > > scatch above and the text below it are incorrect. Here is the way the
> > > DW eDMA can be used:
> > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > CPU/Application Memory is the memory of the CPU attached to the
> > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > by the Rx/Read channels.
> > >
> > > Note it's applicable for both Host and End-point case, when Linux is
> > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > memory into the remote memory. In general the remote memory can be
> > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > each of which is some remote device anyway from the Local CPU
> > > perspective.
> > >
> > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > embedded, which CPU/Application interface is connected to some
> > > embedded SRAM while remote (link partner) interface is directed
> > > towards the PCIe bus. At the same time the device is setup and handled
> > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > think that in order to preserve the normal DMA operations semantics we
> > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > host CPU perspective, since that's the side the DMA controller is
> > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > to copy data from the host CPU memory into the remote device memory.
> > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > would be read data from the Local CPU memory and copied it to the PCIe
> > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > from it's SRAM into the Host CPU memory.
> > >
> > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > a test setup with no real application, while the case 1) is a real setup
> > > available on our SoC and I guess on yours.
> > 
> 
> > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > a test function.
> > I previously sent vNTB patches to implement a virtual network between
> > RC and EP,
> > you can look if you have interest.
> 
> AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> handled by its own CPU, which sets up the DW PCIe EP controller
> together with eDMA synthesized into the CPU' SoC. Am I right? While
> the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> FPGA with PCIe interface and eDMA IP-core installed. In that case all
> the setups are performed by the PCIe Host CPU. That's the root problem
> that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
> 
> So to speak I would suggest for at least to have the scatch fixed in
> accordance with the logic explained in my message.
> 
> > 
> > >
> > > So what I suggest in the framework of this patch is just to implement
> > > the case 1) only. While the case 2) as it's an artificial one can be
> > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > in the kernel anyway. The only exception is an old-time attempt to get
> > > an eDMA IP test-driver mainlined into the kernel:
> > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > But it was long time ago. So it's unlikely to be accepted at all.
> > >
> > > What do you think?
> > >
> > > -Sergey
> > >
> > > > +              *
> > > > +              ****************************************************************/
> > > > +
> > >
> > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > +                     read = true;
> > >
> 
> > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > redundant.
> 
> Am I getting a response on this comment? In accordance with that
> conditional statement having dir == DMA_DEV_TO_MEM means performing
> read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> will be performed. The code path doesn't depend on the chan->dir
> value.
> 

As per the eDMA test application [1] submitted a while ago, my logic is correct:

+	if (thread->direction == DMA_DEV_TO_MEM) {
+		/* DMA_DEV_TO_MEM - WRITE - DMA_FROM_DEVICE */
+		dev_dbg(dev, "%s: DMA_DEV_TO_MEM - WRITE - DMA_FROM_DEVICE\n",
+			dma_chan_name(chan));
+		err = dma_map_sg(dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+		if (!err)
+			goto err_descs;
+
+		sgt->nents = err;
+		/* Endpoint memory */
+		sconf.src_addr = dt_region->paddr;
+		/* CPU memory */
+		sconf.dst_addr = descs[0].paddr;
+	} else {
+		/* DMA_MEM_TO_DEV - READ - DMA_TO_DEVICE */
+		dev_dbg(dev, "%s: DMA_MEM_TO_DEV - READ - DMA_TO_DEVICE\n",
+			dma_chan_name(chan));
+		err = dma_map_sg(dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE);
+		if (!err)
+			goto err_descs;
+
+		sgt->nents = err;
+		/* CPU memory */
+		sconf.src_addr = descs[0].paddr;
+		/* Endpoint memory */
+		sconf.dst_addr = dt_region->paddr;
+	}

[1] https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/

Thanks,
Mani

> -Sergey
> 
> > >
> > > > +
> > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > +             if (read) {
> > > >                       burst->sar = src_addr;
> > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > --
> > > > 2.24.0.rc1
> > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-11 12:38           ` Serge Semin
  2022-03-11 15:37             ` Zhi Li
@ 2022-03-11 17:55             ` Manivannan Sadhasivam
  2022-03-11 19:08               ` Serge Semin
  1 sibling, 1 reply; 52+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-11 17:55 UTC (permalink / raw)
  To: Serge Semin
  Cc: Zhi Li, Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Fri, Mar 11, 2022 at 03:38:57PM +0300, Serge Semin wrote:
> @Manivannan could you join the discussion?
> 
> On Thu, Mar 10, 2022 at 02:16:17PM -0600, Zhi Li wrote:
> > On Thu, Mar 10, 2022 at 1:38 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > > > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > > >
> > > > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > >
> > > > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > > > programs the source and destination addresses for read and write. Since the
> > > > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > > > >
> > > > > > Cc: stable@vger.kernel.org
> > > > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > > > ---
> > > > > > No change between v1 to v4
> > > > > >
> > > > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > index 66dc650577919..507f08db1aad3 100644
> > > > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > >       struct dw_edma_chunk *chunk;
> > > > > >       struct dw_edma_burst *burst;
> > > > > >       struct dw_edma_desc *desc;
> > > > > > +     bool read = false;
> > > > > >       u32 cnt = 0;
> > > > > >       int i;
> > > > > >
> > > > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > >               chunk->ll_region.sz += burst->sz;
> > > > > >               desc->alloc_sz += burst->sz;
> > > > > >
> > > > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > > > +             /****************************************************************
> > > > > > +              *
> > > > >
> > > > > > +              *        Root Complex                           Endpoint
> > > > > > +              * +-----------------------+             +----------------------+
> > > > > > +              * |                       |    TX CH    |                      |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > > > +              * |                       |             |                      |
> > > > > > +              * |                       |    RX CH    |                      |
> > > > > > +              * +-----------------------+             +----------------------+
> > > > > > +              *
> > > > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > > > +              *
> > > > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > > >
> > > > > Either I have some wrong notion about this issue, or something wrong
> > > > > with the explanation above and with this fix below.
> > > > >
> > > > > From my understanding of the possible DW eDMA IP-core setups the
> > > > > scatch above and the text below it are incorrect. Here is the way the
> > > > > DW eDMA can be used:
> > > > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > > > CPU/Application Memory is the memory of the CPU attached to the
> > > > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > > > by the Rx/Read channels.
> > > > >
> > > > > Note it's applicable for both Host and End-point case, when Linux is
> > > > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > > > memory into the remote memory. In general the remote memory can be
> > > > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > > > each of which is some remote device anyway from the Local CPU
> > > > > perspective.
> > > > >
> > > > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > > > embedded, which CPU/Application interface is connected to some
> > > > > embedded SRAM while remote (link partner) interface is directed
> > > > > towards the PCIe bus. At the same time the device is setup and handled
> > > > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > > > think that in order to preserve the normal DMA operations semantics we
> > > > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > > > host CPU perspective, since that's the side the DMA controller is
> > > > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > > > to copy data from the host CPU memory into the remote device memory.
> > > > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > > > would be read data from the Local CPU memory and copied it to the PCIe
> > > > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > > > from it's SRAM into the Host CPU memory.
> > > > >
> > > > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > > > a test setup with no real application, while the case 1) is a real setup
> > > > > available on our SoC and I guess on yours.
> > > >
> > >
> > > > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > > > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > > > a test function.
> > > > I previously sent vNTB patches to implement a virtual network between
> > > > RC and EP,
> > > > you can look if you have interest.
> > >
> > > AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> > > handled by its own CPU, which sets up the DW PCIe EP controller
> > > together with eDMA synthesized into the CPU' SoC. Am I right? While
> > > the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> > > FPGA with PCIe interface and eDMA IP-core installed. In that case all
> > > the setups are performed by the PCIe Host CPU. That's the root problem
> > > that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
> > >
> > > So to speak I would suggest for at least to have the scatch fixed in
> > > accordance with the logic explained in my message.
> > >
> > > >
> > > > >
> > > > > So what I suggest in the framework of this patch is just to implement
> > > > > the case 1) only. While the case 2) as it's an artificial one can be
> > > > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > > > in the kernel anyway. The only exception is an old-time attempt to get
> > > > > an eDMA IP test-driver mainlined into the kernel:
> > > > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > > > But it was long time ago. So it's unlikely to be accepted at all.
> > > > >
> > > > > What do you think?
> > > > >
> > > > > -Sergey
> > > > >
> > > > > > +              *
> > > > > > +              ****************************************************************/
> > > > > > +
> > > > >
> > > > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > +                     read = true;
> > > > >
> > >
> > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > redundant.
> > >
> > > Am I getting a response on this comment? In accordance with that
> > > conditional statement having dir == DMA_DEV_TO_MEM means performing
> > > read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> > > will be performed. The code path doesn't depend on the chan->dir
> > > value.
> > 
> 
> > Only dir is enough.
> 
> Right, in this case the fix is much simpler than suggested here. There
> is no need in additional local variable and complex conditional
> statement. It's supposed to be like this:
> 
> -             if (chan->dir == edma_dir_write) {
> +             if (dir == DMA_DEV_TO_MEM) {
> 
> See my next comment for a detailed explanation.
> 
> > Remote Read,  DMA_DEV_TO_MEM, it is a write channel.
> > SAR is the continual address at EP Side, DAR is a scatter list. RC side
> > 
> > Local Read,  DMA_DEV_TO_MEM, it is a reading channel.
> > SAR is the continual address at RC side,  DAR is a scatter list at EP side
> 
> Right, it's a caller responsibility to use a right channel for the
> operation (by flipping the channel the caller will invert the whole
> logic). But As I see it what you explain and my notion don't match to what
> is depicted on the scatch and written in the text below it. Don't you see?
> 
> -              *        Root Complex                           Endpoint
> +              * Linux Root Port/End-point                  PCIe End-point
>                * +-----------------------+             +----------------------+
> -              * |                       |    TX CH    |                      |
> -              * |                       |             |                      |
> -              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> +              * |                       |             |                      |
> +              * |                       |             |                      |
> +              * |    DEV_TO_MEM   Rx Ch <-------------+ Tx Ch  DEV_TO_MEM    |
>                * |                       |             |                      |
>                * |                       |             |                      |
> -              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> -              * |                       |             |                      |
> -              * |                       |    RX CH    |                      |
> +              * |    MEM_TO_DEV   Tx Ch +-------------> Rx Ch  MEM_TO_DEV    |
> +              * |                       |             |                      |
> +              * |                       |             |                      |
>                * +-----------------------+             +----------------------+
>                *
> -              * If eDMA is controlled by the Root complex, TX channel
> -              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> -              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> +              * If eDMA is controlled by the RP/EP, Rx channel
> +              * (EDMA_DIR_READ) is used for device read (DEV_TO_MEM) and Tx
> +              * channel (EDMA_DIR_WRITE) is used for device write (MEM_TO_DEV).
> +              * (Straightforward case.)
>                *
> -              * If eDMA is controlled by the endpoint, RX channel
> -              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> -              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> +              * If eDMA is embedded into an independent PCIe EP, Tx channel
> +              * (EDMA_DIR_WRITE) is used for device read (DEV_TO_MEM) and Rx
> +              * channel (EDMA_DIR_READ) is used for device write (MEM_TO_DEV).
> 
> I think what was suggested above explains well the semantics you are
> trying to implement here in the framework of this patch.
> 
> > 
> > Actually,  both sides should support a scatter list. Like
> > device_prep_dma_memcpy_sg
> > but it is beyond this patch series.
> 

As I said in other reply, my reasoning was entirely based on the eDMA test
application. Since it came from Synopsys, I went with that logic of channel
configuration.

But if someone from Synopsys confirms that your logic is correct, I'm fine with
reworking my commit.

Thanks,
Mani

> Right, it's beyond your series too, because that feature requires
> additional modifications. I am not asking about that.
> 
> -Sergey
> 
> > 
> > >
> > > -Sergey
> > >
> > > > >
> > > > > > +
> > > > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > > > +             if (read) {
> > > > > >                       burst->sar = src_addr;
> > > > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > --
> > > > > > 2.24.0.rc1
> > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
  2022-03-10 17:52       ` Serge Semin
@ 2022-03-11 17:58         ` Manivannan Sadhasivam
  0 siblings, 0 replies; 52+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-11 17:58 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Thu, Mar 10, 2022 at 08:52:25PM +0300, Serge Semin wrote:
> On Thu, Mar 10, 2022 at 11:11:59PM +0530, Manivannan Sadhasivam wrote:
> > On Thu, Mar 10, 2022 at 08:29:30PM +0300, Serge Semin wrote:
> > > On Wed, Mar 09, 2022 at 03:12:02PM -0600, Frank Li wrote:
> > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > 
> > > > The "direction" member of the "dma_slave_config" structure is deprecated.
> > > > The clients no longer use this field to specify the direction of the slave
> > > > channel. But in the eDMA core, this field is used to differentiate between the
> > > > Root complex (remote) and Endpoint (local) DMA accesses.
> > > > 
> > > > Nevertheless, we can't differentiate between local and remote accesses without
> > > > a dedicated flag. So let's get rid of the old check and add a new check for
> > > > verifying the DMA operation between local and remote memory instead.
> > > > 
> > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > ---
> > > > no chang between v1 to v4
> > > >  drivers/dma/dw-edma/dw-edma-core.c | 17 ++---------------
> > > >  1 file changed, 2 insertions(+), 15 deletions(-)
> > > > 
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > index 507f08db1aad3..47c6a52929fcd 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > @@ -341,22 +341,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > >  	if (!chan->configured)
> > > >  		return NULL;
> > > >  
> > > > -	switch (chan->config.direction) {
> > > > -	case DMA_DEV_TO_MEM: /* local DMA */
> > > > -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ)
> > > > -			break;
> > > > -		return NULL;
> > > > -	case DMA_MEM_TO_DEV: /* local DMA */
> > > > -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE)
> > > > -			break;
> > > 
> > > > +	/* eDMA supports only read and write between local and remote memory */
> > > 
> > > The comment is a bit confusing because both cases are named as
> > > "memory" while the permitted directions contains DEV-part, which
> > > means "device". What I would suggest to write here is something like:
> > > "DW eDMA supports transferring data from/to the CPU/Application memory
> > > to/from the PCIe link partner device by injecting the PCIe MWr/MRd TLPs."
> > > 
> > 
> 
> > End of the day, you'd be transferring data between remote and local memory
> > only and the terms (local and remote) are also used in the databook. So I think
> > the comment is fine.
> 
> Yes, but the databook either adds a note regarding what memory it is
> or it can be inferred from the text context. So at least it would be
> appropriate to preserve the notes here two:
> "eDMA supports only read and write between local (CPU/application) and
> remote (PCIe/link partner) memory." Otherwise it's hard to understand
> what memory the comment states about.
> 

Okay, I'm fine with this.

"eDMA supports only read and write between local (CPU/application) and
remote (PCIe/link partner) memory."

Thanks,
Mani

> -Sergey
> 
> > 
> > Thanks,
> > Mani
> > 
> > > -Sergey
> > > 
> > > > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> > > >  		return NULL;
> > > > -	default: /* remote DMA */
> > > > -		if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_READ)
> > > > -			break;
> > > > -		if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE)
> > > > -			break;
> > > > -		return NULL;
> > > > -	}
> > > >  
> > > >  	if (xfer->type == EDMA_XFER_CYCLIC) {
> > > >  		if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt)
> > > > -- 
> > > > 2.24.0.rc1
> > > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-11 17:41     ` Manivannan Sadhasivam
@ 2022-03-11 19:01       ` Serge Semin
  2022-03-12  5:37         ` Manivannan Sadhasivam
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-11 19:01 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 10, 2022 at 07:31:23PM +0300, Serge Semin wrote:
> > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > 
> > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > programs the source and destination addresses for read and write. Since the
> > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > issue by finding out the read operation first and program the eDMA accordingly.
> > > 
> > > Cc: stable@vger.kernel.org
> > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > > No change between v1 to v4
> > > 
> > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > index 66dc650577919..507f08db1aad3 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > >  	struct dw_edma_chunk *chunk;
> > >  	struct dw_edma_burst *burst;
> > >  	struct dw_edma_desc *desc;
> > > +	bool read = false;
> > >  	u32 cnt = 0;
> > >  	int i;
> > >  
> > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > >  		chunk->ll_region.sz += burst->sz;
> > >  		desc->alloc_sz += burst->sz;
> > >  
> > > -		if (chan->dir == EDMA_DIR_WRITE) {
> > > +		/****************************************************************
> > > +		 *
> > 
> > > +		 *        Root Complex                           Endpoint
> > > +		 * +-----------------------+             +----------------------+
> > > +		 * |                       |    TX CH    |                      |
> > > +		 * |                       |             |                      |
> > > +		 * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > +		 * |                       |             |                      |
> > > +		 * |                       |             |                      |
> > > +		 * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > +		 * |                       |             |                      |
> > > +		 * |                       |    RX CH    |                      |
> > > +		 * +-----------------------+             +----------------------+
> > > +		 *
> > > +		 * If eDMA is controlled by the Root complex, TX channel
> > > +		 * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > +		 * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > +		 *
> > > +		 * If eDMA is controlled by the endpoint, RX channel
> > > +		 * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > +		 * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > 
> > Either I have some wrong notion about this issue, or something wrong
> > with the explanation above and with this fix below.
> > 
> > From my understanding of the possible DW eDMA IP-core setups the
> > scatch above and the text below it are incorrect. Here is the way the
> > DW eDMA can be used:
> > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > CPU/Application Memory is the memory of the CPU attached to the
> > host/EP controller, while the remote (link partner) memory is the PCIe
> > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > by the Rx/Read channels.
> > 
> 

> I'm not aware or even not sure about the use of eDMA in the PCIe host.
> If that's the case, how the endpoint can access it from remote perspective?
> Do you have a usecase or an example where used or even documented?

I am aware. I've got SoC with DW PCIe Host v4.60/v4.70 and eDMA
enabled for each of them. I also poses several manuals of the DW PCIe
Host and End-points of various versions. Both Host and End-points can
have eDMA enabled. But it's possible to have the eDMA accessed via the
PCIe wire only for the End-points and only if the IP-core is
accordingly synthesized. Other than that the eDMA is configurable from
the Local CPU only.

> 
> > Note it's applicable for both Host and End-point case, when Linux is
> > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > end-point, then MEM_TO_DEV means copying data from the local CPU
> > memory into the remote memory. In general the remote memory can be
> > either some PCIe device on the bus or the Root Complex' CPU memory,
> > each of which is some remote device anyway from the Local CPU
> > perspective.
> > 
> > 2) Embedded into the PCIe EP. This case is implemented in the
> > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > prototype kit. It is a normal PCIe peripheral device with eDMA
> > embedded, which CPU/Application interface is connected to some
> > embedded SRAM while remote (link partner) interface is directed
> > towards the PCIe bus. At the same time the device is setup and handled
> > by the code running on a CPU connected to the PCIe Host controller.  I
> > think that in order to preserve the normal DMA operations semantics we
> > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > host CPU perspective, since that's the side the DMA controller is
> > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > to copy data from the host CPU memory into the remote device memory.
> > It means to allocate Rx/Read channel on the eDMA controller, so one
> > would be read data from the Local CPU memory and copied it to the PCIe
> > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > from it's SRAM into the Host CPU memory.
> > 
> > Please note as I understand the case 2) describes the Synopsys PCIe
> > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > a test setup with no real application, while the case 1) is a real setup
> > available on our SoC and I guess on yours.
> > 
> > So what I suggest in the framework of this patch is just to implement
> > the case 1) only. While the case 2) as it's an artificial one can be
> > manually handled by the DMA client drivers. BTW There aren't ones available
> > in the kernel anyway. The only exception is an old-time attempt to get
> > an eDMA IP test-driver mainlined into the kernel:
> > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > But it was long time ago. So it's unlikely to be accepted at all.
> > 
> > What do you think?
> > 
> 

> As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> access to it happens over PCIe bus or by the local CPU.

Not fully correct. Root Ports can also have eDMA embedded. In that
case the eDMA can be only accessible from the local CPU. At the same
time the DW PCIe End-point case is the IP-core synthesize parameters
specific. It's always possible to access the eDMA CSRs from local
CPU, but a particular End-point BAR can be pre-synthesize to map
either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
perform a full End-point configuration. Anyway the case if the eDMA
functionality being accessible over the PCIe wire doesn't really make
much sense with no info regarding the application logic hidden behind
the PCIe End-point interface since SAR/DAR LLP is supposed to be
initialized with an address from the local (application) memory space.

So AFAICS the main usecase of the controller is 1) - when eDMA is a
part of the Root Port/End-point and only local CPU is supposed to have
it accessed and configured.

I can resend this patch with my fix to the problem. What do you think?

-Sergey

> 
> The commit from Alan Mikhak is what I took as a reference since the patch was
> already merged:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> 
> Thanks,
> Mani
> 
> > -Sergey
> > 
> > > +		 *
> > > +		 ****************************************************************/
> > > +
> > 
> > > +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > +			read = true;
> > 
> > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > redundant.
> > 
> > > +
> > > +		/* Program the source and destination addresses for DMA read/write */
> > > +		if (read) {
> > >  			burst->sar = src_addr;
> > >  			if (xfer->type == EDMA_XFER_CYCLIC) {
> > >  				burst->dar = xfer->xfer.cyclic.paddr;
> > > -- 
> > > 2.24.0.rc1
> > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-11 17:55             ` Manivannan Sadhasivam
@ 2022-03-11 19:08               ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-11 19:08 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Zhi Li, Frank Li, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Fri, Mar 11, 2022 at 11:25:56PM +0530, Manivannan Sadhasivam wrote:
> On Fri, Mar 11, 2022 at 03:38:57PM +0300, Serge Semin wrote:
> > @Manivannan could you join the discussion?
> > 
> > On Thu, Mar 10, 2022 at 02:16:17PM -0600, Zhi Li wrote:
> > > On Thu, Mar 10, 2022 at 1:38 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > >
> > > > On Thu, Mar 10, 2022 at 10:50:14AM -0600, Zhi Li wrote:
> > > > > On Thu, Mar 10, 2022 at 10:32 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > > > >
> > > > > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > >
> > > > > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > > > > programs the source and destination addresses for read and write. Since the
> > > > > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > > > > >
> > > > > > > Cc: stable@vger.kernel.org
> > > > > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > > > > ---
> > > > > > > No change between v1 to v4
> > > > > > >
> > > > > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > > > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > > > > >
> > > > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > index 66dc650577919..507f08db1aad3 100644
> > > > > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > > >       struct dw_edma_chunk *chunk;
> > > > > > >       struct dw_edma_burst *burst;
> > > > > > >       struct dw_edma_desc *desc;
> > > > > > > +     bool read = false;
> > > > > > >       u32 cnt = 0;
> > > > > > >       int i;
> > > > > > >
> > > > > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > > > > >               chunk->ll_region.sz += burst->sz;
> > > > > > >               desc->alloc_sz += burst->sz;
> > > > > > >
> > > > > > > -             if (chan->dir == EDMA_DIR_WRITE) {
> > > > > > > +             /****************************************************************
> > > > > > > +              *
> > > > > >
> > > > > > > +              *        Root Complex                           Endpoint
> > > > > > > +              * +-----------------------+             +----------------------+
> > > > > > > +              * |                       |    TX CH    |                      |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > > > > +              * |                       |             |                      |
> > > > > > > +              * |                       |    RX CH    |                      |
> > > > > > > +              * +-----------------------+             +----------------------+
> > > > > > > +              *
> > > > > > > +              * If eDMA is controlled by the Root complex, TX channel
> > > > > > > +              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > > > > +              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > > > > +              *
> > > > > > > +              * If eDMA is controlled by the endpoint, RX channel
> > > > > > > +              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > > > > +              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > > > >
> > > > > > Either I have some wrong notion about this issue, or something wrong
> > > > > > with the explanation above and with this fix below.
> > > > > >
> > > > > > From my understanding of the possible DW eDMA IP-core setups the
> > > > > > scatch above and the text below it are incorrect. Here is the way the
> > > > > > DW eDMA can be used:
> > > > > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > > > > CPU/Application Memory is the memory of the CPU attached to the
> > > > > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > > > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > > > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > > > > by the Rx/Read channels.
> > > > > >
> > > > > > Note it's applicable for both Host and End-point case, when Linux is
> > > > > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > > > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > > > > memory into the remote memory. In general the remote memory can be
> > > > > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > > > > each of which is some remote device anyway from the Local CPU
> > > > > > perspective.
> > > > > >
> > > > > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > > > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > > > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > > > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > > > > embedded, which CPU/Application interface is connected to some
> > > > > > embedded SRAM while remote (link partner) interface is directed
> > > > > > towards the PCIe bus. At the same time the device is setup and handled
> > > > > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > > > > think that in order to preserve the normal DMA operations semantics we
> > > > > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > > > > host CPU perspective, since that's the side the DMA controller is
> > > > > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > > > > to copy data from the host CPU memory into the remote device memory.
> > > > > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > > > > would be read data from the Local CPU memory and copied it to the PCIe
> > > > > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > > > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > > > > from it's SRAM into the Host CPU memory.
> > > > > >
> > > > > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > > > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > > > > a test setup with no real application, while the case 1) is a real setup
> > > > > > available on our SoC and I guess on yours.
> > > > >
> > > >
> > > > > I think yes. But Remote EP also is a one kind of usage module. Just no one
> > > > > writes an EP functional driver for it yet.  Even pci-epf-test was just
> > > > > a test function.
> > > > > I previously sent vNTB patches to implement a virtual network between
> > > > > RC and EP,
> > > > > you can look if you have interest.
> > > >
> > > > AFAIU the remote EP case is the same as 1) anyway. The remote EP is
> > > > handled by its own CPU, which sets up the DW PCIe EP controller
> > > > together with eDMA synthesized into the CPU' SoC. Am I right? While
> > > > the case 2) doesn't have any CPU attached on the PCIe EP. It's just an
> > > > FPGA with PCIe interface and eDMA IP-core installed. In that case all
> > > > the setups are performed by the PCIe Host CPU. That's the root problem
> > > > that causes having all the DEV_TO_MEM/MEM_TO_DEV complications.
> > > >
> > > > So to speak I would suggest for at least to have the scatch fixed in
> > > > accordance with the logic explained in my message.
> > > >
> > > > >
> > > > > >
> > > > > > So what I suggest in the framework of this patch is just to implement
> > > > > > the case 1) only. While the case 2) as it's an artificial one can be
> > > > > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > > > > in the kernel anyway. The only exception is an old-time attempt to get
> > > > > > an eDMA IP test-driver mainlined into the kernel:
> > > > > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > > > > But it was long time ago. So it's unlikely to be accepted at all.
> > > > > >
> > > > > > What do you think?
> > > > > >
> > > > > > -Sergey
> > > > > >
> > > > > > > +              *
> > > > > > > +              ****************************************************************/
> > > > > > > +
> > > > > >
> > > > > > > +             if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > +                 (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > +                     read = true;
> > > > > >
> > > >
> > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > redundant.
> > > >
> > > > Am I getting a response on this comment? In accordance with that
> > > > conditional statement having dir == DMA_DEV_TO_MEM means performing
> > > > read operation. If dir equals DMA_MEM_TO_DEV then a write operation
> > > > will be performed. The code path doesn't depend on the chan->dir
> > > > value.
> > > 
> > 
> > > Only dir is enough.
> > 
> > Right, in this case the fix is much simpler than suggested here. There
> > is no need in additional local variable and complex conditional
> > statement. It's supposed to be like this:
> > 
> > -             if (chan->dir == edma_dir_write) {
> > +             if (dir == DMA_DEV_TO_MEM) {
> > 
> > See my next comment for a detailed explanation.
> > 
> > > Remote Read,  DMA_DEV_TO_MEM, it is a write channel.
> > > SAR is the continual address at EP Side, DAR is a scatter list. RC side
> > > 
> > > Local Read,  DMA_DEV_TO_MEM, it is a reading channel.
> > > SAR is the continual address at RC side,  DAR is a scatter list at EP side
> > 
> > Right, it's a caller responsibility to use a right channel for the
> > operation (by flipping the channel the caller will invert the whole
> > logic). But As I see it what you explain and my notion don't match to what
> > is depicted on the scatch and written in the text below it. Don't you see?
> > 
> > -              *        Root Complex                           Endpoint
> > +              * Linux Root Port/End-point                  PCIe End-point
> >                * +-----------------------+             +----------------------+
> > -              * |                       |    TX CH    |                      |
> > -              * |                       |             |                      |
> > -              * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > +              * |                       |             |                      |
> > +              * |                       |             |                      |
> > +              * |    DEV_TO_MEM   Rx Ch <-------------+ Tx Ch  DEV_TO_MEM    |
> >                * |                       |             |                      |
> >                * |                       |             |                      |
> > -              * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > -              * |                       |             |                      |
> > -              * |                       |    RX CH    |                      |
> > +              * |    MEM_TO_DEV   Tx Ch +-------------> Rx Ch  MEM_TO_DEV    |
> > +              * |                       |             |                      |
> > +              * |                       |             |                      |
> >                * +-----------------------+             +----------------------+
> >                *
> > -              * If eDMA is controlled by the Root complex, TX channel
> > -              * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > -              * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > +              * If eDMA is controlled by the RP/EP, Rx channel
> > +              * (EDMA_DIR_READ) is used for device read (DEV_TO_MEM) and Tx
> > +              * channel (EDMA_DIR_WRITE) is used for device write (MEM_TO_DEV).
> > +              * (Straightforward case.)
> >                *
> > -              * If eDMA is controlled by the endpoint, RX channel
> > -              * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > -              * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > +              * If eDMA is embedded into an independent PCIe EP, Tx channel
> > +              * (EDMA_DIR_WRITE) is used for device read (DEV_TO_MEM) and Rx
> > +              * channel (EDMA_DIR_READ) is used for device write (MEM_TO_DEV).
> > 
> > I think what was suggested above explains well the semantics you are
> > trying to implement here in the framework of this patch.
> > 
> > > 
> > > Actually,  both sides should support a scatter list. Like
> > > device_prep_dma_memcpy_sg
> > > but it is beyond this patch series.
> > 
> 

> As I said in other reply, my reasoning was entirely based on the eDMA test
> application. Since it came from Synopsys, I went with that logic of channel
> configuration.
> 
> But if someone from Synopsys confirms that your logic is correct, I'm fine with
> reworking my commit.

There is no need in waiting for the Synopsys response. I've got info
manuals of my own to say:
1) Your fix is correct, but the conditional statement has redundant
operations. It can be simplified as I suggested.
2) Your scatch and text are incorrect and they must be fixed so not to
be confusing.

-Sergey

> 
> Thanks,
> Mani
> 
> > Right, it's beyond your series too, because that feature requires
> > additional modifications. I am not asking about that.
> > 
> > -Sergey
> > 
> > > 
> > > >
> > > > -Sergey
> > > >
> > > > > >
> > > > > > > +
> > > > > > > +             /* Program the source and destination addresses for DMA read/write */
> > > > > > > +             if (read) {
> > > > > > >                       burst->sar = src_addr;
> > > > > > >                       if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > >                               burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > --
> > > > > > > 2.24.0.rc1
> > > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-11 19:01       ` Serge Semin
@ 2022-03-12  5:37         ` Manivannan Sadhasivam
  2022-03-14  8:33           ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-12  5:37 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> > On Thu, Mar 10, 2022 at 07:31:23PM +0300, Serge Semin wrote:
> > > On Wed, Mar 09, 2022 at 03:12:01PM -0600, Frank Li wrote:
> > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > 
> > > > When eDMA is controlled by the Endpoint (EP), the current logic incorrectly
> > > > programs the source and destination addresses for read and write. Since the
> > > > Root complex and Endpoint uses the opposite channels for read/write, fix the
> > > > issue by finding out the read operation first and program the eDMA accordingly.
> > > > 
> > > > Cc: stable@vger.kernel.org
> > > > Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
> > > > Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > ---
> > > > No change between v1 to v4
> > > > 
> > > >  drivers/dma/dw-edma/dw-edma-core.c | 32 +++++++++++++++++++++++++++++-
> > > >  1 file changed, 31 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > index 66dc650577919..507f08db1aad3 100644
> > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > @@ -334,6 +334,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > >  	struct dw_edma_chunk *chunk;
> > > >  	struct dw_edma_burst *burst;
> > > >  	struct dw_edma_desc *desc;
> > > > +	bool read = false;
> > > >  	u32 cnt = 0;
> > > >  	int i;
> > > >  
> > > > @@ -424,7 +425,36 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> > > >  		chunk->ll_region.sz += burst->sz;
> > > >  		desc->alloc_sz += burst->sz;
> > > >  
> > > > -		if (chan->dir == EDMA_DIR_WRITE) {
> > > > +		/****************************************************************
> > > > +		 *
> > > 
> > > > +		 *        Root Complex                           Endpoint
> > > > +		 * +-----------------------+             +----------------------+
> > > > +		 * |                       |    TX CH    |                      |
> > > > +		 * |                       |             |                      |
> > > > +		 * |      DEV_TO_MEM       <-------------+     MEM_TO_DEV       |
> > > > +		 * |                       |             |                      |
> > > > +		 * |                       |             |                      |
> > > > +		 * |      MEM_TO_DEV       +------------->     DEV_TO_MEM       |
> > > > +		 * |                       |             |                      |
> > > > +		 * |                       |    RX CH    |                      |
> > > > +		 * +-----------------------+             +----------------------+
> > > > +		 *
> > > > +		 * If eDMA is controlled by the Root complex, TX channel
> > > > +		 * (EDMA_DIR_WRITE) is used for memory read (DEV_TO_MEM) and RX
> > > > +		 * channel (EDMA_DIR_READ) is used for memory write (MEM_TO_DEV).
> > > > +		 *
> > > > +		 * If eDMA is controlled by the endpoint, RX channel
> > > > +		 * (EDMA_DIR_READ) is used for memory read (DEV_TO_MEM) and TX
> > > > +		 * channel (EDMA_DIR_WRITE) is used for memory write (MEM_TO_DEV).
> > > 
> > > Either I have some wrong notion about this issue, or something wrong
> > > with the explanation above and with this fix below.
> > > 
> > > From my understanding of the possible DW eDMA IP-core setups the
> > > scatch above and the text below it are incorrect. Here is the way the
> > > DW eDMA can be used:
> > > 1) Embedded into the DW PCIe Host/EP controller. In this case
> > > CPU/Application Memory is the memory of the CPU attached to the
> > > host/EP controller, while the remote (link partner) memory is the PCIe
> > > bus memory. In this case MEM_TO_DEV operation is supposed to be
> > > performed by the Tx/Write channels, while the DEV_TO_MEM operation -
> > > by the Rx/Read channels.
> > > 
> > 
> 
> > I'm not aware or even not sure about the use of eDMA in the PCIe host.
> > If that's the case, how the endpoint can access it from remote perspective?
> > Do you have a usecase or an example where used or even documented?
> 
> I am aware. I've got SoC with DW PCIe Host v4.60/v4.70 and eDMA
> enabled for each of them. I also poses several manuals of the DW PCIe
> Host and End-points of various versions. Both Host and End-points can
> have eDMA enabled. But it's possible to have the eDMA accessed via the
> PCIe wire only for the End-points and only if the IP-core is
> accordingly synthesized. Other than that the eDMA is configurable from
> the Local CPU only.
> 

Interesting!

> > 
> > > Note it's applicable for both Host and End-point case, when Linux is
> > > running on the CPU-side of the eDMA controller. So if it's DW PCIe
> > > end-point, then MEM_TO_DEV means copying data from the local CPU
> > > memory into the remote memory. In general the remote memory can be
> > > either some PCIe device on the bus or the Root Complex' CPU memory,
> > > each of which is some remote device anyway from the Local CPU
> > > perspective.
> > > 
> > > 2) Embedded into the PCIe EP. This case is implemented in the
> > > drivers/dma/dw-edma/dw-edma-pcie.c driver. AFAICS from the commits log
> > > and from the driver code, that device is a Synopsys PCIe EndPoint IP
> > > prototype kit. It is a normal PCIe peripheral device with eDMA
> > > embedded, which CPU/Application interface is connected to some
> > > embedded SRAM while remote (link partner) interface is directed
> > > towards the PCIe bus. At the same time the device is setup and handled
> > > by the code running on a CPU connected to the PCIe Host controller.  I
> > > think that in order to preserve the normal DMA operations semantics we
> > > still need to consider the MEM_TO_DEV/DEV_TO_MEM operations from the
> > > host CPU perspective, since that's the side the DMA controller is
> > > supposed to be setup from.  In this MEM_TO_DEV is supposed to be used
> > > to copy data from the host CPU memory into the remote device memory.
> > > It means to allocate Rx/Read channel on the eDMA controller, so one
> > > would be read data from the Local CPU memory and copied it to the PCIe
> > > device SRAM. The logic of the DEV_TO_MEM direction would be just
> > > flipped. The eDMA PCIe device shall use Tx/Write channel to copy data
> > > from it's SRAM into the Host CPU memory.
> > > 
> > > Please note as I understand the case 2) describes the Synopsys PCIe
> > > EndPoint IP prototype kit, which is based on some FPGA code. It's just
> > > a test setup with no real application, while the case 1) is a real setup
> > > available on our SoC and I guess on yours.
> > > 
> > > So what I suggest in the framework of this patch is just to implement
> > > the case 1) only. While the case 2) as it's an artificial one can be
> > > manually handled by the DMA client drivers. BTW There aren't ones available
> > > in the kernel anyway. The only exception is an old-time attempt to get
> > > an eDMA IP test-driver mainlined into the kernel:
> > > https://patchwork.kernel.org/project/linux-pci/patch/cc195ac53839b318764c8f6502002cd6d933a923.1547230339.git.gustavo.pimentel@synopsys.com/
> > > But it was long time ago. So it's unlikely to be accepted at all.
> > > 
> > > What do you think?
> > > 
> > 
> 
> > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > access to it happens over PCIe bus or by the local CPU.
> 
> Not fully correct. Root Ports can also have eDMA embedded. In that
> case the eDMA can be only accessible from the local CPU. At the same
> time the DW PCIe End-point case is the IP-core synthesize parameters
> specific. It's always possible to access the eDMA CSRs from local
> CPU, but a particular End-point BAR can be pre-synthesize to map
> either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> perform a full End-point configuration. Anyway the case if the eDMA
> functionality being accessible over the PCIe wire doesn't really make
> much sense with no info regarding the application logic hidden behind
> the PCIe End-point interface since SAR/DAR LLP is supposed to be
> initialized with an address from the local (application) memory space.
> 

Thanks for the explanation, it clarifies my doubt. I got misleaded by the
earlier commits...

> So AFAICS the main usecase of the controller is 1) - when eDMA is a
> part of the Root Port/End-point and only local CPU is supposed to have
> it accessed and configured.
> 
> I can resend this patch with my fix to the problem. What do you think?
> 

Yes, please do.

Thanks,
Mani

> -Sergey
> 
> > 
> > The commit from Alan Mikhak is what I took as a reference since the patch was
> > already merged:
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > 
> > Thanks,
> > Mani
> > 
> > > -Sergey
> > > 
> > > > +		 *
> > > > +		 ****************************************************************/
> > > > +
> > > 
> > > > +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > +			read = true;
> > > 
> > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > redundant.
> > > 
> > > > +
> > > > +		/* Program the source and destination addresses for DMA read/write */
> > > > +		if (read) {
> > > >  			burst->sar = src_addr;
> > > >  			if (xfer->type == EDMA_XFER_CYCLIC) {
> > > >  				burst->dar = xfer->xfer.cyclic.paddr;
> > > > -- 
> > > > 2.24.0.rc1
> > > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-09 21:11 ` [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures Frank Li
  2022-03-10 12:50   ` Serge Semin
  2022-03-10 20:20   ` Serge Semin
@ 2022-03-12 19:54   ` Serge Semin
  2 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-12 19:54 UTC (permalink / raw)
  To: Frank Li
  Cc: Serge Semin, gustavo.pimentel, hongxing.zhu, l.stach, linux-imx,
	linux-pci, dmaengine, lznuaa, vkoul, lorenzo.pieralisi, robh, kw,
	bhelgaas, shawnguo, manivannan.sadhasivam

On Wed, Mar 09, 2022 at 03:11:57PM -0600, Frank Li wrote:
> "struct dw_edma_chip" contains an internal structure "struct dw_edma" that
> is used by the eDMA core internally. This structure should not be touched
> by the eDMA controller drivers themselves. But currently, the eDMA
> controller drivers like "dw-edma-pci" allocates and populates this
> internal structure then passes it on to eDMA core. The eDMA core further
> populates the structure and uses it. This is wrong!
> 
> Hence, move all the "struct dw_edma" specifics from controller drivers
> to the eDMA core.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> Change from v3 to v4
>  - Accept most suggestions of Serge Semin
> Change from v2 to v3
>  - none
> Change from v1 to v2
>  - rework commit message
>  - remove duplicate field in struct dw_edma
> 
>  drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
>  drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
>  drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
>  drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
>  include/linux/dma/edma.h                 | 44 +++++++++++++
>  6 files changed, 144 insertions(+), 130 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 53289927dd0d6..1abf41d49f75b 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
>  static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
>  {
>  	struct dw_edma_chan *chan = desc->chan;
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma_chip *chip = chan->dw->chip;
>  	struct dw_edma_chunk *chunk;
>  
>  	chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
> @@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
>  	 */
>  	chunk->cb = !(desc->chunks_alloc % 2);
>  	if (chan->dir == EDMA_DIR_WRITE) {
> -		chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
> -		chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
> +		chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
> +		chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
>  	} else {
> -		chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
> -		chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
> +		chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
> +		chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
>  	}
>  
>  	if (desc->chunk) {
> @@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
>  	if (chan->status != EDMA_ST_IDLE)
>  		return -EBUSY;
>  
> -	pm_runtime_get(chan->chip->dev);
> +	pm_runtime_get(chan->dw->chip->dev);
>  
>  	return 0;
>  }
> @@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
>  		cpu_relax();
>  	}
>  
> -	pm_runtime_put(chan->chip->dev);
> +	pm_runtime_put(chan->dw->chip->dev);
>  }
>  
>  static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,

> @@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,

Please convert the dw_edma_channel_setup() and dw_edma_irq_request()
methods to accepting struct dw_edma *dw instead of struct dw_edma_chip *chip.
Thus we'll have the DW eDMA private data-based internal implementation
is it was originally intended. The chip-info will only be used as a
part of the probe/remove interface.

>  	}
>  
>  	INIT_LIST_HEAD(&dma->channels);
> -	for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
> +	for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
>  		chan = &dw->chan[i];
>  
>  		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> @@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  
>  		chan->vc.chan.private = dt_region;
>  
> -		chan->chip = chip;
> +		chan->dw = dw;
>  		chan->id = j;
>  		chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
>  		chan->configured = false;
> @@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  		chan->status = EDMA_ST_IDLE;
>  
>  		if (write)
> -			chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
> +			chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
>  		else
> -			chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
> +			chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
>  		chan->ll_max -= 1;
>  
>  		dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
>  			 write ? "write" : "read", j, chan->ll_max);
>  
> -		if (dw->nr_irqs == 1)
> +		if (chip->nr_irqs == 1)
>  			pos = 0;
>  		else
>  			pos = off_alloc + (j % alloc);
> @@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  		vchan_init(&chan->vc, dma);
>  
>  		if (write) {
> -			dt_region->paddr = dw->dt_region_wr[j].paddr;
> -			dt_region->vaddr = dw->dt_region_wr[j].vaddr;
> -			dt_region->sz = dw->dt_region_wr[j].sz;
> +			dt_region->paddr = chip->dt_region_wr[j].paddr;
> +			dt_region->vaddr = chip->dt_region_wr[j].vaddr;
> +			dt_region->sz = chip->dt_region_wr[j].sz;
>  		} else {
> -			dt_region->paddr = dw->dt_region_rd[j].paddr;
> -			dt_region->vaddr = dw->dt_region_rd[j].vaddr;
> -			dt_region->sz = dw->dt_region_rd[j].sz;
> +			dt_region->paddr = chip->dt_region_rd[j].paddr;
> +			dt_region->vaddr = chip->dt_region_rd[j].vaddr;
> +			dt_region->sz = chip->dt_region_rd[j].sz;
>  		}
>  
>  		dw_edma_v0_core_device_config(chan);
> @@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  
>  	ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
>  
> -	if (dw->nr_irqs < 1)
> +	if (chip->nr_irqs < 1)
>  		return -EINVAL;
>  
> -	if (dw->nr_irqs == 1) {
> +	if (chip->nr_irqs == 1) {
>  		/* Common IRQ shared among all channels */
> -		irq = dw->ops->irq_vector(dev, 0);
> +		irq = chip->ops->irq_vector(dev, 0);
>  		err = request_irq(irq, dw_edma_interrupt_common,
>  				  IRQF_SHARED, dw->name, &dw->irq[0]);
>  		if (err) {
> -			dw->nr_irqs = 0;
> +			chip->nr_irqs = 0;
>  			return err;
>  		}
>  
> @@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  			get_cached_msi_msg(irq, &dw->irq[0].msi);
>  	} else {
>  		/* Distribute IRQs equally among all channels */
> -		int tmp = dw->nr_irqs;
> +		int tmp = chip->nr_irqs;
>  
>  		while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
>  			dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
> @@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  		dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
>  
>  		for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
> -			irq = dw->ops->irq_vector(dev, i);
> +			irq = chip->ops->irq_vector(dev, i);
>  			err = request_irq(irq,
>  					  i < *wr_alloc ?
>  						dw_edma_interrupt_write :
> @@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  					  IRQF_SHARED, dw->name,
>  					  &dw->irq[i]);
>  			if (err) {
> -				dw->nr_irqs = i;
> +				chip->nr_irqs = i;
>  				return err;
>  			}
>  
> @@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
>  				get_cached_msi_msg(irq, &dw->irq[i].msi);
>  		}
>  
> -		dw->nr_irqs = i;
> +		chip->nr_irqs = i;
>  	}
>  
>  	return err;
> @@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	if (!dev)
>  		return -EINVAL;
>  
> -	dw = chip->dw;
> -	if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
> +	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	chip->dw = dw;
> +	dw->chip = chip;
> +
> +	if (!chip->nr_irqs || !chip->ops)
>  		return -EINVAL;
>  
>  	raw_spin_lock_init(&dw->lock);
>  
> -	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,

> +

Redundant empty line. Please drop it.

-Sergey

> +	dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
>  	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
>  
> -	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
> +	dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
>  			      dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
>  	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
>  
> @@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	/* Disable eDMA, only to establish the ideal initial conditions */
>  	dw_edma_v0_core_off(dw);
>  
> +	dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> +	if (!dw->irq)
> +		return -ENOMEM;
> +
>  	/* Request IRQs */
>  	err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
>  	if (err)
> @@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	return 0;
>  
>  err_irq_free:
> -	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> -		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> +	for (i = (chip->nr_irqs - 1); i >= 0; i--)
> +		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
>  
> -	dw->nr_irqs = 0;
> +	chip->nr_irqs = 0;
>  
>  	return err;
>  }
> @@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  	dw_edma_v0_core_off(dw);
>  
>  	/* Free irqs */
> -	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> -		free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> +	for (i = (chip->nr_irqs - 1); i >= 0; i--)
> +		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
>  
>  	/* Power management */
>  	pm_runtime_disable(dev);
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index 60316d408c3e0..e254c2fc3d9cf 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -15,20 +15,12 @@
>  #include "../virt-dma.h"
>  
>  #define EDMA_LL_SZ					24
> -#define EDMA_MAX_WR_CH					8
> -#define EDMA_MAX_RD_CH					8
>  
>  enum dw_edma_dir {
>  	EDMA_DIR_WRITE = 0,
>  	EDMA_DIR_READ
>  };
>  
> -enum dw_edma_map_format {
> -	EDMA_MF_EDMA_LEGACY = 0x0,
> -	EDMA_MF_EDMA_UNROLL = 0x1,
> -	EDMA_MF_HDMA_COMPAT = 0x5
> -};
> -
>  enum dw_edma_request {
>  	EDMA_REQ_NONE = 0,
>  	EDMA_REQ_STOP,
> @@ -57,12 +49,6 @@ struct dw_edma_burst {
>  	u32				sz;
>  };
>  
> -struct dw_edma_region {
> -	phys_addr_t			paddr;
> -	void				__iomem *vaddr;
> -	size_t				sz;
> -};
> -
>  struct dw_edma_chunk {
>  	struct list_head		list;
>  	struct dw_edma_chan		*chan;
> @@ -87,7 +73,7 @@ struct dw_edma_desc {
>  
>  struct dw_edma_chan {
>  	struct virt_dma_chan		vc;
> -	struct dw_edma_chip		*chip;
> +	struct dw_edma			*dw;
>  	int				id;
>  	enum dw_edma_dir		dir;
>  
> @@ -109,10 +95,6 @@ struct dw_edma_irq {
>  	struct dw_edma			*dw;
>  };
>  
> -struct dw_edma_core_ops {
> -	int	(*irq_vector)(struct device *dev, unsigned int nr);
> -};
> -
>  struct dw_edma {
>  	char				name[20];
>  
> @@ -122,21 +104,13 @@ struct dw_edma {
>  	struct dma_device		rd_edma;
>  	u16				rd_ch_cnt;
>  
> -	struct dw_edma_region		rg_region;	/* Registers */
> -	struct dw_edma_region		ll_region_wr[EDMA_MAX_WR_CH];
> -	struct dw_edma_region		ll_region_rd[EDMA_MAX_RD_CH];
> -	struct dw_edma_region		dt_region_wr[EDMA_MAX_WR_CH];
> -	struct dw_edma_region		dt_region_rd[EDMA_MAX_RD_CH];
> -
>  	struct dw_edma_irq		*irq;
> -	int				nr_irqs;
> -
> -	enum dw_edma_map_format		mf;
>  
>  	struct dw_edma_chan		*chan;
> -	const struct dw_edma_core_ops	*ops;
>  
>  	raw_spinlock_t			lock;		/* Only for legacy */
> +
> +	struct dw_edma_chip             *chip;
>  #ifdef CONFIG_DEBUG_FS
>  	struct dentry			*debugfs;
>  #endif /* CONFIG_DEBUG_FS */
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 44f6e09bdb531..2c1c5fa4e9f28 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	struct dw_edma_pcie_data vsec_data;
>  	struct device *dev = &pdev->dev;
>  	struct dw_edma_chip *chip;
> -	struct dw_edma *dw;
>  	int err, nr_irqs;
>  	int i, mask;
>  
> @@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	if (!chip)
>  		return -ENOMEM;
>  
> -	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> -	if (!dw)
> -		return -ENOMEM;
> -
>  	/* IRQs allocation */
>  	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
>  					PCI_IRQ_MSI | PCI_IRQ_MSIX);
> @@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	}
>  
>  	/* Data structure initialization */
> -	chip->dw = dw;
>  	chip->dev = dev;
>  	chip->id = pdev->devfn;
> -	chip->irq = pdev->irq;
>  
> -	dw->mf = vsec_data.mf;
> -	dw->nr_irqs = nr_irqs;
> -	dw->ops = &dw_edma_pcie_core_ops;
> -	dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
> -	dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
> +	chip->mf = vsec_data.mf;
> +	chip->nr_irqs = nr_irqs;
> +	chip->ops = &dw_edma_pcie_core_ops;
>  
> -	dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> -	if (!dw->rg_region.vaddr)
> -		return -ENOMEM;
> +	chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> +	chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
>  
> -	dw->rg_region.vaddr += vsec_data.rg.off;
> -	dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
> -	dw->rg_region.paddr += vsec_data.rg.off;
> -	dw->rg_region.sz = vsec_data.rg.sz;
> +	chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> +	if (!chip->rg_region.vaddr)
> +		return -ENOMEM;
>  
> -	for (i = 0; i < dw->wr_ch_cnt; i++) {
> -		struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
> -		struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
> +	for (i = 0; i < chip->wr_ch_cnt; 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];
>  		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
>  
> @@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		dt_region->sz = dt_block->sz;
>  	}
>  
> -	for (i = 0; i < dw->rd_ch_cnt; i++) {
> -		struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
> -		struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
> +	for (i = 0; i < chip->rd_ch_cnt; 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];
>  		struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
>  
> @@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	}
>  
>  	/* Debug info */
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY)
> -		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
> -	else if (dw->mf == EDMA_MF_EDMA_UNROLL)
> -		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
> -	else if (dw->mf == EDMA_MF_HDMA_COMPAT)
> -		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
> +	if (chip->mf == EDMA_MF_EDMA_LEGACY)
> +		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
> +	else if (chip->mf == EDMA_MF_EDMA_UNROLL)
> +		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
> +	else if (chip->mf == EDMA_MF_HDMA_COMPAT)
> +		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
>  	else
> -		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
> +		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
>  
> -	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> +	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
>  		vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> -		dw->rg_region.vaddr, &dw->rg_region.paddr);
> +		chip->rg_region.vaddr);
>  
>  
> -	for (i = 0; i < dw->wr_ch_cnt; i++) {
> +	for (i = 0; i < chip->wr_ch_cnt; i++) {
>  		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, dw->ll_region_wr[i].sz,
> -			dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
> +			vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
> +			chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
> -			dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
> +			vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
> +			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
>  	}
>  
> -	for (i = 0; i < dw->rd_ch_cnt; i++) {
> +	for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
> -			dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
> +			vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
> +			chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
> -			dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
> +			vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
> +			chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
>  	}
>  
> -	pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
> +	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
>  
>  	/* Validating if PCI interrupts were enabled */
>  	if (!pci_dev_msi_enabled(pdev)) {
> @@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		return -EPERM;
>  	}
>  
> -	dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> -	if (!dw->irq)
> -		return -ENOMEM;
> -
>  	/* Starting eDMA driver */
>  	err = dw_edma_probe(chip);
>  	if (err) {
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index 329fc2e57b703..e507e076fad16 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -25,7 +25,7 @@ enum dw_edma_control {
>  
>  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  {
> -	return dw->rg_region.vaddr;
> +	return dw->chip->rg_region.vaddr;
>  }
>  
>  #define SET_32(dw, name, value)				\
> @@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  static inline struct dw_edma_v0_ch_regs __iomem *
>  __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY)
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
>  		return &(__dw_regs(dw)->type.legacy.ch);
>  
>  	if (dir == EDMA_DIR_WRITE)
> @@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
>  static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			     u32 value, void __iomem *addr)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  {
>  	u32 value;
>  
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			     u64 value, void __iomem *addr)
>  {
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  {
>  	u32 value;
>  
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
>  		unsigned long flags;
>  
> @@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
>  
>  enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp;
>  
>  	tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
> @@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
>  
>  void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  
>  	SET_RW_32(dw, chan->dir, int_clear,
>  		  FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
> @@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
>  
>  void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  
>  	SET_RW_32(dw, chan->dir, int_clear,
>  		  FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
> @@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
>  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  {
>  	struct dw_edma_chan *chan = chunk->chan;
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp;
>  
>  	dw_edma_v0_core_write_chunk(chunk);
> @@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  	if (first) {
>  		/* Enable engine */
>  		SET_RW_32(dw, chan->dir, engine_en, BIT(0));
> -		if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +		if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  			switch (chan->id) {
>  			case 0:
>  				SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
> @@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
>  
>  int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
>  {
> -	struct dw_edma *dw = chan->chip->dw;
> +	struct dw_edma *dw = chan->dw;
>  	u32 tmp = 0;
>  
>  	/* MSI done addr - low, high */
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 4b3bcffd15ef1..edb7e137cb35a 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -54,7 +54,7 @@ struct debugfs_entries {
>  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  {
>  	void __iomem *reg = (void __force __iomem *)data;
> -	if (dw->mf == EDMA_MF_EDMA_LEGACY &&
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
>  	    reg >= (void __iomem *)&regs->type.legacy.ch) {
>  		void __iomem *ptr = &regs->type.legacy.ch;
>  		u32 viewport_sel = 0;
> @@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
>  
> -	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
>  		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
> @@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
>  
> -	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> +	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
>  		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
>  		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
> @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!dw)
>  		return;
>  
> -	regs = dw->rg_region.vaddr;
> +	regs = dw->chip->rg_region.vaddr;
>  	if (!regs)
>  		return;
>  
> @@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!dw->debugfs)
>  		return;
>  
> -	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
> +	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
>  	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
>  	debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
>  
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index cab6e18773dad..a9bee4aeb2eee 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -12,19 +12,63 @@
>  #include <linux/device.h>
>  #include <linux/dmaengine.h>
>  
> +#define EDMA_MAX_WR_CH                                  8
> +#define EDMA_MAX_RD_CH                                  8
> +
>  struct dw_edma;
>  
> +struct dw_edma_region {
> +	phys_addr_t	paddr;
> +	void __iomem	*vaddr;
> +	size_t		sz;
> +};
> +
> +struct dw_edma_core_ops {
> +	int (*irq_vector)(struct device *dev, unsigned int nr);
> +};
> +
> +enum dw_edma_map_format {
> +	EDMA_MF_EDMA_LEGACY = 0x0,
> +	EDMA_MF_EDMA_UNROLL = 0x1,
> +	EDMA_MF_HDMA_COMPAT = 0x5
> +};
> +
>  /**
>   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
>   * @dev:		 struct device of the eDMA controller
>   * @id:			 instance ID
>   * @irq:		 irq line
> + * @nr_irqs:		 total dma irq number
> + * @ops			 DMA channel to IRQ number mapping
> + * @wr_ch_cnt		 DMA write channel number
> + * @rd_ch_cnt		 DMA read channel number
> + * @rg_region		 DMA register region
> + * @ll_region_wr	 DMA descriptor link list memory for write channel
> + * @ll_region_rd	 DMA descriptor link list memory for read channel
> + * @mf			 DMA register map format
>   * @dw:			 struct dw_edma that is filed by dw_edma_probe()
>   */
>  struct dw_edma_chip {
>  	struct device		*dev;
>  	int			id;
>  	int			irq;
> +	int			nr_irqs;
> +	const struct dw_edma_core_ops   *ops;
> +
> +	struct dw_edma_region	rg_region;
> +
> +	u16			wr_ch_cnt;
> +	u16			rd_ch_cnt;
> +	/* link list address */
> +	struct dw_edma_region	ll_region_wr[EDMA_MAX_WR_CH];
> +	struct dw_edma_region	ll_region_rd[EDMA_MAX_RD_CH];
> +
> +	/* data region */
> +	struct dw_edma_region	dt_region_wr[EDMA_MAX_WR_CH];
> +	struct dw_edma_region	dt_region_rd[EDMA_MAX_RD_CH];
> +
> +	enum dw_edma_map_format	mf;
> +
>  	struct dw_edma		*dw;
>  };
>  
> -- 
> 2.24.0.rc1
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures
  2022-03-11 15:29         ` Zhi Li
@ 2022-03-12 19:56           ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-12 19:56 UTC (permalink / raw)
  To: Zhi Li
  Cc: Frank Li, Serge Semin, gustavo.pimentel, hongxing.zhu,
	Lucas Stach, dl-linux-imx, linux-pci, dmaengine, vkoul,
	lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo,
	Manivannan Sadhasivam

On Fri, Mar 11, 2022 at 09:29:08AM -0600, Zhi Li wrote:
> On Fri, Mar 11, 2022 at 5:03 AM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > On Thu, Mar 10, 2022 at 02:29:15PM -0600, Zhi Li wrote:
> > >  in
> > >
> > > On Thu, Mar 10, 2022 at 2:20 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > > >
> > > > On Wed, Mar 09, 2022 at 03:11:57PM -0600, Frank Li wrote:
> > > > > "struct dw_edma_chip" contains an internal structure "struct dw_edma" that
> > > > > is used by the eDMA core internally. This structure should not be touched
> > > > > by the eDMA controller drivers themselves. But currently, the eDMA
> > > > > controller drivers like "dw-edma-pci" allocates and populates this
> > > > > internal structure then passes it on to eDMA core. The eDMA core further
> > > > > populates the structure and uses it. This is wrong!
> > > > >
> > > > > Hence, move all the "struct dw_edma" specifics from controller drivers
> > > > > to the eDMA core.
> > > > >
> > > > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > > > ---
> > > > > Change from v3 to v4
> > > > >  - Accept most suggestions of Serge Semin
> > > > > Change from v2 to v3
> > > > >  - none
> > > > > Change from v1 to v2
> > > > >  - rework commit message
> > > > >  - remove duplicate field in struct dw_edma
> > > > >
> > > > >  drivers/dma/dw-edma/dw-edma-core.c       | 81 +++++++++++++----------
> > > > >  drivers/dma/dw-edma/dw-edma-core.h       | 32 +--------
> > > > >  drivers/dma/dw-edma/dw-edma-pcie.c       | 83 ++++++++++--------------
> > > > >  drivers/dma/dw-edma/dw-edma-v0-core.c    | 24 +++----
> > > > >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 10 +--
> > > > >  include/linux/dma/edma.h                 | 44 +++++++++++++
> > > > >  6 files changed, 144 insertions(+), 130 deletions(-)
> > > > >
> > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > index 53289927dd0d6..1abf41d49f75b 100644
> > > > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > > > @@ -65,7 +65,7 @@ static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
> > > > >  static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> > > > >  {
> > > > >       struct dw_edma_chan *chan = desc->chan;
> > > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > > +     struct dw_edma_chip *chip = chan->dw->chip;
> > > > >       struct dw_edma_chunk *chunk;
> > > > >
> > > > >       chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
> > > > > @@ -82,11 +82,11 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
> > > > >        */
> > > > >       chunk->cb = !(desc->chunks_alloc % 2);
> > > > >       if (chan->dir == EDMA_DIR_WRITE) {
> > > > > -             chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
> > > > > -             chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
> > > > > +             chunk->ll_region.paddr = chip->ll_region_wr[chan->id].paddr;
> > > > > +             chunk->ll_region.vaddr = chip->ll_region_wr[chan->id].vaddr;
> > > > >       } else {
> > > > > -             chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
> > > > > -             chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
> > > > > +             chunk->ll_region.paddr = chip->ll_region_rd[chan->id].paddr;
> > > > > +             chunk->ll_region.vaddr = chip->ll_region_rd[chan->id].vaddr;
> > > > >       }
> > > > >
> > > > >       if (desc->chunk) {
> > > > > @@ -664,7 +664,7 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
> > > > >       if (chan->status != EDMA_ST_IDLE)
> > > > >               return -EBUSY;
> > > > >
> > > > > -     pm_runtime_get(chan->chip->dev);
> > > > > +     pm_runtime_get(chan->dw->chip->dev);
> > > > >
> > > > >       return 0;
> > > > >  }
> > > > > @@ -686,7 +686,7 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
> > > > >               cpu_relax();
> > > > >       }
> > > > >
> > > > > -     pm_runtime_put(chan->chip->dev);
> > > > > +     pm_runtime_put(chan->dw->chip->dev);
> > > > >  }
> > > > >
> > > > >  static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > > > @@ -718,7 +718,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > > >       }
> > > > >
> > > > >       INIT_LIST_HEAD(&dma->channels);
> > > > > -     for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
> > > > > +     for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
> > > > >               chan = &dw->chan[i];
> > > > >
> > > > >               dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> > > > > @@ -727,7 +727,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > > >
> > > > >               chan->vc.chan.private = dt_region;
> > > > >
> > > > > -             chan->chip = chip;
> > > > > +             chan->dw = dw;
> > > > >               chan->id = j;
> > > > >               chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
> > > > >               chan->configured = false;
> > > > > @@ -735,15 +735,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > > >               chan->status = EDMA_ST_IDLE;
> > > > >
> > > > >               if (write)
> > > > > -                     chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
> > > > > +                     chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
> > > > >               else
> > > > > -                     chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
> > > > > +                     chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
> > > > >               chan->ll_max -= 1;
> > > > >
> > > > >               dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
> > > > >                        write ? "write" : "read", j, chan->ll_max);
> > > > >
> > > > > -             if (dw->nr_irqs == 1)
> > > > > +             if (chip->nr_irqs == 1)
> > > > >                       pos = 0;
> > > > >               else
> > > > >                       pos = off_alloc + (j % alloc);
> > > > > @@ -767,13 +767,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> > > > >               vchan_init(&chan->vc, dma);
> > > > >
> > > > >               if (write) {
> > > > > -                     dt_region->paddr = dw->dt_region_wr[j].paddr;
> > > > > -                     dt_region->vaddr = dw->dt_region_wr[j].vaddr;
> > > > > -                     dt_region->sz = dw->dt_region_wr[j].sz;
> > > > > +                     dt_region->paddr = chip->dt_region_wr[j].paddr;
> > > > > +                     dt_region->vaddr = chip->dt_region_wr[j].vaddr;
> > > > > +                     dt_region->sz = chip->dt_region_wr[j].sz;
> > > > >               } else {
> > > > > -                     dt_region->paddr = dw->dt_region_rd[j].paddr;
> > > > > -                     dt_region->vaddr = dw->dt_region_rd[j].vaddr;
> > > > > -                     dt_region->sz = dw->dt_region_rd[j].sz;
> > > > > +                     dt_region->paddr = chip->dt_region_rd[j].paddr;
> > > > > +                     dt_region->vaddr = chip->dt_region_rd[j].vaddr;
> > > > > +                     dt_region->sz = chip->dt_region_rd[j].sz;
> > > > >               }
> > > > >
> > > > >               dw_edma_v0_core_device_config(chan);
> > > > > @@ -840,16 +840,16 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > > >
> > > > >       ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
> > > > >
> > > > > -     if (dw->nr_irqs < 1)
> > > > > +     if (chip->nr_irqs < 1)
> > > > >               return -EINVAL;
> > > > >
> > > > > -     if (dw->nr_irqs == 1) {
> > > > > +     if (chip->nr_irqs == 1) {
> > > > >               /* Common IRQ shared among all channels */
> > > > > -             irq = dw->ops->irq_vector(dev, 0);
> > > > > +             irq = chip->ops->irq_vector(dev, 0);
> > > > >               err = request_irq(irq, dw_edma_interrupt_common,
> > > > >                                 IRQF_SHARED, dw->name, &dw->irq[0]);
> > > > >               if (err) {
> > > > > -                     dw->nr_irqs = 0;
> > > > > +                     chip->nr_irqs = 0;
> > > > >                       return err;
> > > > >               }
> > > > >
> > > > > @@ -857,7 +857,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > > >                       get_cached_msi_msg(irq, &dw->irq[0].msi);
> > > > >       } else {
> > > > >               /* Distribute IRQs equally among all channels */
> > > > > -             int tmp = dw->nr_irqs;
> > > > > +             int tmp = chip->nr_irqs;
> > > > >
> > > > >               while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
> > > > >                       dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
> > > > > @@ -868,7 +868,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > > >               dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
> > > > >
> > > > >               for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
> > > > > -                     irq = dw->ops->irq_vector(dev, i);
> > > > > +                     irq = chip->ops->irq_vector(dev, i);
> > > > >                       err = request_irq(irq,
> > > > >                                         i < *wr_alloc ?
> > > > >                                               dw_edma_interrupt_write :
> > > > > @@ -876,7 +876,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > > >                                         IRQF_SHARED, dw->name,
> > > > >                                         &dw->irq[i]);
> > > > >                       if (err) {
> > > > > -                             dw->nr_irqs = i;
> > > > > +                             chip->nr_irqs = i;
> > > > >                               return err;
> > > > >                       }
> > > > >
> > > > > @@ -884,7 +884,7 @@ static int dw_edma_irq_request(struct dw_edma_chip *chip,
> > > > >                               get_cached_msi_msg(irq, &dw->irq[i].msi);
> > > > >               }
> > > > >
> > > > > -             dw->nr_irqs = i;
> > > > > +             chip->nr_irqs = i;
> > > > >       }
> > > > >
> > > > >       return err;
> > > > > @@ -905,17 +905,24 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > > > >       if (!dev)
> > > > >               return -EINVAL;
> > > > >
> > > > > -     dw = chip->dw;
> > > > > -     if (!dw || !dw->irq || !dw->ops || !dw->ops->irq_vector)
> > > > > +     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > > > > +     if (!dw)
> > > > > +             return -ENOMEM;
> > > > > +
> > > > > +     chip->dw = dw;
> > > > > +     dw->chip = chip;
> > > > > +
> > > > > +     if (!chip->nr_irqs || !chip->ops)
> > > > >               return -EINVAL;
> > > > >
> > > > >       raw_spin_lock_init(&dw->lock);
> > > > >
> > > > > -     dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt,
> > > > > +
> > > > > +     dw->wr_ch_cnt = min_t(u16, chip->wr_ch_cnt,
> > > > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
> > > > >       dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> > > > >
> > > > > -     dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt,
> > > > > +     dw->rd_ch_cnt = min_t(u16, chip->rd_ch_cnt,
> > > > >                             dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
> > > > >       dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> > > > >
> > > > > @@ -936,6 +943,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > > > >       /* Disable eDMA, only to establish the ideal initial conditions */
> > > > >       dw_edma_v0_core_off(dw);
> > > > >
> > > > > +     dw->irq = devm_kcalloc(dev, chip->nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > > > > +     if (!dw->irq)
> > > > > +             return -ENOMEM;
> > > > > +
> > > > >       /* Request IRQs */
> > > > >       err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
> > > > >       if (err)
> > > > > @@ -960,10 +971,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> > > > >       return 0;
> > > > >
> > > > >  err_irq_free:
> > > > > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > > > > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > > > > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > > > > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> > > > >
> > > > > -     dw->nr_irqs = 0;
> > > > > +     chip->nr_irqs = 0;
> > > > >
> > > > >       return err;
> > > > >  }
> > > > > @@ -980,8 +991,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> > > > >       dw_edma_v0_core_off(dw);
> > > > >
> > > > >       /* Free irqs */
> > > > > -     for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > > > > -             free_irq(dw->ops->irq_vector(dev, i), &dw->irq[i]);
> > > > > +     for (i = (chip->nr_irqs - 1); i >= 0; i--)
> > > > > +             free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> > > > >
> > > > >       /* Power management */
> > > > >       pm_runtime_disable(dev);
> > > > > diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> > > > > index 60316d408c3e0..e254c2fc3d9cf 100644
> > > > > --- a/drivers/dma/dw-edma/dw-edma-core.h
> > > > > +++ b/drivers/dma/dw-edma/dw-edma-core.h
> > > > > @@ -15,20 +15,12 @@
> > > > >  #include "../virt-dma.h"
> > > > >
> > > > >  #define EDMA_LL_SZ                                   24
> > > > > -#define EDMA_MAX_WR_CH                                       8
> > > > > -#define EDMA_MAX_RD_CH                                       8
> > > > >
> > > > >  enum dw_edma_dir {
> > > > >       EDMA_DIR_WRITE = 0,
> > > > >       EDMA_DIR_READ
> > > > >  };
> > > > >
> > > > > -enum dw_edma_map_format {
> > > > > -     EDMA_MF_EDMA_LEGACY = 0x0,
> > > > > -     EDMA_MF_EDMA_UNROLL = 0x1,
> > > > > -     EDMA_MF_HDMA_COMPAT = 0x5
> > > > > -};
> > > > > -
> > > > >  enum dw_edma_request {
> > > > >       EDMA_REQ_NONE = 0,
> > > > >       EDMA_REQ_STOP,
> > > > > @@ -57,12 +49,6 @@ struct dw_edma_burst {
> > > > >       u32                             sz;
> > > > >  };
> > > > >
> > > > > -struct dw_edma_region {
> > > > > -     phys_addr_t                     paddr;
> > > > > -     void                            __iomem *vaddr;
> > > > > -     size_t                          sz;
> > > > > -};
> > > > > -
> > > > >  struct dw_edma_chunk {
> > > > >       struct list_head                list;
> > > > >       struct dw_edma_chan             *chan;
> > > > > @@ -87,7 +73,7 @@ struct dw_edma_desc {
> > > > >
> > > > >  struct dw_edma_chan {
> > > > >       struct virt_dma_chan            vc;
> > > > > -     struct dw_edma_chip             *chip;
> > > > > +     struct dw_edma                  *dw;
> > > > >       int                             id;
> > > > >       enum dw_edma_dir                dir;
> > > > >
> > > > > @@ -109,10 +95,6 @@ struct dw_edma_irq {
> > > > >       struct dw_edma                  *dw;
> > > > >  };
> > > > >
> > > > > -struct dw_edma_core_ops {
> > > > > -     int     (*irq_vector)(struct device *dev, unsigned int nr);
> > > > > -};
> > > > > -
> > > > >  struct dw_edma {
> > > > >       char                            name[20];
> > > > >
> > > > > @@ -122,21 +104,13 @@ struct dw_edma {
> > > > >       struct dma_device               rd_edma;
> > > > >       u16                             rd_ch_cnt;
> > > > >
> > > > > -     struct dw_edma_region           rg_region;      /* Registers */
> > > > > -     struct dw_edma_region           ll_region_wr[EDMA_MAX_WR_CH];
> > > > > -     struct dw_edma_region           ll_region_rd[EDMA_MAX_RD_CH];
> > > > > -     struct dw_edma_region           dt_region_wr[EDMA_MAX_WR_CH];
> > > > > -     struct dw_edma_region           dt_region_rd[EDMA_MAX_RD_CH];
> > > > > -
> > > > >       struct dw_edma_irq              *irq;
> > > > > -     int                             nr_irqs;
> > > > > -
> > > > > -     enum dw_edma_map_format         mf;
> > > > >
> > > > >       struct dw_edma_chan             *chan;
> > > > > -     const struct dw_edma_core_ops   *ops;
> > > > >
> > > > >       raw_spinlock_t                  lock;           /* Only for legacy */
> > > > > +
> > > > > +     struct dw_edma_chip             *chip;
> > > > >  #ifdef CONFIG_DEBUG_FS
> > > > >       struct dentry                   *debugfs;
> > > > >  #endif /* CONFIG_DEBUG_FS */
> > > > > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > > index 44f6e09bdb531..2c1c5fa4e9f28 100644
> > > > > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > > > > @@ -148,7 +148,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > > >       struct dw_edma_pcie_data vsec_data;
> > > > >       struct device *dev = &pdev->dev;
> > > > >       struct dw_edma_chip *chip;
> > > > > -     struct dw_edma *dw;
> > > > >       int err, nr_irqs;
> > > > >       int i, mask;
> > > > >
> > > > > @@ -214,10 +213,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > > >       if (!chip)
> > > > >               return -ENOMEM;
> > > > >
> > > > > -     dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> > > > > -     if (!dw)
> > > > > -             return -ENOMEM;
> > > > > -
> > > > >       /* IRQs allocation */
> > > > >       nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
> > > > >                                       PCI_IRQ_MSI | PCI_IRQ_MSIX);
> > > > > @@ -228,29 +223,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > > >       }
> > > > >
> > > > >       /* Data structure initialization */
> > > > > -     chip->dw = dw;
> > > > >       chip->dev = dev;
> > > > >       chip->id = pdev->devfn;
> > > > > -     chip->irq = pdev->irq;
> > > > >
> > > > > -     dw->mf = vsec_data.mf;
> > > > > -     dw->nr_irqs = nr_irqs;
> > > > > -     dw->ops = &dw_edma_pcie_core_ops;
> > > > > -     dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > > > -     dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > > > > +     chip->mf = vsec_data.mf;
> > > > > +     chip->nr_irqs = nr_irqs;
> > > > > +     chip->ops = &dw_edma_pcie_core_ops;
> > > > >
> > > > > -     dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > > > > -     if (!dw->rg_region.vaddr)
> > > > > -             return -ENOMEM;
> > > > > +     chip->wr_ch_cnt = vsec_data.wr_ch_cnt;
> > > > > +     chip->rd_ch_cnt = vsec_data.rd_ch_cnt;
> > > > >
> > > > > -     dw->rg_region.vaddr += vsec_data.rg.off;
> > > > > -     dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
> > > > > -     dw->rg_region.paddr += vsec_data.rg.off;
> > > > > -     dw->rg_region.sz = vsec_data.rg.sz;
> > > > > +     chip->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
> > > > > +     if (!chip->rg_region.vaddr)
> > > > > +             return -ENOMEM;
> > > > >
> > > > > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > > > > -             struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
> > > > > -             struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
> > > > > +     for (i = 0; i < chip->wr_ch_cnt; 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];
> > > > >               struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
> > > > >
> > > > > @@ -273,9 +262,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > > >               dt_region->sz = dt_block->sz;
> > > > >       }
> > > > >
> > > > > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > > > > -             struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
> > > > > -             struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
> > > > > +     for (i = 0; i < chip->rd_ch_cnt; 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];
> > > > >               struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
> > > > >
> > > > > @@ -299,45 +288,45 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > > >       }
> > > > >
> > > > >       /* Debug info */
> > > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > > > > -             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
> > > > > -     else if (dw->mf == EDMA_MF_EDMA_UNROLL)
> > > > > -             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", dw->mf);
> > > > > -     else if (dw->mf == EDMA_MF_HDMA_COMPAT)
> > > > > -             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", dw->mf);
> > > > > +     if (chip->mf == EDMA_MF_EDMA_LEGACY)
> > > > > +             pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
> > > > > +     else if (chip->mf == EDMA_MF_EDMA_UNROLL)
> > > > > +             pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
> > > > > +     else if (chip->mf == EDMA_MF_HDMA_COMPAT)
> > > > > +             pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
> > > > >       else
> > > > > -             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
> > > > > +             pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
> > > > >
> > > > > -     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > > > > +     pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
> > > > >               vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
> > > > > -             dw->rg_region.vaddr, &dw->rg_region.paddr);
> > > > > +             chip->rg_region.vaddr);
> > > > >
> > > > >
> > > > > -     for (i = 0; i < dw->wr_ch_cnt; i++) {
> > > > > +     for (i = 0; i < chip->wr_ch_cnt; i++) {
> > > > >               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, dw->ll_region_wr[i].sz,
> > > > > -                     dw->ll_region_wr[i].vaddr, &dw->ll_region_wr[i].paddr);
> > > > > +                     vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
> > > > > +                     chip->ll_region_wr[i].vaddr, &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, dw->dt_region_wr[i].sz,
> > > > > -                     dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
> > > > > +                     vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
> > > > > +                     chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
> > > > >       }
> > > > >
> > > > > -     for (i = 0; i < dw->rd_ch_cnt; i++) {
> > > > > +     for (i = 0; i < chip->rd_ch_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, dw->ll_region_rd[i].sz,
> > > > > -                     dw->ll_region_rd[i].vaddr, &dw->ll_region_rd[i].paddr);
> > > > > +                     vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
> > > > > +                     chip->ll_region_rd[i].vaddr, &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, dw->dt_region_rd[i].sz,
> > > > > -                     dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
> > > > > +                     vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
> > > > > +                     chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
> > > > >       }
> > > > >
> > > > > -     pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
> > > > > +     pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
> > > > >
> > > > >       /* Validating if PCI interrupts were enabled */
> > > > >       if (!pci_dev_msi_enabled(pdev)) {
> > > > > @@ -345,10 +334,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> > > > >               return -EPERM;
> > > > >       }
> > > > >
> > > > > -     dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
> > > > > -     if (!dw->irq)
> > > > > -             return -ENOMEM;
> > > > > -
> > > > >       /* Starting eDMA driver */
> > > > >       err = dw_edma_probe(chip);
> > > > >       if (err) {
> > > > > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > > > index 329fc2e57b703..e507e076fad16 100644
> > > > > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > > > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > > > > @@ -25,7 +25,7 @@ enum dw_edma_control {
> > > > >
> > > > >  static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> > > > >  {
> > > > > -     return dw->rg_region.vaddr;
> > > > > +     return dw->chip->rg_region.vaddr;
> > > > >  }
> > > > >
> > > > >  #define SET_32(dw, name, value)                              \
> > > > > @@ -96,7 +96,7 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> > > > >  static inline struct dw_edma_v0_ch_regs __iomem *
> > > > >  __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> > > > >  {
> > > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY)
> > > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
> > > > >               return &(__dw_regs(dw)->type.legacy.ch);
> > > > >
> > > > >       if (dir == EDMA_DIR_WRITE)
> > > > > @@ -108,7 +108,7 @@ __dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
> > > > >  static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > > >                            u32 value, void __iomem *addr)
> > > > >  {
> > > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > > >               u32 viewport_sel;
> > > > >               unsigned long flags;
> > > > >
> > > > > @@ -133,7 +133,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > > >  {
> > > > >       u32 value;
> > > > >
> > > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > > >               u32 viewport_sel;
> > > > >               unsigned long flags;
> > > > >
> > > > > @@ -169,7 +169,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > > >  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > > >                            u64 value, void __iomem *addr)
> > > > >  {
> > > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > > >               u32 viewport_sel;
> > > > >               unsigned long flags;
> > > > >
> > > > > @@ -194,7 +194,7 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> > > > >  {
> > > > >       u32 value;
> > > > >
> > > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY) {
> > > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> > > > >               u32 viewport_sel;
> > > > >               unsigned long flags;
> > > > >
> > > > > @@ -256,7 +256,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
> > > > >
> > > > >  enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> > > > >  {
> > > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > > +     struct dw_edma *dw = chan->dw;
> > > > >       u32 tmp;
> > > > >
> > > > >       tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
> > > > > @@ -272,7 +272,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
> > > > >
> > > > >  void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> > > > >  {
> > > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > > +     struct dw_edma *dw = chan->dw;
> > > > >
> > > > >       SET_RW_32(dw, chan->dir, int_clear,
> > > > >                 FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
> > > > > @@ -280,7 +280,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
> > > > >
> > > > >  void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
> > > > >  {
> > > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > > +     struct dw_edma *dw = chan->dw;
> > > > >
> > > > >       SET_RW_32(dw, chan->dir, int_clear,
> > > > >                 FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
> > > > > @@ -357,7 +357,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> > > > >  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > > > >  {
> > > > >       struct dw_edma_chan *chan = chunk->chan;
> > > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > > +     struct dw_edma *dw = chan->dw;
> > > > >       u32 tmp;
> > > > >
> > > > >       dw_edma_v0_core_write_chunk(chunk);
> > > > > @@ -365,7 +365,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > > > >       if (first) {
> > > > >               /* Enable engine */
> > > > >               SET_RW_32(dw, chan->dir, engine_en, BIT(0));
> > > > > -             if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > > > +             if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > > > >                       switch (chan->id) {
> > > > >                       case 0:
> > > > >                               SET_RW_COMPAT(dw, chan->dir, ch0_pwr_en,
> > > > > @@ -431,7 +431,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > > > >
> > > > >  int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
> > > > >  {
> > > > > -     struct dw_edma *dw = chan->chip->dw;
> > > > > +     struct dw_edma *dw = chan->dw;
> > > > >       u32 tmp = 0;
> > > > >
> > > > >       /* MSI done addr - low, high */
> > > > > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > > > index 4b3bcffd15ef1..edb7e137cb35a 100644
> > > > > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > > > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > > > > @@ -54,7 +54,7 @@ struct debugfs_entries {
> > > > >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> > > > >  {
> > > > >       void __iomem *reg = (void __force __iomem *)data;
> > > > > -     if (dw->mf == EDMA_MF_EDMA_LEGACY &&
> > > > > +     if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
> > > > >           reg >= (void __iomem *)&regs->type.legacy.ch) {
> > > > >               void __iomem *ptr = &regs->type.legacy.ch;
> > > > >               u32 viewport_sel = 0;
> > > > > @@ -173,7 +173,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
> > > > >       nr_entries = ARRAY_SIZE(debugfs_regs);
> > > > >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> > > > >
> > > > > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > > > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > > > >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> > > > >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> > > > >                                          regs_dir);
> > > > > @@ -242,7 +242,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
> > > > >       nr_entries = ARRAY_SIZE(debugfs_regs);
> > > > >       dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> > > > >
> > > > > -     if (dw->mf == EDMA_MF_HDMA_COMPAT) {
> > > > > +     if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
> > > > >               nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
> > > > >               dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
> > > > >                                          regs_dir);
> > > > > @@ -288,7 +288,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> > > > >       if (!dw)
> > > > >               return;
> > > > >
> > > > > -     regs = dw->rg_region.vaddr;
> > > > > +     regs = dw->chip->rg_region.vaddr;
> > > > >       if (!regs)
> > > > >               return;
> > > > >
> > > > > @@ -296,7 +296,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
> > > > >       if (!dw->debugfs)
> > > > >               return;
> > > > >
> > > > > -     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
> > > > > +     debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
> > > > >       debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
> > > > >       debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
> > > > >
> > > > > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > > > > index cab6e18773dad..a9bee4aeb2eee 100644
> > > > > --- a/include/linux/dma/edma.h
> > > > > +++ b/include/linux/dma/edma.h
> > > > > @@ -12,19 +12,63 @@
> > > > >  #include <linux/device.h>
> > > > >  #include <linux/dmaengine.h>
> > > > >
> > > > > +#define EDMA_MAX_WR_CH                                  8
> > > > > +#define EDMA_MAX_RD_CH                                  8
> > > > > +
> > > > >  struct dw_edma;
> > > > >
> > > > > +struct dw_edma_region {
> > > > > +     phys_addr_t     paddr;
> > > > > +     void __iomem    *vaddr;
> > > > > +     size_t          sz;
> > > > > +};
> > > > > +
> > > > > +struct dw_edma_core_ops {
> > > > > +     int (*irq_vector)(struct device *dev, unsigned int nr);
> > > > > +};
> > > > > +
> > > > > +enum dw_edma_map_format {
> > > > > +     EDMA_MF_EDMA_LEGACY = 0x0,
> > > > > +     EDMA_MF_EDMA_UNROLL = 0x1,
> > > > > +     EDMA_MF_HDMA_COMPAT = 0x5
> > > > > +};
> > > > > +
> > > > >  /**
> > > > >   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
> > > > >   * @dev:              struct device of the eDMA controller
> > > > >   * @id:                       instance ID
> > > > >   * @irq:              irq line
> > > > > + * @nr_irqs:          total dma irq number
> > > > > + * @ops                       DMA channel to IRQ number mapping
> > > > > + * @wr_ch_cnt                 DMA write channel number
> > > > > + * @rd_ch_cnt                 DMA read channel number
> > > > > + * @rg_region                 DMA register region
> > > > > + * @ll_region_wr      DMA descriptor link list memory for write channel
> > > > > + * @ll_region_rd      DMA descriptor link list memory for read channel
> > > > > + * @mf                        DMA register map format
> > > > >   * @dw:                       struct dw_edma that is filed by dw_edma_probe()
> > > > >   */
> > > > >  struct dw_edma_chip {
> > > > >       struct device           *dev;
> > > > >       int                     id;
> > > > >       int                     irq;
> > > > > +     int                     nr_irqs;
> > > > > +     const struct dw_edma_core_ops   *ops;
> > > > > +
> > > > > +     struct dw_edma_region   rg_region;
> > > > > +
> > > > > +     u16                     wr_ch_cnt;
> > > > > +     u16                     rd_ch_cnt;
> > > > > +     /* link list address */
> > > > > +     struct dw_edma_region   ll_region_wr[EDMA_MAX_WR_CH];
> > > > > +     struct dw_edma_region   ll_region_rd[EDMA_MAX_RD_CH];
> > > > > +
> > > > > +     /* data region */
> > > > > +     struct dw_edma_region   dt_region_wr[EDMA_MAX_WR_CH];
> > > > > +     struct dw_edma_region   dt_region_rd[EDMA_MAX_RD_CH];
> > > > > +
> > > > > +     enum dw_edma_map_format mf;
> > > > > +
> > > >
> > > > >       struct dw_edma          *dw;
> > > >
> > > > Please drop this field from here and just change the dw_edma_probe()
> > > > prototype to returning a pointer to the struct dw_edma structure. Like
> > > > this:
> > > > struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
> > > > void dw_edma_remove(struct dw_edma *dw);
> > >
> >
> > > Actually, I don't think it is good to drop it now.
> > >
> > > struct dw_edma *dw_edma_probe(const struct dw_edma_chip *chip);
> > >
> > > Users likely put struct dw_edma_chip in stack.
> > > foo()
> > > {
> > >         struct dw_edma_chip chip
> > >         dw = dw_edma_proble(&chip);
> > > }
> > >
> > > but now, edma_core_driver still does not save chip information to dw_edma
> >
> > Neither current implementation nor implementation suggested by me
> > permits having the struct dw_edma_chip structure instance allocated on
> > stack,
> 
> Yes, but original implement
>      int dw_edma_probe(struct dw_edma_chip *chip)
>      int dw_edma_remove (struct dw_edma_chip *chip)
> 
> User knows the chip will be used at remove, so it will be saved in a safe place.
> 
> struct dw_edma* dw_edma_probe(struct dw_edma_chip*chip)
> look like chip only use once when call dw_edma_probe,
> User most like use stack if he don't read dw_edma_probe's implement.
> 
> >  since the pointer to the structure is then preserved in the
> > dw_edma all the way until the device/driver isn't removed (it will
> > require some more modifications, which I can't request from you).
> > What approach proposed by me provides is a way to statically define
> > the struct dw_edma_chip object. Seeing the eDMA driver doesn't change
> > the structure fields we can extend the API functionality. In this
> > case the probe()/remote() methods semantics turns to be cleaner and
> > looking more like the i2c-board-info design.
> 
> I grep probe under include/*, I found most *_probe() function return int,
> I think a benefit is It can return different error codes, especially
> EPROBE_DEFER.
> Of course,  EPROBE_DEFER will not happen in this case.  But I think
> it'd be better
> to follow common sense.
> 
> > That we'll be able to
> > gain almost with no much efforts. Just fix the
> > dw_edma_probe()/dw_edma_remove() method prototype as I suggested
> > (Don't forget the const-modifier in the probe argument and in the
> > dw_edma.dw field).
> 

> It is not an effort problem.  Just which one is better and prevents
> some protiental
> problems and is easy to use.

Seems reasonable now. Thanks for elaborating your intentions. No
objections against the suggested approach then.

-Serge

> 
> I suggest we can move this change to future patch, which save chip
> info to dw_edma
> and don't direct refer chip, which pass down at dw_edma_probe()
> 
> >
> > -Sergey
> >
> > >
> > > >
> > > > By doing so we'll be able to have the chip data being const and at least
> > > > statically defined.
> > > >
> > > > -Sergey
> > > >
> > > > >  };
> > > > >
> > > > > --
> > > > > 2.24.0.rc1
> > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-12  5:37         ` Manivannan Sadhasivam
@ 2022-03-14  8:33           ` Serge Semin
  2022-03-18 18:06             ` Manivannan Sadhasivam
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-14  8:33 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Sat, Mar 12, 2022 at 11:07:20AM +0530, Manivannan Sadhasivam wrote:
> On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> > On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:

[nip]

> > 
> > > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > > access to it happens over PCIe bus or by the local CPU.
> > 
> > Not fully correct. Root Ports can also have eDMA embedded. In that
> > case the eDMA can be only accessible from the local CPU. At the same
> > time the DW PCIe End-point case is the IP-core synthesize parameters
> > specific. It's always possible to access the eDMA CSRs from local
> > CPU, but a particular End-point BAR can be pre-synthesize to map
> > either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> > perform a full End-point configuration. Anyway the case if the eDMA
> > functionality being accessible over the PCIe wire doesn't really make
> > much sense with no info regarding the application logic hidden behind
> > the PCIe End-point interface since SAR/DAR LLP is supposed to be
> > initialized with an address from the local (application) memory space.
> > 
> 
> Thanks for the explanation, it clarifies my doubt. I got misleaded by the
> earlier commits...
> 
> > So AFAICS the main usecase of the controller is 1) - when eDMA is a
> > part of the Root Port/End-point and only local CPU is supposed to have
> > it accessed and configured.
> > 
> > I can resend this patch with my fix to the problem. What do you think?
> > 
> 

> Yes, please do.

Ok. I'll be AFK today, but will send my patches tomorrow.  @Frank,
Could you please hold on with respinning the series for a few days?
I'll send out some of my patches then with a note which one of them
could be picked up by you and merged into this series.

-Sergey

> 
> Thanks,
> Mani
> 
> > -Sergey
> > 
> > > 
> > > The commit from Alan Mikhak is what I took as a reference since the patch was
> > > already merged:
> > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > > 
> > > Thanks,
> > > Mani
> > > 
> > > > -Sergey
> > > > 
> > > > > +		 *
> > > > > +		 ****************************************************************/
> > > > > +
> > > > 
> > > > > +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > +			read = true;
> > > > 
> > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > redundant.
> > > > 
> > > > > +
> > > > > +		/* Program the source and destination addresses for DMA read/write */
> > > > > +		if (read) {
> > > > >  			burst->sar = src_addr;
> > > > >  			if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > >  				burst->dar = xfer->xfer.cyclic.paddr;
> > > > > -- 
> > > > > 2.24.0.rc1
> > > > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-14  8:33           ` Serge Semin
@ 2022-03-18 18:06             ` Manivannan Sadhasivam
  2022-03-18 18:19               ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-18 18:06 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Mon, Mar 14, 2022 at 11:33:40AM +0300, Serge Semin wrote:
> On Sat, Mar 12, 2022 at 11:07:20AM +0530, Manivannan Sadhasivam wrote:
> > On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> > > On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> 
> [nip]
> 
> > > 
> > > > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > > > access to it happens over PCIe bus or by the local CPU.
> > > 
> > > Not fully correct. Root Ports can also have eDMA embedded. In that
> > > case the eDMA can be only accessible from the local CPU. At the same
> > > time the DW PCIe End-point case is the IP-core synthesize parameters
> > > specific. It's always possible to access the eDMA CSRs from local
> > > CPU, but a particular End-point BAR can be pre-synthesize to map
> > > either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> > > perform a full End-point configuration. Anyway the case if the eDMA
> > > functionality being accessible over the PCIe wire doesn't really make
> > > much sense with no info regarding the application logic hidden behind
> > > the PCIe End-point interface since SAR/DAR LLP is supposed to be
> > > initialized with an address from the local (application) memory space.
> > > 
> > 
> > Thanks for the explanation, it clarifies my doubt. I got misleaded by the
> > earlier commits...
> > 
> > > So AFAICS the main usecase of the controller is 1) - when eDMA is a
> > > part of the Root Port/End-point and only local CPU is supposed to have
> > > it accessed and configured.
> > > 
> > > I can resend this patch with my fix to the problem. What do you think?
> > > 
> > 
> 
> > Yes, please do.
> 
> Ok. I'll be AFK today, but will send my patches tomorrow.  @Frank,
> Could you please hold on with respinning the series for a few days?
> I'll send out some of my patches then with a note which one of them
> could be picked up by you and merged into this series.
> 

Any update on your patches?

Btw, my colleage worked on merging the two dma devices used by the eDMA core
for read & write channels into one. Initially I thought that was not needed as
he did that for devicetree integration, but looking deeply I think that patch is
necessary irrespective of DT.

One standout problem is, we can't register debugfs directory under "dmaengine"
properly because, both read and write dma devices share the same parent
chip->dev.

Thanks,
Mani

> -Sergey
> 
> > 
> > Thanks,
> > Mani
> > 
> > > -Sergey
> > > 
> > > > 
> > > > The commit from Alan Mikhak is what I took as a reference since the patch was
> > > > already merged:
> > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > > > 
> > > > Thanks,
> > > > Mani
> > > > 
> > > > > -Sergey
> > > > > 
> > > > > > +		 *
> > > > > > +		 ****************************************************************/
> > > > > > +
> > > > > 
> > > > > > +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > +			read = true;
> > > > > 
> > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > redundant.
> > > > > 
> > > > > > +
> > > > > > +		/* Program the source and destination addresses for DMA read/write */
> > > > > > +		if (read) {
> > > > > >  			burst->sar = src_addr;
> > > > > >  			if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > >  				burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > -- 
> > > > > > 2.24.0.rc1
> > > > > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-18 18:06             ` Manivannan Sadhasivam
@ 2022-03-18 18:19               ` Serge Semin
  2022-03-20 23:16                 ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-18 18:19 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Fri, Mar 18, 2022 at 11:36:05PM +0530, Manivannan Sadhasivam wrote:
> On Mon, Mar 14, 2022 at 11:33:40AM +0300, Serge Semin wrote:
> > On Sat, Mar 12, 2022 at 11:07:20AM +0530, Manivannan Sadhasivam wrote:
> > > On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> > > > On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> > 
> > [nip]
> > 
> > > > 
> > > > > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > > > > access to it happens over PCIe bus or by the local CPU.
> > > > 
> > > > Not fully correct. Root Ports can also have eDMA embedded. In that
> > > > case the eDMA can be only accessible from the local CPU. At the same
> > > > time the DW PCIe End-point case is the IP-core synthesize parameters
> > > > specific. It's always possible to access the eDMA CSRs from local
> > > > CPU, but a particular End-point BAR can be pre-synthesize to map
> > > > either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> > > > perform a full End-point configuration. Anyway the case if the eDMA
> > > > functionality being accessible over the PCIe wire doesn't really make
> > > > much sense with no info regarding the application logic hidden behind
> > > > the PCIe End-point interface since SAR/DAR LLP is supposed to be
> > > > initialized with an address from the local (application) memory space.
> > > > 
> > > 
> > > Thanks for the explanation, it clarifies my doubt. I got misleaded by the
> > > earlier commits...
> > > 
> > > > So AFAICS the main usecase of the controller is 1) - when eDMA is a
> > > > part of the Root Port/End-point and only local CPU is supposed to have
> > > > it accessed and configured.
> > > > 
> > > > I can resend this patch with my fix to the problem. What do you think?
> > > > 
> > > 
> > 
> > > Yes, please do.
> > 
> > Ok. I'll be AFK today, but will send my patches tomorrow.  @Frank,
> > Could you please hold on with respinning the series for a few days?
> > I'll send out some of my patches then with a note which one of them
> > could be picked up by you and merged into this series.
> > 
> 

> Any update on your patches?

No worries. The patches are ready. But since Frank was on vacation I
decided to rebase all of my work on top of his series. I'll finish it
up shortly and send out my patchset till Monday for review. Then Frank
will be able to pick up two patches from there so to close up his
patchset (I'll give a note which one of them is of Frank' interes).
My series will be able to be merged in after Frank's series is reviewed
and accepted.

> 
> Btw, my colleage worked on merging the two dma devices used by the eDMA core
> for read & write channels into one. Initially I thought that was not needed as
> he did that for devicetree integration, but looking deeply I think that patch is
> necessary irrespective of DT.
> 
> One standout problem is, we can't register debugfs directory under "dmaengine"
> properly because, both read and write dma devices share the same parent
> chip->dev.

Right, my series fixes that and some other problems too. So please be
patient for a few more days.

-Sergey

> 
> Thanks,
> Mani
> 
> > -Sergey
> > 
> > > 
> > > Thanks,
> > > Mani
> > > 
> > > > -Sergey
> > > > 
> > > > > 
> > > > > The commit from Alan Mikhak is what I took as a reference since the patch was
> > > > > already merged:
> > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > > > > 
> > > > > Thanks,
> > > > > Mani
> > > > > 
> > > > > > -Sergey
> > > > > > 
> > > > > > > +		 *
> > > > > > > +		 ****************************************************************/
> > > > > > > +
> > > > > > 
> > > > > > > +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > +			read = true;
> > > > > > 
> > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > redundant.
> > > > > > 
> > > > > > > +
> > > > > > > +		/* Program the source and destination addresses for DMA read/write */
> > > > > > > +		if (read) {
> > > > > > >  			burst->sar = src_addr;
> > > > > > >  			if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > >  				burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > -- 
> > > > > > > 2.24.0.rc1
> > > > > > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-18 18:19               ` Serge Semin
@ 2022-03-20 23:16                 ` Serge Semin
  2022-03-22 13:55                   ` Zhi Li
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-20 23:16 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Frank Li, gustavo.pimentel, hongxing.zhu, l.stach,
	linux-imx, linux-pci, dmaengine, lznuaa, vkoul,
	lorenzo.pieralisi, robh, kw, bhelgaas, shawnguo

On Fri, Mar 18, 2022 at 09:19:13PM +0300, Serge Semin wrote:
> On Fri, Mar 18, 2022 at 11:36:05PM +0530, Manivannan Sadhasivam wrote:
> > On Mon, Mar 14, 2022 at 11:33:40AM +0300, Serge Semin wrote:
> > > On Sat, Mar 12, 2022 at 11:07:20AM +0530, Manivannan Sadhasivam wrote:
> > > > On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> > > > > On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> > > 
> > > [nip]
> > > 
> > > > > 
> > > > > > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > > > > > access to it happens over PCIe bus or by the local CPU.
> > > > > 
> > > > > Not fully correct. Root Ports can also have eDMA embedded. In that
> > > > > case the eDMA can be only accessible from the local CPU. At the same
> > > > > time the DW PCIe End-point case is the IP-core synthesize parameters
> > > > > specific. It's always possible to access the eDMA CSRs from local
> > > > > CPU, but a particular End-point BAR can be pre-synthesize to map
> > > > > either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> > > > > perform a full End-point configuration. Anyway the case if the eDMA
> > > > > functionality being accessible over the PCIe wire doesn't really make
> > > > > much sense with no info regarding the application logic hidden behind
> > > > > the PCIe End-point interface since SAR/DAR LLP is supposed to be
> > > > > initialized with an address from the local (application) memory space.
> > > > > 
> > > > 
> > > > Thanks for the explanation, it clarifies my doubt. I got misleaded by the
> > > > earlier commits...
> > > > 
> > > > > So AFAICS the main usecase of the controller is 1) - when eDMA is a
> > > > > part of the Root Port/End-point and only local CPU is supposed to have
> > > > > it accessed and configured.
> > > > > 
> > > > > I can resend this patch with my fix to the problem. What do you think?
> > > > > 
> > > > 
> > > 
> > > > Yes, please do.
> > > 
> > > Ok. I'll be AFK today, but will send my patches tomorrow.  @Frank,
> > > Could you please hold on with respinning the series for a few days?
> > > I'll send out some of my patches then with a note which one of them
> > > could be picked up by you and merged into this series.
> > > 
> > 
> 

> > Any update on your patches?
> 
> No worries. The patches are ready. But since Frank was on vacation I
> decided to rebase all of my work on top of his series. I'll finish it
> up shortly and send out my patchset till Monday for review. Then Frank
> will be able to pick up two patches from there so to close up his
> patchset (I'll give a note which one of them is of Frank' interes).
> My series will be able to be merged in after Frank's series is reviewed
> and accepted.

Folks, couldn't make it this weekend. Too much sidework to do. Terribly
sorry about that. Will send out the series tomorrow or at most in a day
after tomorrow. Sorry for the inconvenience.

-Sergey

> 
> > 
> > Btw, my colleage worked on merging the two dma devices used by the eDMA core
> > for read & write channels into one. Initially I thought that was not needed as
> > he did that for devicetree integration, but looking deeply I think that patch is
> > necessary irrespective of DT.
> > 
> > One standout problem is, we can't register debugfs directory under "dmaengine"
> > properly because, both read and write dma devices share the same parent
> > chip->dev.
> 
> Right, my series fixes that and some other problems too. So please be
> patient for a few more days.
> 
> -Sergey
> 
> > 
> > Thanks,
> > Mani
> > 
> > > -Sergey
> > > 
> > > > 
> > > > Thanks,
> > > > Mani
> > > > 
> > > > > -Sergey
> > > > > 
> > > > > > 
> > > > > > The commit from Alan Mikhak is what I took as a reference since the patch was
> > > > > > already merged:
> > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > > > > > 
> > > > > > Thanks,
> > > > > > Mani
> > > > > > 
> > > > > > > -Sergey
> > > > > > > 
> > > > > > > > +		 *
> > > > > > > > +		 ****************************************************************/
> > > > > > > > +
> > > > > > > 
> > > > > > > > +		if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > > +		    (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > > +			read = true;
> > > > > > > 
> > > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > > redundant.
> > > > > > > 
> > > > > > > > +
> > > > > > > > +		/* Program the source and destination addresses for DMA read/write */
> > > > > > > > +		if (read) {
> > > > > > > >  			burst->sar = src_addr;
> > > > > > > >  			if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > > >  				burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > > -- 
> > > > > > > > 2.24.0.rc1
> > > > > > > > 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-20 23:16                 ` Serge Semin
@ 2022-03-22 13:55                   ` Zhi Li
  2022-03-22 14:03                     ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Zhi Li @ 2022-03-22 13:55 UTC (permalink / raw)
  To: Serge Semin
  Cc: Manivannan Sadhasivam, Serge Semin, Frank Li, gustavo.pimentel,
	hongxing.zhu, Lucas Stach, dl-linux-imx, linux-pci, dmaengine,
	vkoul, lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Sun, Mar 20, 2022 at 6:16 PM Serge Semin <fancer.lancer@gmail.com> wrote:
>
> On Fri, Mar 18, 2022 at 09:19:13PM +0300, Serge Semin wrote:
> > On Fri, Mar 18, 2022 at 11:36:05PM +0530, Manivannan Sadhasivam wrote:
> > > On Mon, Mar 14, 2022 at 11:33:40AM +0300, Serge Semin wrote:
> > > > On Sat, Mar 12, 2022 at 11:07:20AM +0530, Manivannan Sadhasivam wrote:
> > > > > On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> > > > > > On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> > > >
> > > > [nip]
> > > >
> > > > > >
> > > > > > > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > > > > > > access to it happens over PCIe bus or by the local CPU.
> > > > > >
> > > > > > Not fully correct. Root Ports can also have eDMA embedded. In that
> > > > > > case the eDMA can be only accessible from the local CPU. At the same
> > > > > > time the DW PCIe End-point case is the IP-core synthesize parameters
> > > > > > specific. It's always possible to access the eDMA CSRs from local
> > > > > > CPU, but a particular End-point BAR can be pre-synthesize to map
> > > > > > either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> > > > > > perform a full End-point configuration. Anyway the case if the eDMA
> > > > > > functionality being accessible over the PCIe wire doesn't really make
> > > > > > much sense with no info regarding the application logic hidden behind
> > > > > > the PCIe End-point interface since SAR/DAR LLP is supposed to be
> > > > > > initialized with an address from the local (application) memory space.
> > > > > >
> > > > >
> > > > > Thanks for the explanation, it clarifies my doubt. I got misleaded by the
> > > > > earlier commits...
> > > > >
> > > > > > So AFAICS the main usecase of the controller is 1) - when eDMA is a
> > > > > > part of the Root Port/End-point and only local CPU is supposed to have
> > > > > > it accessed and configured.
> > > > > >
> > > > > > I can resend this patch with my fix to the problem. What do you think?
> > > > > >
> > > > >
> > > >
> > > > > Yes, please do.
> > > >
> > > > Ok. I'll be AFK today, but will send my patches tomorrow.  @Frank,
> > > > Could you please hold on with respinning the series for a few days?
> > > > I'll send out some of my patches then with a note which one of them
> > > > could be picked up by you and merged into this series.
> > > >
> > >
> >
>
> > > Any update on your patches?
> >
> > No worries. The patches are ready. But since Frank was on vacation I
> > decided to rebase all of my work on top of his series. I'll finish it
> > up shortly and send out my patchset till Monday for review. Then Frank
> > will be able to pick up two patches from there so to close up his
> > patchset (I'll give a note which one of them is of Frank' interes).
> > My series will be able to be merged in after Frank's series is reviewed
> > and accepted.
>
> Folks, couldn't make it this weekend. Too much sidework to do. Terribly
> sorry about that. Will send out the series tomorrow or at most in a day
> after tomorrow. Sorry for the inconvenience.

Any update on your patches?

best regards
Frank Li

>
> -Sergey
>
> >
> > >
> > > Btw, my colleage worked on merging the two dma devices used by the eDMA core
> > > for read & write channels into one. Initially I thought that was not needed as
> > > he did that for devicetree integration, but looking deeply I think that patch is
> > > necessary irrespective of DT.
> > >
> > > One standout problem is, we can't register debugfs directory under "dmaengine"
> > > properly because, both read and write dma devices share the same parent
> > > chip->dev.
> >
> > Right, my series fixes that and some other problems too. So please be
> > patient for a few more days.
> >
> > -Sergey
> >
> > >
> > > Thanks,
> > > Mani
> > >
> > > > -Sergey
> > > >
> > > > >
> > > > > Thanks,
> > > > > Mani
> > > > >
> > > > > > -Sergey
> > > > > >
> > > > > > >
> > > > > > > The commit from Alan Mikhak is what I took as a reference since the patch was
> > > > > > > already merged:
> > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > > > > > >
> > > > > > > Thanks,
> > > > > > > Mani
> > > > > > >
> > > > > > > > -Sergey
> > > > > > > >
> > > > > > > > > +                *
> > > > > > > > > +                ****************************************************************/
> > > > > > > > > +
> > > > > > > >
> > > > > > > > > +               if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > > > +                   (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > > > +                       read = true;
> > > > > > > >
> > > > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > > > redundant.
> > > > > > > >
> > > > > > > > > +
> > > > > > > > > +               /* Program the source and destination addresses for DMA read/write */
> > > > > > > > > +               if (read) {
> > > > > > > > >                         burst->sar = src_addr;
> > > > > > > > >                         if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > > > >                                 burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > > > --
> > > > > > > > > 2.24.0.rc1
> > > > > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-22 13:55                   ` Zhi Li
@ 2022-03-22 14:03                     ` Serge Semin
  2022-03-22 22:25                       ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2022-03-22 14:03 UTC (permalink / raw)
  To: Zhi Li
  Cc: Serge Semin, Manivannan Sadhasivam, Frank Li, gustavo.pimentel,
	hongxing.zhu, Lucas Stach, dl-linux-imx, linux-pci, dmaengine,
	vkoul, lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Tue, Mar 22, 2022 at 08:55:49AM -0500, Zhi Li wrote:
> On Sun, Mar 20, 2022 at 6:16 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> >
> > On Fri, Mar 18, 2022 at 09:19:13PM +0300, Serge Semin wrote:
> > > On Fri, Mar 18, 2022 at 11:36:05PM +0530, Manivannan Sadhasivam wrote:
> > > > On Mon, Mar 14, 2022 at 11:33:40AM +0300, Serge Semin wrote:
> > > > > On Sat, Mar 12, 2022 at 11:07:20AM +0530, Manivannan Sadhasivam wrote:
> > > > > > On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> > > > > > > On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> > > > >
> > > > > [nip]
> > > > >
> > > > > > >
> > > > > > > > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > > > > > > > access to it happens over PCIe bus or by the local CPU.
> > > > > > >
> > > > > > > Not fully correct. Root Ports can also have eDMA embedded. In that
> > > > > > > case the eDMA can be only accessible from the local CPU. At the same
> > > > > > > time the DW PCIe End-point case is the IP-core synthesize parameters
> > > > > > > specific. It's always possible to access the eDMA CSRs from local
> > > > > > > CPU, but a particular End-point BAR can be pre-synthesize to map
> > > > > > > either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> > > > > > > perform a full End-point configuration. Anyway the case if the eDMA
> > > > > > > functionality being accessible over the PCIe wire doesn't really make
> > > > > > > much sense with no info regarding the application logic hidden behind
> > > > > > > the PCIe End-point interface since SAR/DAR LLP is supposed to be
> > > > > > > initialized with an address from the local (application) memory space.
> > > > > > >
> > > > > >
> > > > > > Thanks for the explanation, it clarifies my doubt. I got misleaded by the
> > > > > > earlier commits...
> > > > > >
> > > > > > > So AFAICS the main usecase of the controller is 1) - when eDMA is a
> > > > > > > part of the Root Port/End-point and only local CPU is supposed to have
> > > > > > > it accessed and configured.
> > > > > > >
> > > > > > > I can resend this patch with my fix to the problem. What do you think?
> > > > > > >
> > > > > >
> > > > >
> > > > > > Yes, please do.
> > > > >
> > > > > Ok. I'll be AFK today, but will send my patches tomorrow.  @Frank,
> > > > > Could you please hold on with respinning the series for a few days?
> > > > > I'll send out some of my patches then with a note which one of them
> > > > > could be picked up by you and merged into this series.
> > > > >
> > > >
> > >
> >
> > > > Any update on your patches?
> > >
> > > No worries. The patches are ready. But since Frank was on vacation I
> > > decided to rebase all of my work on top of his series. I'll finish it
> > > up shortly and send out my patchset till Monday for review. Then Frank
> > > will be able to pick up two patches from there so to close up his
> > > patchset (I'll give a note which one of them is of Frank' interes).
> > > My series will be able to be merged in after Frank's series is reviewed
> > > and accepted.
> >
> > Folks, couldn't make it this weekend. Too much sidework to do. Terribly
> > sorry about that. Will send out the series tomorrow or at most in a day
> > after tomorrow. Sorry for the inconvenience.
> 

> Any update on your patches?

The patches are ready. Writing cover-letters and sending them out this
night. Sorry for the delay.

-Sergey

> 
> best regards
> Frank Li
> 
> >
> > -Sergey
> >
> > >
> > > >
> > > > Btw, my colleage worked on merging the two dma devices used by the eDMA core
> > > > for read & write channels into one. Initially I thought that was not needed as
> > > > he did that for devicetree integration, but looking deeply I think that patch is
> > > > necessary irrespective of DT.
> > > >
> > > > One standout problem is, we can't register debugfs directory under "dmaengine"
> > > > properly because, both read and write dma devices share the same parent
> > > > chip->dev.
> > >
> > > Right, my series fixes that and some other problems too. So please be
> > > patient for a few more days.
> > >
> > > -Sergey
> > >
> > > >
> > > > Thanks,
> > > > Mani
> > > >
> > > > > -Sergey
> > > > >
> > > > > >
> > > > > > Thanks,
> > > > > > Mani
> > > > > >
> > > > > > > -Sergey
> > > > > > >
> > > > > > > >
> > > > > > > > The commit from Alan Mikhak is what I took as a reference since the patch was
> > > > > > > > already merged:
> > > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > > > > > > >
> > > > > > > > Thanks,
> > > > > > > > Mani
> > > > > > > >
> > > > > > > > > -Sergey
> > > > > > > > >
> > > > > > > > > > +                *
> > > > > > > > > > +                ****************************************************************/
> > > > > > > > > > +
> > > > > > > > >
> > > > > > > > > > +               if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > > > > +                   (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > > > > +                       read = true;
> > > > > > > > >
> > > > > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > > > > redundant.
> > > > > > > > >
> > > > > > > > > > +
> > > > > > > > > > +               /* Program the source and destination addresses for DMA read/write */
> > > > > > > > > > +               if (read) {
> > > > > > > > > >                         burst->sar = src_addr;
> > > > > > > > > >                         if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > > > > >                                 burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > > > > --
> > > > > > > > > > 2.24.0.rc1
> > > > > > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
  2022-03-22 14:03                     ` Serge Semin
@ 2022-03-22 22:25                       ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2022-03-22 22:25 UTC (permalink / raw)
  To: Zhi Li
  Cc: Serge Semin, Manivannan Sadhasivam, Frank Li, gustavo.pimentel,
	hongxing.zhu, Lucas Stach, dl-linux-imx, linux-pci, dmaengine,
	vkoul, lorenzo.pieralisi, robh, kw, Bjorn Helgaas, Shawn Guo

On Tue, Mar 22, 2022 at 05:03:13PM +0300, Serge Semin wrote:
> On Tue, Mar 22, 2022 at 08:55:49AM -0500, Zhi Li wrote:
> > On Sun, Mar 20, 2022 at 6:16 PM Serge Semin <fancer.lancer@gmail.com> wrote:
> > >
> > > On Fri, Mar 18, 2022 at 09:19:13PM +0300, Serge Semin wrote:
> > > > On Fri, Mar 18, 2022 at 11:36:05PM +0530, Manivannan Sadhasivam wrote:
> > > > > On Mon, Mar 14, 2022 at 11:33:40AM +0300, Serge Semin wrote:
> > > > > > On Sat, Mar 12, 2022 at 11:07:20AM +0530, Manivannan Sadhasivam wrote:
> > > > > > > On Fri, Mar 11, 2022 at 10:01:47PM +0300, Serge Semin wrote:
> > > > > > > > On Fri, Mar 11, 2022 at 11:11:34PM +0530, Manivannan Sadhasivam wrote:
> > > > > >
> > > > > > [nip]
> > > > > >
> > > > > > > >
> > > > > > > > > As per my understanding, the eDMA is solely used in the PCIe endpoint. And the
> > > > > > > > > access to it happens over PCIe bus or by the local CPU.
> > > > > > > >
> > > > > > > > Not fully correct. Root Ports can also have eDMA embedded. In that
> > > > > > > > case the eDMA can be only accessible from the local CPU. At the same
> > > > > > > > time the DW PCIe End-point case is the IP-core synthesize parameters
> > > > > > > > specific. It's always possible to access the eDMA CSRs from local
> > > > > > > > CPU, but a particular End-point BAR can be pre-synthesize to map
> > > > > > > > either Port Logic, or eDMA or iATU CSRs. Thus a PCIe root port can
> > > > > > > > perform a full End-point configuration. Anyway the case if the eDMA
> > > > > > > > functionality being accessible over the PCIe wire doesn't really make
> > > > > > > > much sense with no info regarding the application logic hidden behind
> > > > > > > > the PCIe End-point interface since SAR/DAR LLP is supposed to be
> > > > > > > > initialized with an address from the local (application) memory space.
> > > > > > > >
> > > > > > >
> > > > > > > Thanks for the explanation, it clarifies my doubt. I got misleaded by the
> > > > > > > earlier commits...
> > > > > > >
> > > > > > > > So AFAICS the main usecase of the controller is 1) - when eDMA is a
> > > > > > > > part of the Root Port/End-point and only local CPU is supposed to have
> > > > > > > > it accessed and configured.
> > > > > > > >
> > > > > > > > I can resend this patch with my fix to the problem. What do you think?
> > > > > > > >
> > > > > > >
> > > > > >
> > > > > > > Yes, please do.
> > > > > >
> > > > > > Ok. I'll be AFK today, but will send my patches tomorrow.  @Frank,
> > > > > > Could you please hold on with respinning the series for a few days?
> > > > > > I'll send out some of my patches then with a note which one of them
> > > > > > could be picked up by you and merged into this series.
> > > > > >
> > > > >
> > > >
> > >
> > > > > Any update on your patches?
> > > >
> > > > No worries. The patches are ready. But since Frank was on vacation I
> > > > decided to rebase all of my work on top of his series. I'll finish it
> > > > up shortly and send out my patchset till Monday for review. Then Frank
> > > > will be able to pick up two patches from there so to close up his
> > > > patchset (I'll give a note which one of them is of Frank' interes).
> > > > My series will be able to be merged in after Frank's series is reviewed
> > > > and accepted.
> > >
> > > Folks, couldn't make it this weekend. Too much sidework to do. Terribly
> > > sorry about that. Will send out the series tomorrow or at most in a day
> > > after tomorrow. Sorry for the inconvenience.
> > 
> 

> > Any update on your patches?
> 
> The patches are ready. Writing cover-letters and sending them out this
> night. Sorry for the delay.

Ah, couldn't finish the letters this night. Will send it tomorrow at
midday. Sorry one more time.

-Sergey

> 
> -Sergey
> 
> > 
> > best regards
> > Frank Li
> > 
> > >
> > > -Sergey
> > >
> > > >
> > > > >
> > > > > Btw, my colleage worked on merging the two dma devices used by the eDMA core
> > > > > for read & write channels into one. Initially I thought that was not needed as
> > > > > he did that for devicetree integration, but looking deeply I think that patch is
> > > > > necessary irrespective of DT.
> > > > >
> > > > > One standout problem is, we can't register debugfs directory under "dmaengine"
> > > > > properly because, both read and write dma devices share the same parent
> > > > > chip->dev.
> > > >
> > > > Right, my series fixes that and some other problems too. So please be
> > > > patient for a few more days.
> > > >
> > > > -Sergey
> > > >
> > > > >
> > > > > Thanks,
> > > > > Mani
> > > > >
> > > > > > -Sergey
> > > > > >
> > > > > > >
> > > > > > > Thanks,
> > > > > > > Mani
> > > > > > >
> > > > > > > > -Sergey
> > > > > > > >
> > > > > > > > >
> > > > > > > > > The commit from Alan Mikhak is what I took as a reference since the patch was
> > > > > > > > > already merged:
> > > > > > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/dma/dw-edma?id=bd96f1b2f43a39310cc576bb4faf2ea24317a4c9
> > > > > > > > >
> > > > > > > > > Thanks,
> > > > > > > > > Mani
> > > > > > > > >
> > > > > > > > > > -Sergey
> > > > > > > > > >
> > > > > > > > > > > +                *
> > > > > > > > > > > +                ****************************************************************/
> > > > > > > > > > > +
> > > > > > > > > >
> > > > > > > > > > > +               if ((dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) ||
> > > > > > > > > > > +                   (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE))
> > > > > > > > > > > +                       read = true;
> > > > > > > > > >
> > > > > > > > > > Seeing the driver support only two directions DMA_DEV_TO_MEM/DMA_DEV_TO_MEM
> > > > > > > > > > and EDMA_DIR_READ/EDMA_DIR_WRITE, this conditional statement seems
> > > > > > > > > > redundant.
> > > > > > > > > >
> > > > > > > > > > > +
> > > > > > > > > > > +               /* Program the source and destination addresses for DMA read/write */
> > > > > > > > > > > +               if (read) {
> > > > > > > > > > >                         burst->sar = src_addr;
> > > > > > > > > > >                         if (xfer->type == EDMA_XFER_CYCLIC) {
> > > > > > > > > > >                                 burst->dar = xfer->xfer.cyclic.paddr;
> > > > > > > > > > > --
> > > > > > > > > > > 2.24.0.rc1
> > > > > > > > > > >

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2022-03-22 22:25 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-09 21:11 [PATCH v4 0/8] Enable designware PCI EP EDMA locally Frank Li
2022-03-09 21:11 ` [PATCH v4 1/8] dmaengine: dw-edma: Detach the private data and chip info structures Frank Li
2022-03-10 12:50   ` Serge Semin
2022-03-10 20:20   ` Serge Semin
2022-03-10 20:29     ` Zhi Li
2022-03-11 11:03       ` Serge Semin
2022-03-11 15:29         ` Zhi Li
2022-03-12 19:56           ` Serge Semin
2022-03-12 19:54   ` Serge Semin
2022-03-09 21:11 ` [PATCH v4 2/8] dmaengine: dw-edma: remove unused field irq in struct dw_edma_chip Frank Li
2022-03-10 12:52   ` Serge Semin
2022-03-09 21:11 ` [PATCH v4 3/8] dmaengine: dw-edma: change rg_region to reg_base " Frank Li
2022-03-10 12:56   ` Serge Semin
2022-03-09 21:12 ` [PATCH v4 4/8] dmaengine: dw-edma: rename wr(rd)_ch_cnt to ll_wr(rd)_cnt " Frank Li
2022-03-10 12:37   ` Serge Semin
2022-03-10 16:26     ` Zhi Li
2022-03-10 16:51       ` Zhi Li
2022-03-10 18:45         ` Serge Semin
2022-03-09 21:12 ` [PATCH v4 5/8] dmaengine: dw-edma: Fix programming the source & dest addresses for ep Frank Li
2022-03-10 16:31   ` Serge Semin
2022-03-10 16:50     ` Zhi Li
2022-03-10 19:37       ` Serge Semin
2022-03-10 20:16         ` Zhi Li
2022-03-11 12:38           ` Serge Semin
2022-03-11 15:37             ` Zhi Li
2022-03-11 16:03               ` Zhi Li
2022-03-11 17:14                 ` Serge Semin
2022-03-11 17:55             ` Manivannan Sadhasivam
2022-03-11 19:08               ` Serge Semin
2022-03-11 17:46         ` Manivannan Sadhasivam
2022-03-11 17:41     ` Manivannan Sadhasivam
2022-03-11 19:01       ` Serge Semin
2022-03-12  5:37         ` Manivannan Sadhasivam
2022-03-14  8:33           ` Serge Semin
2022-03-18 18:06             ` Manivannan Sadhasivam
2022-03-18 18:19               ` Serge Semin
2022-03-20 23:16                 ` Serge Semin
2022-03-22 13:55                   ` Zhi Li
2022-03-22 14:03                     ` Serge Semin
2022-03-22 22:25                       ` Serge Semin
2022-03-09 21:12 ` [PATCH v4 6/8] dmaengine: dw-edma: Don't rely on the deprecated "direction" member Frank Li
2022-03-10 17:29   ` Serge Semin
2022-03-10 17:41     ` Manivannan Sadhasivam
2022-03-10 17:52       ` Serge Semin
2022-03-11 17:58         ` Manivannan Sadhasivam
2022-03-09 21:12 ` [PATCH v4 7/8] dmaengine: dw-edma: add flags at struct dw_edma_chip Frank Li
2022-03-10  1:07   ` kernel test robot
2022-03-10  1:07   ` kernel test robot
2022-03-10 17:46   ` Serge Semin
2022-03-10 17:54     ` Zhi Li
2022-03-10 18:25       ` Serge Semin
2022-03-09 21:12 ` [PATCH v4 8/8] PCI: endpoint: functions/pci-epf-test: Support PCI controller DMA Frank Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).